summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/aoa/codecs/Makefile4
-rw-r--r--sound/aoa/codecs/onyx.c (renamed from sound/aoa/codecs/snd-aoa-codec-onyx.c)12
-rw-r--r--sound/aoa/codecs/onyx.h (renamed from sound/aoa/codecs/snd-aoa-codec-onyx.h)0
-rw-r--r--sound/aoa/codecs/tas-basstreble.h (renamed from sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h)0
-rw-r--r--sound/aoa/codecs/tas-gain-table.h (renamed from sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h)0
-rw-r--r--sound/aoa/codecs/tas.c (renamed from sound/aoa/codecs/snd-aoa-codec-tas.c)8
-rw-r--r--sound/aoa/codecs/tas.h (renamed from sound/aoa/codecs/snd-aoa-codec-tas.h)0
-rw-r--r--sound/aoa/codecs/toonie.c (renamed from sound/aoa/codecs/snd-aoa-codec-toonie.c)2
-rw-r--r--sound/aoa/core/Makefile8
-rw-r--r--sound/aoa/core/alsa.c (renamed from sound/aoa/core/snd-aoa-alsa.c)4
-rw-r--r--sound/aoa/core/alsa.h (renamed from sound/aoa/core/snd-aoa-alsa.h)0
-rw-r--r--sound/aoa/core/core.c (renamed from sound/aoa/core/snd-aoa-core.c)2
-rw-r--r--sound/aoa/core/gpio-feature.c (renamed from sound/aoa/core/snd-aoa-gpio-feature.c)2
-rw-r--r--sound/aoa/core/gpio-pmf.c (renamed from sound/aoa/core/snd-aoa-gpio-pmf.c)0
-rw-r--r--sound/aoa/fabrics/Makefile2
-rw-r--r--sound/aoa/fabrics/layout.c (renamed from sound/aoa/fabrics/snd-aoa-fabric-layout.c)2
-rw-r--r--sound/aoa/soundbus/i2sbus/Makefile2
-rw-r--r--sound/aoa/soundbus/i2sbus/control.c (renamed from sound/aoa/soundbus/i2sbus/i2sbus-control.c)0
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c (renamed from sound/aoa/soundbus/i2sbus/i2sbus-core.c)4
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h2
-rw-r--r--sound/aoa/soundbus/i2sbus/interface.h (renamed from sound/aoa/soundbus/i2sbus/i2sbus-interface.h)0
-rw-r--r--sound/aoa/soundbus/i2sbus/pcm.c (renamed from sound/aoa/soundbus/i2sbus/i2sbus-pcm.c)0
-rw-r--r--sound/core/Kconfig21
-rw-r--r--sound/core/Makefile2
-rw-r--r--sound/core/device.c4
-rw-r--r--sound/core/hrtimer.c140
-rw-r--r--sound/core/info.c17
-rw-r--r--sound/core/init.c71
-rw-r--r--sound/core/jack.c9
-rw-r--r--sound/core/seq/seq.c4
-rw-r--r--sound/drivers/Kconfig2
-rw-r--r--sound/drivers/pcsp/pcsp.c8
-rw-r--r--sound/drivers/pcsp/pcsp.h3
-rw-r--r--sound/drivers/pcsp/pcsp_lib.c168
-rw-r--r--sound/pci/Kconfig127
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c2
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c5
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c494
-rw-r--r--sound/pci/hda/Kconfig138
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_codec.c594
-rw-r--r--sound/pci/hda/hda_codec.h79
-rw-r--r--sound/pci/hda/hda_eld.c590
-rw-r--r--sound/pci/hda/hda_generic.c20
-rw-r--r--sound/pci/hda/hda_hwdep.c232
-rw-r--r--sound/pci/hda/hda_intel.c330
-rw-r--r--sound/pci/hda/hda_local.h100
-rw-r--r--sound/pci/hda/hda_patch.h2
-rw-r--r--sound/pci/hda/hda_proc.c91
-rw-r--r--sound/pci/hda/patch_analog.c105
-rw-r--r--sound/pci/hda/patch_atihdmi.c1
-rw-r--r--sound/pci/hda/patch_conexant.c11
-rw-r--r--sound/pci/hda/patch_intelhdmi.c685
-rw-r--r--sound/pci/hda/patch_nvhdmi.c1
-rw-r--r--sound/pci/hda/patch_realtek.c1637
-rw-r--r--sound/pci/hda/patch_sigmatel.c703
-rw-r--r--sound/pci/hda/patch_via.c73
-rw-r--r--sound/pci/ice1712/ice1724.c23
-rw-r--r--sound/pci/mixart/mixart.c4
-rw-r--r--sound/pci/oxygen/oxygen.c4
-rw-r--r--sound/pci/pcxhr/Makefile2
-rw-r--r--sound/pci/pcxhr/pcxhr.c556
-rw-r--r--sound/pci/pcxhr/pcxhr.h76
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c291
-rw-r--r--sound/pci/pcxhr/pcxhr_core.h5
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c158
-rw-r--r--sound/pci/pcxhr/pcxhr_mix22.c820
-rw-r--r--sound/pci/pcxhr/pcxhr_mix22.h56
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c556
-rw-r--r--sound/pci/rme9652/hdsp.c2
-rw-r--r--sound/pci/rme9652/hdspm.c2
-rw-r--r--sound/ppc/pmac.c2
-rw-r--r--sound/ppc/tumbler.c3
-rw-r--r--sound/usb/caiaq/caiaq-control.c73
-rw-r--r--sound/usb/caiaq/caiaq-device.c2
76 files changed, 6643 insertions, 2519 deletions
diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile
index 31cbe68fd42f..c3ee77fc4b2d 100644
--- a/sound/aoa/codecs/Makefile
+++ b/sound/aoa/codecs/Makefile
@@ -1,3 +1,7 @@
+snd-aoa-codec-onyx-objs := onyx.o
+snd-aoa-codec-tas-objs := tas.o
+snd-aoa-codec-toonie-objs := toonie.o
+
obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o
obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o
obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/onyx.c
index 6a3837d480e5..15500b9d2da0 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -37,7 +37,7 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
-#include "snd-aoa-codec-onyx.h"
+#include "onyx.h"
#include "../aoa.h"
#include "../soundbus/soundbus.h"
@@ -292,7 +292,7 @@ static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new capture_source_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* If we name this 'Input Source', it properly shows up in
- * alsamixer as a selection, * but it's shown under the
+ * alsamixer as a selection, * but it's shown under the
* 'Playback' category.
* If I name it 'Capture Source', it shows up in strange
* ways (two bools of which one can be selected at a
@@ -477,7 +477,7 @@ static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol,
ucontrol->value.iec958.status[3] = 0x3f;
ucontrol->value.iec958.status[4] = 0x0f;
-
+
return 0;
}
@@ -682,7 +682,7 @@ static int onyx_usable(struct codec_info_item *cii,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
- analog_enabled =
+ analog_enabled =
(v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
!= (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
mutex_unlock(&onyx->mutex);
@@ -882,7 +882,7 @@ static int onyx_init_codec(struct aoa_codec *codec)
msleep(1);
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
msleep(1);
-
+
if (onyx_register_init(onyx)) {
printk(KERN_ERR PFX "failed to initialise onyx registers\n");
return -ENODEV;
@@ -1069,7 +1069,7 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter)
/* if that didn't work, try desperate mode for older
* machines that have stuff missing from the device tree */
-
+
if (!of_device_is_compatible(busnode, "k2-i2c"))
return -ENODEV;
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/onyx.h
index ffd20254ff76..ffd20254ff76 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.h
+++ b/sound/aoa/codecs/onyx.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h b/sound/aoa/codecs/tas-basstreble.h
index 69b61136fd54..69b61136fd54 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h
+++ b/sound/aoa/codecs/tas-basstreble.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h b/sound/aoa/codecs/tas-gain-table.h
index 4cfa6757715e..4cfa6757715e 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h
+++ b/sound/aoa/codecs/tas-gain-table.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/tas.c
index 6c515b2b8bbd..008e0f85097d 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -71,9 +71,9 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("tas codec driver for snd-aoa");
-#include "snd-aoa-codec-tas.h"
-#include "snd-aoa-codec-tas-gain-table.h"
-#include "snd-aoa-codec-tas-basstreble.h"
+#include "tas.h"
+#include "tas-gain-table.h"
+#include "tas-basstreble.h"
#include "../aoa.h"
#include "../soundbus/soundbus.h"
@@ -880,7 +880,7 @@ static void tas_exit_codec(struct aoa_codec *codec)
return;
tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
}
-
+
static struct i2c_driver tas_driver;
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/tas.h
index ae177e3466e6..ae177e3466e6 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.h
+++ b/sound/aoa/codecs/tas.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-toonie.c b/sound/aoa/codecs/toonie.c
index 3c7d1d8a9a6f..f13827e17562 100644
--- a/sound/aoa/codecs/snd-aoa-codec-toonie.c
+++ b/sound/aoa/codecs/toonie.c
@@ -131,7 +131,7 @@ static int __init toonie_init(void)
toonie->codec.owner = THIS_MODULE;
toonie->codec.init = toonie_init_codec;
toonie->codec.exit = toonie_exit_codec;
-
+
if (aoa_codec_register(&toonie->codec)) {
kfree(toonie);
return -EINVAL;
diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile
index 62dc7287f663..a1596e88c718 100644
--- a/sound/aoa/core/Makefile
+++ b/sound/aoa/core/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_SND_AOA) += snd-aoa.o
-snd-aoa-objs := snd-aoa-core.o \
- snd-aoa-alsa.o \
- snd-aoa-gpio-pmf.o \
- snd-aoa-gpio-feature.o
+snd-aoa-objs := core.o \
+ alsa.o \
+ gpio-pmf.o \
+ gpio-feature.o
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/alsa.c
index 17fe689ed287..617850463582 100644
--- a/sound/aoa/core/snd-aoa-alsa.c
+++ b/sound/aoa/core/alsa.c
@@ -6,7 +6,7 @@
* GPL v2, can be found in COPYING.
*/
#include <linux/module.h>
-#include "snd-aoa-alsa.h"
+#include "alsa.h"
static int index = -1;
module_param(index, int, 0444);
@@ -64,7 +64,7 @@ int aoa_snd_device_new(snd_device_type_t type,
{
struct snd_card *card = aoa_get_card();
int err;
-
+
if (!card) return -ENOMEM;
err = snd_device_new(card, type, device_data, ops);
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/alsa.h
index 9669e4489cab..9669e4489cab 100644
--- a/sound/aoa/core/snd-aoa-alsa.h
+++ b/sound/aoa/core/alsa.h
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/core.c
index 19fdae400687..10bec6c61382 100644
--- a/sound/aoa/core/snd-aoa-core.c
+++ b/sound/aoa/core/core.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/list.h>
#include "../aoa.h"
-#include "snd-aoa-alsa.h"
+#include "alsa.h"
MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/gpio-feature.c
index 805dcbff2257..c93ad5dec66b 100644
--- a/sound/aoa/core/snd-aoa-gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -5,7 +5,7 @@
*
* GPL v2, can be found in COPYING.
*
- * This file contains the GPIO control routines for
+ * This file contains the GPIO control routines for
* direct (through feature calls) access to the GPIO
* registers.
*/
diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/gpio-pmf.c
index 5ca2220eac7d..5ca2220eac7d 100644
--- a/sound/aoa/core/snd-aoa-gpio-pmf.c
+++ b/sound/aoa/core/gpio-pmf.c
diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile
index 55fc5e7e52cf..da37c10eca51 100644
--- a/sound/aoa/fabrics/Makefile
+++ b/sound/aoa/fabrics/Makefile
@@ -1 +1,3 @@
+snd-aoa-fabric-layout-objs += layout.o
+
obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/layout.c
index dea7abb082cd..ad60f5d10e82 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -66,7 +66,7 @@ struct layout {
unsigned int layout_id;
struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
int flags;
-
+
/* if busname is not assigned, we use 'Master' below,
* so that our layout table doesn't need to be filled
* too much.
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile
index e57a5cf65655..1b949b2a4028 100644
--- a/sound/aoa/soundbus/i2sbus/Makefile
+++ b/sound/aoa/soundbus/i2sbus/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o
-snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o
+snd-aoa-i2sbus-objs := core.o pcm.o control.o
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/control.c
index 87beb4ad4d63..87beb4ad4d63 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-control.c
+++ b/sound/aoa/soundbus/i2sbus/control.c
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/core.c
index b4590df07466..be468edf3ecb 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -64,7 +64,7 @@ static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
struct dbdma_command_mem *r)
{
if (!r->space) return;
-
+
dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev,
r->size, r->space, r->bus_addr);
}
@@ -247,7 +247,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
* but request_resource doesn't know about parents and
* contained resources...
*/
- dev->allocated_resource[i] =
+ dev->allocated_resource[i] =
request_mem_region(dev->resources[i].start,
dev->resources[i].end -
dev->resources[i].start + 1,
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index ff29654782c9..befefd99e271 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -18,7 +18,7 @@
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
-#include "i2sbus-interface.h"
+#include "interface.h"
#include "../soundbus.h"
struct i2sbus_control {
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/interface.h
index c6b5f5452d20..c6b5f5452d20 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h
+++ b/sound/aoa/soundbus/i2sbus/interface.h
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index 59bacd365733..59bacd365733 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 66348c92f88d..7bbdda041a99 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -95,6 +95,26 @@ config SND_SEQUENCER_OSS
this will be compiled as a module. The module will be called
snd-seq-oss.
+config SND_HRTIMER
+ tristate "HR-timer backend support"
+ depends on HIGH_RES_TIMERS
+ select SND_TIMER
+ help
+ Say Y here to enable HR-timer backend for ALSA timer. ALSA uses
+ the hrtimer as a precise timing source. The ALSA sequencer code
+ also can use this timing source.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hrtimer.
+
+config SND_SEQ_HRTIMER_DEFAULT
+ bool "Use HR-timer as default sequencer timer"
+ depends on SND_HRTIMER && SND_SEQUENCER
+ default y
+ help
+ Say Y here to use the HR-timer backend as the default sequencer
+ timer.
+
config SND_RTCTIMER
tristate "RTC Timer support"
depends on RTC
@@ -114,6 +134,7 @@ config SND_RTCTIMER
config SND_SEQ_RTCTIMER_DEFAULT
bool "Use RTC as default sequencer timer"
depends on SND_RTCTIMER && SND_SEQUENCER
+ depends on !SND_SEQ_HRTIMER_DEFAULT
default y
help
Say Y here to use the RTC timer as the default sequencer
diff --git a/sound/core/Makefile b/sound/core/Makefile
index d57125a5687d..4229052e7b91 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -17,12 +17,14 @@ snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o
snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
+snd-hrtimer-objs := hrtimer.o
snd-rtctimer-objs := rtctimer.o
snd-hwdep-objs := hwdep.o
obj-$(CONFIG_SND) += snd.o
obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
obj-$(CONFIG_SND_TIMER) += snd-timer.o
+obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
diff --git a/sound/core/device.c b/sound/core/device.c
index c58d8227254c..a67dfac08c03 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -98,7 +98,7 @@ int snd_device_free(struct snd_card *card, void *device_data)
kfree(dev);
return 0;
}
- snd_printd("device free %p (from %p), not found\n", device_data,
+ snd_printd("device free %p (from %pF), not found\n", device_data,
__builtin_return_address(0));
return -ENXIO;
}
@@ -135,7 +135,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
}
return 0;
}
- snd_printd("device disconnect %p (from %p), not found\n", device_data,
+ snd_printd("device disconnect %p (from %pF), not found\n", device_data,
__builtin_return_address(0));
return -ENXIO;
}
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
new file mode 100644
index 000000000000..b712d7f211ff
--- /dev/null
+++ b/sound/core/hrtimer.c
@@ -0,0 +1,140 @@
+/*
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/hrtimer.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("ALSA hrtimer backend");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
+
+#define NANO_SEC 1000000000UL /* 10^9 in sec */
+static unsigned int resolution;
+
+struct snd_hrtimer {
+ struct snd_timer *timer;
+ struct hrtimer hrt;
+};
+
+static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
+ struct snd_timer *t = stime->timer;
+ hrtimer_forward_now(hrt, ktime_set(0, t->sticks * resolution));
+ snd_timer_interrupt(stime->timer, t->sticks);
+ return HRTIMER_RESTART;
+}
+
+static int snd_hrtimer_open(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime;
+
+ stime = kmalloc(sizeof(*stime), GFP_KERNEL);
+ if (!stime)
+ return -ENOMEM;
+ hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ stime->timer = t;
+ stime->hrt.cb_mode = HRTIMER_CB_SOFTIRQ;
+ stime->hrt.function = snd_hrtimer_callback;
+ t->private_data = stime;
+ return 0;
+}
+
+static int snd_hrtimer_close(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime = t->private_data;
+
+ if (stime) {
+ hrtimer_cancel(&stime->hrt);
+ kfree(stime);
+ t->private_data = NULL;
+ }
+ return 0;
+}
+
+static int snd_hrtimer_start(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime = t->private_data;
+
+ hrtimer_start(&stime->hrt, ktime_set(0, t->sticks * resolution),
+ HRTIMER_MODE_REL);
+ return 0;
+}
+
+static int snd_hrtimer_stop(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime = t->private_data;
+
+ hrtimer_cancel(&stime->hrt);
+ return 0;
+}
+
+static struct snd_timer_hardware hrtimer_hw = {
+ .flags = (SNDRV_TIMER_HW_AUTO |
+ /*SNDRV_TIMER_HW_FIRST |*/
+ SNDRV_TIMER_HW_TASKLET),
+ .open = snd_hrtimer_open,
+ .close = snd_hrtimer_close,
+ .start = snd_hrtimer_start,
+ .stop = snd_hrtimer_stop,
+};
+
+/*
+ * entry functions
+ */
+
+static struct snd_timer *mytimer;
+
+static int __init snd_hrtimer_init(void)
+{
+ struct snd_timer *timer;
+ struct timespec tp;
+ int err;
+
+ hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+ if (tp.tv_sec > 0 || !tp.tv_nsec) {
+ snd_printk(KERN_ERR
+ "snd-hrtimer: Invalid resolution %u.%09u",
+ (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
+ return -EINVAL;
+ }
+ resolution = tp.tv_nsec;
+
+ /* Create a new timer and set up the fields */
+ err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
+ &timer);
+ if (err < 0)
+ return err;
+
+ timer->module = THIS_MODULE;
+ strcpy(timer->name, "HR timer");
+ timer->hw = hrtimer_hw;
+ timer->hw.resolution = resolution;
+ timer->hw.ticks = NANO_SEC / resolution;
+
+ err = snd_timer_global_register(timer);
+ if (err < 0) {
+ snd_timer_global_free(timer);
+ return err;
+ }
+ mytimer = timer; /* remember this */
+
+ return 0;
+}
+
+static void __exit snd_hrtimer_exit(void)
+{
+ if (mytimer) {
+ snd_timer_global_free(mytimer);
+ mytimer = NULL;
+ }
+}
+
+module_init(snd_hrtimer_init);
+module_exit(snd_hrtimer_exit);
diff --git a/sound/core/info.c b/sound/core/info.c
index 527b207462b0..70fa87189f36 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -653,6 +653,23 @@ int snd_info_card_register(struct snd_card *card)
}
/*
+ * called on card->id change
+ */
+void snd_info_card_id_change(struct snd_card *card)
+{
+ mutex_lock(&info_mutex);
+ if (card->proc_root_link) {
+ snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
+ card->proc_root_link = NULL;
+ }
+ if (strcmp(card->id, card->proc_root->name))
+ card->proc_root_link = proc_symlink(card->id,
+ snd_proc_root,
+ card->proc_root->name);
+ mutex_unlock(&info_mutex);
+}
+
+/*
* de-register the card proc file
* called from init.c
*/
diff --git a/sound/core/init.c b/sound/core/init.c
index b47ff8b44be8..0d5520c415d3 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -533,6 +533,65 @@ static void choose_default_id(struct snd_card *card)
}
}
+#ifndef CONFIG_SYSFS_DEPRECATED
+static ssize_t
+card_id_show_attr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)");
+}
+
+static ssize_t
+card_id_store_attr(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ char buf1[sizeof(card->id)];
+ size_t copy = count > sizeof(card->id) - 1 ?
+ sizeof(card->id) - 1 : count;
+ size_t idx;
+ int c;
+
+ for (idx = 0; idx < copy; idx++) {
+ c = buf[idx];
+ if (!isalnum(c) && c != '_' && c != '-')
+ return -EINVAL;
+ }
+ memcpy(buf1, buf, copy);
+ buf1[copy] = '\0';
+ mutex_lock(&snd_card_mutex);
+ if (!snd_info_check_reserved_words(buf1)) {
+ __exist:
+ mutex_unlock(&snd_card_mutex);
+ return -EEXIST;
+ }
+ for (idx = 0; idx < snd_ecards_limit; idx++) {
+ if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
+ goto __exist;
+ }
+ strcpy(card->id, buf1);
+ snd_info_card_id_change(card);
+ mutex_unlock(&snd_card_mutex);
+
+ return count;
+}
+
+static struct device_attribute card_id_attrs =
+ __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
+
+static ssize_t
+card_number_show_attr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1);
+}
+
+static struct device_attribute card_number_attrs =
+ __ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+#endif /* CONFIG_SYSFS_DEPRECATED */
+
/**
* snd_card_register - register the soundcard
* @card: soundcard structure
@@ -553,7 +612,7 @@ int snd_card_register(struct snd_card *card)
#ifndef CONFIG_SYSFS_DEPRECATED
if (!card->card_dev) {
card->card_dev = device_create(sound_class, card->dev,
- MKDEV(0, 0), NULL,
+ MKDEV(0, 0), card,
"card%i", card->number);
if (IS_ERR(card->card_dev))
card->card_dev = NULL;
@@ -576,6 +635,16 @@ int snd_card_register(struct snd_card *card)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
+#ifndef CONFIG_SYSFS_DEPRECATED
+ if (card->card_dev) {
+ err = device_create_file(card->card_dev, &card_id_attrs);
+ if (err < 0)
+ return err;
+ err = device_create_file(card->card_dev, &card_number_attrs);
+ if (err < 0)
+ return err;
+ }
+#endif
return 0;
}
diff --git a/sound/core/jack.c b/sound/core/jack.c
index bd2d9e6b55e9..284432f427f4 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device)
else
input_free_device(jack->input_dev);
+ kfree(jack->id);
kfree(jack);
return 0;
@@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
if (jack == NULL)
return -ENOMEM;
- jack->id = id;
+ jack->id = kstrdup(id, GFP_KERNEL);
jack->input_dev = input_allocate_device();
if (jack->input_dev == NULL) {
@@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
if (type & SND_JACK_HEADPHONE)
input_set_capability(jack->input_dev, EV_SW,
SW_HEADPHONE_INSERT);
+ if (type & SND_JACK_LINEOUT)
+ input_set_capability(jack->input_dev, EV_SW,
+ SW_LINEOUT_INSERT);
if (type & SND_JACK_MICROPHONE)
input_set_capability(jack->input_dev, EV_SW,
SW_MICROPHONE_INSERT);
@@ -153,6 +157,9 @@ void snd_jack_report(struct snd_jack *jack, int status)
if (jack->type & SND_JACK_HEADPHONE)
input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
status & SND_JACK_HEADPHONE);
+ if (jack->type & SND_JACK_LINEOUT)
+ input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
+ status & SND_JACK_LINEOUT);
if (jack->type & SND_JACK_MICROPHONE)
input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
status & SND_JACK_MICROPHONE);
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index ee0f8405ab35..bf09a5ad1865 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -43,7 +43,9 @@ int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL;
int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
int seq_default_timer_card = -1;
int seq_default_timer_device =
-#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT
+#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT
+ SNDRV_TIMER_GLOBAL_HRTIMER
+#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT)
SNDRV_TIMER_GLOBAL_RTC
#else
SNDRV_TIMER_GLOBAL_SYSTEM
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 255fd18b9aec..0bcf14640fde 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -163,7 +163,7 @@ config SND_ML403_AC97CR
config SND_AC97_POWER_SAVE
bool "AC97 Power-Saving Mode"
- depends on SND_AC97_CODEC && EXPERIMENTAL
+ depends on SND_AC97_CODEC
default n
help
Say Y here to enable the aggressive power-saving support of
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 1899cf0685bc..2a02f704f366 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
return -EINVAL;
hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ;
+ pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
pcsp_chip.timer.function = pcsp_do_timer;
card = snd_card_new(index, id, THIS_MODULE, 0);
@@ -188,10 +188,8 @@ static int __devexit pcsp_remove(struct platform_device *dev)
static void pcsp_stop_beep(struct snd_pcsp *chip)
{
- spin_lock_irq(&chip->substream_lock);
- if (!chip->playback_substream)
- pcspkr_stop_sound();
- spin_unlock_irq(&chip->substream_lock);
+ pcsp_sync_stop(chip);
+ pcspkr_stop_sound();
}
#ifdef CONFIG_PM
diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h
index 1d661f795e8c..cdef2664218f 100644
--- a/sound/drivers/pcsp/pcsp.h
+++ b/sound/drivers/pcsp/pcsp.h
@@ -62,6 +62,8 @@ struct snd_pcsp {
unsigned short port, irq, dma;
spinlock_t substream_lock;
struct snd_pcm_substream *playback_substream;
+ unsigned int fmt_size;
+ unsigned int is_signed;
size_t playback_ptr;
size_t period_ptr;
atomic_t timer_active;
@@ -77,6 +79,7 @@ struct snd_pcsp {
extern struct snd_pcsp pcsp_chip;
extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle);
+extern void pcsp_sync_stop(struct snd_pcsp *chip);
extern int snd_pcsp_new_pcm(struct snd_pcsp *chip);
extern int snd_pcsp_new_mixer(struct snd_pcsp *chip);
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 1f42e4063118..84cc2658c05b 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
#include <sound/pcm.h>
#include <asm/io.h>
#include "pcsp.h"
@@ -19,61 +20,57 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
#define DMIX_WANTS_S16 1
-enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+/*
+ * Call snd_pcm_period_elapsed in a tasklet
+ * This avoids spinlock messes and long-running irq contexts
+ */
+static void pcsp_call_pcm_elapsed(unsigned long priv)
+{
+ if (atomic_read(&pcsp_chip.timer_active)) {
+ struct snd_pcm_substream *substream;
+ substream = pcsp_chip.playback_substream;
+ if (substream)
+ snd_pcm_period_elapsed(substream);
+ }
+}
+
+static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0);
+
+/* write the port and returns the next expire time in ns;
+ * called at the trigger-start and in hrtimer callback
+ */
+static unsigned long pcsp_timer_update(struct hrtimer *handle)
{
unsigned char timer_cnt, val;
- int fmt_size, periods_elapsed;
u64 ns;
- size_t period_bytes, buffer_bytes;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+ unsigned long flags;
if (chip->thalf) {
outb(chip->val61, 0x61);
chip->thalf = 0;
if (!atomic_read(&chip->timer_active))
- return HRTIMER_NORESTART;
- hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer),
- ktime_set(0, chip->ns_rem));
- return HRTIMER_RESTART;
+ return 0;
+ return chip->ns_rem;
}
- spin_lock_irq(&chip->substream_lock);
- /* Takashi Iwai says regarding this extra lock:
-
- If the irq handler handles some data on the DMA buffer, it should
- do snd_pcm_stream_lock().
- That protects basically against all races among PCM callbacks, yes.
- However, there are two remaining issues:
- 1. The substream pointer you try to lock isn't protected _before_
- this lock yet.
- 2. snd_pcm_period_elapsed() itself acquires the lock.
- The requirement of another lock is because of 1. When you get
- chip->playback_substream, it's not protected.
- Keeping this lock while snd_pcm_period_elapsed() assures the substream
- is still protected (at least, not released). And the other status is
- handled properly inside snd_pcm_stream_lock() in
- snd_pcm_period_elapsed().
-
- */
- if (!chip->playback_substream)
- goto exit_nr_unlock1;
- substream = chip->playback_substream;
- snd_pcm_stream_lock(substream);
if (!atomic_read(&chip->timer_active))
- goto exit_nr_unlock2;
+ return 0;
+ substream = chip->playback_substream;
+ if (!substream)
+ return 0;
runtime = substream->runtime;
- fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3;
/* assume it is mono! */
- val = runtime->dma_area[chip->playback_ptr + fmt_size - 1];
- if (snd_pcm_format_signed(runtime->format))
+ val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1];
+ if (chip->is_signed)
val ^= 0x80;
timer_cnt = val * CUR_DIV() / 256;
if (timer_cnt && chip->enable) {
- spin_lock(&i8253_lock);
+ spin_lock_irqsave(&i8253_lock, flags);
if (!nforce_wa) {
outb_p(chip->val61, 0x61);
outb_p(timer_cnt, 0x42);
@@ -82,12 +79,39 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
outb(chip->val61 ^ 2, 0x61);
chip->thalf = 1;
}
- spin_unlock(&i8253_lock);
+ spin_unlock_irqrestore(&i8253_lock, flags);
}
+ chip->ns_rem = PCSP_PERIOD_NS();
+ ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
+ chip->ns_rem -= ns;
+ return ns;
+}
+
+enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+{
+ struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+ struct snd_pcm_substream *substream;
+ int periods_elapsed, pointer_update;
+ size_t period_bytes, buffer_bytes;
+ unsigned long ns;
+ unsigned long flags;
+
+ pointer_update = !chip->thalf;
+ ns = pcsp_timer_update(handle);
+ if (!ns)
+ return HRTIMER_NORESTART;
+
+ /* update the playback position */
+ substream = chip->playback_substream;
+ if (!substream)
+ return HRTIMER_NORESTART;
+
period_bytes = snd_pcm_lib_period_bytes(substream);
buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
- chip->playback_ptr += PCSP_INDEX_INC() * fmt_size;
+
+ spin_lock_irqsave(&chip->substream_lock, flags);
+ chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size;
periods_elapsed = chip->playback_ptr - chip->period_ptr;
if (periods_elapsed < 0) {
#if PCSP_DEBUG
@@ -102,41 +126,30 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
* or ALSA will BUG on us. */
chip->playback_ptr %= buffer_bytes;
- snd_pcm_stream_unlock(substream);
-
if (periods_elapsed) {
- snd_pcm_period_elapsed(substream);
chip->period_ptr += periods_elapsed * period_bytes;
chip->period_ptr %= buffer_bytes;
}
+ spin_unlock_irqrestore(&chip->substream_lock, flags);
- spin_unlock_irq(&chip->substream_lock);
+ if (periods_elapsed)
+ tasklet_schedule(&pcsp_pcm_tasklet);
- if (!atomic_read(&chip->timer_active))
- return HRTIMER_NORESTART;
+ hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns));
- chip->ns_rem = PCSP_PERIOD_NS();
- ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
- chip->ns_rem -= ns;
- hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer),
- ktime_set(0, ns));
return HRTIMER_RESTART;
-
-exit_nr_unlock2:
- snd_pcm_stream_unlock(substream);
-exit_nr_unlock1:
- spin_unlock_irq(&chip->substream_lock);
- return HRTIMER_NORESTART;
}
-static void pcsp_start_playing(struct snd_pcsp *chip)
+static int pcsp_start_playing(struct snd_pcsp *chip)
{
+ unsigned long ns;
+
#if PCSP_DEBUG
printk(KERN_INFO "PCSP: start_playing called\n");
#endif
if (atomic_read(&chip->timer_active)) {
printk(KERN_ERR "PCSP: Timer already active\n");
- return;
+ return -EIO;
}
spin_lock(&i8253_lock);
@@ -146,7 +159,12 @@ static void pcsp_start_playing(struct snd_pcsp *chip)
atomic_set(&chip->timer_active, 1);
chip->thalf = 0;
- hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
+ ns = pcsp_timer_update(&pcsp_chip.timer);
+ if (!ns)
+ return -EIO;
+
+ hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL);
+ return 0;
}
static void pcsp_stop_playing(struct snd_pcsp *chip)
@@ -165,26 +183,35 @@ static void pcsp_stop_playing(struct snd_pcsp *chip)
spin_unlock(&i8253_lock);
}
+/*
+ * Force to stop and sync the stream
+ */
+void pcsp_sync_stop(struct snd_pcsp *chip)
+{
+ local_irq_disable();
+ pcsp_stop_playing(chip);
+ local_irq_enable();
+ hrtimer_cancel(&chip->timer);
+ tasklet_kill(&pcsp_pcm_tasklet);
+}
+
static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
{
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
#if PCSP_DEBUG
printk(KERN_INFO "PCSP: close called\n");
#endif
- if (atomic_read(&chip->timer_active)) {
- printk(KERN_ERR "PCSP: timer still active\n");
- pcsp_stop_playing(chip);
- }
- spin_lock_irq(&chip->substream_lock);
+ pcsp_sync_stop(chip);
chip->playback_substream = NULL;
- spin_unlock_irq(&chip->substream_lock);
return 0;
}
static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
+ struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
int err;
+ pcsp_sync_stop(chip);
err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (err < 0)
@@ -194,9 +221,11 @@ static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
{
+ struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
#if PCSP_DEBUG
printk(KERN_INFO "PCSP: hw_free called\n");
#endif
+ pcsp_sync_stop(chip);
return snd_pcm_lib_free_pages(substream);
}
@@ -212,8 +241,12 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
snd_pcm_lib_period_bytes(substream),
substream->runtime->periods);
#endif
+ pcsp_sync_stop(chip);
chip->playback_ptr = 0;
chip->period_ptr = 0;
+ chip->fmt_size =
+ snd_pcm_format_physical_width(substream->runtime->format) >> 3;
+ chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
return 0;
}
@@ -226,8 +259,7 @@ static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
- pcsp_start_playing(chip);
- break;
+ return pcsp_start_playing(chip);
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
pcsp_stop_playing(chip);
@@ -242,7 +274,11 @@ static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream
*substream)
{
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
- return bytes_to_frames(substream->runtime, chip->playback_ptr);
+ unsigned int pos;
+ spin_lock(&chip->substream_lock);
+ pos = chip->playback_ptr;
+ spin_unlock(&chip->substream_lock);
+ return bytes_to_frames(substream->runtime, pos);
}
static struct snd_pcm_hardware snd_pcsp_playback = {
@@ -279,9 +315,7 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream)
return -EBUSY;
}
runtime->hw = snd_pcsp_playback;
- spin_lock_irq(&chip->substream_lock);
chip->playback_substream = substream;
- spin_unlock_irq(&chip->substream_lock);
return 0;
}
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 7003711f4fcc..6e3a1848447c 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -208,7 +208,8 @@ config SND_OXYGEN
* AuzenTech X-Meridian
* Bgears b-Enspirer
* Club3D Theatron DTS
- * HT-Omega Claro
+ * HT-Omega Claro (plus)
+ * HT-Omega Claro halo (XT)
* Razer Barracuda AC-1
* Sondigo Inferno
@@ -497,129 +498,7 @@ config SND_FM801_TEA575X
depends on SND_FM801_TEA575X_BOOL
default SND_FM801
-config SND_HDA_INTEL
- tristate "Intel HD Audio"
- select SND_PCM
- select SND_VMASTER
- help
- Say Y here to include support for Intel "High Definition
- Audio" (Azalia) motherboard devices.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-hda-intel.
-
-config SND_HDA_HWDEP
- bool "Build hwdep interface for HD-audio driver"
- depends on SND_HDA_INTEL
- select SND_HWDEP
- help
- Say Y here to build a hwdep interface for HD-audio driver.
- This interface can be used for out-of-band communication
- with codecs for debugging purposes.
-
-config SND_HDA_INPUT_BEEP
- bool "Support digital beep via input layer"
- depends on SND_HDA_INTEL
- depends on INPUT=y || INPUT=SND_HDA_INTEL
- help
- Say Y here to build a digital beep interface for HD-audio
- driver. This interface is used to generate digital beeps.
-
-config SND_HDA_CODEC_REALTEK
- bool "Build Realtek HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include Realtek HD-audio codec support in
- snd-hda-intel driver, such as ALC880.
-
-config SND_HDA_CODEC_ANALOG
- bool "Build Analog Device HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include Analog Device HD-audio codec support in
- snd-hda-intel driver, such as AD1986A.
-
-config SND_HDA_CODEC_SIGMATEL
- bool "Build IDT/Sigmatel HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include IDT (Sigmatel) HD-audio codec support in
- snd-hda-intel driver, such as STAC9200.
-
-config SND_HDA_CODEC_VIA
- bool "Build VIA HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include VIA HD-audio codec support in
- snd-hda-intel driver, such as VT1708.
-
-config SND_HDA_CODEC_ATIHDMI
- bool "Build ATI HDMI HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include ATI HDMI HD-audio codec support in
- snd-hda-intel driver, such as ATI RS600 HDMI.
-
-config SND_HDA_CODEC_NVHDMI
- bool "Build NVIDIA HDMI HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include NVIDIA HDMI HD-audio codec support in
- snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
-config SND_HDA_CODEC_CONEXANT
- bool "Build Conexant HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include Conexant HD-audio codec support in
- snd-hda-intel driver, such as CX20549.
-
-config SND_HDA_CODEC_CMEDIA
- bool "Build C-Media HD-audio codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include C-Media HD-audio codec support in
- snd-hda-intel driver, such as CMI9880.
-
-config SND_HDA_CODEC_SI3054
- bool "Build Silicon Labs 3054 HD-modem codec support"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to include Silicon Labs 3054 HD-modem codec
- (and compatibles) support in snd-hda-intel driver.
-
-config SND_HDA_GENERIC
- bool "Enable generic HD-audio codec parser"
- depends on SND_HDA_INTEL
- default y
- help
- Say Y here to enable the generic HD-audio codec parser
- in snd-hda-intel driver.
-
-config SND_HDA_POWER_SAVE
- bool "Aggressive power-saving on HD-audio"
- depends on SND_HDA_INTEL && EXPERIMENTAL
- help
- Say Y here to enable more aggressive power-saving mode on
- HD-audio driver. The power-saving timeout can be configured
- via power_save option or over sysfs on-the-fly.
-
-config SND_HDA_POWER_SAVE_DEFAULT
- int "Default time-out for HD-audio power-save mode"
- depends on SND_HDA_POWER_SAVE
- default 0
- help
- The default time-out value in seconds for HD-audio automatic
- power-save mode. 0 means to disable the power-save mode.
+source "sound/pci/hda/Kconfig"
config SND_HDSP
tristate "RME Hammerfall DSP Audio"
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index bd510eceff1f..e2b843b4f9d0 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -175,7 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q", patch_wolfson04, NULL},
{ 0x574d4C05, 0xffffffff, "WM9705,WM9710", patch_wolfson05, NULL},
{ 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL},
-{ 0x574d4C12, 0xffffffff, "WM9711,WM9712", patch_wolfson11, NULL},
+{ 0x574d4C12, 0xffffffff, "WM9711,WM9712,WM9715", patch_wolfson11, NULL},
{ 0x574d4c13, 0xffffffff, "WM9713,WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF},
{ 0x594d4800, 0xffffffff, "YMF743", patch_yamaha_ymf743, NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL, NULL },
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 6e831aff1bd0..2c7cd97d2234 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -2832,6 +2832,8 @@ static int patch_alc655(struct snd_ac97 * ac97)
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
else
val |= (1 << 1); /* Pin 47 is spdif input pin */
+ /* this seems missing on some hardwares */
+ ac97->ext_id |= AC97_EI_SPDIF;
}
val &= ~(1 << 12); /* vref enable */
snd_ac97_write_cache(ac97, 0x7a, val);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index fb6dc3980257..8ab07aa63652 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -3640,7 +3640,10 @@ int snd_cs46xx_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct snd_cs46xx *chip = card->private_data;
- int i, amp_saved;
+ int amp_saved;
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ int i;
+#endif
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index de5ee8f097f6..7958006a1d66 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -69,7 +69,7 @@ MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
* EMU10K1 init / done
*************************************************************************/
-void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch)
+void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch)
{
snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0);
snd_emu10k1_ptr_write(emu, IP, ch, 0);
@@ -151,9 +151,9 @@ static unsigned int i2c_adc_init[][2] = {
{ 0x12, 0x32 }, /* ALC Control 3 */
{ 0x13, 0x00 }, /* Noise gate control */
{ 0x14, 0xa6 }, /* Limiter control */
- { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */
+ { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for A2ZS Notebook */
};
-
+
static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
{
unsigned int silent_page;
@@ -161,8 +161,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
u32 tmp;
/* disable audio and lock cache */
- outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
- emu->port + HCFG);
+ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK |
+ HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
/* reset recording buffers */
snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE);
@@ -179,7 +179,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);
snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);
- if (emu->audigy){
+ if (emu->audigy) {
/* set SPDIF bypass mode */
snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT);
/* enable rear left + rear right AC97 slots */
@@ -197,12 +197,12 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
/* Hacks for Alice3 to work independent of haP16V driver */
- //Setup SRCMulti_I2S SamplingRate
+ /* Setup SRCMulti_I2S SamplingRate */
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp &= 0xfffff1ff;
tmp |= (0x2<<9);
snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
-
+
/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14);
/* Setup SRCMulti Input Audio Enable */
@@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
/* Hacks for Alice3 to work independent of haP16V driver */
snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
- //Setup SRCMulti_I2S SamplingRate
+ /* Setup SRCMulti_I2S SamplingRate */
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp &= 0xfffff1ff;
tmp |= (0x2<<9);
@@ -270,13 +270,13 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
size = ARRAY_SIZE(i2c_adc_init);
for (n = 0; n < size; n++)
snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);
- for (n=0; n < 4; n++) {
- emu->i2c_capture_volume[n][0]= 0xcf;
- emu->i2c_capture_volume[n][1]= 0xcf;
+ for (n = 0; n < 4; n++) {
+ emu->i2c_capture_volume[n][0] = 0xcf;
+ emu->i2c_capture_volume[n][1] = 0xcf;
}
}
-
+
snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */
snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */
@@ -313,7 +313,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
(emu->model == 0x21 && emu->revision < 6))
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG);
else
- // With on-chip joystick
+ /* With on-chip joystick */
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
if (enable_ir) { /* enable IR for SB Live */
@@ -335,9 +335,9 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);
udelay(100);
outl(reg, emu->port + HCFG);
- }
+ }
}
-
+
if (emu->card_capabilities->emu_model) {
; /* Disable all access to A_IOCFG for the emu1010 */
} else if (emu->card_capabilities->i2c_adc) {
@@ -364,7 +364,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
-
+
if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
/* Unmute Analog now. Set GPO6 to 1 for Apollo.
* This has to be done after init ALice3 I2SOut beyond 48KHz.
@@ -378,12 +378,12 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG);
}
}
-
+
#if 0
{
unsigned int tmp;
/* FIXME: the following routine disables LiveDrive-II !! */
- // TOSLink detection
+ /* TOSLink detection */
emu->tos_link = 0;
tmp = inl(emu->port + HCFG);
if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
@@ -400,7 +400,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
}
-int snd_emu10k1_done(struct snd_emu10k1 * emu)
+int snd_emu10k1_done(struct snd_emu10k1 *emu)
{
int ch;
@@ -495,7 +495,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu)
#define EC_LAST_PROMFILE_ADDR 0x2f
-#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The
+#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The
* can be up to 30 characters in length
* and is stored as a NULL-terminated
* ASCII string. Any unused bytes must be
@@ -503,8 +503,8 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu)
#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */
-/* Most of this stuff is pretty self-evident. According to the hardware
- * dudes, we need to leave the ADCCAL bit low in order to avoid a DC
+/* Most of this stuff is pretty self-evident. According to the hardware
+ * dudes, we need to leave the ADCCAL bit low in order to avoid a DC
* offset problem. Weird.
*/
#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \
@@ -523,7 +523,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu)
* register.
*/
-static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value)
+static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value)
{
unsigned short count;
unsigned int data;
@@ -561,7 +561,7 @@ static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value
* channel.
*/
-static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu,
+static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu,
unsigned short gain)
{
unsigned int bit;
@@ -574,7 +574,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu,
for (bit = (1 << 15); bit; bit >>= 1) {
unsigned int value;
-
+
value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA);
if (gain & bit)
@@ -589,7 +589,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu,
snd_emu10k1_ecard_write(emu, emu->ecard_ctrl);
}
-static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu)
{
unsigned int hc_value;
@@ -598,7 +598,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu)
EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) |
EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL);
- /* Step 0: Set the codec type in the hardware control register
+ /* Step 0: Set the codec type in the hardware control register
* and enable audio output */
hc_value = inl(emu->port + HCFG);
outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG);
@@ -629,7 +629,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu)
return 0;
}
-static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
{
unsigned long special_port;
unsigned int value;
@@ -656,7 +656,7 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
return 0;
}
-static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename)
+static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename)
{
int err;
int n, i;
@@ -666,11 +666,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
unsigned long flags;
const struct firmware *fw_entry;
- if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
- snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err);
+ err = request_firmware(&fw_entry, filename, &emu->pci->dev);
+ if (err != 0) {
+ snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err);
return err;
}
- snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+ snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size);
/* The FPGA is a Xilinx Spartan IIE XC2S50E */
/* GPIO7 -> FPGA PGMN
@@ -685,13 +686,13 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
write_post = inl(emu->port + A_IOCFG);
udelay(100); /* Allow FPGA memory to clean */
- for(n = 0; n < fw_entry->size; n++) {
- value=fw_entry->data[n];
- for(i = 0; i < 8; i++) {
+ for (n = 0; n < fw_entry->size; n++) {
+ value = fw_entry->data[n];
+ for (i = 0; i < 8; i++) {
reg = 0x80;
if (value & 0x1)
reg = reg | 0x20;
- value = value >> 1;
+ value = value >> 1;
outl(reg, emu->port + A_IOCFG);
write_post = inl(emu->port + A_IOCFG);
outl(reg | 0x40, emu->port + A_IOCFG);
@@ -703,14 +704,14 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
write_post = inl(emu->port + A_IOCFG);
spin_unlock_irqrestore(&emu->emu_lock, flags);
- release_firmware(fw_entry);
+ release_firmware(fw_entry);
return 0;
}
static int emu1010_firmware_thread(void *data)
{
- struct snd_emu10k1 * emu = data;
- int tmp,tmp2;
+ struct snd_emu10k1 *emu = data;
+ int tmp, tmp2;
int reg;
int err;
@@ -719,50 +720,50 @@ static int emu1010_firmware_thread(void *data)
msleep_interruptible(1000);
if (kthread_should_stop())
break;
- snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
/* Return to Audio Dock programming mode */
snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK);
if (emu->card_capabilities->emu_model ==
EMU_MODEL_EMU1010) {
- if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+ err = snd_emu1010_load_firmware(emu, DOCK_FILENAME);
+ if (err != 0)
continue;
- }
} else if (emu->card_capabilities->emu_model ==
EMU_MODEL_EMU1010B) {
- if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+ err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME);
+ if (err != 0)
continue;
- }
} else if (emu->card_capabilities->emu_model ==
EMU_MODEL_EMU1616) {
- if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+ err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME);
+ if (err != 0)
continue;
- }
}
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 );
- snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
- snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);
+ snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg);
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
- snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
+ snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
if ((reg & 0x1f) != 0x15) {
/* FPGA failed to be programmed */
- snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
+ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg);
continue;
}
snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
- snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
- snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
- snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
+ snd_printk("Audio Dock ver:%d.%d\n", tmp, tmp2);
/* Sync clocking between 1010 and Dock */
/* Allow DLL to settle */
msleep(10);
/* Unmute all. Default is muted after a firmware load */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
}
}
snd_printk(KERN_INFO "emu1010: firmware thread stopping\n");
@@ -800,10 +801,10 @@ static int emu1010_firmware_thread(void *data)
* 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
* 16 x 32-bit capture - snd_emu10k1_capture_efx_ops
*/
-static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
{
unsigned int i;
- int tmp,tmp2;
+ int tmp, tmp2;
int reg;
int err;
const char *filename = NULL;
@@ -818,7 +819,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
* Lock Tank Memory Cache,
* Mute all codecs.
*/
- outl(0x0005a004, emu->port + HCFG);
+ outl(0x0005a004, emu->port + HCFG);
/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
* Mute all codecs.
*/
@@ -829,25 +830,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
outl(0x0005a000, emu->port + HCFG);
/* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
- snd_printdd("reg1=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
+ snd_printdd("reg1 = 0x%x\n", reg);
if ((reg & 0x3f) == 0x15) {
/* FPGA netlist already present so clear it */
/* Return to programming mode */
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02);
}
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
- snd_printdd("reg2=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
+ snd_printdd("reg2 = 0x%x\n", reg);
if ((reg & 0x3f) == 0x15) {
/* FPGA failed to return to programming mode */
snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
return -ENODEV;
}
- snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
+ snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg);
switch (emu->card_capabilities->emu_model) {
case EMU_MODEL_EMU1010:
filename = HANA_FILENAME;
@@ -876,25 +877,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
}
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
if ((reg & 0x3f) != 0x15) {
/* FPGA failed to be programmed */
- snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
+ snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg);
return -ENODEV;
}
snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
- snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp );
- snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 );
- snd_printk("Hana ver:%d.%d\n",tmp ,tmp2);
+ snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp);
+ snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2);
+ snd_printk("emu1010: Hana version: %d.%d\n", tmp, tmp2);
/* Enable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON);
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
- snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
- snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
+ snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
+ snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp);
/* Optical -> ADAT I/O */
/* 0 : SPDIF
* 1 : ADAT
@@ -904,41 +905,42 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
tmp = 0;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp );
- snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp);
/* Set no attenuation on Audio Dock pads. */
- snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00);
emu->emu1010.adc_pads = 0x00;
- snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp);
/* Unmute Audio dock DACs, Headphone source DAC-4. */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
- snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);
+ snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp);
/* DAC PADs. */
- snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f);
emu->emu1010.dac_pads = 0x0f;
- snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
- snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp);
/* SPDIF Format. Set Consumer mode, 24bit, copy enable */
- snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10);
/* MIDI routing */
- snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19);
/* Unknown. */
- snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c );
- /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c);
+ /* IRQ Enable: Alll on */
+ /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */
/* IRQ Enable: All off */
- snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
- snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
+ snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg);
/* Default WCLK set to 48kHz. */
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00);
/* Word Clock source, Internal 48kHz x1 */
- snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
- //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
+ /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
/* Audio Dock LEDs. */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);
#if 0
/* For 96kHz */
@@ -992,7 +994,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
* Defaults only, users will set their own values anyways, let's
* just copy/paste.
*/
-
+
snd_emu1010_fpga_link_dst_src_write(emu,
EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
snd_emu1010_fpga_link_dst_src_write(emu,
@@ -1037,19 +1039,19 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
snd_emu1010_fpga_link_dst_src_write(emu,
EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2);
#endif
- for (i = 0;i < 0x20; i++ ) {
- /* AudioDock Elink <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE);
+ for (i = 0; i < 0x20; i++) {
+ /* AudioDock Elink <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE);
}
- for (i = 0;i < 4; i++) {
+ for (i = 0; i < 4; i++) {
/* Hana SPDIF Out <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE);
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE);
}
- for (i = 0;i < 7; i++) {
+ for (i = 0; i < 7; i++) {
/* Hamoa DAC <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE);
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE);
}
- for (i = 0;i < 7; i++) {
+ for (i = 0; i < 7; i++) {
/* Hana ADAT Out <- Silence */
snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE);
}
@@ -1065,30 +1067,30 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1);
snd_emu1010_fpga_link_dst_src_write(emu,
EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1);
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01); /* Unmute all */
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp);
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
-
/* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
* Lock Sound Memory Cache, Lock Tank Memory Cache,
* Mute all codecs.
*/
- outl(0x0000a000, emu->port + HCFG);
+ outl(0x0000a000, emu->port + HCFG);
/* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
* Lock Sound Memory Cache, Lock Tank Memory Cache,
* Un-Mute all codecs.
*/
outl(0x0000a001, emu->port + HCFG);
-
+
/* Initial boot complete. Now patches */
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
- snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
- snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
- snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
- snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
- snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
- snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp);
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp);
+ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */
/* Start Micro/Audio Dock firmware loader thread */
if (!emu->emu1010.firmware_thread) {
@@ -1218,20 +1220,20 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
emu->emu1010.output_source[23] = 28;
}
/* TEMP: Select SPDIF in/out */
- //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */
+ /* snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); */ /* Output spdif */
/* TEMP: Select 48kHz SPDIF out */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */
snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */
/* Word Clock source, Internal 48kHz x1 */
- snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
- //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
+ /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
emu->emu1010.internal_clock = 1; /* 48000 */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); /* Set LEDs on Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */
- //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */
- //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */
- //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */
+ /* snd_emu1010_fpga_write(emu, 0x7, 0x0); */ /* Mute all */
+ /* snd_emu1010_fpga_write(emu, 0x7, 0x1); */ /* Unmute all */
+ /* snd_emu1010_fpga_write(emu, 0xe, 0x12); */ /* Set LEDs on Audio Dock */
return 0;
}
@@ -1247,13 +1249,13 @@ static void free_pm_buffer(struct snd_emu10k1 *emu);
static int snd_emu10k1_free(struct snd_emu10k1 *emu)
{
if (emu->port) { /* avoid access to already used hardware */
- snd_emu10k1_fx8010_tram_setup(emu, 0);
+ snd_emu10k1_fx8010_tram_setup(emu, 0);
snd_emu10k1_done(emu);
snd_emu10k1_free_efx(emu);
- }
+ }
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
/* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
}
if (emu->emu1010.firmware_thread)
kthread_stop(emu->emu1010.firmware_thread);
@@ -1278,7 +1280,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
#endif
if (emu->port)
pci_release_regions(emu->pci);
- if (emu->card_capabilities->ca0151_chip) /* P16V */
+ if (emu->card_capabilities->ca0151_chip) /* P16V */
snd_p16v_free(emu);
pci_disable_device(emu->pci);
kfree(emu);
@@ -1292,21 +1294,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device)
}
static struct snd_emu_chip_details emu_chip_details[] = {
- /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
- /* Tested by James@superbug.co.uk 3rd July 2005 */
- /* DSP: CA0108-IAT
- * DAC: CS4382-KQ
- * ADC: Philips 1361T
- * AC97: STAC9750
- * CA0151: None
- */
- {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
- .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]",
- .id = "Audigy2",
- .emu10k2_chip = 1,
- .ca0108_chip = 1,
- .spk71 = 1,
- .ac97_chip = 1} ,
/* Audigy4 (Not PRO) SB0610 */
/* Tested by James@superbug.co.uk 4th April 2006 */
/* A_IOCFG bits
@@ -1346,20 +1333,37 @@ static struct snd_emu_chip_details emu_chip_details[] = {
* CA0151: None
*/
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
- .driver = "Audigy2", .name = "Audigy 4 [SB0610]",
+ .driver = "Audigy2", .name = "SB Audigy 4 [SB0610]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.spk71 = 1,
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
.ac97_chip = 1} ,
+ /* Audigy 2 Value AC3 out does not work yet.
+ * Need to find out how to turn off interpolators.
+ */
+ /* Tested by James@superbug.co.uk 3rd July 2005 */
+ /* DSP: CA0108-IAT
+ * DAC: CS4382-KQ
+ * ADC: Philips 1361T
+ * AC97: STAC9750
+ * CA0151: None
+ */
+ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
+ .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]",
+ .id = "Audigy2",
+ .emu10k2_chip = 1,
+ .ca0108_chip = 1,
+ .spk71 = 1,
+ .ac97_chip = 1} ,
/* Audigy 2 ZS Notebook Cardbus card.*/
/* Tested by James@superbug.co.uk 6th November 2006 */
/* Audio output 7.1/Headphones working.
* Digital output working. (AC3 not checked, only PCM)
* Audio Mic/Line inputs working.
* Digital input not tested.
- */
+ */
/* DSP: Tina2
* DAC: Wolfson WM8768/WM8568
* ADC: Wolfson WM8775
@@ -1386,7 +1390,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
*
*/
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
- .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]",
+ .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1396,7 +1400,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.spk71 = 1} ,
/* Tested by James@superbug.co.uk 4th Nov 2007. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
- .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]",
+ .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1404,47 +1408,49 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.spk71 = 1 ,
.emu_model = EMU_MODEL_EMU1616},
/* Tested by James@superbug.co.uk 4th Nov 2007. */
+ /* This is MAEM8960, 0202 is MAEM 8980 */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
- .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]",
+ .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.spk71 = 1,
- .emu_model = EMU_MODEL_EMU1010B},
+ .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */
/* Tested by James@superbug.co.uk 8th July 2005. */
+ /* This is MAEM8810, 0202 is MAEM8820 */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
- .driver = "Audigy2", .name = "E-mu 1010 [4001]",
+ .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.spk71 = 1,
- .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */
+ .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */
/* EMU0404b */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
- .driver = "Audigy2", .name = "E-mu 0404b [4002]",
+ .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.spk71 = 1,
- .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
+ .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */
/* Tested by James@superbug.co.uk 20-3-2007. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102,
- .driver = "Audigy2", .name = "E-mu 0404 [4002]",
+ .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.spk71 = 1,
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
- /* Audigy4 (Not PRO) SB0610 */
- {.vendor = 0x1102, .device = 0x0008,
- .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]",
+ /* Note that all E-mu cards require kernel 2.6 or newer. */
+ {.vendor = 0x1102, .device = 0x0008,
+ .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.ac97_chip = 1} ,
/* Tested by James@superbug.co.uk 3rd July 2005 */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
- .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]",
+ .driver = "Audigy2", .name = "SB Audigy 4 PRO [SB0380]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1457,7 +1463,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
* Just like 0x20021102
*/
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20061102,
- .driver = "Audigy2", .name = "Audigy 2 [SB0350b]",
+ .driver = "Audigy2", .name = "SB Audigy 2 [SB0350b]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1467,7 +1473,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.invert_shared_spdif = 1, /* digital/analog switch swapped */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102,
- .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]",
+ .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1477,7 +1483,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.invert_shared_spdif = 1, /* digital/analog switch swapped */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102,
- .driver = "Audigy2", .name = "Audigy 2 ZS [2001]",
+ .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0360]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1495,7 +1501,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
* CA0151: Yes
*/
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102,
- .driver = "Audigy2", .name = "Audigy 2 [SB0240]",
+ .driver = "Audigy2", .name = "SB Audigy 2 [SB0240]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1505,7 +1511,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
- .driver = "Audigy2", .name = "Audigy 2 EX [1005]",
+ .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1515,7 +1521,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
/* Dell OEM/Creative Labs Audigy 2 ZS */
/* See ALSA bug#1365 */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10031102,
- .driver = "Audigy2", .name = "Audigy 2 ZS [SB0353]",
+ .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0353]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1524,7 +1530,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.spdif_bug = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
- .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]",
+ .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1535,7 +1541,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .revision = 0x04,
- .driver = "Audigy2", .name = "Audigy 2 [Unknown]",
+ .driver = "Audigy2", .name = "SB Audigy 2 [Unknown]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1543,78 +1549,79 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.spdif_bug = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
- .driver = "Audigy", .name = "Audigy 1 [SB0090]",
+ .driver = "Audigy", .name = "SB Audigy 1 [SB0092]",
.id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102,
- .driver = "Audigy", .name = "Audigy 1 ES [SB0160]",
+ .driver = "Audigy", .name = "SB Audigy 1 ES [SB0160]",
.id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.spdif_bug = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102,
- .driver = "Audigy", .name = "Audigy 1 [SB0090]",
+ .driver = "Audigy", .name = "SB Audigy 1 [SB0090]",
.id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004,
- .driver = "Audigy", .name = "Audigy 1 [Unknown]",
+ .driver = "Audigy", .name = "Audigy 1 [Unknown]",
.id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ac97_chip = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
- .driver = "EMU10K1", .name = "SBLive! [SB0105]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102,
+ .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806b1102,
+ .driver = "EMU10K1", .name = "SB Live! [SB0105]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102,
- .driver = "EMU10K1", .name = "SBLive! Value [SB0103]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806a1102,
+ .driver = "EMU10K1", .name = "SB Live! Value [SB0103]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
- .driver = "EMU10K1", .name = "SBLive! Value [SB0101]",
+ .driver = "EMU10K1", .name = "SB Live! Value [SB0101]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
/* Tested by ALSA bug#1680 26th December 2005 */
- /* note: It really has SB0220 written on the card. */
+ /* note: It really has SB0220 written on the card, */
+ /* but it's SB0228 according to kx.inf */
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102,
- .driver = "EMU10K1", .name = "SB Live 5.1 Dell OEM [SB0220]",
+ .driver = "EMU10K1", .name = "SB Live! 5.1 Dell OEM [SB0228]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
/* Tested by Thomas Zehetbauer 27th Aug 2005 */
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
- .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]",
- .id = "Live",
- .emu10k1_chip = 1,
- .ac97_chip = 1,
- .sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102,
- .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]",
+ .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
- .driver = "EMU10K1", .name = "SB Live 5.1",
+ .driver = "EMU10K1", .name = "SB Live! 5.1",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
/* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
- .driver = "EMU10K1", .name = "SBLive 5.1 [SB0060]",
+ .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0060]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 2, /* ac97 is optional; both SBLive 5.1 and platinum
@@ -1622,78 +1629,78 @@ static struct snd_emu_chip_details emu_chip_details[] = {
*/
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4850]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4850]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
- .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]",
+ .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4871]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4871]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4831]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4831]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4870]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4870]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
/* Tested by James@superbug.co.uk 3rd July 2005 */
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4832]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4832]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4830]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4830]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
- .driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
+ .driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4780]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4780]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
- .driver = "EMU10K1", .name = "E-mu APS [4001]",
+ .driver = "EMU10K1", .name = "E-mu APS [PC545]",
.id = "APS",
.emu10k1_chip = 1,
.ecard = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
- .driver = "EMU10K1", .name = "SBLive! [CT4620]",
+ .driver = "EMU10K1", .name = "SB Live! [CT4620]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4670]",
+ .driver = "EMU10K1", .name = "SB Live! Value [CT4670]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002,
- .driver = "EMU10K1", .name = "SB Live [Unknown]",
+ .driver = "EMU10K1", .name = "SB Live! [Unknown]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
@@ -1702,13 +1709,13 @@ static struct snd_emu_chip_details emu_chip_details[] = {
};
int __devinit snd_emu10k1_create(struct snd_card *card,
- struct pci_dev * pci,
+ struct pci_dev *pci,
unsigned short extin_mask,
unsigned short extout_mask,
long max_cache_bytes,
int enable_ir,
uint subsystem,
- struct snd_emu10k1 ** remu)
+ struct snd_emu10k1 **remu)
{
struct snd_emu10k1 *emu;
int idx, err;
@@ -1718,11 +1725,12 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
static struct snd_device_ops ops = {
.dev_free = snd_emu10k1_dev_free,
};
-
+
*remu = NULL;
/* enable PCI device */
- if ((err = pci_enable_device(pci)) < 0)
+ err = pci_enable_device(pci);
+ if (err < 0)
return err;
emu = kzalloc(sizeof(*emu), GFP_KERNEL);
@@ -1749,16 +1757,17 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
- snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model);
+ snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model);
for (c = emu_chip_details; c->vendor; c++) {
if (c->vendor == pci->vendor && c->device == pci->device) {
if (subsystem) {
- if (c->subsystem && (c->subsystem == subsystem) ) {
+ if (c->subsystem && (c->subsystem == subsystem))
break;
- } else continue;
+ else
+ continue;
} else {
- if (c->subsystem && (c->subsystem != emu->serial) )
+ if (c->subsystem && (c->subsystem != emu->serial))
continue;
if (c->revision && c->revision != emu->revision)
continue;
@@ -1774,14 +1783,18 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
}
emu->card_capabilities = c;
if (c->subsystem && !subsystem)
- snd_printdd("Sound card name=%s\n", c->name);
- else if (subsystem)
- snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n",
- c->name, pci->vendor, pci->device, emu->serial, c->subsystem);
- else
- snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n",
- c->name, pci->vendor, pci->device, emu->serial);
-
+ snd_printdd("Sound card name = %s\n", c->name);
+ else if (subsystem)
+ snd_printdd("Sound card name = %s, "
+ "vendor = 0x%x, device = 0x%x, subsystem = 0x%x. "
+ "Forced to subsytem = 0x%x\n", c->name,
+ pci->vendor, pci->device, emu->serial, c->subsystem);
+ else
+ snd_printdd("Sound card name = %s, "
+ "vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n",
+ c->name, pci->vendor, pci->device,
+ emu->serial);
+
if (!*card->id && c->id) {
int i, n = 0;
strlcpy(card->id, c->id, sizeof(card->id));
@@ -1815,7 +1828,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
else
emu->gpr_base = FXGPREGBASE;
- if ((err = pci_request_regions(pci, "EMU10K1")) < 0) {
+ err = pci_request_regions(pci, "EMU10K1");
+ if (err < 0) {
kfree(emu);
pci_disable_device(pci);
return err;
@@ -1862,21 +1876,25 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
emu->enable_ir = enable_ir;
if (emu->card_capabilities->ca_cardbus_chip) {
- if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
+ err = snd_emu10k1_cardbus_init(emu);
+ if (err < 0)
goto error;
}
if (emu->card_capabilities->ecard) {
- if ((err = snd_emu10k1_ecard_init(emu)) < 0)
+ err = snd_emu10k1_ecard_init(emu);
+ if (err < 0)
goto error;
} else if (emu->card_capabilities->emu_model) {
- if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
- snd_emu10k1_free(emu);
- return err;
- }
+ err = snd_emu10k1_emu1010_init(emu);
+ if (err < 0) {
+ snd_emu10k1_free(emu);
+ return err;
+ }
} else {
/* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
does not support this, it shouldn't do any harm */
- snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
+ snd_emu10k1_ptr_write(emu, AC97SLOT, 0,
+ AC97SLOT_CNTR|AC97SLOT_LFE);
}
/* initialize TRAM setup */
@@ -1916,7 +1934,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
snd_emu10k1_synth_alloc(emu, 4096);
if (emu->reserved_page)
emu->reserved_page->map_locked = 1;
-
+
/* Clear silent pages and set up pointers */
memset(emu->silent_page.area, 0, PAGE_SIZE);
silent_page = emu->silent_page.addr << 1;
@@ -1929,19 +1947,23 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
emu->voices[idx].number = idx;
}
- if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0)
+ err = snd_emu10k1_init(emu, enable_ir, 0);
+ if (err < 0)
goto error;
#ifdef CONFIG_PM
- if ((err = alloc_pm_buffer(emu)) < 0)
+ err = alloc_pm_buffer(emu);
+ if (err < 0)
goto error;
#endif
/* Initialize the effect engine */
- if ((err = snd_emu10k1_init_efx(emu)) < 0)
+ err = snd_emu10k1_init_efx(emu);
+ if (err < 0)
goto error;
snd_emu10k1_audio_enable(emu);
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0)
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops);
+ if (err < 0)
goto error;
#ifdef CONFIG_PROC_FS
@@ -1981,7 +2003,7 @@ static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu)
if (emu->audigy)
size += ARRAY_SIZE(saved_regs_audigy);
emu->saved_ptr = vmalloc(4 * NUM_G * size);
- if (! emu->saved_ptr)
+ if (!emu->saved_ptr)
return -ENOMEM;
if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0)
return -ENOMEM;
@@ -2026,7 +2048,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
if (emu->card_capabilities->ecard)
snd_emu10k1_ecard_init(emu);
else if (emu->card_capabilities->emu_model)
- snd_emu10k1_emu1010_init(emu);
+ snd_emu10k1_emu1010_init(emu);
else
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
snd_emu10k1_init(emu, emu->enable_ir, 1);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
new file mode 100644
index 000000000000..ccf7326a667a
--- /dev/null
+++ b/sound/pci/hda/Kconfig
@@ -0,0 +1,138 @@
+menuconfig SND_HDA_INTEL
+ tristate "Intel HD Audio"
+ select SND_PCM
+ select SND_VMASTER
+ select SND_JACK if INPUT=y || INPUT=SND
+ help
+ Say Y here to include support for Intel "High Definition
+ Audio" (Azalia) and its compatible devices.
+
+ This option enables the HD-audio controller. Don't forget
+ to choose the appropriate codec options below.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hda-intel.
+
+if SND_HDA_INTEL
+
+config SND_HDA_HWDEP
+ bool "Build hwdep interface for HD-audio driver"
+ select SND_HWDEP
+ help
+ Say Y here to build a hwdep interface for HD-audio driver.
+ This interface can be used for out-of-band communication
+ with codecs for debugging purposes.
+
+config SND_HDA_RECONFIG
+ bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)"
+ depends on SND_HDA_HWDEP && EXPERIMENTAL
+ help
+ Say Y here to enable the HD-audio codec re-configuration feature.
+ This adds the sysfs interfaces to allow user to clear the whole
+ codec configuration, change the codec setup, add extra verbs,
+ and re-configure the codec dynamically.
+
+config SND_HDA_INPUT_BEEP
+ bool "Support digital beep via input layer"
+ depends on INPUT=y || INPUT=SND_HDA_INTEL
+ help
+ Say Y here to build a digital beep interface for HD-audio
+ driver. This interface is used to generate digital beeps.
+
+config SND_HDA_CODEC_REALTEK
+ bool "Build Realtek HD-audio codec support"
+ default y
+ help
+ Say Y here to include Realtek HD-audio codec support in
+ snd-hda-intel driver, such as ALC880.
+
+config SND_HDA_CODEC_ANALOG
+ bool "Build Analog Device HD-audio codec support"
+ default y
+ help
+ Say Y here to include Analog Device HD-audio codec support in
+ snd-hda-intel driver, such as AD1986A.
+
+config SND_HDA_CODEC_SIGMATEL
+ bool "Build IDT/Sigmatel HD-audio codec support"
+ default y
+ help
+ Say Y here to include IDT (Sigmatel) HD-audio codec support in
+ snd-hda-intel driver, such as STAC9200.
+
+config SND_HDA_CODEC_VIA
+ bool "Build VIA HD-audio codec support"
+ default y
+ help
+ Say Y here to include VIA HD-audio codec support in
+ snd-hda-intel driver, such as VT1708.
+
+config SND_HDA_CODEC_ATIHDMI
+ bool "Build ATI HDMI HD-audio codec support"
+ default y
+ help
+ Say Y here to include ATI HDMI HD-audio codec support in
+ snd-hda-intel driver, such as ATI RS600 HDMI.
+
+config SND_HDA_CODEC_NVHDMI
+ bool "Build NVIDIA HDMI HD-audio codec support"
+ default y
+ help
+ Say Y here to include NVIDIA HDMI HD-audio codec support in
+ snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
+
+config SND_HDA_CODEC_INTELHDMI
+ bool "Build INTEL HDMI HD-audio codec support"
+ default y
+ help
+ Say Y here to include INTEL HDMI HD-audio codec support in
+ snd-hda-intel driver, such as Eaglelake integrated HDMI.
+
+config SND_HDA_ELD
+ def_bool y
+ depends on SND_HDA_CODEC_INTELHDMI
+
+config SND_HDA_CODEC_CONEXANT
+ bool "Build Conexant HD-audio codec support"
+ default y
+ help
+ Say Y here to include Conexant HD-audio codec support in
+ snd-hda-intel driver, such as CX20549.
+
+config SND_HDA_CODEC_CMEDIA
+ bool "Build C-Media HD-audio codec support"
+ default y
+ help
+ Say Y here to include C-Media HD-audio codec support in
+ snd-hda-intel driver, such as CMI9880.
+
+config SND_HDA_CODEC_SI3054
+ bool "Build Silicon Labs 3054 HD-modem codec support"
+ default y
+ help
+ Say Y here to include Silicon Labs 3054 HD-modem codec
+ (and compatibles) support in snd-hda-intel driver.
+
+config SND_HDA_GENERIC
+ bool "Enable generic HD-audio codec parser"
+ default y
+ help
+ Say Y here to enable the generic HD-audio codec parser
+ in snd-hda-intel driver.
+
+config SND_HDA_POWER_SAVE
+ bool "Aggressive power-saving on HD-audio"
+ help
+ Say Y here to enable more aggressive power-saving mode on
+ HD-audio driver. The power-saving timeout can be configured
+ via power_save option or over sysfs on-the-fly.
+
+config SND_HDA_POWER_SAVE_DEFAULT
+ int "Default time-out for HD-audio power-save mode"
+ depends on SND_HDA_POWER_SAVE
+ default 0
+ help
+ The default time-out value in seconds for HD-audio automatic
+ power-save mode. 0 means to disable the power-save mode.
+
+endif
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 1980c6d207e7..6daf5fd9a279 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -4,6 +4,7 @@ snd-hda-intel-y := hda_intel.o
# designed to be individual modules
snd-hda-intel-y += hda_codec.o
snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
+snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o
snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
@@ -16,5 +17,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o
+snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index eb9164176dab..a867e1e8658a 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -33,14 +33,6 @@
#include <sound/hda_hwdep.h>
#include "hda_patch.h" /* codec presets */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-/* define this option here to hide as static */
-static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-module_param(power_save, int, 0644);
-MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
- "(in second, 0 = disable).");
-#endif
-
/*
* vendor / preset table
*/
@@ -98,6 +90,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
snd_hda_preset_nvhdmi,
#endif
+#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
+ snd_hda_preset_intelhdmi,
+#endif
NULL
};
@@ -108,6 +103,69 @@ static void hda_keep_power_on(struct hda_codec *codec);
static inline void hda_keep_power_on(struct hda_codec *codec) {}
#endif
+const char *snd_hda_get_jack_location(u32 cfg)
+{
+ static char *bases[7] = {
+ "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
+ };
+ static unsigned char specials_idx[] = {
+ 0x07, 0x08,
+ 0x17, 0x18, 0x19,
+ 0x37, 0x38
+ };
+ static char *specials[] = {
+ "Rear Panel", "Drive Bar",
+ "Riser", "HDMI", "ATAPI",
+ "Mobile-In", "Mobile-Out"
+ };
+ int i;
+ cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
+ if ((cfg & 0x0f) < 7)
+ return bases[cfg & 0x0f];
+ for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
+ if (cfg == specials_idx[i])
+ return specials[i];
+ }
+ return "UNKNOWN";
+}
+
+const char *snd_hda_get_jack_connectivity(u32 cfg)
+{
+ static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
+
+ return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3];
+}
+
+const char *snd_hda_get_jack_type(u32 cfg)
+{
+ static char *jack_types[16] = {
+ "Line Out", "Speaker", "HP Out", "CD",
+ "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
+ "Line In", "Aux", "Mic", "Telephony",
+ "SPDIF In", "Digitial In", "Reserved", "Other"
+ };
+
+ return jack_types[(cfg & AC_DEFCFG_DEVICE)
+ >> AC_DEFCFG_DEVICE_SHIFT];
+}
+
+/*
+ * Compose a 32bit command word to be sent to the HD-audio controller
+ */
+static inline unsigned int
+make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+ unsigned int verb, unsigned int parm)
+{
+ u32 val;
+
+ val = (u32)(codec->addr & 0x0f) << 28;
+ val |= (u32)direct << 27;
+ val |= (u32)nid << 20;
+ val |= verb << 8;
+ val |= parm;
+ return val;
+}
+
/**
* snd_hda_codec_read - send a command and get the response
* @codec: the HDA codec
@@ -124,14 +182,17 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
int direct,
unsigned int verb, unsigned int parm)
{
+ struct hda_bus *bus = codec->bus;
unsigned int res;
+
+ res = make_codec_cmd(codec, nid, direct, verb, parm);
snd_hda_power_up(codec);
- mutex_lock(&codec->bus->cmd_mutex);
- if (!codec->bus->ops.command(codec, nid, direct, verb, parm))
- res = codec->bus->ops.get_response(codec);
+ mutex_lock(&bus->cmd_mutex);
+ if (!bus->ops.command(bus, res))
+ res = bus->ops.get_response(bus);
else
res = (unsigned int)-1;
- mutex_unlock(&codec->bus->cmd_mutex);
+ mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
return res;
}
@@ -151,11 +212,15 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
unsigned int verb, unsigned int parm)
{
+ struct hda_bus *bus = codec->bus;
+ unsigned int res;
int err;
+
+ res = make_codec_cmd(codec, nid, direct, verb, parm);
snd_hda_power_up(codec);
- mutex_lock(&codec->bus->cmd_mutex);
- err = codec->bus->ops.command(codec, nid, direct, verb, parm);
- mutex_unlock(&codec->bus->cmd_mutex);
+ mutex_lock(&bus->cmd_mutex);
+ err = bus->ops.command(bus, res);
+ mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
return err;
}
@@ -345,7 +410,7 @@ static void process_unsol_events(struct work_struct *work)
/*
* initialize unsolicited queue
*/
-static int __devinit init_unsol_queue(struct hda_bus *bus)
+static int init_unsol_queue(struct hda_bus *bus)
{
struct hda_bus_unsolicited *unsol;
@@ -391,9 +456,24 @@ static int snd_hda_bus_free(struct hda_bus *bus)
static int snd_hda_bus_dev_free(struct snd_device *device)
{
struct hda_bus *bus = device->device_data;
+ bus->shutdown = 1;
return snd_hda_bus_free(bus);
}
+#ifdef CONFIG_SND_HDA_HWDEP
+static int snd_hda_bus_dev_register(struct snd_device *device)
+{
+ struct hda_bus *bus = device->device_data;
+ struct hda_codec *codec;
+ list_for_each_entry(codec, &bus->codec_list, list) {
+ snd_hda_hwdep_add_sysfs(codec);
+ }
+ return 0;
+}
+#else
+#define snd_hda_bus_dev_register NULL
+#endif
+
/**
* snd_hda_bus_new - create a HDA bus
* @card: the card entry
@@ -409,6 +489,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
struct hda_bus *bus;
int err;
static struct snd_device_ops dev_ops = {
+ .dev_register = snd_hda_bus_dev_register,
.dev_free = snd_hda_bus_dev_free,
};
@@ -430,6 +511,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
bus->private_data = temp->private_data;
bus->pci = temp->pci;
bus->modelname = temp->modelname;
+ bus->power_save = temp->power_save;
bus->ops = temp->ops;
mutex_init(&bus->cmd_mutex);
@@ -447,7 +529,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
#ifdef CONFIG_SND_HDA_GENERIC
#define is_generic_config(codec) \
- (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic"))
+ (codec->modelname && !strcmp(codec->modelname, "generic"))
#else
#define is_generic_config(codec) 0
#endif
@@ -455,7 +537,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
/*
* find a matching codec preset
*/
-static const struct hda_codec_preset __devinit *
+static const struct hda_codec_preset *
find_codec_preset(struct hda_codec *codec)
{
const struct hda_codec_preset **tbl, *preset;
@@ -482,15 +564,14 @@ find_codec_preset(struct hda_codec *codec)
}
/*
- * snd_hda_get_codec_name - store the codec name
+ * get_codec_name - store the codec name
*/
-void snd_hda_get_codec_name(struct hda_codec *codec,
- char *name, int namelen)
+static int get_codec_name(struct hda_codec *codec)
{
const struct hda_vendor_id *c;
const char *vendor = NULL;
u16 vendor_id = codec->vendor_id >> 16;
- char tmp[16];
+ char tmp[16], name[32];
for (c = hda_vendor_ids; c->id; c++) {
if (c->id == vendor_id) {
@@ -503,10 +584,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
vendor = tmp;
}
if (codec->preset && codec->preset->name)
- snprintf(name, namelen, "%s %s", vendor, codec->preset->name);
+ snprintf(name, sizeof(name), "%s %s", vendor,
+ codec->preset->name);
else
- snprintf(name, namelen, "%s ID %x", vendor,
+ snprintf(name, sizeof(name), "%s ID %x", vendor,
codec->vendor_id & 0xffff);
+ codec->name = kstrdup(name, GFP_KERNEL);
+ if (!codec->name)
+ return -ENOMEM;
+ return 0;
}
/*
@@ -571,11 +657,14 @@ static void snd_hda_codec_free(struct hda_codec *codec)
flush_scheduled_work();
#endif
list_del(&codec->list);
+ snd_array_free(&codec->mixers);
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
+ kfree(codec->name);
+ kfree(codec->modelname);
kfree(codec->wcaps);
kfree(codec);
}
@@ -617,6 +706,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
mutex_init(&codec->spdif_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
+ snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
+ if (codec->bus->modelname) {
+ codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
+ if (!codec->modelname) {
+ snd_hda_codec_free(codec);
+ return -ENODEV;
+ }
+ }
#ifdef CONFIG_SND_HDA_POWER_SAVE
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
@@ -662,12 +759,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_SUBSYSTEM_ID, 0);
}
+ if (bus->modelname)
+ codec->modelname = kstrdup(bus->modelname, GFP_KERNEL);
+
+ err = snd_hda_codec_configure(codec);
+ if (err < 0) {
+ snd_hda_codec_free(codec);
+ return err;
+ }
+ snd_hda_codec_proc_new(codec);
+
+ snd_hda_create_hwdep(codec);
+
+ sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
+ codec->subsystem_id, codec->revision_id);
+ snd_component_add(codec->bus->card, component);
+
+ if (codecp)
+ *codecp = codec;
+ return 0;
+}
+
+int snd_hda_codec_configure(struct hda_codec *codec)
+{
+ int err;
codec->preset = find_codec_preset(codec);
+ if (!codec->name) {
+ err = get_codec_name(codec);
+ if (err < 0)
+ return err;
+ }
/* audio codec should override the mixer name */
- if (codec->afg || !*bus->card->mixername)
- snd_hda_get_codec_name(codec, bus->card->mixername,
- sizeof(bus->card->mixername));
+ if (codec->afg || !*codec->bus->card->mixername)
+ strlcpy(codec->bus->card->mixername, codec->name,
+ sizeof(codec->bus->card->mixername));
if (is_generic_config(codec)) {
err = snd_hda_parse_generic_codec(codec);
@@ -684,25 +810,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
printk(KERN_ERR "hda-codec: No codec parser is available\n");
patched:
- if (err < 0) {
- snd_hda_codec_free(codec);
- return err;
- }
-
- if (codec->patch_ops.unsol_event)
- init_unsol_queue(bus);
-
- snd_hda_codec_proc_new(codec);
-#ifdef CONFIG_SND_HDA_HWDEP
- snd_hda_create_hwdep(codec);
-#endif
-
- sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id);
- snd_component_add(codec->bus->card, component);
-
- if (codecp)
- *codecp = codec;
- return 0;
+ if (!err && codec->patch_ops.unsol_event)
+ err = init_unsol_queue(codec->bus);
+ return err;
}
/**
@@ -757,12 +867,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache,
{
memset(cache, 0, sizeof(*cache));
memset(cache->hash, 0xff, sizeof(cache->hash));
- cache->record_size = record_size;
+ snd_array_init(&cache->buf, record_size, 64);
}
static void free_hda_cache(struct hda_cache_rec *cache)
{
- kfree(cache->buffer);
+ snd_array_free(&cache->buf);
}
/* query the hash. allocate an entry if not found. */
@@ -774,35 +884,17 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache,
struct hda_cache_head *info;
while (cur != 0xffff) {
- info = (struct hda_cache_head *)(cache->buffer +
- cur * cache->record_size);
+ info = snd_array_elem(&cache->buf, cur);
if (info->key == key)
return info;
cur = info->next;
}
/* add a new hash entry */
- if (cache->num_entries >= cache->size) {
- /* reallocate the array */
- unsigned int new_size = cache->size + 64;
- void *new_buffer;
- new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL);
- if (!new_buffer) {
- snd_printk(KERN_ERR "hda_codec: "
- "can't malloc amp_info\n");
- return NULL;
- }
- if (cache->buffer) {
- memcpy(new_buffer, cache->buffer,
- cache->size * cache->record_size);
- kfree(cache->buffer);
- }
- cache->size = new_size;
- cache->buffer = new_buffer;
- }
- cur = cache->num_entries++;
- info = (struct hda_cache_head *)(cache->buffer +
- cur * cache->record_size);
+ info = snd_array_new(&cache->buf);
+ if (!info)
+ return NULL;
+ cur = snd_array_index(&cache->buf, info);
info->key = key;
info->val = 0;
info->next = cache->hash[idx];
@@ -943,10 +1035,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
/* resume the all amp commands from the cache */
void snd_hda_codec_resume_amp(struct hda_codec *codec)
{
- struct hda_amp_info *buffer = codec->amp_cache.buffer;
+ struct hda_amp_info *buffer = codec->amp_cache.buf.list;
int i;
- for (i = 0; i < codec->amp_cache.size; i++, buffer++) {
+ for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) {
u32 key = buffer->head.key;
hda_nid_t nid;
unsigned int idx, dir, ch;
@@ -1098,6 +1190,63 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
return _snd_hda_find_mixer_ctl(codec, name, 0);
}
+/* Add a control element and assign to the codec */
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
+{
+ int err;
+ struct snd_kcontrol **knewp;
+
+ err = snd_ctl_add(codec->bus->card, kctl);
+ if (err < 0)
+ return err;
+ knewp = snd_array_new(&codec->mixers);
+ if (!knewp)
+ return -ENOMEM;
+ *knewp = kctl;
+ return 0;
+}
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+/* Clear all controls assigned to the given codec */
+void snd_hda_ctls_clear(struct hda_codec *codec)
+{
+ int i;
+ struct snd_kcontrol **kctls = codec->mixers.list;
+ for (i = 0; i < codec->mixers.used; i++)
+ snd_ctl_remove(codec->bus->card, kctls[i]);
+ snd_array_free(&codec->mixers);
+}
+
+void snd_hda_codec_reset(struct hda_codec *codec)
+{
+ int i;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ cancel_delayed_work(&codec->power_work);
+ flush_scheduled_work();
+#endif
+ snd_hda_ctls_clear(codec);
+ /* relase PCMs */
+ for (i = 0; i < codec->num_pcms; i++) {
+ if (codec->pcm_info[i].pcm) {
+ snd_device_free(codec->bus->card,
+ codec->pcm_info[i].pcm);
+ clear_bit(codec->pcm_info[i].device,
+ codec->bus->pcm_dev_bits);
+ }
+ }
+ if (codec->patch_ops.free)
+ codec->patch_ops.free(codec);
+ codec->proc_widget_hook = NULL;
+ codec->spec = NULL;
+ free_hda_cache(&codec->amp_cache);
+ free_hda_cache(&codec->cmd_cache);
+ codec->num_pcms = 0;
+ codec->pcm_info = NULL;
+ codec->preset = NULL;
+}
+#endif /* CONFIG_SND_HDA_RECONFIG */
+
/* create a virtual master control and add slaves */
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char **slaves)
@@ -1115,7 +1264,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
kctl = snd_ctl_make_virtual_master(name, tlv);
if (!kctl)
return -ENOMEM;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
@@ -1577,9 +1726,11 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
}
for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
kctl = snd_ctl_new1(dig_mix, codec);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.index = idx;
kctl->private_value = nid;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
}
@@ -1623,7 +1774,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
if (!mout->dig_out_nid)
return 0;
/* ATTENTION: here mout is passed as private_data, instead of codec */
- return snd_ctl_add(codec->bus->card,
+ return snd_hda_ctl_add(codec,
snd_ctl_new1(&spdif_share_sw, mout));
}
@@ -1725,7 +1876,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
kctl = snd_ctl_new1(dig_mix, codec);
kctl->private_value = nid;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
}
@@ -1761,10 +1912,14 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm)
{
+ struct hda_bus *bus = codec->bus;
+ unsigned int res;
int err;
+
+ res = make_codec_cmd(codec, nid, direct, verb, parm);
snd_hda_power_up(codec);
- mutex_lock(&codec->bus->cmd_mutex);
- err = codec->bus->ops.command(codec, nid, direct, verb, parm);
+ mutex_lock(&bus->cmd_mutex);
+ err = bus->ops.command(bus, res);
if (!err) {
struct hda_cache_head *c;
u32 key = build_cmd_cache_key(nid, verb);
@@ -1772,7 +1927,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
if (c)
c->val = parm;
}
- mutex_unlock(&codec->bus->cmd_mutex);
+ mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
return err;
}
@@ -1780,10 +1935,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
/* resume the all commands from the cache */
void snd_hda_codec_resume_cache(struct hda_codec *codec)
{
- struct hda_cache_head *buffer = codec->cmd_cache.buffer;
+ struct hda_cache_head *buffer = codec->cmd_cache.buf.list;
int i;
- for (i = 0; i < codec->cmd_cache.size; i++, buffer++) {
+ for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) {
u32 key = buffer->key;
if (!key)
continue;
@@ -1868,6 +2023,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
}
}
+#ifdef CONFIG_SND_HDA_HWDEP
+/* execute additional init verbs */
+static void hda_exec_init_verbs(struct hda_codec *codec)
+{
+ if (codec->init_verbs.list)
+ snd_hda_sequence_write(codec, codec->init_verbs.list);
+}
+#else
+static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
+#endif
+
#ifdef SND_HDA_NEEDS_RESUME
/*
* call suspend and power-down; used both from PM and power-save
@@ -1894,6 +2060,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
hda_set_power_state(codec,
codec->afg ? codec->afg : codec->mfg,
AC_PWRST_D0);
+ hda_exec_init_verbs(codec);
if (codec->patch_ops.resume)
codec->patch_ops.resume(codec);
else {
@@ -1919,23 +2086,31 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
- int err = 0;
- /* fake as if already powered-on */
- hda_keep_power_on(codec);
- /* then fire up */
- hda_set_power_state(codec,
- codec->afg ? codec->afg : codec->mfg,
- AC_PWRST_D0);
- /* continue to initialize... */
- if (codec->patch_ops.init)
- err = codec->patch_ops.init(codec);
- if (!err && codec->patch_ops.build_controls)
- err = codec->patch_ops.build_controls(codec);
- snd_hda_power_down(codec);
+ int err = snd_hda_codec_build_controls(codec);
if (err < 0)
return err;
}
+ return 0;
+}
+int snd_hda_codec_build_controls(struct hda_codec *codec)
+{
+ int err = 0;
+ /* fake as if already powered-on */
+ hda_keep_power_on(codec);
+ /* then fire up */
+ hda_set_power_state(codec,
+ codec->afg ? codec->afg : codec->mfg,
+ AC_PWRST_D0);
+ hda_exec_init_verbs(codec);
+ /* continue to initialize... */
+ if (codec->patch_ops.init)
+ err = codec->patch_ops.init(codec);
+ if (!err && codec->patch_ops.build_controls)
+ err = codec->patch_ops.build_controls(codec);
+ snd_hda_power_down(codec);
+ if (err < 0)
+ return err;
return 0;
}
@@ -2042,7 +2217,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
*
* Returns 0 if successful, otherwise a negative error code.
*/
-int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
{
int i;
@@ -2236,8 +2411,8 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
return 0;
}
-static int __devinit set_pcm_default_values(struct hda_codec *codec,
- struct hda_pcm_stream *info)
+static int set_pcm_default_values(struct hda_codec *codec,
+ struct hda_pcm_stream *info)
{
/* query support PCM information from the given NID */
if (info->nid && (!info->rates || !info->formats)) {
@@ -2263,6 +2438,110 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
return 0;
}
+/*
+ * get the empty PCM device number to assign
+ */
+static int get_empty_pcm_device(struct hda_bus *bus, int type)
+{
+ static const char *dev_name[HDA_PCM_NTYPES] = {
+ "Audio", "SPDIF", "HDMI", "Modem"
+ };
+ /* starting device index for each PCM type */
+ static int dev_idx[HDA_PCM_NTYPES] = {
+ [HDA_PCM_TYPE_AUDIO] = 0,
+ [HDA_PCM_TYPE_SPDIF] = 1,
+ [HDA_PCM_TYPE_HDMI] = 3,
+ [HDA_PCM_TYPE_MODEM] = 6
+ };
+ /* normal audio device indices; not linear to keep compatibility */
+ static int audio_idx[4] = { 0, 2, 4, 5 };
+ int i, dev;
+
+ switch (type) {
+ case HDA_PCM_TYPE_AUDIO:
+ for (i = 0; i < ARRAY_SIZE(audio_idx); i++) {
+ dev = audio_idx[i];
+ if (!test_bit(dev, bus->pcm_dev_bits))
+ break;
+ }
+ if (i >= ARRAY_SIZE(audio_idx)) {
+ snd_printk(KERN_WARNING "Too many audio devices\n");
+ return -EAGAIN;
+ }
+ break;
+ case HDA_PCM_TYPE_SPDIF:
+ case HDA_PCM_TYPE_HDMI:
+ case HDA_PCM_TYPE_MODEM:
+ dev = dev_idx[type];
+ if (test_bit(dev, bus->pcm_dev_bits)) {
+ snd_printk(KERN_WARNING "%s already defined\n",
+ dev_name[type]);
+ return -EAGAIN;
+ }
+ break;
+ default:
+ snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
+ return -EINVAL;
+ }
+ set_bit(dev, bus->pcm_dev_bits);
+ return dev;
+}
+
+/*
+ * attach a new PCM stream
+ */
+static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
+{
+ struct hda_bus *bus = codec->bus;
+ struct hda_pcm_stream *info;
+ int stream, err;
+
+ if (snd_BUG_ON(!pcm->name))
+ return -EINVAL;
+ for (stream = 0; stream < 2; stream++) {
+ info = &pcm->stream[stream];
+ if (info->substreams) {
+ err = set_pcm_default_values(codec, info);
+ if (err < 0)
+ return err;
+ }
+ }
+ return bus->ops.attach_pcm(bus, codec, pcm);
+}
+
+/* assign all PCMs of the given codec */
+int snd_hda_codec_build_pcms(struct hda_codec *codec)
+{
+ unsigned int pcm;
+ int err;
+
+ if (!codec->num_pcms) {
+ if (!codec->patch_ops.build_pcms)
+ return 0;
+ err = codec->patch_ops.build_pcms(codec);
+ if (err < 0)
+ return err;
+ }
+ for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+ struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+ int dev;
+
+ if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
+ return 0; /* no substreams assigned */
+
+ if (!cpcm->pcm) {
+ dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
+ if (dev < 0)
+ return 0;
+ cpcm->device = dev;
+ err = snd_hda_attach_pcm(codec, cpcm);
+ if (err < 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
/**
* snd_hda_build_pcms - build PCM information
* @bus: the BUS
@@ -2294,24 +2573,9 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus)
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
- unsigned int pcm, s;
- int err;
- if (!codec->patch_ops.build_pcms)
- continue;
- err = codec->patch_ops.build_pcms(codec);
+ int err = snd_hda_codec_build_pcms(codec);
if (err < 0)
return err;
- for (pcm = 0; pcm < codec->num_pcms; pcm++) {
- for (s = 0; s < 2; s++) {
- struct hda_pcm_stream *info;
- info = &codec->pcm_info[pcm].stream[s];
- if (!info->substreams)
- continue;
- err = set_pcm_default_values(codec, info);
- if (err < 0)
- return err;
- }
- }
}
return 0;
}
@@ -2333,11 +2597,11 @@ int snd_hda_check_board_config(struct hda_codec *codec,
int num_configs, const char **models,
const struct snd_pci_quirk *tbl)
{
- if (codec->bus->modelname && models) {
+ if (codec->modelname && models) {
int i;
for (i = 0; i < num_configs; i++) {
if (models[i] &&
- !strcmp(codec->bus->modelname, models[i])) {
+ !strcmp(codec->modelname, models[i])) {
snd_printd(KERN_INFO "hda_codec: model '%s' is "
"selected\n", models[i]);
return i;
@@ -2390,7 +2654,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0) {
if (!codec->addr)
return err;
@@ -2398,7 +2662,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
if (!kctl)
return -ENOMEM;
kctl->id.device = codec->addr;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
}
@@ -2414,6 +2678,7 @@ static void hda_power_work(struct work_struct *work)
{
struct hda_codec *codec =
container_of(work, struct hda_codec, power_work.work);
+ struct hda_bus *bus = codec->bus;
if (!codec->power_on || codec->power_count) {
codec->power_transition = 0;
@@ -2421,8 +2686,8 @@ static void hda_power_work(struct work_struct *work)
}
hda_call_codec_suspend(codec);
- if (codec->bus->ops.pm_notify)
- codec->bus->ops.pm_notify(codec);
+ if (bus->ops.pm_notify)
+ bus->ops.pm_notify(bus);
}
static void hda_keep_power_on(struct hda_codec *codec)
@@ -2433,27 +2698,32 @@ static void hda_keep_power_on(struct hda_codec *codec)
void snd_hda_power_up(struct hda_codec *codec)
{
+ struct hda_bus *bus = codec->bus;
+
codec->power_count++;
if (codec->power_on || codec->power_transition)
return;
codec->power_on = 1;
- if (codec->bus->ops.pm_notify)
- codec->bus->ops.pm_notify(codec);
+ if (bus->ops.pm_notify)
+ bus->ops.pm_notify(bus);
hda_call_codec_resume(codec);
cancel_delayed_work(&codec->power_work);
codec->power_transition = 0;
}
+#define power_save(codec) \
+ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
+
void snd_hda_power_down(struct hda_codec *codec)
{
--codec->power_count;
if (!codec->power_on || codec->power_count || codec->power_transition)
return;
- if (power_save) {
+ if (power_save(codec)) {
codec->power_transition = 1; /* avoid reentrance */
schedule_delayed_work(&codec->power_work,
- msecs_to_jiffies(power_save * 1000));
+ msecs_to_jiffies(power_save(codec) * 1000));
}
}
@@ -3109,7 +3379,6 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
/**
* snd_hda_resume - resume the codecs
* @bus: the HDA bus
- * @state: resume state
*
* Returns 0 if successful.
*
@@ -3126,16 +3395,71 @@ int snd_hda_resume(struct hda_bus *bus)
}
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-int snd_hda_codecs_inuse(struct hda_bus *bus)
-{
- struct hda_codec *codec;
+#endif
- list_for_each_entry(codec, &bus->codec_list, list) {
- if (snd_hda_codec_needs_resume(codec))
- return 1;
+/*
+ * generic arrays
+ */
+
+/* get a new element from the given array
+ * if it exceeds the pre-allocated array size, re-allocate the array
+ */
+void *snd_array_new(struct snd_array *array)
+{
+ if (array->used >= array->alloced) {
+ int num = array->alloced + array->alloc_align;
+ void *nlist;
+ if (snd_BUG_ON(num >= 4096))
+ return NULL;
+ nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL);
+ if (!nlist)
+ return NULL;
+ if (array->list) {
+ memcpy(nlist, array->list,
+ array->elem_size * array->alloced);
+ kfree(array->list);
+ }
+ array->list = nlist;
+ array->alloced = num;
}
- return 0;
+ return snd_array_elem(array, array->used++);
+}
+
+/* free the given array elements */
+void snd_array_free(struct snd_array *array)
+{
+ kfree(array->list);
+ array->used = 0;
+ array->alloced = 0;
+ array->list = NULL;
+}
+
+/*
+ * used by hda_proc.c and hda_eld.c
+ */
+void snd_print_pcm_rates(int pcm, char *buf, int buflen)
+{
+ static unsigned int rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000, 384000
+ };
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++)
+ if (pcm & (1 << i))
+ j += snprintf(buf + j, buflen - j, " %d", rates[i]);
+
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+void snd_print_pcm_bits(int pcm, char *buf, int buflen)
+{
+ static unsigned int bits[] = { 8, 16, 20, 24, 32 };
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++)
+ if (pcm & (AC_SUPPCM_BITS_8 << i))
+ j += snprintf(buf + j, buflen - j, " %d", bits[i]);
+
+ buf[j] = '\0'; /* necessary when j == 0 */
}
-#endif
-#endif
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 60468f562400..bbbc83b387d1 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -520,6 +520,36 @@ enum {
#define HDA_MAX_CODEC_ADDRESS 0x0f
/*
+ * generic arrays
+ */
+struct snd_array {
+ unsigned int used;
+ unsigned int alloced;
+ unsigned int elem_size;
+ unsigned int alloc_align;
+ void *list;
+};
+
+void *snd_array_new(struct snd_array *array);
+void snd_array_free(struct snd_array *array);
+static inline void snd_array_init(struct snd_array *array, unsigned int size,
+ unsigned int align)
+{
+ array->elem_size = size;
+ array->alloc_align = align;
+}
+
+static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
+{
+ return array->list + idx * array->elem_size;
+}
+
+static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
+{
+ return (unsigned long)(ptr - array->list) / array->elem_size;
+}
+
+/*
* Structures
*/
@@ -536,15 +566,17 @@ typedef u16 hda_nid_t;
/* bus operators */
struct hda_bus_ops {
/* send a single command */
- int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
- unsigned int verb, unsigned int parm);
+ int (*command)(struct hda_bus *bus, unsigned int cmd);
/* get a response from the last command */
- unsigned int (*get_response)(struct hda_codec *codec);
+ unsigned int (*get_response)(struct hda_bus *bus);
/* free the private data */
void (*private_free)(struct hda_bus *);
+ /* attach a PCM stream */
+ int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
+ struct hda_pcm *pcm);
#ifdef CONFIG_SND_HDA_POWER_SAVE
/* notify power-up/down from codec to controller */
- void (*pm_notify)(struct hda_codec *codec);
+ void (*pm_notify)(struct hda_bus *bus);
#endif
};
@@ -553,6 +585,7 @@ struct hda_bus_template {
void *private_data;
struct pci_dev *pci;
const char *modelname;
+ int *power_save;
struct hda_bus_ops ops;
};
@@ -569,6 +602,7 @@ struct hda_bus {
void *private_data;
struct pci_dev *pci;
const char *modelname;
+ int *power_save;
struct hda_bus_ops ops;
/* codec linked list */
@@ -581,10 +615,12 @@ struct hda_bus {
/* unsolicited event queue */
struct hda_bus_unsolicited *unsol;
- struct snd_info_entry *proc;
+ /* assigned PCMs */
+ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
/* misc op flags */
unsigned int needs_damn_long_delay :1;
+ unsigned int shutdown :1; /* being unloaded */
};
/*
@@ -635,10 +671,7 @@ struct hda_amp_info {
struct hda_cache_rec {
u16 hash[64]; /* hash table for index */
- unsigned int num_entries; /* number of assigned entries */
- unsigned int size; /* allocated size */
- unsigned int record_size; /* record size (including header) */
- void *buffer; /* hash table entries */
+ struct snd_array buf; /* record entries */
};
/* PCM callbacks */
@@ -680,7 +713,8 @@ struct hda_pcm {
char *name;
struct hda_pcm_stream stream[2];
unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */
- int device; /* assigned device number */
+ int device; /* device number to assign */
+ struct snd_pcm *pcm; /* assigned PCM instance */
};
/* codec information */
@@ -699,6 +733,8 @@ struct hda_codec {
/* detected preset */
const struct hda_codec_preset *preset;
+ const char *name; /* codec name */
+ const char *modelname; /* model name for preset */
/* set by patch */
struct hda_codec_ops patch_ops;
@@ -718,6 +754,8 @@ struct hda_codec {
hda_nid_t start_nid;
u32 *wcaps;
+ struct snd_array mixers; /* list of assigned mixer elements */
+
struct hda_cache_rec amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */
@@ -727,7 +765,11 @@ struct hda_codec {
unsigned int spdif_in_enable; /* SPDIF input enable? */
hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
+#ifdef CONFIG_SND_HDA_HWDEP
struct snd_hwdep *hwdep; /* assigned hwdep device */
+ struct snd_array init_verbs; /* additional init verbs */
+ struct snd_array hints; /* additional hints */
+#endif
/* misc flags */
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
@@ -740,6 +782,10 @@ struct hda_codec {
int power_count; /* current (global) power refcount */
struct delayed_work power_work; /* delayed task for powerdown */
#endif
+
+ /* codec-specific additional proc output */
+ void (*proc_widget_hook)(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid);
};
/* direction */
@@ -799,11 +845,13 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
* Mixer
*/
int snd_hda_build_controls(struct hda_bus *bus);
+int snd_hda_codec_build_controls(struct hda_codec *codec);
/*
* PCM
*/
int snd_hda_build_pcms(struct hda_bus *bus);
+int snd_hda_codec_build_pcms(struct hda_codec *codec);
void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag,
int channel_id, int format);
@@ -812,8 +860,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
unsigned int channels,
unsigned int format,
unsigned int maxbps);
-int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
- u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
unsigned int format);
@@ -831,18 +877,23 @@ int snd_hda_resume(struct hda_bus *bus);
#endif
/*
+ * get widget information
+ */
+const char *snd_hda_get_jack_connectivity(u32 cfg);
+const char *snd_hda_get_jack_type(u32 cfg);
+const char *snd_hda_get_jack_location(u32 cfg);
+
+/*
* power saving
*/
#ifdef CONFIG_SND_HDA_POWER_SAVE
void snd_hda_power_up(struct hda_codec *codec);
void snd_hda_power_down(struct hda_codec *codec);
#define snd_hda_codec_needs_resume(codec) codec->power_count
-int snd_hda_codecs_inuse(struct hda_bus *bus);
#else
static inline void snd_hda_power_up(struct hda_codec *codec) {}
static inline void snd_hda_power_down(struct hda_codec *codec) {}
#define snd_hda_codec_needs_resume(codec) 1
-#define snd_hda_codecs_inuse(bus) 1
#endif
#endif /* __SOUND_HDA_CODEC_H */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
new file mode 100644
index 000000000000..fcad5ec31773
--- /dev/null
+++ b/sound/pci/hda/hda_eld.c
@@ -0,0 +1,590 @@
+/*
+ * Generic routines and proc interface for ELD(EDID Like Data) information
+ *
+ * Copyright(c) 2008 Intel Corporation.
+ *
+ * Authors:
+ * Wu Fengguang <wfg@linux.intel.com>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <sound/core.h>
+#include <asm/unaligned.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+enum eld_versions {
+ ELD_VER_CEA_861D = 2,
+ ELD_VER_PARTIAL = 31,
+};
+
+enum cea_edid_versions {
+ CEA_EDID_VER_NONE = 0,
+ CEA_EDID_VER_CEA861 = 1,
+ CEA_EDID_VER_CEA861A = 2,
+ CEA_EDID_VER_CEA861BCD = 3,
+ CEA_EDID_VER_RESERVED = 4,
+};
+
+static char *cea_speaker_allocation_names[] = {
+ /* 0 */ "FL/FR",
+ /* 1 */ "LFE",
+ /* 2 */ "FC",
+ /* 3 */ "RL/RR",
+ /* 4 */ "RC",
+ /* 5 */ "FLC/FRC",
+ /* 6 */ "RLC/RRC",
+ /* 7 */ "FLW/FRW",
+ /* 8 */ "FLH/FRH",
+ /* 9 */ "TC",
+ /* 10 */ "FCH",
+};
+
+static char *eld_connection_type_names[4] = {
+ "HDMI",
+ "DisplayPort",
+ "2-reserved",
+ "3-reserved"
+};
+
+enum cea_audio_coding_types {
+ AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0,
+ AUDIO_CODING_TYPE_LPCM = 1,
+ AUDIO_CODING_TYPE_AC3 = 2,
+ AUDIO_CODING_TYPE_MPEG1 = 3,
+ AUDIO_CODING_TYPE_MP3 = 4,
+ AUDIO_CODING_TYPE_MPEG2 = 5,
+ AUDIO_CODING_TYPE_AACLC = 6,
+ AUDIO_CODING_TYPE_DTS = 7,
+ AUDIO_CODING_TYPE_ATRAC = 8,
+ AUDIO_CODING_TYPE_SACD = 9,
+ AUDIO_CODING_TYPE_EAC3 = 10,
+ AUDIO_CODING_TYPE_DTS_HD = 11,
+ AUDIO_CODING_TYPE_MLP = 12,
+ AUDIO_CODING_TYPE_DST = 13,
+ AUDIO_CODING_TYPE_WMAPRO = 14,
+ AUDIO_CODING_TYPE_REF_CXT = 15,
+ /* also include valid xtypes below */
+ AUDIO_CODING_TYPE_HE_AAC = 15,
+ AUDIO_CODING_TYPE_HE_AAC2 = 16,
+ AUDIO_CODING_TYPE_MPEG_SURROUND = 17,
+};
+
+enum cea_audio_coding_xtypes {
+ AUDIO_CODING_XTYPE_HE_REF_CT = 0,
+ AUDIO_CODING_XTYPE_HE_AAC = 1,
+ AUDIO_CODING_XTYPE_HE_AAC2 = 2,
+ AUDIO_CODING_XTYPE_MPEG_SURROUND = 3,
+ AUDIO_CODING_XTYPE_FIRST_RESERVED = 4,
+};
+
+static char *cea_audio_coding_type_names[] = {
+ /* 0 */ "undefined",
+ /* 1 */ "LPCM",
+ /* 2 */ "AC-3",
+ /* 3 */ "MPEG1",
+ /* 4 */ "MP3",
+ /* 5 */ "MPEG2",
+ /* 6 */ "AAC-LC",
+ /* 7 */ "DTS",
+ /* 8 */ "ATRAC",
+ /* 9 */ "DSD (One Bit Audio)",
+ /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)",
+ /* 11 */ "DTS-HD",
+ /* 12 */ "MLP (Dolby TrueHD)",
+ /* 13 */ "DST",
+ /* 14 */ "WMAPro",
+ /* 15 */ "HE-AAC",
+ /* 16 */ "HE-AACv2",
+ /* 17 */ "MPEG Surround",
+};
+
+/*
+ * The following two lists are shared between
+ * - HDMI audio InfoFrame (source to sink)
+ * - CEA E-EDID Extension (sink to source)
+ */
+
+/*
+ * SS1:SS0 index => sample size
+ */
+static int cea_sample_sizes[4] = {
+ 0, /* 0: Refer to Stream Header */
+ AC_SUPPCM_BITS_16, /* 1: 16 bits */
+ AC_SUPPCM_BITS_20, /* 2: 20 bits */
+ AC_SUPPCM_BITS_24, /* 3: 24 bits */
+};
+
+/*
+ * SF2:SF1:SF0 index => sampling frequency
+ */
+static int cea_sampling_frequencies[8] = {
+ 0, /* 0: Refer to Stream Header */
+ SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
+ SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
+ SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
+ SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
+ SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
+ SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
+ SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
+};
+
+static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+ int byte_index)
+{
+ unsigned int val;
+
+ val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_HDMI_ELDD, byte_index);
+
+#ifdef BE_PARANOID
+ printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+#endif
+
+ if ((val & AC_ELDD_ELD_VALID) == 0) {
+ snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
+ byte_index);
+ val = 0;
+ }
+
+ return val & AC_ELDD_ELD_DATA;
+}
+
+#define GRAB_BITS(buf, byte, lowbit, bits) \
+({ \
+ BUILD_BUG_ON(lowbit > 7); \
+ BUILD_BUG_ON(bits > 8); \
+ BUILD_BUG_ON(bits <= 0); \
+ \
+ (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \
+})
+
+static void hdmi_update_short_audio_desc(struct cea_sad *a,
+ const unsigned char *buf)
+{
+ int i;
+ int val;
+
+ val = GRAB_BITS(buf, 1, 0, 7);
+ a->rates = 0;
+ for (i = 0; i < 7; i++)
+ if (val & (1 << i))
+ a->rates |= cea_sampling_frequencies[i + 1];
+
+ a->channels = GRAB_BITS(buf, 0, 0, 3);
+ a->channels++;
+
+ a->format = GRAB_BITS(buf, 0, 3, 4);
+ switch (a->format) {
+ case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
+ snd_printd(KERN_INFO
+ "HDMI: audio coding type 0 not expected\n");
+ break;
+
+ case AUDIO_CODING_TYPE_LPCM:
+ val = GRAB_BITS(buf, 2, 0, 3);
+ a->sample_bits = 0;
+ for (i = 0; i < 3; i++)
+ if (val & (1 << i))
+ a->sample_bits |= cea_sample_sizes[i + 1];
+ break;
+
+ case AUDIO_CODING_TYPE_AC3:
+ case AUDIO_CODING_TYPE_MPEG1:
+ case AUDIO_CODING_TYPE_MP3:
+ case AUDIO_CODING_TYPE_MPEG2:
+ case AUDIO_CODING_TYPE_AACLC:
+ case AUDIO_CODING_TYPE_DTS:
+ case AUDIO_CODING_TYPE_ATRAC:
+ a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
+ a->max_bitrate *= 8000;
+ break;
+
+ case AUDIO_CODING_TYPE_SACD:
+ break;
+
+ case AUDIO_CODING_TYPE_EAC3:
+ break;
+
+ case AUDIO_CODING_TYPE_DTS_HD:
+ break;
+
+ case AUDIO_CODING_TYPE_MLP:
+ break;
+
+ case AUDIO_CODING_TYPE_DST:
+ break;
+
+ case AUDIO_CODING_TYPE_WMAPRO:
+ a->profile = GRAB_BITS(buf, 2, 0, 3);
+ break;
+
+ case AUDIO_CODING_TYPE_REF_CXT:
+ a->format = GRAB_BITS(buf, 2, 3, 5);
+ if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
+ a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
+ snd_printd(KERN_INFO
+ "HDMI: audio coding xtype %d not expected\n",
+ a->format);
+ a->format = 0;
+ } else
+ a->format += AUDIO_CODING_TYPE_HE_AAC -
+ AUDIO_CODING_XTYPE_HE_AAC;
+ break;
+ }
+}
+
+/*
+ * Be careful, ELD buf could be totally rubbish!
+ */
+static int hdmi_update_eld(struct hdmi_eld *e,
+ const unsigned char *buf, int size)
+{
+ int mnl;
+ int i;
+
+ e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
+ if (e->eld_ver != ELD_VER_CEA_861D &&
+ e->eld_ver != ELD_VER_PARTIAL) {
+ snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n",
+ e->eld_ver);
+ goto out_fail;
+ }
+
+ e->eld_size = size;
+ e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
+ mnl = GRAB_BITS(buf, 4, 0, 5);
+ e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
+
+ e->support_hdcp = GRAB_BITS(buf, 5, 0, 1);
+ e->support_ai = GRAB_BITS(buf, 5, 1, 1);
+ e->conn_type = GRAB_BITS(buf, 5, 2, 2);
+ e->sad_count = GRAB_BITS(buf, 5, 4, 4);
+
+ e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
+ e->spk_alloc = GRAB_BITS(buf, 7, 0, 7);
+
+ e->port_id = get_unaligned_le64(buf + 8);
+
+ /* not specified, but the spec's tendency is little endian */
+ e->manufacture_id = get_unaligned_le16(buf + 16);
+ e->product_id = get_unaligned_le16(buf + 18);
+
+ if (mnl > ELD_MAX_MNL) {
+ snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl);
+ goto out_fail;
+ } else if (ELD_FIXED_BYTES + mnl > size) {
+ snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl);
+ goto out_fail;
+ } else
+ strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl);
+
+ for (i = 0; i < e->sad_count; i++) {
+ if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
+ snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i);
+ goto out_fail;
+ }
+ hdmi_update_short_audio_desc(e->sad + i,
+ buf + ELD_FIXED_BYTES + mnl + 3 * i);
+ }
+
+ return 0;
+
+out_fail:
+ e->eld_ver = 0;
+ return -EINVAL;
+}
+
+static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
+}
+
+static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
+{
+ int eldv;
+ int present;
+
+ present = hdmi_present_sense(codec, nid);
+ eldv = (present & AC_PINSENSE_ELDV);
+ present = (present & AC_PINSENSE_PRESENCE);
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
+ !!present, !!eldv);
+#endif
+
+ return eldv && present;
+}
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
+{
+ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
+ AC_DIPSIZE_ELD_BUF);
+}
+
+int snd_hdmi_get_eld(struct hdmi_eld *eld,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ int i;
+ int ret;
+ int size;
+ unsigned char *buf;
+
+ if (!hdmi_eld_valid(codec, nid))
+ return -ENOENT;
+
+ size = snd_hdmi_get_eld_size(codec, nid);
+ if (size == 0) {
+ /* wfg: workaround for ASUS P5E-VM HDMI board */
+ snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
+ size = 128;
+ }
+ if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
+ snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
+ return -ERANGE;
+ }
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < size; i++)
+ buf[i] = hdmi_get_eld_byte(codec, nid, i);
+
+ ret = hdmi_update_eld(eld, buf, size);
+
+ kfree(buf);
+ return ret;
+}
+
+static void hdmi_show_short_audio_desc(struct cea_sad *a)
+{
+ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+ char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits =";
+
+ if (!a->format)
+ return;
+
+ snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+
+ if (a->format == AUDIO_CODING_TYPE_LPCM)
+ snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+ else if (a->max_bitrate)
+ snprintf(buf2, sizeof(buf2),
+ ", max bitrate = %d", a->max_bitrate);
+ else
+ buf2[0] = '\0';
+
+ printk(KERN_INFO "HDMI: supports coding type %s:"
+ " channels = %d, rates =%s%s\n",
+ cea_audio_coding_type_names[a->format],
+ a->channels,
+ buf,
+ buf2);
+}
+
+void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
+ if (spk_alloc & (1 << i))
+ j += snprintf(buf + j, buflen - j, " %s",
+ cea_speaker_allocation_names[i]);
+ }
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+void snd_hdmi_show_eld(struct hdmi_eld *e)
+{
+ int i;
+
+ printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n",
+ e->monitor_name,
+ eld_connection_type_names[e->conn_type]);
+
+ if (e->spk_alloc) {
+ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+ snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+ printk(KERN_INFO "HDMI: available speakers:%s\n", buf);
+ }
+
+ for (i = 0; i < e->sad_count; i++)
+ hdmi_show_short_audio_desc(e->sad + i);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void hdmi_print_sad_info(int i, struct cea_sad *a,
+ struct snd_info_buffer *buffer)
+{
+ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+
+ snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n",
+ i, a->format, cea_audio_coding_type_names[a->format]);
+ snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
+
+ snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+ snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
+
+ if (a->format == AUDIO_CODING_TYPE_LPCM) {
+ snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf));
+ snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n",
+ i, a->sample_bits, buf);
+ }
+
+ if (a->max_bitrate)
+ snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
+ i, a->max_bitrate);
+
+ if (a->profile)
+ snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
+}
+
+static void hdmi_print_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_eld *e = entry->private_data;
+ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+ int i;
+ static char *eld_versoin_names[32] = {
+ "reserved",
+ "reserved",
+ "CEA-861D or below",
+ [3 ... 30] = "reserved",
+ [31] = "partial"
+ };
+ static char *cea_edid_version_names[8] = {
+ "no CEA EDID Timing Extension block present",
+ "CEA-861",
+ "CEA-861-A",
+ "CEA-861-B, C or D",
+ [4 ... 7] = "reserved"
+ };
+
+ snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
+ snd_iprintf(buffer, "connection_type\t\t%s\n",
+ eld_connection_type_names[e->conn_type]);
+ snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
+ eld_versoin_names[e->eld_ver]);
+ snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
+ cea_edid_version_names[e->cea_edid_ver]);
+ snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
+ snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
+ snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
+ snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
+ snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
+ snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
+
+ snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+ snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
+
+ snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
+
+ for (i = 0; i < e->sad_count; i++)
+ hdmi_print_sad_info(i, e->sad + i, buffer);
+}
+
+static void hdmi_write_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_eld *e = entry->private_data;
+ char line[64];
+ char name[64];
+ char *sname;
+ long long val;
+ int n;
+
+ while (!snd_info_get_line(buffer, line, sizeof(line))) {
+ if (sscanf(line, "%s %llx", name, &val) != 2)
+ continue;
+ /*
+ * We don't allow modification to these fields:
+ * monitor_name manufacture_id product_id
+ * eld_version edid_version
+ */
+ if (!strcmp(name, "connection_type"))
+ e->conn_type = val;
+ else if (!strcmp(name, "port_id"))
+ e->port_id = val;
+ else if (!strcmp(name, "support_hdcp"))
+ e->support_hdcp = val;
+ else if (!strcmp(name, "support_ai"))
+ e->support_ai = val;
+ else if (!strcmp(name, "audio_sync_delay"))
+ e->aud_synch_delay = val;
+ else if (!strcmp(name, "speakers"))
+ e->spk_alloc = val;
+ else if (!strcmp(name, "sad_count"))
+ e->sad_count = val;
+ else if (!strncmp(name, "sad", 3)) {
+ sname = name + 4;
+ n = name[3] - '0';
+ if (name[4] >= '0' && name[4] <= '9') {
+ sname++;
+ n = 10 * n + name[4] - '0';
+ }
+ if (n < 0 || n > 31) /* double the CEA limit */
+ continue;
+ if (!strcmp(sname, "_coding_type"))
+ e->sad[n].format = val;
+ else if (!strcmp(sname, "_channels"))
+ e->sad[n].channels = val;
+ else if (!strcmp(sname, "_rates"))
+ e->sad[n].rates = val;
+ else if (!strcmp(sname, "_bits"))
+ e->sad[n].sample_bits = val;
+ else if (!strcmp(sname, "_max_bitrate"))
+ e->sad[n].max_bitrate = val;
+ else if (!strcmp(sname, "_profile"))
+ e->sad[n].profile = val;
+ if (n >= e->sad_count)
+ e->sad_count = n + 1;
+ }
+ }
+}
+
+
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+ char name[32];
+ struct snd_info_entry *entry;
+ int err;
+
+ snprintf(name, sizeof(name), "eld#%d", codec->addr);
+ err = snd_card_proc_new(codec->bus->card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+ entry->c.text.write = hdmi_write_eld_info;
+ entry->mode |= S_IWUSR;
+ eld->proc_entry = entry;
+
+ return 0;
+}
+
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+ if (!codec->bus->shutdown && eld->proc_entry) {
+ snd_device_free(codec->bus->card, eld->proc_entry);
+ eld->proc_entry = NULL;
+ }
+}
+
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 0ca30894f7c6..98ff010d5b95 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
if (is_loopback)
add_input_loopback(codec, node->nid, HDA_INPUT, index);
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
@@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
if (is_loopback)
add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
}
@@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
(node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
(node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
}
@@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec)
}
/* create input MUX if multiple sources are available */
- if ((err = snd_ctl_add(codec->bus->card,
- snd_ctl_new1(&cap_sel, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
+ if (err < 0)
return err;
/* no volume control? */
@@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec)
HDA_CODEC_VOLUME(name, adc_node->nid,
spec->input_mux.items[i].index,
HDA_INPUT);
- if ((err = snd_ctl_add(codec->bus->card,
- snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
}
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 6e18a422d993..173af489322f 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -23,10 +23,12 @@
#include <linux/pci.h>
#include <linux/compat.h>
#include <linux/mutex.h>
+#include <linux/ctype.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include <sound/hda_hwdep.h>
+#include <sound/minors.h>
/*
* write/read an out-of-bound verb
@@ -95,6 +97,25 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
return 0;
}
+static void clear_hwdep_elements(struct hda_codec *codec)
+{
+ char **head;
+ int i;
+
+ /* clear init verbs */
+ snd_array_free(&codec->init_verbs);
+ /* clear hints */
+ head = codec->hints.list;
+ for (i = 0; i < codec->hints.used; i++, head++)
+ kfree(*head);
+ snd_array_free(&codec->hints);
+}
+
+static void hwdep_free(struct snd_hwdep *hwdep)
+{
+ clear_hwdep_elements(hwdep->private_data);
+}
+
int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
{
char hwname[16];
@@ -109,6 +130,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
sprintf(hwdep->name, "HDA Codec %d", codec->addr);
hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
hwdep->private_data = codec;
+ hwdep->private_free = hwdep_free;
hwdep->exclusive = 1;
hwdep->ops.open = hda_hwdep_open;
@@ -117,5 +139,215 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
#endif
+ snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
+ snd_array_init(&codec->hints, sizeof(char *), 32);
+
return 0;
}
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+
+/*
+ * sysfs interface
+ */
+
+static int clear_codec(struct hda_codec *codec)
+{
+ snd_hda_codec_reset(codec);
+ clear_hwdep_elements(codec);
+ return 0;
+}
+
+static int reconfig_codec(struct hda_codec *codec)
+{
+ int err;
+
+ snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
+ snd_hda_codec_reset(codec);
+ err = snd_hda_codec_configure(codec);
+ if (err < 0)
+ return err;
+ /* rebuild PCMs */
+ err = snd_hda_codec_build_pcms(codec);
+ if (err < 0)
+ return err;
+ /* rebuild mixers */
+ err = snd_hda_codec_build_controls(codec);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+/*
+ * allocate a string at most len chars, and remove the trailing EOL
+ */
+static char *kstrndup_noeol(const char *src, size_t len)
+{
+ char *s = kstrndup(src, len, GFP_KERNEL);
+ char *p;
+ if (!s)
+ return NULL;
+ p = strchr(s, '\n');
+ if (p)
+ *p = 0;
+ return s;
+}
+
+#define CODEC_INFO_SHOW(type) \
+static ssize_t type##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
+ struct hda_codec *codec = hwdep->private_data; \
+ return sprintf(buf, "0x%x\n", codec->type); \
+}
+
+#define CODEC_INFO_STR_SHOW(type) \
+static ssize_t type##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
+ struct hda_codec *codec = hwdep->private_data; \
+ return sprintf(buf, "%s\n", \
+ codec->type ? codec->type : ""); \
+}
+
+CODEC_INFO_SHOW(vendor_id);
+CODEC_INFO_SHOW(subsystem_id);
+CODEC_INFO_SHOW(revision_id);
+CODEC_INFO_SHOW(afg);
+CODEC_INFO_SHOW(mfg);
+CODEC_INFO_STR_SHOW(name);
+CODEC_INFO_STR_SHOW(modelname);
+
+#define CODEC_INFO_STORE(type) \
+static ssize_t type##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
+ struct hda_codec *codec = hwdep->private_data; \
+ char *after; \
+ codec->type = simple_strtoul(buf, &after, 0); \
+ return count; \
+}
+
+#define CODEC_INFO_STR_STORE(type) \
+static ssize_t type##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
+ struct hda_codec *codec = hwdep->private_data; \
+ char *s = kstrndup_noeol(buf, 64); \
+ if (!s) \
+ return -ENOMEM; \
+ kfree(codec->type); \
+ codec->type = s; \
+ return count; \
+}
+
+CODEC_INFO_STORE(vendor_id);
+CODEC_INFO_STORE(subsystem_id);
+CODEC_INFO_STORE(revision_id);
+CODEC_INFO_STR_STORE(name);
+CODEC_INFO_STR_STORE(modelname);
+
+#define CODEC_ACTION_STORE(type) \
+static ssize_t type##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
+ struct hda_codec *codec = hwdep->private_data; \
+ int err = 0; \
+ if (*buf) \
+ err = type##_codec(codec); \
+ return err < 0 ? err : count; \
+}
+
+CODEC_ACTION_STORE(reconfig);
+CODEC_ACTION_STORE(clear);
+
+static ssize_t init_verbs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+ struct hda_codec *codec = hwdep->private_data;
+ char *p;
+ struct hda_verb verb, *v;
+
+ verb.nid = simple_strtoul(buf, &p, 0);
+ verb.verb = simple_strtoul(p, &p, 0);
+ verb.param = simple_strtoul(p, &p, 0);
+ if (!verb.nid || !verb.verb || !verb.param)
+ return -EINVAL;
+ v = snd_array_new(&codec->init_verbs);
+ if (!v)
+ return -ENOMEM;
+ *v = verb;
+ return count;
+}
+
+static ssize_t hints_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+ struct hda_codec *codec = hwdep->private_data;
+ char *p;
+ char **hint;
+
+ if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n')
+ return count;
+ p = kstrndup_noeol(buf, 1024);
+ if (!p)
+ return -ENOMEM;
+ hint = snd_array_new(&codec->hints);
+ if (!hint) {
+ kfree(p);
+ return -ENOMEM;
+ }
+ *hint = p;
+ return count;
+}
+
+#define CODEC_ATTR_RW(type) \
+ __ATTR(type, 0644, type##_show, type##_store)
+#define CODEC_ATTR_RO(type) \
+ __ATTR_RO(type)
+#define CODEC_ATTR_WO(type) \
+ __ATTR(type, 0200, NULL, type##_store)
+
+static struct device_attribute codec_attrs[] = {
+ CODEC_ATTR_RW(vendor_id),
+ CODEC_ATTR_RW(subsystem_id),
+ CODEC_ATTR_RW(revision_id),
+ CODEC_ATTR_RO(afg),
+ CODEC_ATTR_RO(mfg),
+ CODEC_ATTR_RW(name),
+ CODEC_ATTR_RW(modelname),
+ CODEC_ATTR_WO(init_verbs),
+ CODEC_ATTR_WO(hints),
+ CODEC_ATTR_WO(reconfig),
+ CODEC_ATTR_WO(clear),
+};
+
+/*
+ * create sysfs files on hwdep directory
+ */
+int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
+{
+ struct snd_hwdep *hwdep = codec->hwdep;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
+ snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
+ hwdep->device, &codec_attrs[i]);
+ return 0;
+}
+
+#endif /* CONFIG_SND_HDA_RECONFIG */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 35722ec920cb..9350089e1083 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -83,7 +83,10 @@ module_param(enable_msi, int, 0444);
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
#ifdef CONFIG_SND_HDA_POWER_SAVE
-/* power_save option is defined in hda_codec.c */
+static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
+module_param(power_save, int, 0644);
+MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
+ "(in second, 0 = disable).");
/* reset the HD-audio controller in power save mode.
* this may give more power-saving, but will take longer time to
@@ -292,6 +295,8 @@ enum {
/* Define VIA HD Audio Device ID*/
#define VIA_HDAC_DEVICE_ID 0x3288
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
/*
*/
@@ -392,6 +397,7 @@ struct azx {
unsigned int msi :1;
unsigned int irq_pending_warned :1;
unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
+ unsigned int probing :1; /* codec probing phase */
/* for debugging */
unsigned int last_cmd; /* last issued command (to sync) */
@@ -414,6 +420,7 @@ enum {
AZX_DRIVER_ULI,
AZX_DRIVER_NVIDIA,
AZX_DRIVER_TERA,
+ AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */
};
@@ -427,6 +434,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ULI] = "HDA ULI M5461",
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
[AZX_DRIVER_TERA] = "HDA Teradici",
+ [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
/*
@@ -527,9 +535,9 @@ static void azx_free_cmd_io(struct azx *chip)
}
/* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
+static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
{
- struct azx *chip = codec->bus->private_data;
+ struct azx *chip = bus->private_data;
unsigned int wp;
/* add command to corb */
@@ -577,9 +585,9 @@ static void azx_update_rirb(struct azx *chip)
}
/* receive a response */
-static unsigned int azx_rirb_get_response(struct hda_codec *codec)
+static unsigned int azx_rirb_get_response(struct hda_bus *bus)
{
- struct azx *chip = codec->bus->private_data;
+ struct azx *chip = bus->private_data;
unsigned long timeout;
again:
@@ -596,7 +604,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
}
if (time_after(jiffies, timeout))
break;
- if (codec->bus->needs_damn_long_delay)
+ if (bus->needs_damn_long_delay)
msleep(2); /* temporary workaround */
else {
udelay(10);
@@ -624,6 +632,14 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
goto again;
}
+ if (chip->probing) {
+ /* If this critical timeout happens during the codec probing
+ * phase, this is likely an access to a non-existing codec
+ * slot. Better to return an error and reset the system.
+ */
+ return -1;
+ }
+
snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
"switching to single_cmd mode: last cmd=0x%08x\n",
chip->last_cmd);
@@ -646,9 +662,9 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
*/
/* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
+static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
{
- struct azx *chip = codec->bus->private_data;
+ struct azx *chip = bus->private_data;
int timeout = 50;
while (timeout--) {
@@ -671,9 +687,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
}
/* receive a response */
-static unsigned int azx_single_get_response(struct hda_codec *codec)
+static unsigned int azx_single_get_response(struct hda_bus *bus)
{
- struct azx *chip = codec->bus->private_data;
+ struct azx *chip = bus->private_data;
int timeout = 50;
while (timeout--) {
@@ -696,38 +712,29 @@ static unsigned int azx_single_get_response(struct hda_codec *codec)
*/
/* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
- int direct, unsigned int verb,
- unsigned int para)
+static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
{
- struct azx *chip = codec->bus->private_data;
- u32 val;
-
- val = (u32)(codec->addr & 0x0f) << 28;
- val |= (u32)direct << 27;
- val |= (u32)nid << 20;
- val |= verb << 8;
- val |= para;
- chip->last_cmd = val;
+ struct azx *chip = bus->private_data;
+ chip->last_cmd = val;
if (chip->single_cmd)
- return azx_single_send_cmd(codec, val);
+ return azx_single_send_cmd(bus, val);
else
- return azx_corb_send_cmd(codec, val);
+ return azx_corb_send_cmd(bus, val);
}
/* get a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_get_response(struct hda_bus *bus)
{
- struct azx *chip = codec->bus->private_data;
+ struct azx *chip = bus->private_data;
if (chip->single_cmd)
- return azx_single_get_response(codec);
+ return azx_single_get_response(bus);
else
- return azx_rirb_get_response(codec);
+ return azx_rirb_get_response(bus);
}
#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void azx_power_notify(struct hda_codec *codec);
+static void azx_power_notify(struct hda_bus *bus);
#endif
/* reset codec link */
@@ -1184,6 +1191,28 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
return 0;
}
+/*
+ * Probe the given codec address
+ */
+static int probe_codec(struct azx *chip, int addr)
+{
+ unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+ (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+ unsigned int res;
+
+ chip->probing = 1;
+ azx_send_cmd(chip->bus, cmd);
+ res = azx_get_response(chip->bus);
+ chip->probing = 0;
+ if (res == -1)
+ return -EIO;
+ snd_printdd("hda_intel: codec #%d probed OK\n", addr);
+ return 0;
+}
+
+static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+ struct hda_pcm *cpcm);
+static void azx_stop_chip(struct azx *chip);
/*
* Codec initialization
@@ -1194,21 +1223,12 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
[AZX_DRIVER_TERA] = 1,
};
-/* number of slots to probe as default
- * this can be different from azx_max_codecs[] -- e.g. some boards
- * report wrongly the non-existing 4th slot availability
- */
-static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = {
- [AZX_DRIVER_ICH] = 3,
- [AZX_DRIVER_ATI] = 3,
-};
-
static int __devinit azx_codec_create(struct azx *chip, const char *model,
unsigned int codec_probe_mask)
{
struct hda_bus_template bus_temp;
- int c, codecs, audio_codecs, err;
- int def_slots, max_slots;
+ int c, codecs, err;
+ int max_slots;
memset(&bus_temp, 0, sizeof(bus_temp));
bus_temp.private_data = chip;
@@ -1216,7 +1236,9 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
bus_temp.pci = chip->pci;
bus_temp.ops.command = azx_send_cmd;
bus_temp.ops.get_response = azx_get_response;
+ bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
#ifdef CONFIG_SND_HDA_POWER_SAVE
+ bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify;
#endif
@@ -1227,33 +1249,43 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
if (chip->driver_type == AZX_DRIVER_NVIDIA)
chip->bus->needs_damn_long_delay = 1;
- codecs = audio_codecs = 0;
+ codecs = 0;
max_slots = azx_max_codecs[chip->driver_type];
if (!max_slots)
max_slots = AZX_MAX_CODECS;
- def_slots = azx_default_codecs[chip->driver_type];
- if (!def_slots)
- def_slots = max_slots;
- for (c = 0; c < def_slots; c++) {
+
+ /* First try to probe all given codec slots */
+ for (c = 0; c < max_slots; c++) {
+ if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
+ if (probe_codec(chip, c) < 0) {
+ /* Some BIOSen give you wrong codec addresses
+ * that don't exist
+ */
+ snd_printk(KERN_WARNING
+ "hda_intel: Codec #%d probe error; "
+ "disabling it...\n", c);
+ chip->codec_mask &= ~(1 << c);
+ /* More badly, accessing to a non-existing
+ * codec often screws up the controller chip,
+ * and distrubs the further communications.
+ * Thus if an error occurs during probing,
+ * better to reset the controller chip to
+ * get back to the sanity state.
+ */
+ azx_stop_chip(chip);
+ azx_init_chip(chip);
+ }
+ }
+ }
+
+ /* Then create codec instances */
+ for (c = 0; c < max_slots; c++) {
if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
struct hda_codec *codec;
err = snd_hda_codec_new(chip->bus, c, &codec);
if (err < 0)
continue;
codecs++;
- if (codec->afg)
- audio_codecs++;
- }
- }
- if (!audio_codecs) {
- /* probe additional slots if no codec is found */
- for (; c < max_slots; c++) {
- if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
- err = snd_hda_codec_new(chip->bus, c, NULL);
- if (err < 0)
- continue;
- codecs++;
- }
}
}
if (!codecs) {
@@ -1722,111 +1754,59 @@ static struct snd_pcm_ops azx_pcm_ops = {
static void azx_pcm_free(struct snd_pcm *pcm)
{
- kfree(pcm->private_data);
+ struct azx_pcm *apcm = pcm->private_data;
+ if (apcm) {
+ apcm->chip->pcm[pcm->device] = NULL;
+ kfree(apcm);
+ }
}
-static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
- struct hda_pcm *cpcm)
+static int
+azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+ struct hda_pcm *cpcm)
{
- int err;
+ struct azx *chip = bus->private_data;
struct snd_pcm *pcm;
struct azx_pcm *apcm;
+ int pcm_dev = cpcm->device;
+ int s, err;
- /* if no substreams are defined for both playback and capture,
- * it's just a placeholder. ignore it.
- */
- if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
- return 0;
-
- if (snd_BUG_ON(!cpcm->name))
+ if (pcm_dev >= AZX_MAX_PCMS) {
+ snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
+ pcm_dev);
return -EINVAL;
-
- err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
- cpcm->stream[0].substreams,
- cpcm->stream[1].substreams,
+ }
+ if (chip->pcm[pcm_dev]) {
+ snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
+ return -EBUSY;
+ }
+ err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+ cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
+ cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
&pcm);
if (err < 0)
return err;
strcpy(pcm->name, cpcm->name);
- apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
if (apcm == NULL)
return -ENOMEM;
apcm->chip = chip;
apcm->codec = codec;
- apcm->hinfo[0] = &cpcm->stream[0];
- apcm->hinfo[1] = &cpcm->stream[1];
pcm->private_data = apcm;
pcm->private_free = azx_pcm_free;
- if (cpcm->stream[0].substreams)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
- if (cpcm->stream[1].substreams)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
+ if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
+ pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
+ chip->pcm[pcm_dev] = pcm;
+ cpcm->pcm = pcm;
+ for (s = 0; s < 2; s++) {
+ apcm->hinfo[s] = &cpcm->stream[s];
+ if (cpcm->stream[s].substreams)
+ snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
+ }
+ /* buffer pre-allocation */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
1024 * 64, 32 * 1024 * 1024);
- chip->pcm[cpcm->device] = pcm;
- return 0;
-}
-
-static int __devinit azx_pcm_create(struct azx *chip)
-{
- static const char *dev_name[HDA_PCM_NTYPES] = {
- "Audio", "SPDIF", "HDMI", "Modem"
- };
- /* starting device index for each PCM type */
- static int dev_idx[HDA_PCM_NTYPES] = {
- [HDA_PCM_TYPE_AUDIO] = 0,
- [HDA_PCM_TYPE_SPDIF] = 1,
- [HDA_PCM_TYPE_HDMI] = 3,
- [HDA_PCM_TYPE_MODEM] = 6
- };
- /* normal audio device indices; not linear to keep compatibility */
- static int audio_idx[4] = { 0, 2, 4, 5 };
- struct hda_codec *codec;
- int c, err;
- int num_devs[HDA_PCM_NTYPES];
-
- err = snd_hda_build_pcms(chip->bus);
- if (err < 0)
- return err;
-
- /* create audio PCMs */
- memset(num_devs, 0, sizeof(num_devs));
- list_for_each_entry(codec, &chip->bus->codec_list, list) {
- for (c = 0; c < codec->num_pcms; c++) {
- struct hda_pcm *cpcm = &codec->pcm_info[c];
- int type = cpcm->pcm_type;
- switch (type) {
- case HDA_PCM_TYPE_AUDIO:
- if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
- snd_printk(KERN_WARNING
- "Too many audio devices\n");
- continue;
- }
- cpcm->device = audio_idx[num_devs[type]];
- break;
- case HDA_PCM_TYPE_SPDIF:
- case HDA_PCM_TYPE_HDMI:
- case HDA_PCM_TYPE_MODEM:
- if (num_devs[type]) {
- snd_printk(KERN_WARNING
- "%s already defined\n",
- dev_name[type]);
- continue;
- }
- cpcm->device = dev_idx[type];
- break;
- default:
- snd_printk(KERN_WARNING
- "Invalid PCM type %d\n", type);
- continue;
- }
- num_devs[type]++;
- err = create_codec_pcm(chip, codec, cpcm);
- if (err < 0)
- return err;
- }
- }
return 0;
}
@@ -1903,13 +1883,13 @@ static void azx_stop_chip(struct azx *chip)
#ifdef CONFIG_SND_HDA_POWER_SAVE
/* power-up/down the controller */
-static void azx_power_notify(struct hda_codec *codec)
+static void azx_power_notify(struct hda_bus *bus)
{
- struct azx *chip = codec->bus->private_data;
+ struct azx *chip = bus->private_data;
struct hda_codec *c;
int power_on = 0;
- list_for_each_entry(c, &codec->bus->codec_list, list) {
+ list_for_each_entry(c, &bus->codec_list, list) {
if (c->power_on) {
power_on = 1;
break;
@@ -1920,6 +1900,19 @@ static void azx_power_notify(struct hda_codec *codec)
else if (chip->running && power_save_controller)
azx_stop_chip(chip);
}
+
+static int snd_hda_codecs_inuse(struct hda_bus *bus)
+{
+ struct hda_codec *codec;
+
+ list_for_each_entry(codec, &bus->codec_list, list) {
+ if (snd_hda_codec_needs_resume(codec))
+ return 1;
+ }
+ return 0;
+}
+#else /* !CONFIG_SND_HDA_POWER_SAVE */
+#define snd_hda_codecs_inuse(bus) 1
#endif /* CONFIG_SND_HDA_POWER_SAVE */
#ifdef CONFIG_PM
@@ -2095,6 +2088,10 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
+ /* broken BIOS */
+ SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
+ /* including bogus ALC268 in slot#2 that conflicts with ALC888 */
+ SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
{}
};
@@ -2229,6 +2226,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
chip->capture_streams = ATIHDMI_NUM_CAPTURE;
break;
+ case AZX_DRIVER_GENERIC:
default:
chip->playback_streams = ICH6_NUM_PLAYBACK;
chip->capture_streams = ICH6_NUM_CAPTURE;
@@ -2338,40 +2336,30 @@ static int __devinit azx_probe(struct pci_dev *pci,
}
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ if (err < 0)
+ goto out_free;
card->private_data = chip;
/* create codec instances */
err = azx_codec_create(chip, model[dev], probe_mask[dev]);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ if (err < 0)
+ goto out_free;
/* create PCM streams */
- err = azx_pcm_create(chip);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ err = snd_hda_build_pcms(chip->bus);
+ if (err < 0)
+ goto out_free;
/* create mixer controls */
err = azx_mixer_create(chip);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ if (err < 0)
+ goto out_free;
snd_card_set_dev(card, &pci->dev);
err = snd_card_register(card);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ if (err < 0)
+ goto out_free;
pci_set_drvdata(pci, card);
chip->running = 1;
@@ -2380,6 +2368,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
dev++;
return err;
+out_free:
+ snd_card_free(card);
+ return err;
}
static void __devexit azx_remove(struct pci_dev *pci)
@@ -2453,6 +2444,11 @@ static struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
/* Teradici */
{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+ /* AMD Generic, PCI class code and Vendor ID for HD Audio */
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
+ .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+ .class_mask = 0xffffff,
+ .driver_data = AZX_DRIVER_GENERIC },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 7957fefda730..6f2fe0f9fdd8 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const char *name);
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char **slaves);
+void snd_hda_codec_reset(struct hda_codec *codec);
+int snd_hda_codec_configure(struct hda_codec *codec);
/* amp value bits */
#define HDA_AMP_MUTE 0x80
@@ -282,6 +284,12 @@ int snd_hda_codec_proc_new(struct hda_codec *codec);
static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
#endif
+#define SND_PRINT_RATES_ADVISED_BUFSIZE 80
+void snd_print_pcm_rates(int pcm, char *buf, int buflen);
+
+#define SND_PRINT_BITS_ADVISED_BUFSIZE 16
+void snd_print_pcm_bits(int pcm, char *buf, int buflen);
+
/*
* Misc
*/
@@ -364,17 +372,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
/* amp values */
#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
-#define AMP_OUT_MUTE 0xb080
-#define AMP_OUT_UNMUTE 0xb000
-#define AMP_OUT_ZERO 0xb000
+#define AMP_OUT_MUTE 0xb080
+#define AMP_OUT_UNMUTE 0xb000
+#define AMP_OUT_ZERO 0xb000
/* pinctl values */
#define PIN_IN (AC_PINCTL_IN_EN)
-#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
+#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
#define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
-#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
+#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
#define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
-#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
-#define PIN_OUT (AC_PINCTL_OUT_EN)
+#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
+#define PIN_OUT (AC_PINCTL_OUT_EN)
#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
@@ -393,10 +401,26 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps);
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
+void snd_hda_ctls_clear(struct hda_codec *codec);
+
/*
* hwdep interface
*/
+#ifdef CONFIG_SND_HDA_HWDEP
int snd_hda_create_hwdep(struct hda_codec *codec);
+#else
+static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
+#endif
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
+#else
+static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
+{
+ return 0;
+}
+#endif
/*
* power-management
@@ -430,4 +454,66 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
+/*
+ * CEA Short Audio Descriptor data
+ */
+struct cea_sad {
+ int channels;
+ int format; /* (format == 0) indicates invalid SAD */
+ int rates;
+ int sample_bits; /* for LPCM */
+ int max_bitrate; /* for AC3...ATRAC */
+ int profile; /* for WMAPRO */
+};
+
+#define ELD_FIXED_BYTES 20
+#define ELD_MAX_MNL 16
+#define ELD_MAX_SAD 16
+
+/*
+ * ELD: EDID Like Data
+ */
+struct hdmi_eld {
+ int eld_size;
+ int baseline_len;
+ int eld_ver; /* (eld_ver == 0) indicates invalid ELD */
+ int cea_edid_ver;
+ char monitor_name[ELD_MAX_MNL + 1];
+ int manufacture_id;
+ int product_id;
+ u64 port_id;
+ int support_hdcp;
+ int support_ai;
+ int conn_type;
+ int aud_synch_delay;
+ int spk_alloc;
+ int sad_count;
+ struct cea_sad sad[ELD_MAX_SAD];
+#ifdef CONFIG_PROC_FS
+ struct snd_info_entry *proc_entry;
+#endif
+};
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
+int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
+void snd_hdmi_show_eld(struct hdmi_eld *eld);
+
+#ifdef CONFIG_PROC_FS
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld);
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld);
+#else
+static inline int snd_hda_eld_proc_new(struct hda_codec *codec,
+ struct hdmi_eld *eld)
+{
+ return 0;
+}
+static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
+ struct hdmi_eld *eld)
+{
+}
+#endif
+
+#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
+void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
+
#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index dfbcfa88da44..38212c1020a6 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -20,3 +20,5 @@ extern struct hda_codec_preset snd_hda_preset_conexant[];
extern struct hda_codec_preset snd_hda_preset_via[];
/* NVIDIA HDMI codecs */
extern struct hda_codec_preset snd_hda_preset_nvhdmi[];
+/* INTEL HDMI codecs */
+extern struct hda_codec_preset snd_hda_preset_intelhdmi[];
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index c39af986bff1..7ca66d654148 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -91,31 +91,21 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
{
- static unsigned int rates[] = {
- 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
- 96000, 176400, 192000, 384000
- };
- int i;
+ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
pcm &= AC_SUPPCM_RATES;
snd_iprintf(buffer, " rates [0x%x]:", pcm);
- for (i = 0; i < ARRAY_SIZE(rates); i++)
- if (pcm & (1 << i))
- snd_iprintf(buffer, " %d", rates[i]);
- snd_iprintf(buffer, "\n");
+ snd_print_pcm_rates(pcm, buf, sizeof(buf));
+ snd_iprintf(buffer, "%s\n", buf);
}
static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
{
- static unsigned int bits[] = { 8, 16, 20, 24, 32 };
- int i;
+ char buf[SND_PRINT_BITS_ADVISED_BUFSIZE];
- pcm = (pcm >> 16) & 0xff;
- snd_iprintf(buffer, " bits [0x%x]:", pcm);
- for (i = 0; i < ARRAY_SIZE(bits); i++)
- if (pcm & (1 << i))
- snd_iprintf(buffer, " %d", bits[i]);
- snd_iprintf(buffer, "\n");
+ snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff);
+ snd_print_pcm_bits(pcm, buf, sizeof(buf));
+ snd_iprintf(buffer, "%s\n", buf);
}
static void print_pcm_formats(struct snd_info_buffer *buffer,
@@ -145,32 +135,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer,
print_pcm_formats(buffer, stream);
}
-static const char *get_jack_location(u32 cfg)
-{
- static char *bases[7] = {
- "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
- };
- static unsigned char specials_idx[] = {
- 0x07, 0x08,
- 0x17, 0x18, 0x19,
- 0x37, 0x38
- };
- static char *specials[] = {
- "Rear Panel", "Drive Bar",
- "Riser", "HDMI", "ATAPI",
- "Mobile-In", "Mobile-Out"
- };
- int i;
- cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
- if ((cfg & 0x0f) < 7)
- return bases[cfg & 0x0f];
- for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
- if (cfg == specials_idx[i])
- return specials[i];
- }
- return "UNKNOWN";
-}
-
static const char *get_jack_connection(u32 cfg)
{
static char *names[16] = {
@@ -206,13 +170,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
int *supports_vref)
{
static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
- static char *jack_types[16] = {
- "Line Out", "Speaker", "HP Out", "CD",
- "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
- "Line In", "Aux", "Mic", "Telephony",
- "SPDIF In", "Digitial In", "Reserved", "Other"
- };
- static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
unsigned int caps, val;
caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
@@ -274,9 +231,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
- jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
- jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
- get_jack_location(caps));
+ snd_hda_get_jack_type(caps),
+ snd_hda_get_jack_connectivity(caps),
+ snd_hda_get_jack_location(caps));
snd_iprintf(buffer, " Conn = %s, Color = %s\n",
get_jack_connection(caps),
get_jack_color(caps));
@@ -457,17 +414,6 @@ static void print_conn_list(struct snd_info_buffer *buffer,
}
}
-static void print_realtek_coef(struct snd_info_buffer *buffer,
- struct hda_codec *codec, hda_nid_t nid)
-{
- int coeff = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PROC_COEF, 0);
- snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
- coeff = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_COEF_INDEX, 0);
- snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
-}
-
static void print_gpio(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
{
@@ -500,12 +446,13 @@ static void print_gpio(struct snd_info_buffer *buffer,
for (i = 0; i < max; ++i)
snd_iprintf(buffer,
" IO[%d]: enable=%d, dir=%d, wake=%d, "
- "sticky=%d, data=%d\n", i,
+ "sticky=%d, data=%d, unsol=%d\n", i,
(enable & (1<<i)) ? 1 : 0,
(direction & (1<<i)) ? 1 : 0,
(wake & (1<<i)) ? 1 : 0,
(sticky & (1<<i)) ? 1 : 0,
- (data & (1<<i)) ? 1 : 0);
+ (data & (1<<i)) ? 1 : 0,
+ (unsol & (1<<i)) ? 1 : 0);
/* FIXME: add GPO and GPI pin information */
}
@@ -513,12 +460,11 @@ static void print_codec_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hda_codec *codec = entry->private_data;
- char buf[32];
hda_nid_t nid;
int i, nodes;
- snd_hda_get_codec_name(codec, buf, sizeof(buf));
- snd_iprintf(buffer, "Codec: %s\n", buf);
+ snd_iprintf(buffer, "Codec: %s\n",
+ codec->name ? codec->name : "Not Set");
snd_iprintf(buffer, "Address: %d\n", codec->addr);
snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
@@ -547,6 +493,8 @@ static void print_codec_info(struct snd_info_entry *entry,
}
print_gpio(buffer, codec, codec->afg);
+ if (codec->proc_widget_hook)
+ codec->proc_widget_hook(buffer, codec, codec->afg);
for (i = 0; i < nodes; i++, nid++) {
unsigned int wid_caps =
@@ -649,9 +597,8 @@ static void print_codec_info(struct snd_info_entry *entry,
if (wid_caps & AC_WCAP_PROC_WID)
print_proc_caps(buffer, codec, nid);
- /* NID 0x20 == Realtek Define Registers */
- if (codec->vendor_id == 0x10ec && nid == 0x20)
- print_realtek_coef(buffer, codec, nid);
+ if (codec->proc_widget_hook)
+ codec->proc_widget_hook(buffer, codec, nid);
}
snd_hda_power_down(codec);
}
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 686c77491dea..0cc6be12b8b7 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -67,8 +67,7 @@ struct ad198x_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
- unsigned int num_kctl_alloc, num_kctl_used;
- struct snd_kcontrol_new *kctl_alloc;
+ struct snd_array kctls;
struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
@@ -154,6 +153,8 @@ static const char *ad_slave_sws[] = {
NULL
};
+static void ad198x_free_kctls(struct hda_codec *codec);
+
static int ad198x_build_controls(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
@@ -202,6 +203,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
return err;
}
+ ad198x_free_kctls(codec); /* no longer needed */
return 0;
}
@@ -375,16 +377,27 @@ static int ad198x_build_pcms(struct hda_codec *codec)
return 0;
}
-static void ad198x_free(struct hda_codec *codec)
+static void ad198x_free_kctls(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
- unsigned int i;
- if (spec->kctl_alloc) {
- for (i = 0; i < spec->num_kctl_used; i++)
- kfree(spec->kctl_alloc[i].name);
- kfree(spec->kctl_alloc);
+ if (spec->kctls.list) {
+ struct snd_kcontrol_new *kctl = spec->kctls.list;
+ int i;
+ for (i = 0; i < spec->kctls.used; i++)
+ kfree(kctl[i].name);
}
+ snd_array_free(&spec->kctls);
+}
+
+static void ad198x_free(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec = codec->spec;
+
+ if (!spec)
+ return;
+
+ ad198x_free_kctls(codec);
kfree(codec->spec);
}
@@ -629,6 +642,36 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "External Amplifier",
+ .info = ad198x_eapd_info,
+ .get = ad198x_eapd_get,
+ .put = ad198x_eapd_put,
+ .private_value = 0x1b | (1 << 8), /* port-D, inversed */
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
+ HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
+ HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
@@ -917,6 +960,7 @@ enum {
AD1986A_LAPTOP_EAPD,
AD1986A_LAPTOP_AUTOMUTE,
AD1986A_ULTRA,
+ AD1986A_SAMSUNG,
AD1986A_MODELS
};
@@ -927,6 +971,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = {
[AD1986A_LAPTOP_EAPD] = "laptop-eapd",
[AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
[AD1986A_ULTRA] = "ultra",
+ [AD1986A_SAMSUNG] = "samsung",
};
static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
@@ -949,9 +994,9 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
- SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
- SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
- SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
+ SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
+ SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
@@ -1033,6 +1078,17 @@ static int patch_ad1986a(struct hda_codec *codec)
break;
case AD1986A_LAPTOP_EAPD:
spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+ if (!is_jack_available(codec, 0x25))
+ spec->multiout.dig_out_nid = 0;
+ spec->input_mux = &ad1986a_laptop_eapd_capture_source;
+ break;
+ case AD1986A_SAMSUNG:
+ spec->mixers[0] = ad1986a_samsung_mixers;
spec->num_init_verbs = 3;
spec->init_verbs[1] = ad1986a_eapd_init_verbs;
spec->init_verbs[2] = ad1986a_automic_verbs;
@@ -2452,9 +2508,6 @@ static struct hda_amp_list ad1988_loopbacks[] = {
* Automatic parse of I/O pins from the BIOS configuration
*/
-#define NUM_CONTROL_ALLOC 32
-#define NUM_VERB_ALLOC 32
-
enum {
AD_CTL_WIDGET_VOL,
AD_CTL_WIDGET_MUTE,
@@ -2472,27 +2525,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
{
struct snd_kcontrol_new *knew;
- if (spec->num_kctl_used >= spec->num_kctl_alloc) {
- int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
- knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
- if (! knew)
- return -ENOMEM;
- if (spec->kctl_alloc) {
- memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
- kfree(spec->kctl_alloc);
- }
- spec->kctl_alloc = knew;
- spec->num_kctl_alloc = num;
- }
-
- knew = &spec->kctl_alloc[spec->num_kctl_used];
+ snd_array_init(&spec->kctls, sizeof(*knew), 32);
+ knew = snd_array_new(&spec->kctls);
+ if (!knew)
+ return -ENOMEM;
*knew = ad1988_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL);
if (! knew->name)
return -ENOMEM;
knew->private_value = val;
- spec->num_kctl_used++;
return 0;
}
@@ -2846,8 +2887,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = AD1988_SPDIF_IN;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index ba61575983fd..5603a1acddb1 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -193,7 +193,6 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = {
{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
- { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi },
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 7c1eb23f0cec..076010708152 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -86,8 +86,6 @@ struct conexant_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
- unsigned int num_kctl_alloc, num_kctl_used;
- struct snd_kcontrol_new *kctl_alloc;
struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
@@ -344,15 +342,6 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec)
{
- struct conexant_spec *spec = codec->spec;
- unsigned int i;
-
- if (spec->kctl_alloc) {
- for (i = 0; i < spec->num_kctl_used; i++)
- kfree(spec->kctl_alloc[i].name);
- kfree(spec->kctl_alloc);
- }
-
kfree(codec->spec);
}
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
new file mode 100644
index 000000000000..fe08bef897cd
--- /dev/null
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -0,0 +1,685 @@
+/*
+ *
+ * patch_intelhdmi.c - Patch for Intel HDMI codecs
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * Authors:
+ * Jiang Zhe <zhe.jiang@intel.com>
+ * Wu Fengguang <wfg@linux.intel.com>
+ *
+ * Maintained by:
+ * Wu Fengguang <wfg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include "hda_patch.h"
+
+#define CVT_NID 0x02 /* audio converter */
+#define PIN_NID 0x03 /* HDMI output pin */
+
+#define INTEL_HDMI_EVENT_TAG 0x08
+
+struct intel_hdmi_spec {
+ struct hda_multi_out multiout;
+ struct hda_pcm pcm_rec;
+ struct hdmi_eld sink_eld;
+};
+
+static struct hda_verb pinout_enable_verb[] = {
+ {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {} /* terminator */
+};
+
+static struct hda_verb pinout_disable_verb[] = {
+ {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},
+ {}
+};
+
+static struct hda_verb unsolicited_response_verb[] = {
+ {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN |
+ INTEL_HDMI_EVENT_TAG},
+ {}
+};
+
+static struct hda_verb def_chan_map[] = {
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66},
+ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77},
+ {}
+};
+
+
+struct hdmi_audio_infoframe {
+ u8 type; /* 0x84 */
+ u8 ver; /* 0x01 */
+ u8 len; /* 0x0a */
+
+ u8 checksum; /* PB0 */
+ u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
+ u8 SS01_SF24;
+ u8 CXT04;
+ u8 CA;
+ u8 LFEPBL01_LSV36_DM_INH7;
+ u8 reserved[5]; /* PB6 - PB10 */
+};
+
+/*
+ * CEA speaker placement:
+ *
+ * FLH FCH FRH
+ * FLW FL FLC FC FRC FR FRW
+ *
+ * LFE
+ * TC
+ *
+ * RL RLC RC RRC RR
+ *
+ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
+ * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+ FL = (1 << 0), /* Front Left */
+ FC = (1 << 1), /* Front Center */
+ FR = (1 << 2), /* Front Right */
+ FLC = (1 << 3), /* Front Left Center */
+ FRC = (1 << 4), /* Front Right Center */
+ RL = (1 << 5), /* Rear Left */
+ RC = (1 << 6), /* Rear Center */
+ RR = (1 << 7), /* Rear Right */
+ RLC = (1 << 8), /* Rear Left Center */
+ RRC = (1 << 9), /* Rear Right Center */
+ LFE = (1 << 10), /* Low Frequency Effect */
+ FLW = (1 << 11), /* Front Left Wide */
+ FRW = (1 << 12), /* Front Right Wide */
+ FLH = (1 << 13), /* Front Left High */
+ FCH = (1 << 14), /* Front Center High */
+ FRH = (1 << 15), /* Front Right High */
+ TC = (1 << 16), /* Top Center */
+};
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+ */
+static int eld_speaker_allocation_bits[] = {
+ [0] = FL | FR,
+ [1] = LFE,
+ [2] = FC,
+ [3] = RL | RR,
+ [4] = RC,
+ [5] = FLC | FRC,
+ [6] = RLC | RRC,
+ /* the following are not defined in ELD yet */
+ [7] = FLW | FRW,
+ [8] = FLH | FRH,
+ [9] = TC,
+ [10] = FCH,
+};
+
+struct cea_channel_speaker_allocation {
+ int ca_index;
+ int speakers[8];
+
+ /* derived values, just for convenience */
+ int channels;
+ int spk_mask;
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_setup_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/* channel: 8 7 6 5 4 3 2 1 */
+{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
+ /* 2.1 */
+{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
+ /* Dolby Surround */
+{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
+{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
+{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
+{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
+{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
+{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
+{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
+ /* 5.1 */
+{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
+ /* 6.1 */
+{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
+ /* 7.1 */
+{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
+{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
+{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
+{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
+{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
+{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
+{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
+{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
+{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
+{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
+};
+
+/*
+ * HDMI routines
+ */
+
+#ifdef BE_PARANOID
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid,
+ int *packet_index, int *byte_index)
+{
+ int val;
+
+ val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0);
+
+ *packet_index = val >> 5;
+ *byte_index = val & 0x1f;
+}
+#endif
+
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid,
+ int packet_index, int byte_index)
+{
+ int val;
+
+ val = (packet_index << 5) | (byte_index & 0x1f);
+
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char val)
+{
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+}
+
+static void hdmi_enable_output(struct hda_codec *codec)
+{
+ /* Enable Audio InfoFrame Transmission */
+ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+ snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+ AC_DIPXMIT_BEST);
+ /* Unmute */
+ if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, PIN_NID, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ /* Enable pin out */
+ snd_hda_sequence_write(codec, pinout_enable_verb);
+}
+
+static void hdmi_disable_output(struct hda_codec *codec)
+{
+ snd_hda_sequence_write(codec, pinout_disable_verb);
+ if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, PIN_NID, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ /*
+ * FIXME: noises may arise when playing music after reloading the
+ * kernel module, until the next X restart or monitor repower.
+ */
+}
+
+static int hdmi_get_channel_count(struct hda_codec *codec)
+{
+ return 1 + snd_hda_codec_read(codec, CVT_NID, 0,
+ AC_VERB_GET_CVT_CHAN_COUNT, 0);
+}
+
+static void hdmi_set_channel_count(struct hda_codec *codec, int chs)
+{
+ snd_hda_codec_write(codec, CVT_NID, 0,
+ AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
+
+ if (chs != hdmi_get_channel_count(codec))
+ snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n",
+ chs, hdmi_get_channel_count(codec));
+}
+
+static void hdmi_debug_channel_mapping(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ int i;
+ int slot;
+
+ for (i = 0; i < 8; i++) {
+ slot = snd_hda_codec_read(codec, CVT_NID, 0,
+ AC_VERB_GET_HDMI_CHAN_SLOT, i);
+ printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
+ slot >> 4, slot & 0x7);
+ }
+#endif
+}
+
+static void hdmi_parse_eld(struct hda_codec *codec)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+ struct hdmi_eld *eld = &spec->sink_eld;
+
+ if (!snd_hdmi_get_eld(eld, codec, PIN_NID))
+ snd_hdmi_show_eld(eld);
+}
+
+
+/*
+ * Audio InfoFrame routines
+ */
+
+static void hdmi_debug_dip_size(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ int i;
+ int size;
+
+ size = snd_hdmi_get_eld_size(codec, PIN_NID);
+ printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
+
+ for (i = 0; i < 8; i++) {
+ size = snd_hda_codec_read(codec, PIN_NID, 0,
+ AC_VERB_GET_HDMI_DIP_SIZE, i);
+ printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+ }
+#endif
+}
+
+static void hdmi_clear_dip_buffers(struct hda_codec *codec)
+{
+#ifdef BE_PARANOID
+ int i, j;
+ int size;
+ int pi, bi;
+ for (i = 0; i < 8; i++) {
+ size = snd_hda_codec_read(codec, PIN_NID, 0,
+ AC_VERB_GET_HDMI_DIP_SIZE, i);
+ if (size == 0)
+ continue;
+
+ hdmi_set_dip_index(codec, PIN_NID, i, 0x0);
+ for (j = 1; j < 1000; j++) {
+ hdmi_write_dip_byte(codec, PIN_NID, 0x0);
+ hdmi_get_dip_index(codec, PIN_NID, &pi, &bi);
+ if (pi != i)
+ snd_printd(KERN_INFO "dip index %d: %d != %d\n",
+ bi, pi, i);
+ if (bi == 0) /* byte index wrapped around */
+ break;
+ }
+ snd_printd(KERN_INFO
+ "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
+ i, size, j);
+ }
+#endif
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+ struct hdmi_audio_infoframe *ai)
+{
+ u8 *params = (u8 *)ai;
+ int i;
+
+ hdmi_debug_dip_size(codec);
+ hdmi_clear_dip_buffers(codec); /* be paranoid */
+
+ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+ for (i = 0; i < sizeof(ai); i++)
+ hdmi_write_dip_byte(codec, PIN_NID, params[i]);
+}
+
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+ int i, j;
+ struct cea_channel_speaker_allocation *p;
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ p = channel_allocations + i;
+ p->channels = 0;
+ p->spk_mask = 0;
+ for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+ if (p->speakers[j]) {
+ p->channels++;
+ p->spk_mask |= p->speakers[j];
+ }
+ }
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ * spk_mask => (channel_allocations[]) => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+*/
+static int hdmi_setup_channel_allocation(struct hda_codec *codec,
+ struct hdmi_audio_infoframe *ai)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+ struct hdmi_eld *eld = &spec->sink_eld;
+ int i;
+ int spk_mask = 0;
+ int channels = 1 + (ai->CC02_CT47 & 0x7);
+ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+
+ /*
+ * CA defaults to 0 for basic stereo audio
+ */
+ if (!eld->eld_ver)
+ return 0;
+ if (!eld->spk_alloc)
+ return 0;
+ if (channels <= 2)
+ return 0;
+
+ /*
+ * expand ELD's speaker allocation mask
+ *
+ * ELD tells the speaker mask in a compact(paired) form,
+ * expand ELD's notions to match the ones used by Audio InfoFrame.
+ */
+ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+ if (eld->spk_alloc & (1 << i))
+ spk_mask |= eld_speaker_allocation_bits[i];
+ }
+
+ /* search for the first working match in the CA table */
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channels == channel_allocations[i].channels &&
+ (spk_mask & channel_allocations[i].spk_mask) ==
+ channel_allocations[i].spk_mask) {
+ ai->CA = channel_allocations[i].ca_index;
+ break;
+ }
+ }
+
+ snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
+ snd_printdd(KERN_INFO
+ "HDMI: select CA 0x%x for %d-channel allocation: %s\n",
+ ai->CA, channels, buf);
+
+ return ai->CA;
+}
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+ struct hdmi_audio_infoframe *ai)
+{
+ if (!ai->CA)
+ return;
+
+ /*
+ * TODO: adjust channel mapping if necessary
+ * ALSA sequence is front/surr/clfe/side?
+ */
+
+ snd_hda_sequence_write(codec, def_chan_map);
+ hdmi_debug_channel_mapping(codec);
+}
+
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_audio_infoframe ai = {
+ .type = 0x84,
+ .ver = 0x01,
+ .len = 0x0a,
+ .CC02_CT47 = substream->runtime->channels - 1,
+ };
+
+ hdmi_setup_channel_allocation(codec, &ai);
+ hdmi_setup_channel_mapping(codec, &ai);
+
+ hdmi_fill_audio_infoframe(codec, &ai);
+}
+
+
+/*
+ * Unsolicited events
+ */
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+ int pind = !!(res & AC_UNSOL_RES_PD);
+ int eldv = !!(res & AC_UNSOL_RES_ELDV);
+
+ printk(KERN_INFO
+ "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n",
+ pind, eldv);
+
+ if (pind && eldv) {
+ hdmi_parse_eld(codec);
+ /* TODO: do real things about ELD */
+ }
+}
+
+static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+ int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+ int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
+ int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
+
+ printk(KERN_INFO
+ "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+ subtag,
+ cp_state,
+ cp_ready);
+
+ /* TODO */
+ if (cp_state)
+ ;
+ if (cp_ready)
+ ;
+}
+
+
+static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+ int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+
+ if (tag != INTEL_HDMI_EVENT_TAG) {
+ snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
+ return;
+ }
+
+ if (subtag == 0)
+ hdmi_intrinsic_event(codec, res);
+ else
+ hdmi_non_intrinsic_event(codec, res);
+}
+
+/*
+ * Callbacks
+ */
+
+static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+
+ hdmi_disable_output(codec);
+
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+
+ snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+ format, substream);
+
+ hdmi_set_channel_count(codec, substream->runtime->channels);
+
+ hdmi_setup_audio_infoframe(codec, substream);
+
+ hdmi_enable_output(codec);
+
+ return 0;
+}
+
+static struct hda_pcm_stream intel_hdmi_pcm_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ .nid = CVT_NID, /* NID to query formats and rates and setup streams */
+ .ops = {
+ .open = intel_hdmi_playback_pcm_open,
+ .close = intel_hdmi_playback_pcm_close,
+ .prepare = intel_hdmi_playback_pcm_prepare
+ },
+};
+
+static int intel_hdmi_build_pcms(struct hda_codec *codec)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+ struct hda_pcm *info = &spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "INTEL HDMI";
+ info->pcm_type = HDA_PCM_TYPE_HDMI;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
+
+ return 0;
+}
+
+static int intel_hdmi_build_controls(struct hda_codec *codec)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int intel_hdmi_init(struct hda_codec *codec)
+{
+ /* disable audio output as early as possible */
+ hdmi_disable_output(codec);
+
+ snd_hda_sequence_write(codec, unsolicited_response_verb);
+
+ return 0;
+}
+
+static void intel_hdmi_free(struct hda_codec *codec)
+{
+ struct intel_hdmi_spec *spec = codec->spec;
+
+ snd_hda_eld_proc_free(codec, &spec->sink_eld);
+ kfree(spec);
+}
+
+static struct hda_codec_ops intel_hdmi_patch_ops = {
+ .init = intel_hdmi_init,
+ .free = intel_hdmi_free,
+ .build_pcms = intel_hdmi_build_pcms,
+ .build_controls = intel_hdmi_build_controls,
+ .unsol_event = intel_hdmi_unsol_event,
+};
+
+static int patch_intel_hdmi(struct hda_codec *codec)
+{
+ struct intel_hdmi_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ spec->multiout.num_dacs = 0; /* no analog */
+ spec->multiout.max_channels = 8;
+ spec->multiout.dig_out_nid = CVT_NID;
+
+ codec->spec = spec;
+ codec->patch_ops = intel_hdmi_patch_ops;
+
+ snd_hda_eld_proc_new(codec, &spec->sink_eld);
+
+ init_channel_allocations();
+
+ return 0;
+}
+
+struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
+ { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi },
+ { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi },
+ { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi },
+ { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi },
+ { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
+ {} /* terminator */
+};
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index 2eed2c8b98da..1360d54a7d01 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -28,6 +28,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_patch.h"
struct nvhdmi_spec {
struct hda_multi_out multiout;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index a378c0145125..40b3fcd142a3 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -114,6 +114,7 @@ enum {
ALC268_3ST,
ALC268_TOSHIBA,
ALC268_ACER,
+ ALC268_ACER_DMIC,
ALC268_ACER_ASPIRE_ONE,
ALC268_DELL,
ALC268_ZEPTO,
@@ -130,6 +131,8 @@ enum {
ALC269_QUANTA_FL1,
ALC269_ASUS_EEEPC_P703,
ALC269_ASUS_EEEPC_P901,
+ ALC269_FUJITSU,
+ ALC269_LIFEBOOK,
ALC269_AUTO,
ALC269_MODEL_LAST /* last tag */
};
@@ -152,6 +155,7 @@ enum {
enum {
ALC660VD_3ST,
ALC660VD_3ST_DIG,
+ ALC660VD_ASUS_V1S,
ALC861VD_3ST,
ALC861VD_3ST_DIG,
ALC861VD_6ST_DIG,
@@ -212,6 +216,7 @@ enum {
ALC883_TARGA_2ch_DIG,
ALC883_ACER,
ALC883_ACER_ASPIRE,
+ ALC888_ACER_ASPIRE_4930G,
ALC883_MEDION,
ALC883_MEDION_MD2,
ALC883_LAPTOP_EAPD,
@@ -225,9 +230,11 @@ enum {
ALC883_MITAC,
ALC883_CLEVO_M720,
ALC883_FUJITSU_PI2515,
+ ALC888_FUJITSU_XA3530,
ALC883_3ST_6ch_INTEL,
ALC888_ASUS_M90V,
ALC888_ASUS_EEE1601,
+ ALC1200_ASUS_P5Q,
ALC883_AUTO,
ALC883_MODEL_LAST,
};
@@ -239,6 +246,7 @@ struct alc_spec {
/* codec parameterization */
struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
unsigned int num_mixers;
+ struct snd_kcontrol_new *cap_mixer; /* capture mixer */
const struct hda_verb *init_verbs[5]; /* initialization verbs
* don't forget NULL
@@ -268,6 +276,7 @@ struct alc_spec {
hda_nid_t *adc_nids;
hda_nid_t *capsrc_nids;
hda_nid_t dig_in_nid; /* digital-in NID; optional */
+ unsigned char is_mix_capture; /* matrix-style capture (non-mux) */
/* capture source */
unsigned int num_mux_defs;
@@ -284,8 +293,7 @@ struct alc_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
- unsigned int num_kctl_alloc, num_kctl_used;
- struct snd_kcontrol_new *kctl_alloc;
+ struct snd_array kctls;
struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
@@ -323,6 +331,7 @@ struct alc_config_preset {
struct snd_kcontrol_new *mixers[5]; /* should be identical size
* with spec
*/
+ struct snd_kcontrol_new *cap_mixer; /* capture mixer */
const struct hda_verb *init_verbs[5];
unsigned int num_dacs;
hda_nid_t *dac_nids;
@@ -375,14 +384,39 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
+ const struct hda_input_mux *imux;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+ unsigned int mux_idx;
hda_nid_t nid = spec->capsrc_nids ?
spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
- return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
- nid, &spec->cur_mux[adc_idx]);
-}
+ mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+ imux = &spec->input_mux[mux_idx];
+
+ if (spec->is_mix_capture) {
+ /* Matrix-mixer style (e.g. ALC882) */
+ unsigned int *cur_val = &spec->cur_mux[adc_idx];
+ unsigned int i, idx;
+
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ if (*cur_val == idx)
+ return 0;
+ for (i = 0; i < imux->num_items; i++) {
+ unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
+ snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
+ imux->items[i].index,
+ HDA_AMP_MUTE, v);
+ }
+ *cur_val = idx;
+ return 1;
+ } else {
+ /* MUX style (e.g. ALC880) */
+ return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
+ &spec->cur_mux[adc_idx]);
+ }
+}
/*
* channel mode setting
@@ -717,6 +751,43 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
#endif /* CONFIG_SND_DEBUG */
/*
+ */
+static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
+{
+ if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
+ return;
+ spec->mixers[spec->num_mixers++] = mix;
+}
+
+static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
+{
+ if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
+ return;
+ spec->init_verbs[spec->num_init_verbs++] = verb;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * hook for proc
+ */
+static void print_realtek_coef(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ int coeff;
+
+ if (nid != 0x20)
+ return;
+ coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+ snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
+ coeff = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_COEF_INDEX, 0);
+ snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
+}
+#else
+#define print_realtek_coef NULL
+#endif
+
+/*
* set up from the preset table
*/
static void setup_preset(struct alc_spec *spec,
@@ -725,11 +796,11 @@ static void setup_preset(struct alc_spec *spec,
int i;
for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
- spec->mixers[spec->num_mixers++] = preset->mixers[i];
+ add_mixer(spec, preset->mixers[i]);
+ spec->cap_mixer = preset->cap_mixer;
for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
i++)
- spec->init_verbs[spec->num_init_verbs++] =
- preset->init_verbs[i];
+ add_verb(spec, preset->init_verbs[i]);
spec->channel_mode = preset->channel_mode;
spec->num_channel_mode = preset->num_channel_mode;
@@ -1107,6 +1178,226 @@ static void alc_fix_pincfg(struct hda_codec *codec,
}
/*
+ * ALC888
+ */
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc888_4ST_ch2_intel_init[] = {
+/* Mic-in jack as mic in */
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-in jack as Line in */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-Out as Front */
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+ { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc888_4ST_ch4_intel_init[] = {
+/* Mic-in jack as mic in */
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-in jack as Surround */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as Front */
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+ { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc888_4ST_ch6_intel_init[] = {
+/* Mic-in jack as CLFE */
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-in jack as Surround */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+ { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc888_4ST_ch8_intel_init[] = {
+/* Mic-in jack as CLFE */
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-in jack as Surround */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as Side */
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+ { } /* end */
+};
+
+static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
+ { 2, alc888_4ST_ch2_intel_init },
+ { 4, alc888_4ST_ch4_intel_init },
+ { 6, alc888_4ST_ch6_intel_init },
+ { 8, alc888_4ST_ch8_intel_init },
+};
+
+/*
+ * ALC888 Fujitsu Siemens Amillo xa3530
+ */
+
+static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Connect Internal HP to Front */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect Bass HP to Front */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect Line-Out side jack (SPDIF) to Side */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+/* Connect Mic jack to CLFE */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect Line-in jack to Surround */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect HP out jack to Front */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Enable unsolicited event for HP jack and Line-out jack */
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ {}
+};
+
+static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned int bits;
+ /* Line out presence */
+ present = snd_hda_codec_read(codec, 0x17, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ /* HP out presence */
+ present = present || snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ bits = present ? HDA_AMP_MUTE : 0;
+ /* Toggle internal speakers muting */
+ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+ /* Toggle internal bass muting */
+ snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+}
+
+static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if (res >> 26 == ALC880_HP_EVENT)
+ alc888_fujitsu_xa3530_automute(codec);
+}
+
+
+/*
+ * ALC888 Acer Aspire 4930G model
+ */
+
+static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Connect Internal HP to front */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect HP out to front */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ { }
+};
+
+static struct hda_input_mux alc888_2_capture_sources[2] = {
+ /* Front mic only available on one ADC */
+ {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ { "Front Mic", 0xb },
+ },
+ },
+ {
+ .num_items = 3,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+ }
+};
+
+static struct snd_kcontrol_new alc888_base_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+ HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ { } /* end */
+};
+
+static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned int bits;
+ present = snd_hda_codec_read(codec, 0x15, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ bits = present ? HDA_AMP_MUTE : 0;
+ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+}
+
+static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if (res >> 26 == ALC880_HP_EVENT)
+ alc888_acer_aspire_4930g_automute(codec);
+}
+
+/*
* ALC880 3-stack model
*
* DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
@@ -1205,49 +1496,126 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
};
/* capture mixer elements */
-static struct snd_kcontrol_new alc880_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 3,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
- { } /* end */
-};
+static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ int err;
-/* capture mixer elements (in case NID 0x07 not available) */
-static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
- { } /* end */
-};
+ mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
+ HDA_INPUT);
+ err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+ mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ return err;
+}
+
+static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ int err;
+ mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
+ HDA_INPUT);
+ err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+ mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ return err;
+}
+
+typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol,
+ getput_call_t func)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ int err;
+
+ mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
+ 3, 0, HDA_INPUT);
+ err = func(kcontrol, ucontrol);
+ mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ return err;
+}
+
+static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return alc_cap_getput_caller(kcontrol, ucontrol,
+ snd_hda_mixer_amp_volume_get);
+}
+
+static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return alc_cap_getput_caller(kcontrol, ucontrol,
+ snd_hda_mixer_amp_volume_put);
+}
+
+/* capture mixer elements */
+#define alc_cap_sw_info snd_ctl_boolean_stereo_info
+
+static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return alc_cap_getput_caller(kcontrol, ucontrol,
+ snd_hda_mixer_amp_switch_get);
+}
+
+static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return alc_cap_getput_caller(kcontrol, ucontrol,
+ snd_hda_mixer_amp_switch_put);
+}
+
+#define DEFINE_CAPMIX(num) \
+static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Capture Switch", \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .count = num, \
+ .info = alc_cap_sw_info, \
+ .get = alc_cap_sw_get, \
+ .put = alc_cap_sw_put, \
+ }, \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Capture Volume", \
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
+ .count = num, \
+ .info = alc_cap_vol_info, \
+ .get = alc_cap_vol_get, \
+ .put = alc_cap_vol_put, \
+ .tlv = { .c = alc_cap_vol_tlv }, \
+ }, \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ /* .name = "Capture Source", */ \
+ .name = "Input Source", \
+ .count = num, \
+ .info = alc_mux_enum_info, \
+ .get = alc_mux_enum_get, \
+ .put = alc_mux_enum_put, \
+ }, \
+ { } /* end */ \
+}
+
+/* up to three ADCs */
+DEFINE_CAPMIX(1);
+DEFINE_CAPMIX(2);
+DEFINE_CAPMIX(3);
/*
@@ -1533,18 +1901,6 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{ } /* end */
};
@@ -1619,6 +1975,7 @@ static const char *alc_slave_vols[] = {
"Speaker Playback Volume",
"Mono Playback Volume",
"Line-Out Playback Volume",
+ "PCM Playback Volume",
NULL,
};
@@ -1638,6 +1995,9 @@ static const char *alc_slave_sws[] = {
/*
* build control elements
*/
+
+static void alc_free_kctls(struct hda_codec *codec);
+
static int alc_build_controls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -1649,7 +2009,11 @@ static int alc_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
-
+ if (spec->cap_mixer) {
+ err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
+ if (err < 0)
+ return err;
+ }
if (spec->multiout.dig_out_nid) {
err = snd_hda_create_spdif_out_ctls(codec,
spec->multiout.dig_out_nid);
@@ -1684,6 +2048,7 @@ static int alc_build_controls(struct hda_codec *codec)
return err;
}
+ alc_free_kctls(codec); /* no longer needed */
return 0;
}
@@ -2774,19 +3139,27 @@ static int alc_build_pcms(struct hda_codec *codec)
return 0;
}
+static void alc_free_kctls(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (spec->kctls.list) {
+ struct snd_kcontrol_new *kctl = spec->kctls.list;
+ int i;
+ for (i = 0; i < spec->kctls.used; i++)
+ kfree(kctl[i].name);
+ }
+ snd_array_free(&spec->kctls);
+}
+
static void alc_free(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- unsigned int i;
if (!spec)
return;
- if (spec->kctl_alloc) {
- for (i = 0; i < spec->num_kctl_used; i++)
- kfree(spec->kctl_alloc[i].name);
- kfree(spec->kctl_alloc);
- }
+ alc_free_kctls(codec);
kfree(spec);
codec->spec = NULL; /* to be sure */
}
@@ -3268,6 +3641,8 @@ static struct alc_config_preset alc880_presets[] = {
alc880_gpio2_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_dac_nids),
.dac_nids = alc880_dac_nids,
+ .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
+ .num_adc_nids = 1, /* single ADC */
.hp_nid = 0x03,
.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
.channel_mode = alc880_2_jack_modes,
@@ -3532,9 +3907,6 @@ static struct alc_config_preset alc880_presets[] = {
* Automatic parse of I/O pins from the BIOS configuration
*/
-#define NUM_CONTROL_ALLOC 32
-#define NUM_VERB_ALLOC 32
-
enum {
ALC_CTL_WIDGET_VOL,
ALC_CTL_WIDGET_MUTE,
@@ -3552,29 +3924,15 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
{
struct snd_kcontrol_new *knew;
- if (spec->num_kctl_used >= spec->num_kctl_alloc) {
- int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
- /* array + terminator */
- knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
- if (!knew)
- return -ENOMEM;
- if (spec->kctl_alloc) {
- memcpy(knew, spec->kctl_alloc,
- sizeof(*knew) * spec->num_kctl_alloc);
- kfree(spec->kctl_alloc);
- }
- spec->kctl_alloc = knew;
- spec->num_kctl_alloc = num;
- }
-
- knew = &spec->kctl_alloc[spec->num_kctl_used];
+ snd_array_init(&spec->kctls, sizeof(*knew), 32);
+ knew = snd_array_new(&spec->kctls);
+ if (!knew)
+ return -ENOMEM;
*knew = alc880_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name)
return -ENOMEM;
knew->private_value = val;
- spec->num_kctl_used++;
return 0;
}
@@ -3898,10 +4256,10 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC880_DIGIN_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
- spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
+ add_verb(spec, alc880_volume_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
@@ -3925,6 +4283,17 @@ static void alc880_auto_init(struct hda_codec *codec)
* OK, here we have finally the patch for ALC880
*/
+static void set_capture_mixer(struct alc_spec *spec)
+{
+ static struct snd_kcontrol_new *caps[3] = {
+ alc_capture_mixer1,
+ alc_capture_mixer2,
+ alc_capture_mixer3,
+ };
+ if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3)
+ spec->cap_mixer = caps[spec->num_adc_nids - 1];
+}
+
static int patch_alc880(struct hda_codec *codec)
{
struct alc_spec *spec;
@@ -3980,16 +4349,12 @@ static int patch_alc880(struct hda_codec *codec)
if (wcap != AC_WID_AUD_IN) {
spec->adc_nids = alc880_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
- spec->mixers[spec->num_mixers] =
- alc880_capture_alt_mixer;
- spec->num_mixers++;
} else {
spec->adc_nids = alc880_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
- spec->mixers[spec->num_mixers] = alc880_capture_mixer;
- spec->num_mixers++;
}
}
+ set_capture_mixer(spec);
spec->vmaster_nid = 0x0c;
@@ -4000,6 +4365,7 @@ static int patch_alc880(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc880_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -4024,11 +4390,6 @@ static hda_nid_t alc260_adc_nids_alt[1] = {
0x05,
};
-static hda_nid_t alc260_hp_adc_nids[2] = {
- /* ADC1, 0 */
- 0x05, 0x04
-};
-
/* NIDs used when simultaneous access to both ADCs makes sense. Note that
* alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
*/
@@ -4157,13 +4518,13 @@ static void alc260_hp_master_update(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
unsigned int val = spec->master_sw ? PIN_HP : 0;
/* change HP and line-out pins */
- snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
val);
- snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
val);
/* mono (speaker) depending on the HP jack sense */
val = (val && !spec->jack_present) ? PIN_OUT : 0;
- snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
val);
}
@@ -4242,7 +4603,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
.info = snd_ctl_boolean_mono_info,
.get = alc260_hp_master_sw_get,
.put = alc260_hp_master_sw_put,
- .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
+ .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
},
HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
@@ -4295,7 +4656,7 @@ static void alc260_hp_3013_automute(struct hda_codec *codec)
present = snd_hda_codec_read(codec, 0x15, 0,
AC_VERB_GET_PIN_SENSE, 0);
spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
- alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
+ alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
}
static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
@@ -4427,45 +4788,6 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
{ } /* end */
};
-/* capture mixer elements */
-static struct snd_kcontrol_new alc260_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
- { } /* end */
-};
-
-static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
- { } /* end */
-};
-
/*
* initialization verbs
*/
@@ -5282,7 +5604,6 @@ static struct hda_verb alc260_volume_init_verbs[] = {
static int alc260_parse_auto_config(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- unsigned int wcap;
int err;
static hda_nid_t alc260_ignore[] = { 0x17, 0 };
@@ -5293,7 +5614,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
- if (!spec->kctl_alloc)
+ if (!spec->kctls.list)
return 0; /* can't find valid BIOS pin config */
err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
if (err < 0)
@@ -5303,28 +5624,14 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
- spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
+ add_verb(spec, alc260_volume_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
- /* check whether NID 0x04 is valid */
- wcap = get_wcaps(codec, 0x04);
- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
- if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
- spec->adc_nids = alc260_adc_nids_alt;
- spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
- spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
- } else {
- spec->adc_nids = alc260_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
- spec->mixers[spec->num_mixers] = alc260_capture_mixer;
- }
- spec->num_mixers++;
-
store_pin_configs(codec);
return 1;
}
@@ -5394,12 +5701,11 @@ static struct alc_config_preset alc260_presets[] = {
[ALC260_BASIC] = {
.mixers = { alc260_base_output_mixer,
alc260_input_mixer,
- alc260_pc_beep_mixer,
- alc260_capture_mixer },
+ alc260_pc_beep_mixer },
.init_verbs = { alc260_init_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
+ .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
.adc_nids = alc260_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
@@ -5407,14 +5713,13 @@ static struct alc_config_preset alc260_presets[] = {
},
[ALC260_HP] = {
.mixers = { alc260_hp_output_mixer,
- alc260_input_mixer,
- alc260_capture_alt_mixer },
+ alc260_input_mixer },
.init_verbs = { alc260_init_verbs,
alc260_hp_unsol_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
- .adc_nids = alc260_hp_adc_nids,
+ .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+ .adc_nids = alc260_adc_nids_alt,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
.input_mux = &alc260_capture_source,
@@ -5423,14 +5728,13 @@ static struct alc_config_preset alc260_presets[] = {
},
[ALC260_HP_DC7600] = {
.mixers = { alc260_hp_dc7600_mixer,
- alc260_input_mixer,
- alc260_capture_alt_mixer },
+ alc260_input_mixer },
.init_verbs = { alc260_init_verbs,
alc260_hp_dc7600_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
- .adc_nids = alc260_hp_adc_nids,
+ .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+ .adc_nids = alc260_adc_nids_alt,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
.input_mux = &alc260_capture_source,
@@ -5439,14 +5743,13 @@ static struct alc_config_preset alc260_presets[] = {
},
[ALC260_HP_3013] = {
.mixers = { alc260_hp_3013_mixer,
- alc260_input_mixer,
- alc260_capture_alt_mixer },
+ alc260_input_mixer },
.init_verbs = { alc260_hp_3013_init_verbs,
alc260_hp_3013_unsol_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
- .adc_nids = alc260_hp_adc_nids,
+ .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+ .adc_nids = alc260_adc_nids_alt,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
.input_mux = &alc260_capture_source,
@@ -5454,8 +5757,7 @@ static struct alc_config_preset alc260_presets[] = {
.init_hook = alc260_hp_3013_automute,
},
[ALC260_FUJITSU_S702X] = {
- .mixers = { alc260_fujitsu_mixer,
- alc260_capture_mixer },
+ .mixers = { alc260_fujitsu_mixer },
.init_verbs = { alc260_fujitsu_init_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
@@ -5467,8 +5769,7 @@ static struct alc_config_preset alc260_presets[] = {
.input_mux = alc260_fujitsu_capture_sources,
},
[ALC260_ACER] = {
- .mixers = { alc260_acer_mixer,
- alc260_capture_mixer },
+ .mixers = { alc260_acer_mixer },
.init_verbs = { alc260_acer_init_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
@@ -5480,8 +5781,7 @@ static struct alc_config_preset alc260_presets[] = {
.input_mux = alc260_acer_capture_sources,
},
[ALC260_WILL] = {
- .mixers = { alc260_will_mixer,
- alc260_capture_mixer },
+ .mixers = { alc260_will_mixer },
.init_verbs = { alc260_init_verbs, alc260_will_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
@@ -5493,8 +5793,7 @@ static struct alc_config_preset alc260_presets[] = {
.input_mux = &alc260_capture_source,
},
[ALC260_REPLACER_672V] = {
- .mixers = { alc260_replacer_672v_mixer,
- alc260_capture_mixer },
+ .mixers = { alc260_replacer_672v_mixer },
.init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
@@ -5509,8 +5808,7 @@ static struct alc_config_preset alc260_presets[] = {
},
#ifdef CONFIG_SND_DEBUG
[ALC260_TEST] = {
- .mixers = { alc260_test_mixer,
- alc260_capture_mixer },
+ .mixers = { alc260_test_mixer },
.init_verbs = { alc260_test_init_verbs },
.num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
.dac_nids = alc260_test_dac_nids,
@@ -5569,6 +5867,21 @@ static int patch_alc260(struct hda_codec *codec)
spec->stream_digital_playback = &alc260_pcm_digital_playback;
spec->stream_digital_capture = &alc260_pcm_digital_capture;
+ if (!spec->adc_nids && spec->input_mux) {
+ /* check whether NID 0x04 is valid */
+ unsigned int wcap = get_wcaps(codec, 0x04);
+ wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ /* get type */
+ if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
+ spec->adc_nids = alc260_adc_nids_alt;
+ spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
+ } else {
+ spec->adc_nids = alc260_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
+ }
+ }
+ set_capture_mixer(spec);
+
spec->vmaster_nid = 0x08;
codec->patch_ops = alc_patch_ops;
@@ -5578,6 +5891,7 @@ static int patch_alc260(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc260_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -5625,36 +5939,6 @@ static struct hda_input_mux alc882_capture_source = {
{ "CD", 0x4 },
},
};
-#define alc882_mux_enum_info alc_mux_enum_info
-#define alc882_mux_enum_get alc_mux_enum_get
-
-static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- const struct hda_input_mux *imux = spec->input_mux;
- unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- hda_nid_t nid = spec->capsrc_nids ?
- spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
- unsigned int *cur_val = &spec->cur_mux[adc_idx];
- unsigned int i, idx;
-
- idx = ucontrol->value.enumerated.item[0];
- if (idx >= imux->num_items)
- idx = imux->num_items - 1;
- if (*cur_val == idx)
- return 0;
- for (i = 0; i < imux->num_items; i++) {
- unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
- snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
- imux->items[i].index,
- HDA_AMP_MUTE, v);
- }
- *cur_val = idx;
- return 1;
-}
-
/*
* 2ch mode
*/
@@ -6337,49 +6621,6 @@ static struct hda_verb alc882_auto_init_verbs[] = {
{ }
};
-/* capture mixer elements */
-static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc882_mux_enum_info,
- .get = alc882_mux_enum_get,
- .put = alc882_mux_enum_put,
- },
- { } /* end */
-};
-
-static struct snd_kcontrol_new alc882_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 3,
- .info = alc882_mux_enum_info,
- .get = alc882_mux_enum_get,
- .put = alc882_mux_enum_put,
- },
- { } /* end */
-};
-
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc882_loopbacks alc880_loopbacks
#endif
@@ -6508,8 +6749,7 @@ static struct alc_config_preset alc882_presets[] = {
.init_hook = alc885_imac24_init_hook,
},
[ALC882_TARGA] = {
- .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
- alc882_capture_mixer },
+ .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
.init_verbs = { alc882_init_verbs, alc882_targa_verbs},
.num_dacs = ARRAY_SIZE(alc882_dac_nids),
.dac_nids = alc882_dac_nids,
@@ -6525,8 +6765,7 @@ static struct alc_config_preset alc882_presets[] = {
.init_hook = alc882_targa_automute,
},
[ALC882_ASUS_A7J] = {
- .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
- alc882_capture_mixer },
+ .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
.init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
.num_dacs = ARRAY_SIZE(alc882_dac_nids),
.dac_nids = alc882_dac_nids,
@@ -6831,6 +7070,7 @@ static int patch_alc882(struct hda_codec *codec)
spec->stream_digital_playback = &alc882_pcm_digital_playback;
spec->stream_digital_capture = &alc882_pcm_digital_capture;
+ spec->is_mix_capture = 1; /* matrix-style capture */
if (!spec->adc_nids && spec->input_mux) {
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, 0x07);
@@ -6840,17 +7080,13 @@ static int patch_alc882(struct hda_codec *codec)
spec->adc_nids = alc882_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
spec->capsrc_nids = alc882_capsrc_nids_alt;
- spec->mixers[spec->num_mixers] =
- alc882_capture_alt_mixer;
- spec->num_mixers++;
} else {
spec->adc_nids = alc882_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
spec->capsrc_nids = alc882_capsrc_nids;
- spec->mixers[spec->num_mixers] = alc882_capture_mixer;
- spec->num_mixers++;
}
}
+ set_capture_mixer(spec);
spec->vmaster_nid = 0x0c;
@@ -6861,6 +7097,7 @@ static int patch_alc882(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc882_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -6879,6 +7116,8 @@ static int patch_alc882(struct hda_codec *codec)
#define ALC883_DIGOUT_NID 0x06
#define ALC883_DIGIN_NID 0x0a
+#define ALC1200_DIGOUT_NID 0x10
+
static hda_nid_t alc883_dac_nids[4] = {
/* front, rear, clfe, rear_surr */
0x02, 0x03, 0x04, 0x05
@@ -6889,8 +7128,20 @@ static hda_nid_t alc883_adc_nids[2] = {
0x08, 0x09,
};
+static hda_nid_t alc883_adc_nids_alt[1] = {
+ /* ADC1 */
+ 0x08,
+};
+
+static hda_nid_t alc883_adc_nids_rev[2] = {
+ /* ADC2-1 */
+ 0x09, 0x08
+};
+
static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
+static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+
/* input MUX */
/* FIXME: should be a matrix-type input source selection */
@@ -6957,11 +7208,6 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = {
},
};
-#define alc883_mux_enum_info alc_mux_enum_info
-#define alc883_mux_enum_get alc_mux_enum_get
-/* ALC883 has the ALC882-type input selection */
-#define alc883_mux_enum_put alc882_mux_enum_put
-
/*
* 2ch mode
*/
@@ -7115,19 +7361,6 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7145,19 +7378,6 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7172,19 +7392,6 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7199,19 +7406,6 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7231,19 +7425,6 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7269,17 +7450,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7306,19 +7476,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7344,18 +7501,6 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7376,19 +7521,6 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7404,19 +7536,6 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7429,17 +7548,6 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7453,19 +7561,6 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7479,19 +7574,6 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7504,19 +7586,6 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7544,19 +7613,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
- },
{ } /* end */
};
@@ -7587,6 +7643,10 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
{
@@ -7594,9 +7654,9 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
/* .name = "Capture Source", */
.name = "Input Source",
.count = 1,
- .info = alc883_mux_enum_info,
- .get = alc883_mux_enum_get,
- .put = alc883_mux_enum_put,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
},
{ } /* end */
};
@@ -8251,27 +8311,6 @@ static struct hda_verb alc883_auto_init_verbs[] = {
{ }
};
-/* capture mixer elements */
-static struct snd_kcontrol_new alc883_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = alc882_mux_enum_info,
- .get = alc882_mux_enum_get,
- .put = alc882_mux_enum_put,
- },
- { } /* end */
-};
-
static struct hda_verb alc888_asus_m90v_verbs[] = {
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -8394,6 +8433,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
[ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
[ALC883_ACER] = "acer",
[ALC883_ACER_ASPIRE] = "acer-aspire",
+ [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
[ALC883_MEDION] = "medion",
[ALC883_MEDION_MD2] = "medion-md2",
[ALC883_LAPTOP_EAPD] = "laptop-eapd",
@@ -8407,7 +8447,9 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
[ALC883_MITAC] = "mitac",
[ALC883_CLEVO_M720] = "clevo-m720",
[ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
+ [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
[ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
+ [ALC1200_ASUS_P5Q] = "asus-p5q",
[ALC883_AUTO] = "auto",
};
@@ -8418,6 +8460,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+ ALC888_ACER_ASPIRE_4930G),
SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -8426,6 +8470,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
@@ -8452,6 +8497,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
@@ -8463,6 +8509,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
+ SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
+ ALC888_FUJITSU_XA3530),
SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
@@ -8553,6 +8601,8 @@ static struct alc_config_preset alc883_presets[] = {
.init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
.num_dacs = ARRAY_SIZE(alc883_dac_nids),
.dac_nids = alc883_dac_nids,
+ .adc_nids = alc883_adc_nids_alt,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
.dig_out_nid = ALC883_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
.channel_mode = alc883_3ST_2ch_modes,
@@ -8586,6 +8636,26 @@ static struct alc_config_preset alc883_presets[] = {
.unsol_event = alc883_acer_aspire_unsol_event,
.init_hook = alc883_acer_aspire_automute,
},
+ [ALC888_ACER_ASPIRE_4930G] = {
+ .mixers = { alc888_base_mixer,
+ alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+ alc888_acer_aspire_4930g_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+ .adc_nids = alc883_adc_nids_rev,
+ .capsrc_nids = alc883_capsrc_nids_rev,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+ .channel_mode = alc883_3ST_6ch_modes,
+ .need_dac_fix = 1,
+ .num_mux_defs =
+ ARRAY_SIZE(alc888_2_capture_sources),
+ .input_mux = alc888_2_capture_sources,
+ .unsol_event = alc888_acer_aspire_4930g_unsol_event,
+ .init_hook = alc888_acer_aspire_4930g_automute,
+ },
[ALC883_MEDION] = {
.mixers = { alc883_fivestack_mixer,
alc883_chmode_mixer },
@@ -8593,6 +8663,8 @@ static struct alc_config_preset alc883_presets[] = {
alc883_medion_eapd_verbs },
.num_dacs = ARRAY_SIZE(alc883_dac_nids),
.dac_nids = alc883_dac_nids,
+ .adc_nids = alc883_adc_nids_alt,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
.channel_mode = alc883_sixstack_modes,
.input_mux = &alc883_capture_source,
@@ -8635,6 +8707,8 @@ static struct alc_config_preset alc883_presets[] = {
.init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
.num_dacs = ARRAY_SIZE(alc883_dac_nids),
.dac_nids = alc883_dac_nids,
+ .adc_nids = alc883_adc_nids_alt,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
.channel_mode = alc883_3ST_2ch_modes,
.input_mux = &alc883_lenovo_101e_capture_source,
@@ -8725,14 +8799,30 @@ static struct alc_config_preset alc883_presets[] = {
.unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
.init_hook = alc883_2ch_fujitsu_pi2515_automute,
},
+ [ALC888_FUJITSU_XA3530] = {
+ .mixers = { alc888_base_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs,
+ alc888_fujitsu_xa3530_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+ .adc_nids = alc883_adc_nids_rev,
+ .capsrc_nids = alc883_capsrc_nids_rev,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
+ .channel_mode = alc888_4ST_8ch_intel_modes,
+ .num_mux_defs =
+ ARRAY_SIZE(alc888_2_capture_sources),
+ .input_mux = alc888_2_capture_sources,
+ .unsol_event = alc888_fujitsu_xa3530_unsol_event,
+ .init_hook = alc888_fujitsu_xa3530_automute,
+ },
[ALC888_LENOVO_SKY] = {
.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
.init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
.num_dacs = ARRAY_SIZE(alc883_dac_nids),
.dac_nids = alc883_dac_nids,
.dig_out_nid = ALC883_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
- .adc_nids = alc883_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
.channel_mode = alc883_sixstack_modes,
.need_dac_fix = 1,
@@ -8756,6 +8846,7 @@ static struct alc_config_preset alc883_presets[] = {
},
[ALC888_ASUS_EEE1601] = {
.mixers = { alc883_asus_eee1601_mixer },
+ .cap_mixer = alc883_asus_eee1601_cap_mixer,
.init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
.num_dacs = ARRAY_SIZE(alc883_dac_nids),
.dac_nids = alc883_dac_nids,
@@ -8768,6 +8859,17 @@ static struct alc_config_preset alc883_presets[] = {
.unsol_event = alc883_eee1601_unsol_event,
.init_hook = alc883_eee1601_inithook,
},
+ [ALC1200_ASUS_P5Q] = {
+ .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .dig_out_nid = ALC1200_DIGOUT_NID,
+ .dig_in_nid = ALC883_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+ .channel_mode = alc883_sixstack_modes,
+ .input_mux = &alc883_capture_source,
+ },
};
@@ -8862,8 +8964,6 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
/* hack - override the init verbs */
spec->init_verbs[0] = alc883_auto_init_verbs;
- spec->mixers[spec->num_mixers] = alc883_capture_mixer;
- spec->num_mixers++;
return 1; /* config found */
}
@@ -8946,9 +9046,15 @@ static int patch_alc883(struct hda_codec *codec)
spec->stream_digital_playback = &alc883_pcm_digital_playback;
spec->stream_digital_capture = &alc883_pcm_digital_capture;
- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
- spec->adc_nids = alc883_adc_nids;
- spec->capsrc_nids = alc883_capsrc_nids;
+ if (!spec->num_adc_nids) {
+ spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+ spec->adc_nids = alc883_adc_nids;
+ }
+ if (!spec->capsrc_nids)
+ spec->capsrc_nids = alc883_capsrc_nids;
+ spec->is_mix_capture = 1; /* matrix-style capture */
+ if (!spec->cap_mixer)
+ set_capture_mixer(spec);
spec->vmaster_nid = 0x0c;
@@ -8960,6 +9066,7 @@ static int patch_alc883(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc883_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -9439,20 +9546,6 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{ } /* end */
};
@@ -9969,7 +10062,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
struct alc_spec *spec = codec->spec;
int ret;
- ret = alc882_mux_enum_put(kcontrol, ucontrol);
+ ret = alc_mux_enum_put(kcontrol, ucontrol);
if (!ret)
return 0;
/* reprogram the HP pin as mic or HP according to the input source */
@@ -9986,8 +10079,8 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
- .info = alc882_mux_enum_info,
- .get = alc882_mux_enum_get,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
.put = alc262_ultra_mux_enum_put,
},
{ } /* end */
@@ -10380,10 +10473,10 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC262_DIGIN_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
- spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
+ add_verb(spec, alc262_volume_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
@@ -10466,6 +10559,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
+ SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN",
+ ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
ALC262_TOSHIBA_RX1),
SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
@@ -10624,7 +10719,8 @@ static struct alc_config_preset alc262_presets[] = {
.init_hook = alc262_hippo_automute,
},
[ALC262_ULTRA] = {
- .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
+ .mixers = { alc262_ultra_mixer },
+ .cap_mixer = alc262_ultra_capture_mixer,
.init_verbs = { alc262_ultra_verbs },
.num_dacs = ARRAY_SIZE(alc262_dac_nids),
.dac_nids = alc262_dac_nids,
@@ -10750,6 +10846,7 @@ static int patch_alc262(struct hda_codec *codec)
spec->stream_digital_playback = &alc262_pcm_digital_playback;
spec->stream_digital_capture = &alc262_pcm_digital_capture;
+ spec->is_mix_capture = 1;
if (!spec->adc_nids && spec->input_mux) {
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, 0x07);
@@ -10760,17 +10857,14 @@ static int patch_alc262(struct hda_codec *codec)
spec->adc_nids = alc262_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
spec->capsrc_nids = alc262_capsrc_nids_alt;
- spec->mixers[spec->num_mixers] =
- alc262_capture_alt_mixer;
- spec->num_mixers++;
} else {
spec->adc_nids = alc262_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
spec->capsrc_nids = alc262_capsrc_nids;
- spec->mixers[spec->num_mixers] = alc262_capture_mixer;
- spec->num_mixers++;
}
}
+ if (!spec->cap_mixer)
+ set_capture_mixer(spec);
spec->vmaster_nid = 0x0c;
@@ -10781,6 +10875,7 @@ static int patch_alc262(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc262_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -10942,6 +11037,22 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
{ }
};
+static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
+ /* output mixer control */
+ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = snd_hda_mixer_amp_switch_info,
+ .get = snd_hda_mixer_amp_switch_get,
+ .put = alc268_acer_master_sw_put,
+ .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+ },
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+ { }
+};
+
static struct hda_verb alc268_acer_aspire_one_verbs[] = {
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -11218,10 +11329,6 @@ static struct hda_verb alc268_volume_init_verbs[] = {
{ }
};
-#define alc268_mux_enum_info alc_mux_enum_info
-#define alc268_mux_enum_get alc_mux_enum_get
-#define alc268_mux_enum_put alc_mux_enum_put
-
static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
@@ -11233,9 +11340,9 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
/* .name = "Capture Source", */
.name = "Input Source",
.count = 1,
- .info = alc268_mux_enum_info,
- .get = alc268_mux_enum_get,
- .put = alc268_mux_enum_put,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
},
{ } /* end */
};
@@ -11253,9 +11360,9 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = {
/* .name = "Capture Source", */
.name = "Input Source",
.count = 2,
- .info = alc268_mux_enum_info,
- .get = alc268_mux_enum_get,
- .put = alc268_mux_enum_put,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
},
{ } /* end */
};
@@ -11274,6 +11381,15 @@ static struct hda_input_mux alc268_acer_capture_source = {
.num_items = 3,
.items = {
{ "Mic", 0x0 },
+ { "Internal Mic", 0x1 },
+ { "Line", 0x2 },
+ },
+};
+
+static struct hda_input_mux alc268_acer_dmic_capture_source = {
+ .num_items = 3,
+ .items = {
+ { "Mic", 0x0 },
{ "Internal Mic", 0x6 },
{ "Line", 0x2 },
},
@@ -11512,13 +11628,13 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
if (spec->autocfg.speaker_pins[0] != 0x1d)
- spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
+ add_mixer(spec, alc268_beep_mixer);
- spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+ add_verb(spec, alc268_volume_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
@@ -11554,6 +11670,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = {
[ALC268_3ST] = "3stack",
[ALC268_TOSHIBA] = "toshiba",
[ALC268_ACER] = "acer",
+ [ALC268_ACER_DMIC] = "acer-dmic",
[ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
[ALC268_DELL] = "dell",
[ALC268_ZEPTO] = "zepto",
@@ -11649,6 +11766,23 @@ static struct alc_config_preset alc268_presets[] = {
.unsol_event = alc268_acer_unsol_event,
.init_hook = alc268_acer_init_hook,
},
+ [ALC268_ACER_DMIC] = {
+ .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
+ alc268_beep_mixer },
+ .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+ alc268_acer_verbs },
+ .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+ .dac_nids = alc268_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+ .adc_nids = alc268_adc_nids_alt,
+ .capsrc_nids = alc268_capsrc_nids,
+ .hp_nid = 0x02,
+ .num_channel_mode = ARRAY_SIZE(alc268_modes),
+ .channel_mode = alc268_modes,
+ .input_mux = &alc268_acer_dmic_capture_source,
+ .unsol_event = alc268_acer_unsol_event,
+ .init_hook = alc268_acer_init_hook,
+ },
[ALC268_ACER_ASPIRE_ONE] = {
.mixers = { alc268_acer_aspire_one_mixer,
alc268_capture_alt_mixer },
@@ -11787,15 +11921,11 @@ static int patch_alc268(struct hda_codec *codec)
if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
spec->adc_nids = alc268_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
- spec->mixers[spec->num_mixers] =
- alc268_capture_alt_mixer;
- spec->num_mixers++;
+ add_mixer(spec, alc268_capture_alt_mixer);
} else {
spec->adc_nids = alc268_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
- spec->mixers[spec->num_mixers] =
- alc268_capture_mixer;
- spec->num_mixers++;
+ add_mixer(spec, alc268_capture_mixer);
}
spec->capsrc_nids = alc268_capsrc_nids;
/* set default input source */
@@ -11811,6 +11941,8 @@ static int patch_alc268(struct hda_codec *codec)
if (board_config == ALC268_AUTO)
spec->init_hook = alc268_auto_init;
+ codec->proc_widget_hook = print_realtek_coef;
+
return 0;
}
@@ -11893,6 +12025,31 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
{ }
};
+static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
+ /* output mixer control */
+ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = snd_hda_mixer_amp_switch_info,
+ .get = snd_hda_mixer_amp_switch_get,
+ .put = alc268_acer_master_sw_put,
+ .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+ },
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ { }
+};
+
/* bind volumes of both NID 0x0c and 0x0d */
static struct hda_bind_ctls alc269_epc_bind_vol = {
.ops = &snd_hda_bind_vol,
@@ -11911,28 +12068,18 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
};
/* capture mixer elements */
-static struct snd_kcontrol_new alc269_capture_mixer[] = {
+static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
{ } /* end */
};
-/* capture mixer elements */
-static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+/* FSC amilo */
+static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
{ } /* end */
};
@@ -11953,6 +12100,20 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = {
{ }
};
+static struct hda_verb alc269_lifebook_verbs[] = {
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ { }
+};
+
/* toggle speaker-output according to the hp-jack state */
static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
{
@@ -11978,6 +12139,37 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
AC_VERB_SET_PROC_COEF, 0x480);
}
+/* toggle speaker-output according to the hp-jacks state */
+static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned char bits;
+
+ /* Check laptop headphone socket */
+ present = snd_hda_codec_read(codec, 0x15, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ /* Check port replicator headphone socket */
+ present |= snd_hda_codec_read(codec, 0x1a, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ bits = present ? AMP_IN_MUTE(0) : 0;
+ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+ AMP_IN_MUTE(0), bits);
+ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+ AMP_IN_MUTE(0), bits);
+
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_COEF_INDEX, 0x0c);
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_PROC_COEF, 0x680);
+
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_COEF_INDEX, 0x0c);
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_PROC_COEF, 0x480);
+}
+
static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
{
unsigned int present;
@@ -11988,6 +12180,29 @@ static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
}
+static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
+{
+ unsigned int present_laptop;
+ unsigned int present_dock;
+
+ present_laptop = snd_hda_codec_read(codec, 0x18, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ present_dock = snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ /* Laptop mic port overrides dock mic port, design decision */
+ if (present_dock)
+ snd_hda_codec_write(codec, 0x23, 0,
+ AC_VERB_SET_CONNECT_SEL, 0x3);
+ if (present_laptop)
+ snd_hda_codec_write(codec, 0x23, 0,
+ AC_VERB_SET_CONNECT_SEL, 0x0);
+ if (!present_dock && !present_laptop)
+ snd_hda_codec_write(codec, 0x23, 0,
+ AC_VERB_SET_CONNECT_SEL, 0x1);
+}
+
static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
unsigned int res)
{
@@ -11997,12 +12212,27 @@ static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
alc269_quanta_fl1_mic_automute(codec);
}
+static void alc269_lifebook_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if ((res >> 26) == ALC880_HP_EVENT)
+ alc269_lifebook_speaker_automute(codec);
+ if ((res >> 26) == ALC880_MIC_EVENT)
+ alc269_lifebook_mic_autoswitch(codec);
+}
+
static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
{
alc269_quanta_fl1_speaker_automute(codec);
alc269_quanta_fl1_mic_automute(codec);
}
+static void alc269_lifebook_init_hook(struct hda_codec *codec)
+{
+ alc269_lifebook_speaker_automute(codec);
+ alc269_lifebook_mic_autoswitch(codec);
+}
+
static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
@@ -12303,17 +12533,17 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
/* create a beep mixer control if the pin 0x1d isn't assigned */
for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
if (spec->autocfg.input_pins[i] == 0x1d)
break;
if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
- spec->mixers[spec->num_mixers++] = alc269_beep_mixer;
+ add_mixer(spec, alc269_beep_mixer);
- spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
+ add_verb(spec, alc269_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
/* set default input source */
@@ -12325,8 +12555,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
if (err < 0)
return err;
- spec->mixers[spec->num_mixers] = alc269_capture_mixer;
- spec->num_mixers++;
+ if (!spec->cap_mixer)
+ set_capture_mixer(spec);
store_pin_configs(codec);
return 1;
@@ -12355,7 +12585,9 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {
[ALC269_BASIC] = "basic",
[ALC269_QUANTA_FL1] = "quanta",
[ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
- [ALC269_ASUS_EEEPC_P901] = "eeepc-p901"
+ [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
+ [ALC269_FUJITSU] = "fujitsu",
+ [ALC269_LIFEBOOK] = "lifebook"
};
static struct snd_pci_quirk alc269_cfg_tbl[] = {
@@ -12366,12 +12598,14 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
ALC269_ASUS_EEEPC_P901),
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
ALC269_ASUS_EEEPC_P901),
+ SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
+ SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
{}
};
static struct alc_config_preset alc269_presets[] = {
[ALC269_BASIC] = {
- .mixers = { alc269_base_mixer, alc269_capture_mixer },
+ .mixers = { alc269_base_mixer },
.init_verbs = { alc269_init_verbs },
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
.dac_nids = alc269_dac_nids,
@@ -12393,7 +12627,8 @@ static struct alc_config_preset alc269_presets[] = {
.init_hook = alc269_quanta_fl1_init_hook,
},
[ALC269_ASUS_EEEPC_P703] = {
- .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
+ .mixers = { alc269_eeepc_mixer },
+ .cap_mixer = alc269_epc_capture_mixer,
.init_verbs = { alc269_init_verbs,
alc269_eeepc_amic_init_verbs },
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
@@ -12406,7 +12641,22 @@ static struct alc_config_preset alc269_presets[] = {
.init_hook = alc269_eeepc_amic_inithook,
},
[ALC269_ASUS_EEEPC_P901] = {
- .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer},
+ .mixers = { alc269_eeepc_mixer },
+ .cap_mixer = alc269_epc_capture_mixer,
+ .init_verbs = { alc269_init_verbs,
+ alc269_eeepc_dmic_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+ .dac_nids = alc269_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc269_modes),
+ .channel_mode = alc269_modes,
+ .input_mux = &alc269_eeepc_dmic_capture_source,
+ .unsol_event = alc269_eeepc_dmic_unsol_event,
+ .init_hook = alc269_eeepc_dmic_inithook,
+ },
+ [ALC269_FUJITSU] = {
+ .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
+ .cap_mixer = alc269_epc_capture_mixer,
.init_verbs = { alc269_init_verbs,
alc269_eeepc_dmic_init_verbs },
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
@@ -12418,6 +12668,18 @@ static struct alc_config_preset alc269_presets[] = {
.unsol_event = alc269_eeepc_dmic_unsol_event,
.init_hook = alc269_eeepc_dmic_inithook,
},
+ [ALC269_LIFEBOOK] = {
+ .mixers = { alc269_lifebook_mixer },
+ .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
+ .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+ .dac_nids = alc269_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc269_modes),
+ .channel_mode = alc269_modes,
+ .input_mux = &alc269_capture_source,
+ .unsol_event = alc269_lifebook_unsol_event,
+ .init_hook = alc269_lifebook_init_hook,
+ },
};
static int patch_alc269(struct hda_codec *codec)
@@ -12472,6 +12734,8 @@ static int patch_alc269(struct hda_codec *codec)
spec->adc_nids = alc269_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
spec->capsrc_nids = alc269_capsrc_nids;
+ if (!spec->cap_mixer)
+ set_capture_mixer(spec);
codec->patch_ops = alc_patch_ops;
if (board_config == ALC269_AUTO)
@@ -12480,6 +12744,7 @@ static int patch_alc269(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc269_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -12612,17 +12877,6 @@ static struct snd_kcontrol_new alc861_base_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
- /* Capture mixer control */
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{ } /* end */
};
@@ -12646,17 +12900,6 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
- /* Capture mixer control */
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channel Mode",
@@ -12674,18 +12917,6 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
- /*Capture mixer control */
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
-
{ } /* end */
};
@@ -12709,17 +12940,6 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
- /* Capture mixer control */
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channel Mode",
@@ -12751,17 +12971,6 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
- /* Capture mixer control */
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channel Mode",
@@ -13293,25 +13502,6 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
return 0;
}
-static struct snd_kcontrol_new alc861_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
- { } /* end */
-};
-
static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid,
int pin_type, int dac_idx)
@@ -13402,18 +13592,17 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
- spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
+ add_verb(spec, alc861_auto_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
spec->adc_nids = alc861_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
- spec->mixers[spec->num_mixers] = alc861_capture_mixer;
- spec->num_mixers++;
+ set_capture_mixer(spec);
store_pin_configs(codec);
return 1;
@@ -13644,6 +13833,7 @@ static int patch_alc861(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc861_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -13709,11 +13899,6 @@ static struct hda_input_mux alc861vd_hp_capture_source = {
},
};
-#define alc861vd_mux_enum_info alc_mux_enum_info
-#define alc861vd_mux_enum_get alc_mux_enum_get
-/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
-#define alc861vd_mux_enum_put alc882_mux_enum_put
-
/*
* 2ch mode
*/
@@ -13759,25 +13944,6 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
{ } /* end */
};
-static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc861vd_mux_enum_info,
- .get = alc861vd_mux_enum_get,
- .put = alc861vd_mux_enum_put,
- },
- { } /* end */
-};
-
/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
* Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
*/
@@ -14169,6 +14335,7 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re
static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
[ALC660VD_3ST] = "3stack-660",
[ALC660VD_3ST_DIG] = "3stack-660-digout",
+ [ALC660VD_ASUS_V1S] = "asus-v1s",
[ALC861VD_3ST] = "3stack",
[ALC861VD_3ST_DIG] = "3stack-digout",
[ALC861VD_6ST_DIG] = "6stack-digout",
@@ -14183,7 +14350,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
- SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
+ SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
@@ -14290,6 +14457,21 @@ static struct alc_config_preset alc861vd_presets[] = {
.unsol_event = alc861vd_dallas_unsol_event,
.init_hook = alc861vd_dallas_automute,
},
+ [ALC660VD_ASUS_V1S] = {
+ .mixers = { alc861vd_lenovo_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs,
+ alc861vd_eapd_verbs,
+ alc861vd_lenovo_unsol_verbs },
+ .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+ .dac_nids = alc660vd_dac_nids,
+ .dig_out_nid = ALC861VD_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ .unsol_event = alc861vd_lenovo_unsol_event,
+ .init_hook = alc861vd_lenovo_automute,
+ },
};
/*
@@ -14514,11 +14696,10 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
- spec->init_verbs[spec->num_init_verbs++]
- = alc861vd_volume_init_verbs;
+ add_verb(spec, alc861vd_volume_init_verbs);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
@@ -14585,7 +14766,7 @@ static int patch_alc861vd(struct hda_codec *codec)
spec->stream_name_analog = "ALC660-VD Analog";
spec->stream_name_digital = "ALC660-VD Digital";
/* always turn on EAPD */
- spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs;
+ add_verb(spec, alc660vd_eapd_verbs);
} else {
spec->stream_name_analog = "ALC861VD Analog";
spec->stream_name_digital = "ALC861VD Digital";
@@ -14600,9 +14781,9 @@ static int patch_alc861vd(struct hda_codec *codec)
spec->adc_nids = alc861vd_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
spec->capsrc_nids = alc861vd_capsrc_nids;
+ spec->is_mix_capture = 1;
- spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
- spec->num_mixers++;
+ set_capture_mixer(spec);
spec->vmaster_nid = 0x02;
@@ -14614,6 +14795,7 @@ static int patch_alc861vd(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc861vd_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
@@ -14689,10 +14871,6 @@ static struct hda_input_mux alc663_m51va_capture_source = {
},
};
-#define alc662_mux_enum_info alc_mux_enum_info
-#define alc662_mux_enum_get alc_mux_enum_get
-#define alc662_mux_enum_put alc882_mux_enum_put
-
/*
* 2ch mode
*/
@@ -15278,25 +15456,6 @@ static struct hda_verb alc662_ecs_init_verbs[] = {
{}
};
-/* capture mixer elements */
-static struct snd_kcontrol_new alc662_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc662_mux_enum_info,
- .get = alc662_mux_enum_get,
- .put = alc662_mux_enum_put,
- },
- { } /* end */
-};
-
static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
@@ -15868,7 +16027,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
static struct alc_config_preset alc662_presets[] = {
[ALC662_3ST_2ch_DIG] = {
- .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
+ .mixers = { alc662_3ST_2ch_mixer },
.init_verbs = { alc662_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15879,8 +16038,7 @@ static struct alc_config_preset alc662_presets[] = {
.input_mux = &alc662_capture_source,
},
[ALC662_3ST_6ch_DIG] = {
- .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
- alc662_capture_mixer },
+ .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
.init_verbs = { alc662_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15892,8 +16050,7 @@ static struct alc_config_preset alc662_presets[] = {
.input_mux = &alc662_capture_source,
},
[ALC662_3ST_6ch] = {
- .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
- alc662_capture_mixer },
+ .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
.init_verbs = { alc662_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15903,8 +16060,7 @@ static struct alc_config_preset alc662_presets[] = {
.input_mux = &alc662_capture_source,
},
[ALC662_5ST_DIG] = {
- .mixers = { alc662_base_mixer, alc662_chmode_mixer,
- alc662_capture_mixer },
+ .mixers = { alc662_base_mixer, alc662_chmode_mixer },
.init_verbs = { alc662_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15915,7 +16071,7 @@ static struct alc_config_preset alc662_presets[] = {
.input_mux = &alc662_capture_source,
},
[ALC662_LENOVO_101E] = {
- .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
+ .mixers = { alc662_lenovo_101e_mixer },
.init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15926,7 +16082,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc662_lenovo_101e_all_automute,
},
[ALC662_ASUS_EEEPC_P701] = {
- .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
+ .mixers = { alc662_eeepc_p701_mixer },
.init_verbs = { alc662_init_verbs,
alc662_eeepc_sue_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -15938,7 +16094,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc662_eeepc_inithook,
},
[ALC662_ASUS_EEEPC_EP20] = {
- .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
+ .mixers = { alc662_eeepc_ep20_mixer,
alc662_chmode_mixer },
.init_verbs = { alc662_init_verbs,
alc662_eeepc_ep20_sue_init_verbs },
@@ -15951,7 +16107,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc662_eeepc_ep20_inithook,
},
[ALC662_ECS] = {
- .mixers = { alc662_ecs_mixer, alc662_capture_mixer },
+ .mixers = { alc662_ecs_mixer },
.init_verbs = { alc662_init_verbs,
alc662_ecs_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -15963,7 +16119,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc662_eeepc_inithook,
},
[ALC663_ASUS_M51VA] = {
- .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+ .mixers = { alc663_m51va_mixer },
.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15975,7 +16131,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_m51va_inithook,
},
[ALC663_ASUS_G71V] = {
- .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
+ .mixers = { alc663_g71v_mixer },
.init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15987,7 +16143,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_g71v_inithook,
},
[ALC663_ASUS_H13] = {
- .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+ .mixers = { alc663_m51va_mixer },
.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -15998,7 +16154,7 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_m51va_inithook,
},
[ALC663_ASUS_G50V] = {
- .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
+ .mixers = { alc663_g50v_mixer },
.init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
@@ -16010,7 +16166,8 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_g50v_inithook,
},
[ALC663_ASUS_MODE1] = {
- .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer },
+ .mixers = { alc663_m51va_mixer },
+ .cap_mixer = alc662_auto_capture_mixer,
.init_verbs = { alc662_init_verbs,
alc663_21jd_amic_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16024,7 +16181,8 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_mode1_inithook,
},
[ALC662_ASUS_MODE2] = {
- .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer },
+ .mixers = { alc662_1bjd_mixer },
+ .cap_mixer = alc662_auto_capture_mixer,
.init_verbs = { alc662_init_verbs,
alc662_1bjd_amic_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16037,7 +16195,8 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc662_mode2_inithook,
},
[ALC663_ASUS_MODE3] = {
- .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer },
+ .mixers = { alc663_two_hp_m1_mixer },
+ .cap_mixer = alc662_auto_capture_mixer,
.init_verbs = { alc662_init_verbs,
alc663_two_hp_amic_m1_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16051,8 +16210,8 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_mode3_inithook,
},
[ALC663_ASUS_MODE4] = {
- .mixers = { alc663_asus_21jd_clfe_mixer,
- alc662_auto_capture_mixer},
+ .mixers = { alc663_asus_21jd_clfe_mixer },
+ .cap_mixer = alc662_auto_capture_mixer,
.init_verbs = { alc662_init_verbs,
alc663_21jd_amic_init_verbs},
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16066,8 +16225,8 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_mode4_inithook,
},
[ALC663_ASUS_MODE5] = {
- .mixers = { alc663_asus_15jd_clfe_mixer,
- alc662_auto_capture_mixer },
+ .mixers = { alc663_asus_15jd_clfe_mixer },
+ .cap_mixer = alc662_auto_capture_mixer,
.init_verbs = { alc662_init_verbs,
alc663_15jd_amic_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16081,7 +16240,8 @@ static struct alc_config_preset alc662_presets[] = {
.init_hook = alc663_mode5_inithook,
},
[ALC663_ASUS_MODE6] = {
- .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer },
+ .mixers = { alc663_two_hp_m2_mixer },
+ .cap_mixer = alc662_auto_capture_mixer,
.init_verbs = { alc662_init_verbs,
alc663_two_hp_amic_m2_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16342,24 +16502,20 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
- spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
+ add_verb(spec, alc662_auto_init_verbs);
if (codec->vendor_id == 0x10ec0663)
- spec->init_verbs[spec->num_init_verbs++] =
- alc663_auto_init_verbs;
+ add_verb(spec, alc663_auto_init_verbs);
err = alc_auto_add_mic_boost(codec);
if (err < 0)
return err;
- spec->mixers[spec->num_mixers] = alc662_capture_mixer;
- spec->num_mixers++;
-
store_pin_configs(codec);
return 1;
}
@@ -16435,6 +16591,10 @@ static int patch_alc662(struct hda_codec *codec)
spec->adc_nids = alc662_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
spec->capsrc_nids = alc662_capsrc_nids;
+ spec->is_mix_capture = 1;
+
+ if (!spec->cap_mixer)
+ set_capture_mixer(spec);
spec->vmaster_nid = 0x02;
@@ -16445,6 +16605,7 @@ static int patch_alc662(struct hda_codec *codec)
if (!spec->loopback.amplist)
spec->loopback.amplist = alc662_loopbacks;
#endif
+ codec->proc_widget_hook = print_realtek_coef;
return 0;
}
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 5dd3e89f620a..14db35a61cfe 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -30,17 +30,18 @@
#include <linux/pci.h>
#include <sound/core.h>
#include <sound/asoundef.h>
+#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_patch.h"
#include "hda_beep.h"
-#define NUM_CONTROL_ALLOC 32
-
-#define STAC_VREF_EVENT 0x00
-#define STAC_INSERT_EVENT 0x10
-#define STAC_PWR_EVENT 0x20
-#define STAC_HP_EVENT 0x30
+enum {
+ STAC_VREF_EVENT = 1,
+ STAC_INSERT_EVENT,
+ STAC_PWR_EVENT,
+ STAC_HP_EVENT,
+};
enum {
STAC_REF,
@@ -135,6 +136,19 @@ enum {
STAC_927X_MODELS
};
+struct sigmatel_event {
+ hda_nid_t nid;
+ unsigned char type;
+ unsigned char tag;
+ int data;
+};
+
+struct sigmatel_jack {
+ hda_nid_t nid;
+ int type;
+ struct snd_jack *jack;
+};
+
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
unsigned int num_mixers;
@@ -168,6 +182,12 @@ struct sigmatel_spec {
hda_nid_t *pwr_nids;
hda_nid_t *dac_list;
+ /* jack detection */
+ struct snd_array jacks;
+
+ /* events */
+ struct snd_array events;
+
/* playback */
struct hda_input_mux *mono_mux;
struct hda_input_mux *amp_mux;
@@ -197,7 +217,6 @@ struct sigmatel_spec {
hda_nid_t *pin_nids;
unsigned int num_pins;
unsigned int *pin_configs;
- unsigned int *bios_pin_configs;
/* codec specific stuff */
struct hda_verb *init;
@@ -225,8 +244,7 @@ struct sigmatel_spec {
/* dynamic controls and input_mux */
struct auto_pin_cfg autocfg;
- unsigned int num_kctl_alloc, num_kctl_used;
- struct snd_kcontrol_new *kctl_alloc;
+ struct snd_array kctls;
struct hda_input_mux private_dimux;
struct hda_input_mux private_imux;
struct hda_input_mux private_smux;
@@ -572,12 +590,12 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
else
nid = codec->slave_dig_outs[smux_idx - 1];
if (spec->cur_smux[smux_idx] == smux->num_items - 1)
- val = AMP_OUT_MUTE;
+ val = HDA_AMP_MUTE;
else
- val = AMP_OUT_UNMUTE;
+ val = 0;
/* un/mute SPDIF out */
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, val);
+ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, val);
}
return 0;
}
@@ -1236,9 +1254,14 @@ static const char *slave_sws[] = {
NULL
};
+static void stac92xx_free_kctls(struct hda_codec *codec);
+static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
+
static int stac92xx_build_controls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid;
int err;
int i;
@@ -1253,7 +1276,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
}
if (spec->num_dmuxes > 0) {
stac_dmux_mixer.count = spec->num_dmuxes;
- err = snd_ctl_add(codec->bus->card,
+ err = snd_hda_ctl_add(codec,
snd_ctl_new1(&stac_dmux_mixer, codec));
if (err < 0)
return err;
@@ -1308,6 +1331,37 @@ static int stac92xx_build_controls(struct hda_codec *codec)
return err;
}
+ stac92xx_free_kctls(codec); /* no longer needed */
+
+ /* create jack input elements */
+ if (spec->hp_detect) {
+ for (i = 0; i < cfg->hp_outs; i++) {
+ int type = SND_JACK_HEADPHONE;
+ nid = cfg->hp_pins[i];
+ /* jack detection */
+ if (cfg->hp_outs == i)
+ type |= SND_JACK_LINEOUT;
+ err = stac92xx_add_jack(codec, nid, type);
+ if (err < 0)
+ return err;
+ }
+ }
+ for (i = 0; i < cfg->line_outs; i++) {
+ err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
+ SND_JACK_LINEOUT);
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ nid = cfg->input_pins[i];
+ if (nid) {
+ err = stac92xx_add_jack(codec, nid,
+ SND_JACK_MICROPHONE);
+ if (err < 0)
+ return err;
+ }
+ }
+
return 0;
}
@@ -2193,12 +2247,11 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
int i;
struct sigmatel_spec *spec = codec->spec;
- if (! spec->bios_pin_configs) {
- spec->bios_pin_configs = kcalloc(spec->num_pins,
- sizeof(*spec->bios_pin_configs), GFP_KERNEL);
- if (! spec->bios_pin_configs)
- return -ENOMEM;
- }
+ kfree(spec->pin_configs);
+ spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs),
+ GFP_KERNEL);
+ if (!spec->pin_configs)
+ return -ENOMEM;
for (i = 0; i < spec->num_pins; i++) {
hda_nid_t nid = spec->pin_nids[i];
@@ -2208,7 +2261,7 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
AC_VERB_GET_CONFIG_DEFAULT, 0x00);
snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
nid, pin_cfg);
- spec->bios_pin_configs[i] = pin_cfg;
+ spec->pin_configs[i] = pin_cfg;
}
return 0;
@@ -2250,6 +2303,39 @@ static void stac92xx_set_config_regs(struct hda_codec *codec)
spec->pin_configs[i]);
}
+static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (!pins)
+ return stac92xx_save_bios_config_regs(codec);
+
+ kfree(spec->pin_configs);
+ spec->pin_configs = kmemdup(pins,
+ spec->num_pins * sizeof(*pins),
+ GFP_KERNEL);
+ if (!spec->pin_configs)
+ return -ENOMEM;
+
+ stac92xx_set_config_regs(codec);
+ return 0;
+}
+
+static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_pins; i++) {
+ if (spec->pin_nids[i] == nid) {
+ spec->pin_configs[i] = cfg;
+ stac92xx_set_config_reg(codec, nid, cfg);
+ break;
+ }
+ }
+}
+
/*
* Analog playback callbacks
*/
@@ -2327,7 +2413,7 @@ static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
if (spec->powerdown_adcs) {
msleep(40);
- snd_hda_codec_write_cache(codec, nid, 0,
+ snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
}
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
@@ -2343,7 +2429,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
snd_hda_codec_cleanup_stream(codec, nid);
if (spec->powerdown_adcs)
- snd_hda_codec_write_cache(codec, nid, 0,
+ snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
return 0;
}
@@ -2475,6 +2561,9 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char type);
+
static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2487,7 +2576,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
/* check to be sure that the ports are upto date with
* switch changes
*/
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
return 1;
}
@@ -2527,7 +2616,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
* appropriately according to the pin direction
*/
if (spec->hp_detect)
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
return 1;
}
@@ -2622,28 +2711,16 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
{
struct snd_kcontrol_new *knew;
- if (spec->num_kctl_used >= spec->num_kctl_alloc) {
- int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
- knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
- if (! knew)
- return -ENOMEM;
- if (spec->kctl_alloc) {
- memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
- kfree(spec->kctl_alloc);
- }
- spec->kctl_alloc = knew;
- spec->num_kctl_alloc = num;
- }
-
- knew = &spec->kctl_alloc[spec->num_kctl_used];
+ snd_array_init(&spec->kctls, sizeof(*knew), 32);
+ knew = snd_array_new(&spec->kctls);
+ if (!knew)
+ return -ENOMEM;
*knew = *ktemp;
knew->index = idx;
knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name)
return -ENOMEM;
knew->private_value = val;
- spec->num_kctl_used++;
return 0;
}
@@ -3520,8 +3597,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
if (dig_in && spec->autocfg.dig_in_pin)
spec->dig_in_nid = dig_in;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux;
spec->dinput_mux = &spec->private_dimux;
@@ -3628,8 +3705,8 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = 0x04;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux;
spec->dinput_mux = &spec->private_dimux;
@@ -3673,13 +3750,101 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
+static int stac92xx_add_jack(struct hda_codec *codec,
+ hda_nid_t nid, int type)
+{
+#ifdef CONFIG_SND_JACK
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_jack *jack;
+ int def_conf = snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ int connectivity = get_defcfg_connect(def_conf);
+ char name[32];
+
+ if (connectivity && connectivity != AC_JACK_PORT_FIXED)
+ return 0;
+
+ snd_array_init(&spec->jacks, sizeof(*jack), 32);
+ jack = snd_array_new(&spec->jacks);
+ if (!jack)
+ return -ENOMEM;
+ jack->nid = nid;
+ jack->type = type;
+
+ sprintf(name, "%s at %s %s Jack",
+ snd_hda_get_jack_type(def_conf),
+ snd_hda_get_jack_connectivity(def_conf),
+ snd_hda_get_jack_location(def_conf));
+
+ return snd_jack_new(codec->bus->card, name, type, &jack->jack);
+#else
+ return 0;
+#endif
+}
+
+static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
+ unsigned char type, int data)
+{
+ struct sigmatel_event *event;
+
+ snd_array_init(&spec->events, sizeof(*event), 32);
+ event = snd_array_new(&spec->events);
+ if (!event)
+ return -ENOMEM;
+ event->nid = nid;
+ event->type = type;
+ event->tag = spec->events.used;
+ event->data = data;
+
+ return event->tag;
+}
+
+static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
+ hda_nid_t nid, unsigned char type)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_event *event = spec->events.list;
+ int i;
+
+ for (i = 0; i < spec->events.used; i++, event++) {
+ if (event->nid == nid && event->type == type)
+ return event;
+ }
+ return NULL;
+}
+
+static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
+ unsigned char tag)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_event *event = spec->events.list;
+ int i;
+
+ for (i = 0; i < spec->events.used; i++, event++) {
+ if (event->tag == tag)
+ return event;
+ }
+ return NULL;
+}
+
static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
- unsigned int event)
+ unsigned int type)
{
- if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- (AC_USRSP_EN | event));
+ struct sigmatel_event *event;
+ int tag;
+
+ if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+ return;
+ event = stac_get_event(codec, nid, type);
+ if (event)
+ tag = event->tag;
+ else
+ tag = stac_add_event(codec->spec, nid, type, 0);
+ if (tag < 0)
+ return;
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | tag);
}
static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@ -3701,7 +3866,7 @@ static void stac92xx_power_down(struct hda_codec *codec)
for (dac = spec->dac_list; *dac; dac++)
if (!is_in_dac_nids(spec, *dac) &&
spec->multiout.hp_nid != *dac)
- snd_hda_codec_write_cache(codec, *dac, 0,
+ snd_hda_codec_write(codec, *dac, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
}
@@ -3720,7 +3885,7 @@ static int stac92xx_init(struct hda_codec *codec)
/* power down adcs initially */
if (spec->powerdown_adcs)
for (i = 0; i < spec->num_adcs; i++)
- snd_hda_codec_write_cache(codec,
+ snd_hda_codec_write(codec,
spec->adc_nids[i], 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
@@ -3736,17 +3901,18 @@ static int stac92xx_init(struct hda_codec *codec)
/* set up pins */
if (spec->hp_detect) {
/* Enable unsolicited responses on the HP widget */
- for (i = 0; i < cfg->hp_outs; i++)
- enable_pin_detect(codec, cfg->hp_pins[i],
- STAC_HP_EVENT);
+ for (i = 0; i < cfg->hp_outs; i++) {
+ hda_nid_t nid = cfg->hp_pins[i];
+ enable_pin_detect(codec, nid, STAC_HP_EVENT);
+ }
/* force to enable the first line-out; the others are set up
* in unsol_event
*/
stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
- AC_PINCTL_OUT_EN);
- stac92xx_auto_init_hp_out(codec);
+ AC_PINCTL_OUT_EN);
/* fake event to set up pins */
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
+ STAC_HP_EVENT);
} else {
stac92xx_auto_init_multi_out(codec);
stac92xx_auto_init_hp_out(codec);
@@ -3767,6 +3933,7 @@ static int stac92xx_init(struct hda_codec *codec)
}
pinctl |= AC_PINCTL_IN_EN;
stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ enable_pin_detect(codec, nid, STAC_INSERT_EVENT);
}
}
for (i = 0; i < spec->num_dmics; i++)
@@ -3781,7 +3948,6 @@ static int stac92xx_init(struct hda_codec *codec)
for (i = 0; i < spec->num_pwrs; i++) {
hda_nid_t nid = spec->pwr_nids[i];
int pinctl, def_conf;
- int event = STAC_PWR_EVENT;
if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
continue; /* already has an unsol event */
@@ -3804,30 +3970,52 @@ static int stac92xx_init(struct hda_codec *codec)
stac_toggle_power_map(codec, nid, 1);
continue;
}
- enable_pin_detect(codec, spec->pwr_nids[i], event | i);
- codec->patch_ops.unsol_event(codec, (event | i) << 26);
+ enable_pin_detect(codec, nid, STAC_PWR_EVENT);
+ stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
}
if (spec->dac_list)
stac92xx_power_down(codec);
return 0;
}
+static void stac92xx_free_jacks(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_JACK
+ /* free jack instances manually when clearing/reconfiguring */
+ struct sigmatel_spec *spec = codec->spec;
+ if (!codec->bus->shutdown && spec->jacks.list) {
+ struct sigmatel_jack *jacks = spec->jacks.list;
+ int i;
+ for (i = 0; i < spec->jacks.used; i++)
+ snd_device_free(codec->bus->card, &jacks[i].jack);
+ }
+ snd_array_free(&spec->jacks);
+#endif
+}
+
+static void stac92xx_free_kctls(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (spec->kctls.list) {
+ struct snd_kcontrol_new *kctl = spec->kctls.list;
+ int i;
+ for (i = 0; i < spec->kctls.used; i++)
+ kfree(kctl[i].name);
+ }
+ snd_array_free(&spec->kctls);
+}
+
static void stac92xx_free(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- int i;
if (! spec)
return;
- if (spec->kctl_alloc) {
- for (i = 0; i < spec->num_kctl_used; i++)
- kfree(spec->kctl_alloc[i].name);
- kfree(spec->kctl_alloc);
- }
-
- if (spec->bios_pin_configs)
- kfree(spec->bios_pin_configs);
+ kfree(spec->pin_configs);
+ stac92xx_free_jacks(codec);
+ snd_array_free(&spec->events);
kfree(spec);
snd_hda_detach_beep_device(codec);
@@ -3911,7 +4099,7 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i)
return 0;
}
-static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
+static void stac92xx_hp_detect(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -4007,47 +4195,142 @@ static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid));
}
+static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_jack *jacks = spec->jacks.list;
+
+ if (jacks) {
+ int i;
+ for (i = 0; i < spec->jacks.used; i++) {
+ if (jacks->nid == nid) {
+ unsigned int pin_ctl =
+ snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
+ 0x00);
+ int type = jacks->type;
+ if (type == (SND_JACK_LINEOUT
+ | SND_JACK_HEADPHONE))
+ type = (pin_ctl & AC_PINCTL_HP_EN)
+ ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
+ snd_jack_report(jacks->jack,
+ get_hp_pin_presence(codec, nid)
+ ? type : 0);
+ }
+ jacks++;
+ }
+ }
+}
+
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char type)
+{
+ struct sigmatel_event *event = stac_get_event(codec, nid, type);
+ if (!event)
+ return;
+ codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
+}
+
static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct sigmatel_spec *spec = codec->spec;
- int idx = res >> 26 & 0x0f;
+ struct sigmatel_event *event;
+ int tag, data;
+
+ tag = (res >> 26) & 0x7f;
+ event = stac_get_event_from_tag(codec, tag);
+ if (!event)
+ return;
- switch ((res >> 26) & 0x70) {
+ switch (event->type) {
case STAC_HP_EVENT:
- stac92xx_hp_detect(codec, res);
+ stac92xx_hp_detect(codec);
/* fallthru */
+ case STAC_INSERT_EVENT:
case STAC_PWR_EVENT:
if (spec->num_pwrs > 0)
- stac92xx_pin_sense(codec, idx);
+ stac92xx_pin_sense(codec, event->nid);
+ stac92xx_report_jack(codec, event->nid);
break;
- case STAC_VREF_EVENT: {
- int data = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DATA, 0);
+ case STAC_VREF_EVENT:
+ data = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
/* toggle VREF state based on GPIOx status */
snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
- !!(data & (1 << idx)));
+ !!(data & (1 << event->data)));
break;
- }
}
}
+#ifdef CONFIG_PROC_FS
+static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ if (nid == codec->afg)
+ snd_iprintf(buffer, "Power-Map: 0x%02x\n",
+ snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
+}
+
+static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
+ struct hda_codec *codec,
+ unsigned int verb)
+{
+ snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
+ snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
+}
+
+/* stac92hd71bxx, stac92hd73xx */
+static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ stac92hd_proc_hook(buffer, codec, nid);
+ if (nid == codec->afg)
+ analog_loop_proc_hook(buffer, codec, 0xfa0);
+}
+
+static void stac9205_proc_hook(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ if (nid == codec->afg)
+ analog_loop_proc_hook(buffer, codec, 0xfe0);
+}
+
+static void stac927x_proc_hook(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ if (nid == codec->afg)
+ analog_loop_proc_hook(buffer, codec, 0xfeb);
+}
+#else
+#define stac92hd_proc_hook NULL
+#define stac92hd7x_proc_hook NULL
+#define stac9205_proc_hook NULL
+#define stac927x_proc_hook NULL
+#endif
+
#ifdef SND_HDA_NEEDS_RESUME
static int stac92xx_resume(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
stac92xx_set_config_regs(codec);
- snd_hda_sequence_write(codec, spec->init);
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data);
+ stac92xx_init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
- /* power down inactive DACs */
- if (spec->dac_list)
- stac92xx_power_down(codec);
- /* invoke unsolicited event to reset the HP state */
+ /* fake event to set up pins again to override cached values */
if (spec->hp_detect)
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
+ STAC_HP_EVENT);
+ return 0;
+}
+
+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ if (spec->eapd_mask)
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data &
+ ~spec->eapd_mask);
return 0;
}
#endif
@@ -4059,6 +4342,7 @@ static struct hda_codec_ops stac92xx_patch_ops = {
.free = stac92xx_free,
.unsol_event = stac92xx_unsol_event,
#ifdef SND_HDA_NEEDS_RESUME
+ .suspend = stac92xx_suspend,
.resume = stac92xx_resume,
#endif
};
@@ -4081,14 +4365,12 @@ static int patch_stac9200(struct hda_codec *codec)
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else {
- spec->pin_configs = stac9200_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac9200_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
spec->multiout.max_channels = 2;
@@ -4144,14 +4426,12 @@ static int patch_stac925x(struct hda_codec *codec)
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
"using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else if (stac925x_brd_tbl[spec->board_config] != NULL){
- spec->pin_configs = stac925x_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac925x_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
spec->multiout.max_channels = 2;
@@ -4233,14 +4513,12 @@ again:
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
" STAC92HD73XX, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else {
- spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac92hd73xx_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
@@ -4353,6 +4631,8 @@ again:
codec->patch_ops = stac92xx_patch_ops;
+ codec->proc_widget_hook = stac92hd7x_proc_hook;
+
return 0;
}
@@ -4413,14 +4693,12 @@ again:
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
" STAC92HD83XXX, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else {
- spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac92hd83xxx_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
err = stac92xx_parse_auto_config(codec, 0x1d, 0);
@@ -4441,56 +4719,10 @@ again:
codec->patch_ops = stac92xx_patch_ops;
- return 0;
-}
-
-#ifdef SND_HDA_NEEDS_RESUME
-static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
-{
- struct sigmatel_spec *spec = codec->spec;
- int i;
- snd_hda_codec_write_cache(codec, codec->afg, 0,
- AC_VERB_SET_POWER_STATE, pwr);
-
- msleep(1);
- for (i = 0; i < spec->num_adcs; i++) {
- snd_hda_codec_write_cache(codec,
- spec->adc_nids[i], 0,
- AC_VERB_SET_POWER_STATE, pwr);
- }
-};
-
-static int stac92hd71xx_resume(struct hda_codec *codec)
-{
- stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
- return stac92xx_resume(codec);
-}
+ codec->proc_widget_hook = stac92hd_proc_hook;
-static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
- if (spec->eapd_mask)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data &
- ~spec->eapd_mask);
return 0;
-};
-
-#endif
-
-static struct hda_codec_ops stac92hd71bxx_patch_ops = {
- .build_controls = stac92xx_build_controls,
- .build_pcms = stac92xx_build_pcms,
- .init = stac92xx_init,
- .free = stac92xx_free,
- .unsol_event = stac92xx_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
- .resume = stac92hd71xx_resume,
- .suspend = stac92hd71xx_suspend,
-#endif
-};
+}
static struct hda_input_mux stac92hd71bxx_dmux = {
.num_items = 4,
@@ -4527,14 +4759,12 @@ again:
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
" STAC92HD71BXX, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else {
- spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac92hd71bxx_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
if (spec->board_config > STAC_92HD71BXX_REF) {
@@ -4557,21 +4787,21 @@ again:
switch (spec->board_config) {
case STAC_HP_M4:
/* Enable VREF power saving on GPIO1 detect */
+ err = stac_add_event(spec, codec->afg,
+ STAC_VREF_EVENT, 0x02);
+ if (err < 0)
+ return err;
snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
snd_hda_codec_write_cache(codec, codec->afg, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- (AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | err);
spec->gpio_mask |= 0x02;
break;
}
if ((codec->revision_id & 0xf) == 0 ||
- (codec->revision_id & 0xf) == 1) {
-#ifdef SND_HDA_NEEDS_RESUME
- codec->patch_ops = stac92hd71bxx_patch_ops;
-#endif
+ (codec->revision_id & 0xf) == 1)
spec->stream_delay = 40; /* 40 milliseconds */
- }
/* no output amps */
spec->num_pwrs = 0;
@@ -4580,15 +4810,11 @@ again:
/* disable VSW */
spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
- stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
+ stac_change_pin_config(codec, 0xf, 0x40f000f0);
break;
case 0x111d7603: /* 6 Port with Analog Mixer */
- if ((codec->revision_id & 0xf) == 1) {
-#ifdef SND_HDA_NEEDS_RESUME
- codec->patch_ops = stac92hd71bxx_patch_ops;
-#endif
+ if ((codec->revision_id & 0xf) == 1)
spec->stream_delay = 40; /* 40 milliseconds */
- }
/* no output amps */
spec->num_pwrs = 0;
@@ -4618,7 +4844,7 @@ again:
switch (spec->board_config) {
case STAC_HP_M4:
/* enable internal microphone */
- stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
+ stac_change_pin_config(codec, 0x0e, 0x01813040);
stac92xx_auto_set_pinctl(codec, 0x0e,
AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
/* fallthru */
@@ -4663,6 +4889,8 @@ again:
return err;
}
+ codec->proc_widget_hook = stac92hd7x_proc_hook;
+
return 0;
};
@@ -4724,14 +4952,12 @@ static int patch_stac922x(struct hda_codec *codec)
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
"using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
- spec->pin_configs = stac922x_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac922x_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
spec->adc_nids = stac922x_adc_nids;
@@ -4794,14 +5020,12 @@ static int patch_stac927x(struct hda_codec *codec)
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
"STAC927x, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else {
- spec->pin_configs = stac927x_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac927x_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
spec->digbeep_nid = 0x23;
@@ -4831,15 +5055,15 @@ static int patch_stac927x(struct hda_codec *codec)
case 0x10280209:
case 0x1028022e:
/* correct the device field to SPDIF out */
- stac92xx_set_config_reg(codec, 0x21, 0x01442070);
+ stac_change_pin_config(codec, 0x21, 0x01442070);
break;
};
/* configure the analog microphone on some laptops */
- stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
+ stac_change_pin_config(codec, 0x0c, 0x90a79130);
/* correct the front output jack as a hp out */
- stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
+ stac_change_pin_config(codec, 0x0f, 0x0227011f);
/* correct the front input jack as a mic */
- stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
+ stac_change_pin_config(codec, 0x0e, 0x02a79130);
/* fallthru */
case STAC_DELL_3ST:
/* GPIO2 High = Enable EAPD */
@@ -4887,6 +5111,8 @@ static int patch_stac927x(struct hda_codec *codec)
codec->patch_ops = stac92xx_patch_ops;
+ codec->proc_widget_hook = stac927x_proc_hook;
+
/*
* !!FIXME!!
* The STAC927x seem to require fairly long delays for certain
@@ -4921,14 +5147,12 @@ static int patch_stac9205(struct hda_codec *codec)
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
- spec->pin_configs = spec->bios_pin_configs;
- } else {
- spec->pin_configs = stac9205_brd_tbl[spec->board_config];
- stac92xx_set_config_regs(codec);
+ } else
+ err = stac_save_pin_cfgs(codec,
+ stac9205_brd_tbl[spec->board_config]);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
}
spec->digbeep_nid = 0x23;
@@ -4955,15 +5179,18 @@ static int patch_stac9205(struct hda_codec *codec)
switch (spec->board_config){
case STAC_9205_DELL_M43:
/* Enable SPDIF in/out */
- stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
- stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
+ stac_change_pin_config(codec, 0x1f, 0x01441030);
+ stac_change_pin_config(codec, 0x20, 0x1c410030);
/* Enable unsol response for GPIO4/Dock HP connection */
+ err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
+ if (err < 0)
+ return err;
snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
- (AC_USRSP_EN | STAC_HP_EVENT));
+ AC_USRSP_EN | err);
spec->gpio_dir = 0x0b;
spec->eapd_mask = 0x01;
@@ -5001,6 +5228,8 @@ static int patch_stac9205(struct hda_codec *codec)
codec->patch_ops = stac92xx_patch_ops;
+ codec->proc_widget_hook = stac9205_proc_hook;
+
return 0;
}
@@ -5057,29 +5286,11 @@ static struct hda_verb vaio_ar_init[] = {
{}
};
-/* bind volumes of both NID 0x02 and 0x05 */
-static struct hda_bind_ctls vaio_bind_master_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-/* bind volumes of both NID 0x02 and 0x05 */
-static struct hda_bind_ctls vaio_bind_master_sw = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
- 0,
- },
-};
-
static struct snd_kcontrol_new vaio_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
@@ -5095,8 +5306,10 @@ static struct snd_kcontrol_new vaio_mixer[] = {
};
static struct snd_kcontrol_new vaio_ar_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 63e4871e5d8f..05182be1c9f0 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -53,9 +53,6 @@
#define AMP_VAL_IDX_SHIFT 19
#define AMP_VAL_IDX_MASK (0x0f<<19)
-#define NUM_CONTROL_ALLOC 32
-#define NUM_VERB_ALLOC 32
-
/* Pin Widget NID */
#define VT1708_HP_NID 0x13
#define VT1708_DIGOUT_NID 0x14
@@ -145,8 +142,6 @@ enum {
AUTO_SEQ_SIDE
};
-#define get_amp_nid(kc) ((kc)->private_value & 0xffff)
-
/* Some VT1708S based boards gets the micboost setting wrong, so we have
* to apply some brute-force and re-write the TLV's by software. */
static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
@@ -227,8 +222,7 @@ struct via_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
- unsigned int num_kctl_alloc, num_kctl_used;
- struct snd_kcontrol_new *kctl_alloc;
+ struct snd_array kctls;
struct hda_input_mux private_imux[2];
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
@@ -272,33 +266,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
{
struct snd_kcontrol_new *knew;
- if (spec->num_kctl_used >= spec->num_kctl_alloc) {
- int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
- /* array + terminator */
- knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
- if (!knew)
- return -ENOMEM;
- if (spec->kctl_alloc) {
- memcpy(knew, spec->kctl_alloc,
- sizeof(*knew) * spec->num_kctl_alloc);
- kfree(spec->kctl_alloc);
- }
- spec->kctl_alloc = knew;
- spec->num_kctl_alloc = num;
- }
-
- knew = &spec->kctl_alloc[spec->num_kctl_used];
+ snd_array_init(&spec->kctls, sizeof(*knew), 32);
+ knew = snd_array_new(&spec->kctls);
+ if (!knew)
+ return -ENOMEM;
*knew = vt1708_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL);
-
if (!knew->name)
return -ENOMEM;
knew->private_value = val;
- spec->num_kctl_used++;
return 0;
}
+static void via_free_kctls(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+
+ if (spec->kctls.list) {
+ struct snd_kcontrol_new *kctl = spec->kctls.list;
+ int i;
+ for (i = 0; i < spec->kctls.used; i++)
+ kfree(kctl[i].name);
+ }
+ snd_array_free(&spec->kctls);
+}
+
/* create input playback/capture controls for the given pin */
static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
const char *ctlname, int idx, int mix_nid)
@@ -896,6 +888,7 @@ static int via_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
+ via_free_kctls(codec); /* no longer needed */
return 0;
}
@@ -941,17 +934,11 @@ static int via_build_pcms(struct hda_codec *codec)
static void via_free(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
- unsigned int i;
if (!spec)
return;
- if (spec->kctl_alloc) {
- for (i = 0; i < spec->num_kctl_used; i++)
- kfree(spec->kctl_alloc[i].name);
- kfree(spec->kctl_alloc);
- }
-
+ via_free_kctls(codec);
kfree(codec->spec);
}
@@ -1373,8 +1360,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = VT1708_DIGIN_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
@@ -1846,8 +1833,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = VT1709_DIGIN_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0];
@@ -2390,8 +2377,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = VT1708B_DIGIN_NID;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0];
@@ -2855,8 +2842,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
spec->extra_dig_out_nid = 0x15;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0];
@@ -3174,8 +3161,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
spec->extra_dig_out_nid = 0x1B;
- if (spec->kctl_alloc)
- spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0];
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 1b3f11702713..0dfa0540ce2c 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -382,23 +382,25 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
unsigned char status_mask =
VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM;
int handled = 0;
-#ifdef CONFIG_SND_DEBUG
int timeout = 0;
-#endif
while (1) {
status = inb(ICEREG1724(ice, IRQSTAT));
status &= status_mask;
if (status == 0)
break;
-#ifdef CONFIG_SND_DEBUG
if (++timeout > 10) {
- printk(KERN_ERR
- "ice1724: Too long irq loop, status = 0x%x\n",
- status);
+ status = inb(ICEREG1724(ice, IRQSTAT));
+ printk(KERN_ERR "ice1724: Too long irq loop, "
+ "status = 0x%x\n", status);
+ if (status & VT1724_IRQ_MPU_TX) {
+ printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
+ outb(inb(ICEREG1724(ice, IRQMASK)) |
+ VT1724_IRQ_MPU_TX,
+ ICEREG1724(ice, IRQMASK));
+ }
break;
}
-#endif
handled = 1;
if (status & VT1724_IRQ_MPU_TX) {
spin_lock(&ice->reg_lock);
@@ -2351,7 +2353,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
{
struct snd_ice1712 *ice;
int err;
- unsigned char mask;
static struct snd_device_ops ops = {
.dev_free = snd_vt1724_dev_free,
};
@@ -2412,9 +2413,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
return -EIO;
}
- /* unmask used interrupts */
- mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
- outb(mask, ICEREG1724(ice, IRQMASK));
+ /* MPU_RX and TX irq masks are cleared later dynamically */
+ outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
+
/* don't handle FIFO overrun/underruns (just yet),
* since they cause machine lockups
*/
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index ae7601f353a7..f23a73577c22 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1010,7 +1010,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *
.dev_free = snd_mixart_chip_dev_free,
};
- mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (! chip) {
snd_printk(KERN_ERR "cannot allocate chip\n");
return -ENOMEM;
@@ -1025,6 +1025,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *
return err;
}
+ mgr->chip[idx] = chip;
snd_card_set_dev(card, &mgr->pci->dev);
return 0;
@@ -1377,6 +1378,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
if ((err = snd_mixart_create(mgr, card, i)) < 0) {
+ snd_card_free(card);
snd_mixart_free(mgr);
return err;
}
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index b60f6212745a..de999c6d6dd3 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -61,6 +61,7 @@ MODULE_PARM_DESC(enable, "enable card");
enum {
MODEL_CMEDIA_REF, /* C-Media's reference design */
MODEL_MERIDIAN, /* AuzenTech X-Meridian */
+ MODEL_HALO, /* HT-Omega Claro halo */
};
static struct pci_device_id oxygen_ids[] __devinitdata = {
@@ -74,6 +75,7 @@ static struct pci_device_id oxygen_ids[] __devinitdata = {
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
+ { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO },
{ }
};
MODULE_DEVICE_TABLE(pci, oxygen_ids);
@@ -301,6 +303,8 @@ static int generic_probe(struct oxygen *chip, unsigned long driver_data)
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF;
+ }
+ if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) {
chip->model.misc_flags = OXYGEN_MISC_MIDI;
chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
}
diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile
index 10473c05918d..b06128e918ca 100644
--- a/sound/pci/pcxhr/Makefile
+++ b/sound/pci/pcxhr/Makefile
@@ -1,2 +1,2 @@
-snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o
+snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o
obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 73de6e989b3d..05a1b6cbd72b 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -40,18 +40,20 @@
#include "pcxhr_mixer.h"
#include "pcxhr_hwdep.h"
#include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
#define DRIVER_NAME "pcxhr"
-MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>");
+MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>, "
+ "Marc Titinger <titinger@digigram.com>");
MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING);
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}");
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int mono[SNDRV_CARDS]; /* capture in mono only */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+static int mono[SNDRV_CARDS]; /* capture mono only */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard");
@@ -67,18 +69,58 @@ enum {
PCI_ID_PCX882HR,
PCI_ID_VX881HR,
PCI_ID_PCX881HR,
+ PCI_ID_VX882E,
+ PCI_ID_PCX882E,
+ PCI_ID_VX881E,
+ PCI_ID_PCX881E,
+ PCI_ID_VX1222HR,
PCI_ID_PCX1222HR,
+ PCI_ID_VX1221HR,
PCI_ID_PCX1221HR,
+ PCI_ID_VX1222E,
+ PCI_ID_PCX1222E,
+ PCI_ID_VX1221E,
+ PCI_ID_PCX1221E,
+ PCI_ID_VX222HR,
+ PCI_ID_VX222E,
+ PCI_ID_PCX22HR,
+ PCI_ID_PCX22E,
+ PCI_ID_VX222HRMIC,
+ PCI_ID_VX222E_MIC,
+ PCI_ID_PCX924HR,
+ PCI_ID_PCX924E,
+ PCI_ID_PCX924HRMIC,
+ PCI_ID_PCX924E_MIC,
PCI_ID_LAST
};
static struct pci_device_id pcxhr_ids[] = {
- { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, /* VX882HR */
- { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, /* PCX882HR */
- { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, /* VX881HR */
- { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, /* PCX881HR */
- { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, /* PCX1222HR */
- { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, /* PCX1221HR */
+ { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, },
+ { 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, },
+ { 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, },
+ { 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, },
+ { 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, },
+ { 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, },
+ { 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, },
+ { 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, },
+ { 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, },
+ { 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, },
+ { 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, },
+ { 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, },
+ { 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },
+ { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },
+ { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, },
{ 0, }
};
@@ -88,27 +130,55 @@ struct board_parameters {
char* board_name;
short playback_chips;
short capture_chips;
+ short fw_file_set;
short firmware_num;
};
static struct board_parameters pcxhr_board_params[] = {
-[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 41, },
-[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 41, },
-[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 41, },
-[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 41, },
-[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 42, },
-[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 42, },
+[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 0, 41 },
+[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 0, 41 },
+[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 0, 41 },
+[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 0, 41 },
+[PCI_ID_VX882E] = { "VX882e", 4, 4, 1, 41 },
+[PCI_ID_PCX882E] = { "PCX882e", 4, 4, 1, 41 },
+[PCI_ID_VX881E] = { "VX881e", 4, 4, 1, 41 },
+[PCI_ID_PCX881E] = { "PCX881e", 4, 4, 1, 41 },
+[PCI_ID_VX1222HR] = { "VX1222HR", 6, 1, 2, 42 },
+[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 2, 42 },
+[PCI_ID_VX1221HR] = { "VX1221HR", 6, 1, 2, 42 },
+[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 2, 42 },
+[PCI_ID_VX1222E] = { "VX1222e", 6, 1, 3, 42 },
+[PCI_ID_PCX1222E] = { "PCX1222e", 6, 1, 3, 42 },
+[PCI_ID_VX1221E] = { "VX1221e", 6, 1, 3, 42 },
+[PCI_ID_PCX1221E] = { "PCX1221e", 6, 1, 3, 42 },
+[PCI_ID_VX222HR] = { "VX222HR", 1, 1, 4, 44 },
+[PCI_ID_VX222E] = { "VX222e", 1, 1, 4, 44 },
+[PCI_ID_PCX22HR] = { "PCX22HR", 1, 0, 4, 44 },
+[PCI_ID_PCX22E] = { "PCX22e", 1, 0, 4, 44 },
+[PCI_ID_VX222HRMIC] = { "VX222HR-Mic", 1, 1, 5, 44 },
+[PCI_ID_VX222E_MIC] = { "VX222e-Mic", 1, 1, 5, 44 },
+[PCI_ID_PCX924HR] = { "PCX924HR", 1, 1, 5, 44 },
+[PCI_ID_PCX924E] = { "PCX924e", 1, 1, 5, 44 },
+[PCI_ID_PCX924HRMIC] = { "PCX924HR-Mic", 1, 1, 5, 44 },
+[PCI_ID_PCX924E_MIC] = { "PCX924e-Mic", 1, 1, 5, 44 },
};
+/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */
+/* VX222HR, VX222e, PCX22HR and PCX22e */
+#define PCXHR_BOARD_HAS_AES1(x) (x->fw_file_set != 4)
+/* some boards do not support 192kHz on digital AES input plugs */
+#define PCXHR_BOARD_AESIN_NO_192K(x) ((x->capture_chips == 0) || \
+ (x->fw_file_set == 0) || \
+ (x->fw_file_set == 2))
static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
unsigned int* realfreq)
{
unsigned int reg;
- if (freq < 6900 || freq > 110250)
+ if (freq < 6900 || freq > 110000)
return -EINVAL;
- reg = (28224000 * 10) / freq;
- reg = (reg + 5) / 10;
+ reg = (28224000 * 2) / freq;
+ reg = (reg - 1) / 2;
if (reg < 0x200)
*pllreg = reg + 0x800;
else if (reg < 0x400)
@@ -121,7 +191,7 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
reg &= ~3;
}
if (realfreq)
- *realfreq = ((28224000 * 10) / reg + 5) / 10;
+ *realfreq = (28224000 / (reg + 1));
return 0;
}
@@ -151,11 +221,6 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
#define PCXHR_FREQ_AES_3 0x03
#define PCXHR_FREQ_AES_4 0x0d
-#define PCXHR_MODIFY_CLOCK_S_BIT 0x04
-
-#define PCXHR_IRQ_TIMER_FREQ 92000
-#define PCXHR_IRQ_TIMER_PERIOD 48
-
static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
unsigned int *reg, unsigned int *freq)
{
@@ -196,19 +261,32 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0) {
snd_printk(KERN_ERR
- "error CMD_ACCESS_IO_WRITE for PLL register : %x!\n",
- err );
+ "error CMD_ACCESS_IO_WRITE "
+ "for PLL register : %x!\n", err);
return err;
}
}
break;
- case PCXHR_CLOCK_TYPE_WORD_CLOCK : val = PCXHR_FREQ_WORD_CLOCK; break;
- case PCXHR_CLOCK_TYPE_AES_SYNC : val = PCXHR_FREQ_SYNC_AES; break;
- case PCXHR_CLOCK_TYPE_AES_1 : val = PCXHR_FREQ_AES_1; break;
- case PCXHR_CLOCK_TYPE_AES_2 : val = PCXHR_FREQ_AES_2; break;
- case PCXHR_CLOCK_TYPE_AES_3 : val = PCXHR_FREQ_AES_3; break;
- case PCXHR_CLOCK_TYPE_AES_4 : val = PCXHR_FREQ_AES_4; break;
- default : return -EINVAL;
+ case PCXHR_CLOCK_TYPE_WORD_CLOCK:
+ val = PCXHR_FREQ_WORD_CLOCK;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_SYNC:
+ val = PCXHR_FREQ_SYNC_AES;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_1:
+ val = PCXHR_FREQ_AES_1;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_2:
+ val = PCXHR_FREQ_AES_2;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_3:
+ val = PCXHR_FREQ_AES_3;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_4:
+ val = PCXHR_FREQ_AES_4;
+ break;
+ default:
+ return -EINVAL;
}
*reg = val;
*freq = realfreq;
@@ -216,14 +294,13 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
}
-int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
+static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
+ unsigned int rate,
+ int *changed)
{
unsigned int val, realfreq, speed;
struct pcxhr_rmh rmh;
- int err, changed;
-
- if (rate == 0)
- return 0; /* nothing to do */
+ int err;
err = pcxhr_get_clock_reg(mgr, rate, &val, &realfreq);
if (err)
@@ -237,13 +314,17 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
else
speed = 2; /* quad speed */
if (mgr->codec_speed != speed) {
- pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */
+ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */
rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+ if (DSP_EXT_CMD_SET(mgr)) {
+ rmh.cmd[1] = 1;
+ rmh.cmd_len = 2;
+ }
err = pcxhr_send_msg(mgr, &rmh);
if (err)
return err;
- pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */
+ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */
rmh.cmd[0] |= IO_NUM_SPEED_RATIO;
rmh.cmd[1] = speed;
rmh.cmd_len = 2;
@@ -253,25 +334,57 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
}
/* set the new frequency */
snd_printdd("clock register : set %x\n", val);
- err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, &changed);
+ err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK,
+ val, changed);
if (err)
return err;
+
mgr->sample_rate_real = realfreq;
mgr->cur_clock_type = mgr->use_clock_type;
/* unmute after codec speed modes */
if (mgr->codec_speed != speed) {
- pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */
+ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */
rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+ if (DSP_EXT_CMD_SET(mgr)) {
+ rmh.cmd[1] = 1;
+ rmh.cmd_len = 2;
+ }
err = pcxhr_send_msg(mgr, &rmh);
if (err)
return err;
- mgr->codec_speed = speed; /* save new codec speed */
+ mgr->codec_speed = speed; /* save new codec speed */
}
+ snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
+ rate, realfreq);
+ return 0;
+}
+
+#define PCXHR_MODIFY_CLOCK_S_BIT 0x04
+
+#define PCXHR_IRQ_TIMER_FREQ 92000
+#define PCXHR_IRQ_TIMER_PERIOD 48
+
+int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
+{
+ struct pcxhr_rmh rmh;
+ int err, changed;
+
+ if (rate == 0)
+ return 0; /* nothing to do */
+
+ if (mgr->is_hr_stereo)
+ err = hr222_sub_set_clock(mgr, rate, &changed);
+ else
+ err = pcxhr_sub_set_clock(mgr, rate, &changed);
+
+ if (err)
+ return err;
+
if (changed) {
pcxhr_init_rmh(&rmh, CMD_MODIFY_CLOCK);
- rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */
+ rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */
if (rate < PCXHR_IRQ_TIMER_FREQ)
rmh.cmd[1] = PCXHR_IRQ_TIMER_PERIOD;
else
@@ -282,26 +395,39 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
if (err)
return err;
}
- snd_printdd("pcxhr_set_clock to %dHz (realfreq=%d)\n", rate, realfreq);
return 0;
}
-int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type,
- int *sample_rate)
+static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr,
+ enum pcxhr_clock_type clock_type,
+ int *sample_rate)
{
struct pcxhr_rmh rmh;
unsigned char reg;
int err, rate;
switch (clock_type) {
- case PCXHR_CLOCK_TYPE_WORD_CLOCK : reg = REG_STATUS_WORD_CLOCK; break;
- case PCXHR_CLOCK_TYPE_AES_SYNC : reg = REG_STATUS_AES_SYNC; break;
- case PCXHR_CLOCK_TYPE_AES_1 : reg = REG_STATUS_AES_1; break;
- case PCXHR_CLOCK_TYPE_AES_2 : reg = REG_STATUS_AES_2; break;
- case PCXHR_CLOCK_TYPE_AES_3 : reg = REG_STATUS_AES_3; break;
- case PCXHR_CLOCK_TYPE_AES_4 : reg = REG_STATUS_AES_4; break;
- default : return -EINVAL;
+ case PCXHR_CLOCK_TYPE_WORD_CLOCK:
+ reg = REG_STATUS_WORD_CLOCK;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_SYNC:
+ reg = REG_STATUS_AES_SYNC;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_1:
+ reg = REG_STATUS_AES_1;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_2:
+ reg = REG_STATUS_AES_2;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_3:
+ reg = REG_STATUS_AES_3;
+ break;
+ case PCXHR_CLOCK_TYPE_AES_4:
+ reg = REG_STATUS_AES_4;
+ break;
+ default:
+ return -EINVAL;
}
pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
rmh.cmd_len = 2;
@@ -311,7 +437,7 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_
err = pcxhr_send_msg(mgr, &rmh);
if (err)
return err;
- udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */
+ udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */
mgr->last_reg_stat = reg;
}
rmh.cmd[1] = REG_STATUS_CURRENT;
@@ -336,6 +462,18 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_
}
+int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
+ enum pcxhr_clock_type clock_type,
+ int *sample_rate)
+{
+ if (mgr->is_hr_stereo)
+ return hr222_get_external_clock(mgr, clock_type,
+ sample_rate);
+ else
+ return pcxhr_sub_get_external_clock(mgr, clock_type,
+ sample_rate);
+}
+
/*
* start or stop playback/capture substream
*/
@@ -350,7 +488,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
start = 1;
else {
if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) {
- snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state CANNOT be stopped\n");
+ snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state "
+ "CANNOT be stopped\n");
return -EINVAL;
}
start = 0;
@@ -359,11 +498,12 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
return -EINVAL;
stream->timer_abs_periods = 0;
- stream->timer_period_frag = 0; /* reset theoretical stream pos */
+ stream->timer_period_frag = 0; /* reset theoretical stream pos */
stream->timer_buf_periods = 0;
stream->timer_is_synced = 0;
- stream_mask = stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
+ stream_mask =
+ stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
pcxhr_init_rmh(&rmh, start ? CMD_START_STREAM : CMD_STOP_STREAM);
pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
@@ -373,8 +513,10 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
- snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", err);
- stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
+ snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n",
+ err);
+ stream->status =
+ start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
return err;
}
@@ -399,13 +541,15 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
header = HEADER_FMT_BASE_LIN;
break;
case SNDRV_PCM_FORMAT_S16_LE:
- header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS | HEADER_FMT_INTEL;
+ header = HEADER_FMT_BASE_LIN |
+ HEADER_FMT_16BITS | HEADER_FMT_INTEL;
break;
case SNDRV_PCM_FORMAT_S16_BE:
header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS;
break;
case SNDRV_PCM_FORMAT_S24_3LE:
- header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS | HEADER_FMT_INTEL;
+ header = HEADER_FMT_BASE_LIN |
+ HEADER_FMT_24BITS | HEADER_FMT_INTEL;
break;
case SNDRV_PCM_FORMAT_S24_3BE:
header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS;
@@ -414,7 +558,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL;
break;
default:
- snd_printk(KERN_ERR "error pcxhr_set_format() : unknown format\n");
+ snd_printk(KERN_ERR
+ "error pcxhr_set_format() : unknown format\n");
return -EINVAL;
}
chip = snd_pcm_substream_chip(stream->substream);
@@ -432,14 +577,31 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
is_capture = stream->pipe->is_capture;
stream_num = is_capture ? 0 : stream->substream->number;
- pcxhr_init_rmh(&rmh, is_capture ? CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
- pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
- if (is_capture)
- rmh.cmd[0] |= 1<<12;
+ pcxhr_init_rmh(&rmh, is_capture ?
+ CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
+ pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
+ stream_num, 0);
+ if (is_capture) {
+ /* bug with old dsp versions: */
+ /* bit 12 also sets the format of the playback stream */
+ if (DSP_EXT_CMD_SET(chip->mgr))
+ rmh.cmd[0] |= 1<<10;
+ else
+ rmh.cmd[0] |= 1<<12;
+ }
rmh.cmd[1] = 0;
- rmh.cmd[2] = header >> 8;
- rmh.cmd[3] = (header & 0xff) << 16;
- rmh.cmd_len = 4;
+ rmh.cmd_len = 2;
+ if (DSP_EXT_CMD_SET(chip->mgr)) {
+ /* add channels and set bit 19 if channels>2 */
+ rmh.cmd[1] = stream->channels;
+ if (!is_capture) {
+ /* playback : add channel mask to command */
+ rmh.cmd[2] = (stream->channels == 1) ? 0x01 : 0x03;
+ rmh.cmd_len = 3;
+ }
+ }
+ rmh.cmd[rmh.cmd_len++] = header >> 8;
+ rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err);
@@ -456,30 +618,38 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE);
stream_num = is_capture ? 0 : subs->number;
- snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n",
+ snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : "
+ "addr(%p) bytes(%zx) subs(%d)\n",
is_capture ? 'c' : 'p',
chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
subs->runtime->dma_bytes, subs->number);
pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
- pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
+ pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
+ stream_num, 0);
/* max buffer size is 2 MByte */
snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000);
- rmh.cmd[1] = subs->runtime->dma_bytes * 8; /* size in bits */
- rmh.cmd[2] = subs->runtime->dma_addr >> 24; /* most significant byte */
- rmh.cmd[2] |= 1<<19; /* this is a circular buffer */
- rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; /* least 3 significant bytes */
+ /* size in bits */
+ rmh.cmd[1] = subs->runtime->dma_bytes * 8;
+ /* most significant byte */
+ rmh.cmd[2] = subs->runtime->dma_addr >> 24;
+ /* this is a circular buffer */
+ rmh.cmd[2] |= 1<<19;
+ /* least 3 significant bytes */
+ rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD;
rmh.cmd_len = 4;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
- snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
+ snd_printk(KERN_ERR
+ "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
return err;
}
#if 0
-static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count)
+static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream,
+ snd_pcm_uframes_t *sample_count)
{
struct pcxhr_rmh rmh;
int err;
@@ -533,8 +703,8 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
for (j = 0; j < chip->nb_streams_play; j++) {
if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) {
playback_mask |= (1 << pipe->first_audio);
- break; /* add only once, as all playback streams of
- * one chip use the same pipe
+ break; /* add only once, as all playback
+ * streams of one chip use the same pipe
*/
}
}
@@ -545,19 +715,21 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
return;
}
- snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n",
+ snd_printdd("pcxhr_trigger_tasklet : "
+ "playback_mask=%x capture_mask=%x\n",
playback_mask, capture_mask);
/* synchronous stop of all the pipes concerned */
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
if (err) {
mutex_unlock(&mgr->setup_mutex);
- snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n",
+ snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+ "error stop pipes (P%x C%x)\n",
playback_mask, capture_mask);
return;
}
- /* unfortunately the dsp lost format and buffer info with the stop pipe */
+ /* the dsp lost format and buffer info with the stop pipe */
for (i = 0; i < mgr->num_cards; i++) {
struct pcxhr_stream *stream;
chip = mgr->chip[i];
@@ -596,12 +768,15 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
if (err) {
mutex_unlock(&mgr->setup_mutex);
- snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n",
+ snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+ "error start pipes (P%x C%x)\n",
playback_mask, capture_mask);
return;
}
- /* put the streams into the running state now (increment pointer by interrupt) */
+ /* put the streams into the running state now
+ * (increment pointer by interrupt)
+ */
spin_lock_irqsave(&mgr->lock, flags);
for ( i =0; i < mgr->num_cards; i++) {
struct pcxhr_stream *stream;
@@ -615,7 +790,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
stream = &chip->playback_stream[j];
if (stream->status == PCXHR_STREAM_STATUS_STARTED) {
/* playback will already have advanced ! */
- stream->timer_period_frag += PCXHR_GRANULARITY;
+ stream->timer_period_frag += mgr->granularity;
stream->status = PCXHR_STREAM_STATUS_RUNNING;
}
}
@@ -697,12 +872,14 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start)
pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT);
if (start) {
- mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; /* last dsp time invalid */
- rmh.cmd[0] |= PCXHR_GRANULARITY;
+ /* last dsp time invalid */
+ mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+ rmh.cmd[0] |= mgr->granularity;
}
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0)
- snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err);
+ snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n",
+ err);
return err;
}
@@ -713,38 +890,16 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs)
{
struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
struct pcxhr_mgr *mgr = chip->mgr;
- /*
- struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data;
- */
int err = 0;
snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
subs->runtime->period_size, subs->runtime->periods,
subs->runtime->buffer_size);
- /*
- if(subs->runtime->period_size <= PCXHR_GRANULARITY) {
- snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n",
- (unsigned int)subs->runtime->period_size);
- return -EINVAL;
- }
- */
-
mutex_lock(&mgr->setup_mutex);
do {
- /* if the stream was stopped before, format and buffer were reset */
- /*
- if(stream->status == PCXHR_STREAM_STATUS_STOPPED) {
- err = pcxhr_set_format(stream);
- if(err) break;
- err = pcxhr_update_r_buffer(stream);
- if(err) break;
- }
- */
-
/* only the first stream can choose the sample rate */
- /* the further opened streams will be limited to its frequency (see open) */
/* set the clock only once (first stream) */
if (mgr->sample_rate != subs->runtime->rate) {
err = pcxhr_set_clock(mgr, subs->runtime->rate);
@@ -787,22 +942,9 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs,
stream->channels = channels;
stream->format = format;
- /* set the format to the board */
- /*
- err = pcxhr_set_format(stream);
- if(err) {
- mutex_unlock(&mgr->setup_mutex);
- return err;
- }
- */
/* allocate buffer */
err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));
- /*
- if (err > 0) {
- err = pcxhr_update_r_buffer(stream);
- }
- */
mutex_unlock(&mgr->setup_mutex);
return err;
@@ -820,14 +962,18 @@ static int pcxhr_hw_free(struct snd_pcm_substream *subs)
*/
static struct snd_pcm_hardware pcxhr_caps =
{
- .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
- 0 /*SNDRV_PCM_INFO_PAUSE*/),
- .formats = ( SNDRV_PCM_FMTBIT_U8 |
- SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
- SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
- SNDRV_PCM_FMTBIT_FLOAT_LE ),
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = (SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S24_3BE |
+ SNDRV_PCM_FMTBIT_FLOAT_LE),
+ .rates = (SNDRV_PCM_RATE_CONTINUOUS |
+ SNDRV_PCM_RATE_8000_192000),
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
@@ -847,6 +993,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
struct pcxhr_mgr *mgr = chip->mgr;
struct snd_pcm_runtime *runtime = subs->runtime;
struct pcxhr_stream *stream;
+ int err;
mutex_lock(&mgr->setup_mutex);
@@ -874,6 +1021,18 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
return -EBUSY;
}
+ /* float format support is in some cases buggy on stereo cards */
+ if (mgr->is_hr_stereo)
+ runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_FLOAT_LE;
+
+ /* buffer-size should better be multiple of period-size */
+ err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0) {
+ mutex_unlock(&mgr->setup_mutex);
+ return err;
+ }
+
/* if a sample rate is already used or fixed by external clock,
* the stream cannot change
*/
@@ -889,7 +1048,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
mutex_unlock(&mgr->setup_mutex);
return -EBUSY;
}
- runtime->hw.rate_min = runtime->hw.rate_max = external_rate;
+ runtime->hw.rate_min = external_rate;
+ runtime->hw.rate_max = external_rate;
}
}
@@ -899,9 +1059,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
runtime->private_data = stream;
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
-
+ /* better get a divisor of granularity values (96 or 192) */
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
snd_pcm_set_sync(subs);
mgr->ref_count_rate++;
@@ -919,11 +1081,12 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
mutex_lock(&mgr->setup_mutex);
- snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number);
+ snd_printdd("pcxhr_close chip%d subs%d\n",
+ chip->chip_idx, subs->number);
/* sample rate released */
if (--mgr->ref_count_rate == 0) {
- mgr->sample_rate = 0; /* the sample rate is no more locked */
+ mgr->sample_rate = 0; /* the sample rate is no more locked */
pcxhr_hardware_timer(mgr, 0); /* stop the DSP-timer */
}
@@ -1016,7 +1179,8 @@ static int pcxhr_chip_dev_free(struct snd_device *device)
/*
*/
-static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, int idx)
+static int __devinit pcxhr_create(struct pcxhr_mgr *mgr,
+ struct snd_card *card, int idx)
{
int err;
struct snd_pcxhr *chip;
@@ -1024,7 +1188,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card,
.dev_free = pcxhr_chip_dev_free,
};
- mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (! chip) {
snd_printk(KERN_ERR "cannot allocate chip\n");
return -ENOMEM;
@@ -1040,7 +1204,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card,
if (idx < mgr->capture_chips) {
if (mgr->mono_capture)
- chip->nb_streams_capt = 2; /* 2 mono streams (left+right) */
+ chip->nb_streams_capt = 2; /* 2 mono streams */
else
chip->nb_streams_capt = 1; /* or 1 stereo stream */
}
@@ -1050,13 +1214,15 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card,
return err;
}
+ mgr->chip[idx] = chip;
snd_card_set_dev(card, &mgr->pci->dev);
return 0;
}
/* proc interface */
-static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+static void pcxhr_proc_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
struct snd_pcxhr *chip = entry->private_data;
struct pcxhr_mgr *mgr = chip->mgr;
@@ -1069,8 +1235,10 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer
short ver_maj = (mgr->dsp_version >> 16) & 0xff;
short ver_min = (mgr->dsp_version >> 8) & 0xff;
short ver_build = mgr->dsp_version & 0xff;
- snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING);
- snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build);
+ snd_iprintf(buffer, "module version %s\n",
+ PCXHR_DRIVER_VERSION_STRING);
+ snd_iprintf(buffer, "dsp version %d.%d.%d\n",
+ ver_maj, ver_min, ver_build);
if (mgr->board_has_analog)
snd_iprintf(buffer, "analog io available\n");
else
@@ -1084,18 +1252,22 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer
if (ref > 0) {
if (mgr->sample_rate_real != 0 &&
mgr->sample_rate_real != 48000) {
- ref = (ref * 48000) / mgr->sample_rate_real;
- if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ)
+ ref = (ref * 48000) /
+ mgr->sample_rate_real;
+ if (mgr->sample_rate_real >=
+ PCXHR_IRQ_TIMER_FREQ)
ref *= 2;
}
cur = 100 - (100 * cur) / ref;
snd_iprintf(buffer, "cpu load %d%%\n", cur);
- snd_iprintf(buffer, "buffer pool %d/%d kWords\n",
+ snd_iprintf(buffer, "buffer pool %d/%d\n",
rmh.stat[2], rmh.stat[3]);
}
}
- snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY);
- snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err);
+ snd_iprintf(buffer, "dma granularity : %d\n",
+ mgr->granularity);
+ snd_iprintf(buffer, "dsp time errors : %d\n",
+ mgr->dsp_time_err);
snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n",
mgr->async_err_pipe_xrun);
snd_iprintf(buffer, "dsp async stream xrun errors : %d\n",
@@ -1110,33 +1282,52 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer
rmh.cmd_idx = CMD_LAST_INDEX;
if( ! pcxhr_send_msg(mgr, &rmh) ) {
int i;
+ if (rmh.stat_len > 8)
+ rmh.stat_len = 8;
for (i = 0; i < rmh.stat_len; i++)
- snd_iprintf(buffer, "debug[%02d] = %06x\n", i, rmh.stat[i]);
+ snd_iprintf(buffer, "debug[%02d] = %06x\n",
+ i, rmh.stat[i]);
}
} else
snd_iprintf(buffer, "no firmware loaded\n");
snd_iprintf(buffer, "\n");
}
-static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+static void pcxhr_proc_sync(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
struct snd_pcxhr *chip = entry->private_data;
struct pcxhr_mgr *mgr = chip->mgr;
- static char *texts[7] = {
- "Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4"
+ static const char *textsHR22[3] = {
+ "Internal", "AES Sync", "AES 1"
+ };
+ static const char *textsPCXHR[7] = {
+ "Internal", "Word", "AES Sync",
+ "AES 1", "AES 2", "AES 3", "AES 4"
};
+ const char **texts;
+ int max_clock;
+ if (mgr->is_hr_stereo) {
+ texts = textsHR22;
+ max_clock = HR22_CLOCK_TYPE_MAX;
+ } else {
+ texts = textsPCXHR;
+ max_clock = PCXHR_CLOCK_TYPE_MAX;
+ }
snd_iprintf(buffer, "\n%s\n", mgr->longname);
- snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]);
- snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real);
-
+ snd_iprintf(buffer, "Current Sample Clock\t: %s\n",
+ texts[mgr->cur_clock_type]);
+ snd_iprintf(buffer, "Current Sample Rate\t= %d\n",
+ mgr->sample_rate_real);
/* commands available when embedded DSP is running */
if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
int i, err, sample_rate;
- for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) {
+ for (i = 1; i <= max_clock; i++) {
err = pcxhr_get_external_clock(mgr, i, &sample_rate);
if (err)
break;
- snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate);
+ snd_iprintf(buffer, "%s Clock\t\t= %d\n",
+ texts[i], sample_rate);
}
} else
snd_iprintf(buffer, "no firmware loaded\n");
@@ -1194,7 +1385,8 @@ static int pcxhr_free(struct pcxhr_mgr *mgr)
/*
* probe function - creates the card manager
*/
-static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+static int __devinit pcxhr_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
{
static int dev;
struct pcxhr_mgr *mgr;
@@ -1217,7 +1409,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
/* check if we can restrict PCI DMA transfers to 32 bits */
if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) {
- snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+ snd_printk(KERN_ERR "architecture does not support "
+ "32bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1234,11 +1427,25 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
pci_disable_device(pci);
return -ENODEV;
}
- card_name = pcxhr_board_params[pci_id->driver_data].board_name;
- mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips;
- mgr->capture_chips = pcxhr_board_params[pci_id->driver_data].capture_chips;
- mgr->firmware_num = pcxhr_board_params[pci_id->driver_data].firmware_num;
+ card_name =
+ pcxhr_board_params[pci_id->driver_data].board_name;
+ mgr->playback_chips =
+ pcxhr_board_params[pci_id->driver_data].playback_chips;
+ mgr->capture_chips =
+ pcxhr_board_params[pci_id->driver_data].capture_chips;
+ mgr->fw_file_set =
+ pcxhr_board_params[pci_id->driver_data].fw_file_set;
+ mgr->firmware_num =
+ pcxhr_board_params[pci_id->driver_data].firmware_num;
mgr->mono_capture = mono[dev];
+ mgr->is_hr_stereo = (mgr->playback_chips == 1);
+ mgr->board_has_aes1 = PCXHR_BOARD_HAS_AES1(mgr);
+ mgr->board_aes_in_192k = !PCXHR_BOARD_AESIN_NO_192K(mgr);
+
+ if (mgr->is_hr_stereo)
+ mgr->granularity = PCXHR_GRANULARITY_HR22;
+ else
+ mgr->granularity = PCXHR_GRANULARITY;
/* resource assignment */
if ((err = pci_request_regions(pci, card_name)) < 0) {
@@ -1261,7 +1468,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
mgr->irq = pci->irq;
sprintf(mgr->shortname, "Digigram %s", card_name);
- sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname,
+ sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i",
+ mgr->shortname,
mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq);
/* ISR spinlock */
@@ -1272,10 +1480,14 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
mutex_init(&mgr->setup_mutex);
/* init taslket */
- tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr);
- tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr);
+ tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet,
+ (unsigned long) mgr);
+ tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet,
+ (unsigned long) mgr);
+
mgr->prmh = kmalloc(sizeof(*mgr->prmh) +
- sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS),
+ sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS -
+ PCXHR_SIZE_MAX_STATUS),
GFP_KERNEL);
if (! mgr->prmh) {
pcxhr_free(mgr);
@@ -1296,7 +1508,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
else
idx = index[dev] + i;
- snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i);
+ snprintf(tmpid, sizeof(tmpid), "%s-%d",
+ id[dev] ? id[dev] : card_name, i);
card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
if (! card) {
@@ -1310,6 +1523,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
if ((err = pcxhr_create(mgr, card, i)) < 0) {
+ snd_card_free(card);
pcxhr_free(mgr);
return err;
}
diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h
index 652064787a55..84131a916c92 100644
--- a/sound/pci/pcxhr/pcxhr.h
+++ b/sound/pci/pcxhr/pcxhr.h
@@ -27,15 +27,18 @@
#include <linux/mutex.h>
#include <sound/pcm.h>
-#define PCXHR_DRIVER_VERSION 0x000804 /* 0.8.4 */
-#define PCXHR_DRIVER_VERSION_STRING "0.8.4" /* 0.8.4 */
+#define PCXHR_DRIVER_VERSION 0x000905 /* 0.9.5 */
+#define PCXHR_DRIVER_VERSION_STRING "0.9.5" /* 0.9.5 */
-#define PCXHR_MAX_CARDS 6
-#define PCXHR_PLAYBACK_STREAMS 4
+#define PCXHR_MAX_CARDS 6
+#define PCXHR_PLAYBACK_STREAMS 4
-#define PCXHR_GRANULARITY 96 /* transfer granularity (should be min 96 and multiple of 48) */
-#define PCXHR_GRANULARITY_MIN 96 /* transfer granularity of pipes and the dsp time (MBOX4) */
+#define PCXHR_GRANULARITY 96 /* min 96 and multiple of 48 */
+/* transfer granularity of pipes and the dsp time (MBOX4) */
+#define PCXHR_GRANULARITY_MIN 96
+/* TODO : granularity could be 64 or 128 */
+#define PCXHR_GRANULARITY_HR22 192 /* granularity for stereo cards */
struct snd_pcxhr;
struct pcxhr_mgr;
@@ -51,6 +54,11 @@ enum pcxhr_clock_type {
PCXHR_CLOCK_TYPE_AES_2,
PCXHR_CLOCK_TYPE_AES_3,
PCXHR_CLOCK_TYPE_AES_4,
+ PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4,
+ HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL,
+ HR22_CLOCK_TYPE_AES_SYNC,
+ HR22_CLOCK_TYPE_AES_1,
+ HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1,
};
struct pcxhr_mgr {
@@ -61,6 +69,8 @@ struct pcxhr_mgr {
int irq;
+ int granularity;
+
/* card access with 1 mem bar and 2 io bar's */
unsigned long port[3];
@@ -83,11 +93,16 @@ struct pcxhr_mgr {
/* hardware interface */
unsigned int dsp_loaded; /* bit flags of loaded dsp indices */
unsigned int dsp_version; /* read from embedded once firmware is loaded */
- int board_has_analog; /* if 0 the board is digital only */
- int mono_capture; /* if 1 the board does mono capture */
- int playback_chips; /* 4 or 6 */
- int capture_chips; /* 4 or 1 */
- int firmware_num; /* 41 or 42 */
+ int playback_chips;
+ int capture_chips;
+ int fw_file_set;
+ int firmware_num;
+ int is_hr_stereo:1;
+ int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */
+ int board_has_analog:1; /* if 0 the board is digital only */
+ int board_has_mic:1; /* if 1 the board has microphone input */
+ int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
+ int mono_capture:1; /* if 1 the board does mono capture */
struct snd_dma_buffer hostport;
@@ -106,6 +121,9 @@ struct pcxhr_mgr {
int async_err_stream_xrun;
int async_err_pipe_xrun;
int async_err_other_last;
+
+ unsigned char xlx_cfg; /* copy of PCXHR_XLX_CFG register */
+ unsigned char xlx_selmic; /* copy of PCXHR_XLX_SELMIC register */
};
@@ -155,24 +173,30 @@ struct snd_pcxhr {
struct snd_pcm *pcm; /* PCM */
- struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */
- struct pcxhr_pipe capture_pipe[2]; /* 1 stereo pipe or 2 mono pipes */
+ struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */
+ struct pcxhr_pipe capture_pipe[2]; /* 1 stereo or 2 mono pipes */
struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS];
- struct pcxhr_stream capture_stream[2]; /* 1 stereo stream or 2 mono streams */
+ struct pcxhr_stream capture_stream[2]; /* 1 stereo or 2 mono streams */
int nb_streams_play;
int nb_streams_capt;
- int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */
- int analog_playback_volume[2]; /* Mixer : Master Playback Volume */
- int analog_capture_volume[2]; /* Mixer : Master Capture Volume */
- int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [streams][stereo]*/
- int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [streams][stereo]*/
- int digital_capture_volume[2]; /* Mixer : Digital Capture Volume [stereo] */
- int monitoring_active[2]; /* Mixer : Monitoring Active */
- int monitoring_volume[2]; /* Mixer : Monitoring Volume */
- int audio_capture_source; /* Mixer : Audio Capture Source */
- unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */
+ int analog_playback_active[2]; /* Mixer : Master Playback !mute */
+ int analog_playback_volume[2]; /* Mixer : Master Playback Volume */
+ int analog_capture_volume[2]; /* Mixer : Master Capture Volume */
+ int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2];
+ int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2];
+ int digital_capture_volume[2]; /* Mixer : Digital Capture Volume */
+ int monitoring_active[2]; /* Mixer : Monitoring Active */
+ int monitoring_volume[2]; /* Mixer : Monitoring Volume */
+ int audio_capture_source; /* Mixer : Audio Capture Source */
+ int mic_volume; /* used by cards with MIC only */
+ int mic_boost; /* used by cards with MIC only */
+ int mic_active; /* used by cards with MIC only */
+ int analog_capture_active; /* used by cards with MIC only */
+ int phantom_power; /* used by cards with MIC only */
+
+ unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */
};
struct pcxhr_hostport
@@ -184,6 +208,8 @@ struct pcxhr_hostport
/* exported */
int pcxhr_create_pcm(struct snd_pcxhr *chip);
int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate);
-int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, int *sample_rate);
+int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
+ enum pcxhr_clock_type clock_type,
+ int *sample_rate);
#endif /* __SOUND_PCXHR_H */
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 7143259cfe34..d5f18226261d 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -132,13 +132,15 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
*read = PCXHR_INPB(mgr, reg);
if ((*read & mask) == bit) {
if (i > 100)
- snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n",
+ snd_printdd("ATTENTION! check_reg(%x) "
+ "loopcount=%d\n",
reg, i);
return 0;
}
i++;
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n",
+ snd_printk(KERN_ERR
+ "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
reg, mask, *read);
return -EIO;
}
@@ -159,18 +161,22 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
#define PCXHR_IT_TEST_XILINX (0x0000003C | PCXHR_MASK_IT_HF1 | \
PCXHR_MASK_IT_MANAGE_HF5)
#define PCXHR_IT_DOWNLOAD_BOOT (0x0000000C | PCXHR_MASK_IT_HF1 | \
- PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)
+ PCXHR_MASK_IT_MANAGE_HF5 | \
+ PCXHR_MASK_IT_WAIT)
#define PCXHR_IT_RESET_BOARD_FUNC (0x0000000C | PCXHR_MASK_IT_HF0 | \
- PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA)
+ PCXHR_MASK_IT_MANAGE_HF5 | \
+ PCXHR_MASK_IT_WAIT_EXTRA)
#define PCXHR_IT_DOWNLOAD_DSP (0x0000000C | \
- PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)
+ PCXHR_MASK_IT_MANAGE_HF5 | \
+ PCXHR_MASK_IT_WAIT)
#define PCXHR_IT_DEBUG (0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)
#define PCXHR_IT_RESET_SEMAPHORE (0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)
#define PCXHR_IT_MESSAGE (0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)
#define PCXHR_IT_RESET_CHK (0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)
#define PCXHR_IT_UPDATE_RBUFFER (0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)
-static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic)
+static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
+ unsigned int itdsp, int atomic)
{
int err;
unsigned char reg;
@@ -178,17 +184,21 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom
if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
/* clear hf5 bit */
PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
- PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);
+ PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) &
+ ~PCXHR_MBOX0_HF5);
}
if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {
- reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
+ reg = (PCXHR_ICR_HI08_RREQ |
+ PCXHR_ICR_HI08_TREQ |
+ PCXHR_ICR_HI08_HDRQ);
if (itdsp & PCXHR_MASK_IT_HF0)
reg |= PCXHR_ICR_HI08_HF0;
if (itdsp & PCXHR_MASK_IT_HF1)
reg |= PCXHR_ICR_HI08_HF1;
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
}
- reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC);
+ reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) |
+ PCXHR_CVR_HI08_HC);
PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);
if (itdsp & PCXHR_MASK_IT_WAIT) {
if (atomic)
@@ -211,10 +221,14 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom
}
if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
/* wait for hf5 bit */
- err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,
- PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &reg);
+ err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
+ PCXHR_MBOX0_HF5,
+ PCXHR_MBOX0_HF5,
+ PCXHR_TIMEOUT_DSP,
+ &reg);
if (err) {
- snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n");
+ snd_printk(KERN_ERR
+ "pcxhr_send_it_dsp : TIMEOUT HF5\n");
return err;
}
}
@@ -263,7 +277,8 @@ void pcxhr_enable_dsp(struct pcxhr_mgr *mgr)
/*
* load the xilinx image
*/
-int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second)
+int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
+ const struct firmware *xilinx, int second)
{
unsigned int i;
unsigned int chipsc;
@@ -274,7 +289,9 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin
/* test first xilinx */
chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
/* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
- /* this bit will always be 1; no possibility to test presence of first xilinx */
+ /* this bit will always be 1;
+ * no possibility to test presence of first xilinx
+ */
if(second) {
if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
snd_printk(KERN_ERR "error loading first xilinx\n");
@@ -290,7 +307,8 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin
data = *image;
mask = 0x80;
while (mask) {
- chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
+ chipsc &= ~(PCXHR_CHIPSC_DATA_CLK |
+ PCXHR_CHIPSC_DATA_IN);
if (data & mask)
chipsc |= PCXHR_CHIPSC_DATA_IN;
PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
@@ -330,15 +348,20 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
data = dsp->data + i;
if (i == 0) {
/* test data header consistency */
- len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]);
- if (len && dsp->size != (len + 2) * 3)
+ len = (unsigned int)((data[0]<<16) +
+ (data[1]<<8) +
+ data[2]);
+ if (len && (dsp->size != (len + 2) * 3))
return -EINVAL;
}
/* wait DSP ready for new transfer */
- err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
- PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy);
+ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+ PCXHR_ISR_HI08_TRDY,
+ PCXHR_ISR_HI08_TRDY,
+ PCXHR_TIMEOUT_DSP, &dummy);
if (err) {
- snd_printk(KERN_ERR "dsp loading error at position %d\n", i);
+ snd_printk(KERN_ERR
+ "dsp loading error at position %d\n", i);
return err;
}
/* send host data */
@@ -357,7 +380,8 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
/*
* load the eeprom image
*/
-int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom)
+int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
+ const struct firmware *eeprom)
{
int err;
unsigned char reg;
@@ -365,7 +389,9 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eepro
/* init value of the ICR register */
reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {
- /* no need to load the eeprom binary, but init the HI08 interface */
+ /* no need to load the eeprom binary,
+ * but init the HI08 interface
+ */
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);
msleep(PCXHR_WAIT_DEFAULT);
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
@@ -429,8 +455,10 @@ int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp)
if (err)
return err;
/* wait for chk bit */
- return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
- PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy);
+ return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+ PCXHR_ISR_HI08_CHK,
+ PCXHR_ISR_HI08_CHK,
+ PCXHR_TIMEOUT_DSP, &dummy);
}
@@ -443,8 +471,8 @@ struct pcxhr_cmd_info {
/* RMH status type */
enum {
RMH_SSIZE_FIXED = 0, /* status size fix (st_length = 0..x) */
- RMH_SSIZE_ARG = 1, /* status size given in the LSB byte (used with st_length = 1) */
- RMH_SSIZE_MASK = 2, /* status size given in bitmask (used with st_length = 1) */
+ RMH_SSIZE_ARG = 1, /* status size given in the LSB byte */
+ RMH_SSIZE_MASK = 2, /* status size given in bitmask */
};
/*
@@ -474,7 +502,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
[CMD_UPDATE_R_BUFFERS] = { 0x840000, 0, RMH_SSIZE_FIXED },
[CMD_FORMAT_STREAM_OUT] = { 0x860000, 0, RMH_SSIZE_FIXED },
[CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED },
-[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, /* stat_len = nb_streams * 2 */
+[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED },
[CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED },
};
@@ -524,10 +552,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
for (i = 0; i < rmh->stat_len; i++) {
/* wait for receiver full */
- err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF,
- PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, &reg);
+ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+ PCXHR_ISR_HI08_RXDF,
+ PCXHR_ISR_HI08_RXDF,
+ PCXHR_TIMEOUT_DSP, &reg);
if (err) {
- snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
+ snd_printk(KERN_ERR "ERROR RMH stat: "
+ "ISR:RXDF=1 (ISR = %x; i=%d )\n",
reg, i);
return err;
}
@@ -537,10 +568,10 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
/* need to update rmh->stat_len on the fly ?? */
- if (i==0) {
+ if (!i) {
if (rmh->dsp_stat != RMH_SSIZE_FIXED) {
if (rmh->dsp_stat == RMH_SSIZE_ARG) {
- rmh->stat_len = (u16)(data & 0x0000ff) + 1;
+ rmh->stat_len = (data & 0x0000ff) + 1;
data &= 0xffff00;
} else {
/* rmh->dsp_stat == RMH_SSIZE_MASK */
@@ -562,7 +593,8 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
rmh->stat[i] = data;
}
if (rmh->stat_len > max_stat_len) {
- snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len);
+ snd_printdd("PCXHR : rmh->stat_len=%x too big\n",
+ rmh->stat_len);
rmh->stat_len = max_stat_len;
}
return 0;
@@ -605,7 +637,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
data &= 0xff7fff; /* MASK_1_WORD_COMMAND */
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (rmh->cmd_idx < CMD_LAST_INDEX)
- snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]);
+ snd_printdd("MSG cmd[0]=%x (%s)\n",
+ data, cmd_names[rmh->cmd_idx]);
#endif
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
@@ -619,8 +652,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
if (rmh->cmd_len > 1) {
/* send length */
data = rmh->cmd_len - 1;
- err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
- PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &reg);
+ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+ PCXHR_ISR_HI08_TRDY,
+ PCXHR_ISR_HI08_TRDY,
+ PCXHR_TIMEOUT_DSP, &reg);
if (err)
return err;
PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
@@ -653,8 +688,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
/* test status ISR */
if (reg & PCXHR_ISR_HI08_ERR) {
/* ERROR, wait for receiver full */
- err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF,
- PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, &reg);
+ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+ PCXHR_ISR_HI08_RXDF,
+ PCXHR_ISR_HI08_RXDF,
+ PCXHR_TIMEOUT_DSP, &reg);
if (err) {
snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
return err;
@@ -663,7 +700,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
- snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data);
+ snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n",
+ rmh->cmd_idx, data);
err = -EINVAL;
} else {
/* read the response data */
@@ -732,8 +770,9 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
{
int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2);
- /* least segnificant 12 bits are the pipe states for the playback audios */
- /* next 12 bits are the pipe states for the capture audios
+ /* least segnificant 12 bits are the pipe states
+ * for the playback audios
+ * next 12 bits are the pipe states for the capture audios
* (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
*/
start_mask &= 0xffffff;
@@ -744,7 +783,8 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
#define PCXHR_PIPE_STATE_CAPTURE_OFFSET 12
#define MAX_WAIT_FOR_DSP 20
-static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry)
+static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
+ int audio_mask, int *retry)
{
struct pcxhr_rmh rmh;
int err;
@@ -760,17 +800,20 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *
} else {
/* can start capture pipe */
pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
- PCXHR_PIPE_STATE_CAPTURE_OFFSET,
- 0, 0);
+ PCXHR_PIPE_STATE_CAPTURE_OFFSET,
+ 0, 0);
}
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
snd_printk(KERN_ERR
- "error pipe start (CMD_CAN_START_PIPE) err=%x!\n",
+ "error pipe start "
+ "(CMD_CAN_START_PIPE) err=%x!\n",
err);
return err;
}
- /* if the pipe couldn't be prepaired for start, retry it later */
+ /* if the pipe couldn't be prepaired for start,
+ * retry it later
+ */
if (rmh.stat[0] == 0)
*retry |= (1<<audio);
}
@@ -795,14 +838,14 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
} else {
/* stop capture pipe */
pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
- PCXHR_PIPE_STATE_CAPTURE_OFFSET,
- 0, 0);
+ PCXHR_PIPE_STATE_CAPTURE_OFFSET,
+ 0, 0);
}
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
snd_printk(KERN_ERR
- "error pipe stop (CMD_STOP_PIPE) err=%x!\n",
- err);
+ "error pipe stop "
+ "(CMD_STOP_PIPE) err=%x!\n", err);
return err;
}
}
@@ -822,15 +865,16 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
if (audio_mask & 1) {
pcxhr_init_rmh(&rmh, CMD_CONF_PIPE);
if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET)
- pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0, 1 << audio);
+ pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0,
+ 1 << audio);
else
pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0,
1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
snd_printk(KERN_ERR
- "error pipe start (CMD_CONF_PIPE) err=%x!\n",
- err);
+ "error pipe start "
+ "(CMD_CONF_PIPE) err=%x!\n", err);
return err;
}
}
@@ -841,7 +885,9 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
- snd_printk(KERN_ERR "error pipe start (CMD_SEND_IRQA) err=%x!\n", err );
+ snd_printk(KERN_ERR
+ "error pipe start (CMD_SEND_IRQA) err=%x!\n",
+ err);
return err;
}
return 0;
@@ -849,7 +895,8 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
-int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_mask, int start)
+int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
+ int capture_mask, int start)
{
int state, i, err;
int audio_mask;
@@ -858,21 +905,23 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m
struct timeval my_tv1, my_tv2;
do_gettimeofday(&my_tv1);
#endif
- audio_mask = (playback_mask | (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
+ audio_mask = (playback_mask |
+ (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
/* current pipe state (playback + record) */
state = pcxhr_pipes_running(mgr);
snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n",
start ? "START" : "STOP", audio_mask, state);
if (start) {
- audio_mask &= ~state; /* start only pipes that are not yet started */
+ /* start only pipes that are not yet started */
+ audio_mask &= ~state;
state = audio_mask;
for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
err = pcxhr_prepair_pipe_start(mgr, state, &state);
if (err)
return err;
if (state == 0)
- break; /* success, all pipes prepaired for start */
- mdelay(1); /* otherwise wait 1 millisecond and retry */
+ break; /* success, all pipes prepaired */
+ mdelay(1); /* wait 1 millisecond and retry */
}
} else {
audio_mask &= state; /* stop only pipes that are started */
@@ -891,7 +940,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m
if ((state & audio_mask) == (start ? audio_mask : 0))
break;
if (++i >= MAX_WAIT_FOR_DSP * 100) {
- snd_printk(KERN_ERR "error pipe start/stop (ED_NO_RESPONSE_AT_IRQA)\n");
+ snd_printk(KERN_ERR "error pipe start/stop\n");
return -EBUSY;
}
udelay(10); /* wait 10 microseconds */
@@ -918,7 +967,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
spin_lock_irqsave(&mgr->msg_lock, flags);
if ((mgr->io_num_reg_cont & mask) == value) {
- snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value);
+ snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n",
+ mask, value);
if (changed)
*changed = 0;
spin_unlock_irqrestore(&mgr->msg_lock, flags);
@@ -971,7 +1021,8 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
err = ((err >> 12) & 0xfff);
if (!err)
return 0;
- snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src],
+ snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
+ err_src_name[err_src],
is_capture ? "Record" : "Play", pipe, err);
if (err == 0xe01)
mgr->async_err_stream_xrun++;
@@ -996,6 +1047,13 @@ void pcxhr_msg_tasklet(unsigned long arg)
snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n");
if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n");
+ if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
+ /* clear events FREQ_CHANGE and TIME_CODE */
+ pcxhr_init_rmh(prmh, CMD_TEST_IT);
+ err = pcxhr_send_msg(mgr, prmh);
+ snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n",
+ err, prmh->stat[0]);
+ }
if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n");
@@ -1005,18 +1063,22 @@ void pcxhr_msg_tasklet(unsigned long arg)
prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
err = pcxhr_send_msg(mgr, prmh);
if (err)
- snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", err);
+ snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n",
+ err);
i = 1;
while (i < prmh->stat_len) {
- int nb_audio = (prmh->stat[i] >> FIELD_SIZE) & MASK_FIRST_FIELD;
- int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD;
+ int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) &
+ MASK_FIRST_FIELD);
+ int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) &
+ MASK_FIRST_FIELD);
int pipe = prmh->stat[i] & MASK_FIRST_FIELD;
int is_capture = prmh->stat[i] & 0x400000;
u32 err2;
if (prmh->stat[i] & 0x800000) { /* if BIT_END */
snd_printdd("TASKLET : End%sPipe %d\n",
- is_capture ? "Record" : "Play", pipe);
+ is_capture ? "Record" : "Play",
+ pipe);
}
i++;
err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
@@ -1062,7 +1124,7 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT);
pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
stream->pipe->first_audio, 0, stream_mask);
- /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */
+ /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */
err = pcxhr_send_msg(mgr, &rmh);
if (err)
@@ -1072,18 +1134,21 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
hw_sample_count += (u_int64_t)rmh.stat[1];
snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n",
- stream->pipe->is_capture ? 'C':'P', stream->substream->number,
+ stream->pipe->is_capture ? 'C' : 'P',
+ stream->substream->number,
(long unsigned int)hw_sample_count,
(long unsigned int)(stream->timer_abs_periods +
- stream->timer_period_frag + PCXHR_GRANULARITY));
-
+ stream->timer_period_frag +
+ mgr->granularity));
return hw_sample_count;
}
static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
- struct pcxhr_stream *stream, int samples_to_add)
+ struct pcxhr_stream *stream,
+ int samples_to_add)
{
- if (stream->substream && (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
+ if (stream->substream &&
+ (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
u_int64_t new_sample_count;
int elapsed = 0;
int hardware_read = 0;
@@ -1092,20 +1157,22 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
if (samples_to_add < 0) {
stream->timer_is_synced = 0;
/* add default if no hardware_read possible */
- samples_to_add = PCXHR_GRANULARITY;
+ samples_to_add = mgr->granularity;
}
if (!stream->timer_is_synced) {
- if (stream->timer_abs_periods != 0 ||
- stream->timer_period_frag + PCXHR_GRANULARITY >=
- runtime->period_size) {
- new_sample_count = pcxhr_stream_read_position(mgr, stream);
+ if ((stream->timer_abs_periods != 0) ||
+ ((stream->timer_period_frag + samples_to_add) >=
+ runtime->period_size)) {
+ new_sample_count =
+ pcxhr_stream_read_position(mgr, stream);
hardware_read = 1;
- if (new_sample_count >= PCXHR_GRANULARITY_MIN) {
- /* sub security offset because of jitter and
- * finer granularity of dsp time (MBOX4)
+ if (new_sample_count >= mgr->granularity) {
+ /* sub security offset because of
+ * jitter and finer granularity of
+ * dsp time (MBOX4)
*/
- new_sample_count -= PCXHR_GRANULARITY_MIN;
+ new_sample_count -= mgr->granularity;
stream->timer_is_synced = 1;
}
}
@@ -1128,12 +1195,15 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
stream->timer_buf_periods = 0;
stream->timer_abs_periods = new_elapse_pos;
}
- if (new_sample_count >= stream->timer_abs_periods)
- stream->timer_period_frag = (u_int32_t)(new_sample_count -
- stream->timer_abs_periods);
- else
- snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n",
+ if (new_sample_count >= stream->timer_abs_periods) {
+ stream->timer_period_frag =
+ (u_int32_t)(new_sample_count -
+ stream->timer_abs_periods);
+ } else {
+ snd_printk(KERN_ERR
+ "ERROR new_sample_count too small ??? %ld\n",
(long unsigned int)new_sample_count);
+ }
if (elapsed) {
spin_unlock(&mgr->lock);
@@ -1143,7 +1213,6 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
}
}
-
irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
{
struct pcxhr_mgr *mgr = dev_id;
@@ -1156,7 +1225,8 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
spin_unlock(&mgr->lock);
- return IRQ_NONE; /* this device did not cause the interrupt */
+ /* this device did not cause the interrupt */
+ return IRQ_NONE;
}
/* clear interrupt */
@@ -1167,10 +1237,12 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
if (reg & PCXHR_IRQ_TIMER) {
int timer_toggle = reg & PCXHR_IRQ_TIMER;
/* is a 24 bit counter */
- int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
+ int dsp_time_new =
+ PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
int dsp_time_diff = dsp_time_new - mgr->dsp_time_last;
- if (dsp_time_diff < 0 && mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID) {
+ if ((dsp_time_diff < 0) &&
+ (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
snd_printdd("ERROR DSP TIME old(%d) new(%d) -> "
"resynchronize all streams\n",
mgr->dsp_time_last, dsp_time_new);
@@ -1178,40 +1250,49 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (dsp_time_diff == 0)
- snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new);
- else if (dsp_time_diff >= (2*PCXHR_GRANULARITY))
+ snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n",
+ dsp_time_new);
+ else if (dsp_time_diff >= (2*mgr->granularity))
snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
- mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last);
+ mgr->dsp_time_last,
+ dsp_time_new - mgr->dsp_time_last);
+ else if (dsp_time_diff % mgr->granularity)
+ snd_printdd("ERROR DSP TIME increased by %d\n",
+ dsp_time_diff);
#endif
mgr->dsp_time_last = dsp_time_new;
- if (timer_toggle == mgr->timer_toggle)
+ if (timer_toggle == mgr->timer_toggle) {
snd_printdd("ERROR TIMER TOGGLE\n");
+ mgr->dsp_time_err++;
+ }
mgr->timer_toggle = timer_toggle;
reg &= ~PCXHR_IRQ_TIMER;
for (i = 0; i < mgr->num_cards; i++) {
chip = mgr->chip[i];
for (j = 0; j < chip->nb_streams_capt; j++)
- pcxhr_update_timer_pos(mgr, &chip->capture_stream[j],
- dsp_time_diff);
+ pcxhr_update_timer_pos(mgr,
+ &chip->capture_stream[j],
+ dsp_time_diff);
}
for (i = 0; i < mgr->num_cards; i++) {
chip = mgr->chip[i];
for (j = 0; j < chip->nb_streams_play; j++)
- pcxhr_update_timer_pos(mgr, &chip->playback_stream[j],
- dsp_time_diff);
+ pcxhr_update_timer_pos(mgr,
+ &chip->playback_stream[j],
+ dsp_time_diff);
}
}
/* other irq's handled in the tasklet */
if (reg & PCXHR_IRQ_MASK) {
-
- /* as we didn't request any notifications, some kind of xrun error
- * will probably occured
- */
- /* better resynchronize all streams next interrupt : */
- mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
-
+ if (reg & PCXHR_IRQ_ASYNC) {
+ /* as we didn't request any async notifications,
+ * some kind of xrun error will probably occured
+ */
+ /* better resynchronize all streams next interrupt : */
+ mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+ }
mgr->src_it_dsp = reg;
tasklet_hi_schedule(&mgr->msg_taskq);
}
diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
index d9a4ab609875..bbbd66d13a64 100644
--- a/sound/pci/pcxhr/pcxhr_core.h
+++ b/sound/pci/pcxhr/pcxhr_core.h
@@ -65,7 +65,7 @@ enum {
CMD_RESYNC_AUDIO_INPUTS, /* cmd_len = 1 stat_len = 0 */
CMD_GET_DSP_RESOURCES, /* cmd_len = 1 stat_len = 4 */
CMD_SET_TIMER_INTERRUPT, /* cmd_len = 1 stat_len = 0 */
- CMD_RES_PIPE, /* cmd_len = 2 stat_len = 0 */
+ CMD_RES_PIPE, /* cmd_len >=2 stat_len = 0 */
CMD_FREE_PIPE, /* cmd_len = 1 stat_len = 0 */
CMD_CONF_PIPE, /* cmd_len = 2 stat_len = 0 */
CMD_STOP_PIPE, /* cmd_len = 1 stat_len = 0 */
@@ -96,6 +96,8 @@ void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd);
void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh* rmh, int capture, unsigned int param1,
unsigned int param2, unsigned int param3);
+#define DSP_EXT_CMD_SET(x) (x->dsp_version > 0x012800)
+
/*
send the rmh
*/
@@ -110,6 +112,7 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh);
#define IO_NUM_REG_STATUS 5
#define IO_NUM_REG_CUER 10
#define IO_NUM_UER_CHIP_REG 11
+#define IO_NUM_REG_CONFIG_SRC 12
#define IO_NUM_REG_OUT_ANA_LEVEL 20
#define IO_NUM_REG_IN_ANA_LEVEL 21
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 96640d9c227d..592743a298b0 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -31,6 +31,7 @@
#include "pcxhr_mixer.h"
#include "pcxhr_hwdep.h"
#include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
@@ -40,10 +41,10 @@
#endif
+static int pcxhr_sub_init(struct pcxhr_mgr *mgr);
/*
* get basic information and init pcxhr card
*/
-
static int pcxhr_init_board(struct pcxhr_mgr *mgr)
{
int err;
@@ -68,7 +69,7 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
return -EINVAL;
/* test 8 or 2 phys in */
- if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) !=
+ if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
mgr->capture_chips * 2)
return -EINVAL;
/* test max nb substream per board */
@@ -77,20 +78,34 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
/* test max nb substream per pipe */
if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
return -EINVAL;
+ snd_printdd("supported formats : playback=%x capture=%x\n",
+ rmh.stat[2], rmh.stat[3]);
pcxhr_init_rmh(&rmh, CMD_VERSION);
/* firmware num for DSP */
rmh.cmd[0] |= mgr->firmware_num;
/* transfer granularity in samples (should be multiple of 48) */
- rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY;
+ rmh.cmd[1] = (1<<23) + mgr->granularity;
rmh.cmd_len = 2;
err = pcxhr_send_msg(mgr, &rmh);
if (err)
return err;
- snd_printdd("PCXHR DSP version is %d.%d.%d\n",
- (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
+ snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
+ (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
mgr->dsp_version = rmh.stat[0];
+ if (mgr->is_hr_stereo)
+ err = hr222_sub_init(mgr);
+ else
+ err = pcxhr_sub_init(mgr);
+ return err;
+}
+
+static int pcxhr_sub_init(struct pcxhr_mgr *mgr)
+{
+ int err;
+ struct pcxhr_rmh rmh;
+
/* get options */
pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
rmh.cmd[0] |= IO_NUM_REG_STATUS;
@@ -100,20 +115,22 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
if (err)
return err;
- if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD)
- mgr->board_has_analog = 1; /* analog addon board available */
- else
- /* analog addon board not available -> no support for instance */
- return -EINVAL;
+ if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) ==
+ REG_STATUS_OPT_ANALOG_BOARD)
+ mgr->board_has_analog = 1; /* analog addon board found */
/* unmute inputs */
err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
REG_CONT_UNMUTE_INPUTS, NULL);
if (err)
return err;
- /* unmute outputs */
- pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */
+ /* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */
+ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+ if (DSP_EXT_CMD_SET(mgr)) {
+ rmh.cmd[1] = 1; /* unmute digital plugs */
+ rmh.cmd_len = 2;
+ }
err = pcxhr_send_msg(mgr, &rmh);
return err;
}
@@ -124,19 +141,25 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr)
if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
/* mute outputs */
+ if (!mgr->is_hr_stereo) {
/* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
pcxhr_send_msg(mgr, &rmh);
/* mute inputs */
- pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL);
+ pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
+ 0, NULL);
+ }
+ /* stereo cards mute with reset of dsp */
}
/* reset pcxhr dsp */
- if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
+ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
pcxhr_reset_dsp(mgr);
/* reset second xilinx */
- if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX))
+ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) {
pcxhr_reset_xilinx_com(mgr);
+ mgr->dsp_loaded = 1;
+ }
return;
}
@@ -144,8 +167,9 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr)
/*
* allocate a playback/capture pipe (pcmp0/pcmc0)
*/
-static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe,
- int is_capture, int pin)
+static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
+ struct pcxhr_pipe *pipe,
+ int is_capture, int pin)
{
int stream_count, audio_count;
int err;
@@ -161,15 +185,23 @@ static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pi
stream_count = PCXHR_PLAYBACK_STREAMS;
audio_count = 2; /* always stereo */
}
- snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p');
+ snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n",
+ pin, is_capture ? 'c' : 'p');
pipe->is_capture = is_capture;
pipe->first_audio = pin;
/* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
- pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count);
+ pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin,
+ audio_count, stream_count);
+ rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */
+ if (DSP_EXT_CMD_SET(mgr)) {
+ /* add channel mask to command */
+ rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03;
+ }
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err );
+ snd_printk(KERN_ERR "error pipe allocation "
+ "(CMD_RES_PIPE) err=%x!\n", err);
return err;
}
pipe->status = PCXHR_PIPE_DEFINED;
@@ -199,10 +231,12 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
snd_printk(KERN_ERR "error stopping pipe!\n");
/* release the pipe */
pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
- pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0);
+ pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
+ 0, 0);
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0)
- snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err);
+ snd_printk(KERN_ERR "error pipe release "
+ "(CMD_FREE_PIPE) err(%x)\n", err);
pipe->status = PCXHR_PIPE_UNDEFINED;
return err;
}
@@ -248,15 +282,16 @@ static int pcxhr_start_pipes(struct pcxhr_mgr *mgr)
for (i = 0; i < mgr->num_cards; i++) {
chip = mgr->chip[i];
if (chip->nb_streams_play)
- playback_mask |= (1 << chip->playback_pipe.first_audio);
+ playback_mask |= 1 << chip->playback_pipe.first_audio;
for (j = 0; j < chip->nb_streams_capt; j++)
- capture_mask |= (1 << chip->capture_pipe[j].first_audio);
+ capture_mask |= 1 << chip->capture_pipe[j].first_audio;
}
return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
}
-static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp)
+static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
+ const struct firmware *dsp)
{
int err, card_index;
@@ -330,22 +365,33 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmwar
int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
{
- static char *fw_files[5] = {
- "xi_1_882.dat",
- "xc_1_882.dat",
- "e321_512.e56",
- "b321_512.b56",
- "d321_512.d56"
+ static char *fw_files[][5] = {
+ [0] = { "xlxint.dat", "xlxc882hr.dat",
+ "dspe882.e56", "dspb882hr.b56", "dspd882.d56" },
+ [1] = { "xlxint.dat", "xlxc882e.dat",
+ "dspe882.e56", "dspb882e.b56", "dspd882.d56" },
+ [2] = { "xlxint.dat", "xlxc1222hr.dat",
+ "dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" },
+ [3] = { "xlxint.dat", "xlxc1222e.dat",
+ "dspe882.e56", "dspb1222e.b56", "dspd1222.d56" },
+ [4] = { NULL, "xlxc222.dat",
+ "dspe924.e56", "dspb924.b56", "dspd222.d56" },
+ [5] = { NULL, "xlxc924.dat",
+ "dspe924.e56", "dspb924.b56", "dspd222.d56" },
};
char path[32];
const struct firmware *fw_entry;
int i, err;
+ int fw_set = mgr->fw_file_set;
- for (i = 0; i < ARRAY_SIZE(fw_files); i++) {
- sprintf(path, "pcxhr/%s", fw_files[i]);
+ for (i = 0; i < 5; i++) {
+ if (!fw_files[fw_set][i])
+ continue;
+ sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
- snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path);
+ snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n",
+ path);
return -ENOENT;
}
/* fake hwdep dsp record */
@@ -358,11 +404,26 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
return 0;
}
-MODULE_FIRMWARE("pcxhr/xi_1_882.dat");
-MODULE_FIRMWARE("pcxhr/xc_1_882.dat");
-MODULE_FIRMWARE("pcxhr/e321_512.e56");
-MODULE_FIRMWARE("pcxhr/b321_512.b56");
-MODULE_FIRMWARE("pcxhr/d321_512.d56");
+MODULE_FIRMWARE("pcxhr/xlxint.dat");
+MODULE_FIRMWARE("pcxhr/xlxc882hr.dat");
+MODULE_FIRMWARE("pcxhr/xlxc882e.dat");
+MODULE_FIRMWARE("pcxhr/dspe882.e56");
+MODULE_FIRMWARE("pcxhr/dspb882hr.b56");
+MODULE_FIRMWARE("pcxhr/dspb882e.b56");
+MODULE_FIRMWARE("pcxhr/dspd882.d56");
+
+MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat");
+MODULE_FIRMWARE("pcxhr/xlxc1222e.dat");
+MODULE_FIRMWARE("pcxhr/dspb1222hr.b56");
+MODULE_FIRMWARE("pcxhr/dspb1222e.b56");
+MODULE_FIRMWARE("pcxhr/dspd1222.d56");
+
+MODULE_FIRMWARE("pcxhr/xlxc222.dat");
+MODULE_FIRMWARE("pcxhr/xlxc924.dat");
+MODULE_FIRMWARE("pcxhr/dspe924.e56");
+MODULE_FIRMWARE("pcxhr/dspb924.b56");
+MODULE_FIRMWARE("pcxhr/dspd222.d56");
+
#else /* old style firmware loading */
@@ -373,7 +434,8 @@ MODULE_FIRMWARE("pcxhr/d321_512.d56");
static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw,
struct snd_hwdep_dsp_status *info)
{
- strcpy(info->id, "pcxhr");
+ struct pcxhr_mgr *mgr = hw->private_data;
+ sprintf(info->id, "pcxhr%d", mgr->fw_file_set);
info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX;
if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))
@@ -393,8 +455,8 @@ static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw,
fw.size = dsp->length;
fw.data = vmalloc(fw.size);
if (! fw.data) {
- snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image (%lu bytes)\n",
- (unsigned long)fw.size);
+ snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image "
+ "(%lu bytes)\n", (unsigned long)fw.size);
return -ENOMEM;
}
if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) {
@@ -424,8 +486,11 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
int err;
struct snd_hwdep *hw;
- /* only create hwdep interface for first cardX (see "index" module parameter)*/
- if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0)
+ /* only create hwdep interface for first cardX
+ * (see "index" module parameter)
+ */
+ err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw);
+ if (err < 0)
return err;
hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
@@ -435,10 +500,13 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
hw->exclusive = 1;
+ /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */
+ hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0;
mgr->dsp_loaded = 0;
sprintf(hw->name, PCXHR_HWDEP_ID);
- if ((err = snd_card_register(mgr->chip[0]->card)) < 0)
+ err = snd_card_register(mgr->chip[0]->card);
+ if (err < 0)
return err;
return 0;
}
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c
new file mode 100644
index 000000000000..ff019126b672
--- /dev/null
+++ b/sound/pci/pcxhr/pcxhr_mix22.c
@@ -0,0 +1,820 @@
+/*
+ * Driver for Digigram pcxhr compatible soundcards
+ *
+ * mixer interface for stereo cards
+ *
+ * Copyright (c) 2004 by Digigram <alsa@digigram.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/asoundef.h>
+#include "pcxhr.h"
+#include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
+
+
+/* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */
+#define PCXHR_DSP_RESET 0x20
+#define PCXHR_XLX_CFG 0x24
+#define PCXHR_XLX_RUER 0x28
+#define PCXHR_XLX_DATA 0x2C
+#define PCXHR_XLX_STATUS 0x30
+#define PCXHR_XLX_LOFREQ 0x34
+#define PCXHR_XLX_HIFREQ 0x38
+#define PCXHR_XLX_CSUER 0x3C
+#define PCXHR_XLX_SELMIC 0x40
+
+#define PCXHR_DSP 2
+
+/* byte access only ! */
+#define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x))
+#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x))
+
+
+/* values for PCHR_DSP_RESET register */
+#define PCXHR_DSP_RESET_DSP 0x01
+#define PCXHR_DSP_RESET_MUTE 0x02
+#define PCXHR_DSP_RESET_CODEC 0x08
+
+/* values for PCHR_XLX_CFG register */
+#define PCXHR_CFG_SYNCDSP_MASK 0x80
+#define PCXHR_CFG_DEPENDENCY_MASK 0x60
+#define PCXHR_CFG_INDEPENDANT_SEL 0x00
+#define PCXHR_CFG_MASTER_SEL 0x40
+#define PCXHR_CFG_SLAVE_SEL 0x20
+#define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */
+#define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */
+#define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */
+#define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */
+#define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */
+
+/* values for PCHR_XLX_DATA register */
+#define PCXHR_DATA_CODEC 0x80
+#define AKM_POWER_CONTROL_CMD 0xA007
+#define AKM_RESET_ON_CMD 0xA100
+#define AKM_RESET_OFF_CMD 0xA103
+#define AKM_CLOCK_INF_55K_CMD 0xA240
+#define AKM_CLOCK_SUP_55K_CMD 0xA24D
+#define AKM_MUTE_CMD 0xA38D
+#define AKM_UNMUTE_CMD 0xA30D
+#define AKM_LEFT_LEVEL_CMD 0xA600
+#define AKM_RIGHT_LEVEL_CMD 0xA700
+
+/* values for PCHR_XLX_STATUS register - READ */
+#define PCXHR_STAT_SRC_LOCK 0x01
+#define PCXHR_STAT_LEVEL_IN 0x02
+#define PCXHR_STAT_MIC_CAPS 0x10
+/* values for PCHR_XLX_STATUS register - WRITE */
+#define PCXHR_STAT_FREQ_SYNC_MASK 0x01
+#define PCXHR_STAT_FREQ_UER1_MASK 0x02
+#define PCXHR_STAT_FREQ_SAVE_MASK 0x80
+
+/* values for PCHR_XLX_CSUER register */
+#define PCXHR_SUER1_BIT_U_READ_MASK 0x80
+#define PCXHR_SUER1_BIT_C_READ_MASK 0x40
+#define PCXHR_SUER1_DATA_PRESENT_MASK 0x20
+#define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10
+#define PCXHR_SUER_BIT_U_READ_MASK 0x08
+#define PCXHR_SUER_BIT_C_READ_MASK 0x04
+#define PCXHR_SUER_DATA_PRESENT_MASK 0x02
+#define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01
+
+#define PCXHR_SUER_BIT_U_WRITE_MASK 0x02
+#define PCXHR_SUER_BIT_C_WRITE_MASK 0x01
+
+/* values for PCXHR_XLX_SELMIC register - WRITE */
+#define PCXHR_SELMIC_PREAMPLI_OFFSET 2
+#define PCXHR_SELMIC_PREAMPLI_MASK 0x0C
+#define PCXHR_SELMIC_PHANTOM_ALIM 0x80
+
+
+static const unsigned char g_hr222_p_level[] = {
+ 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */
+ 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */
+ 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */
+ 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */
+ 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */
+ 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */
+ 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */
+ 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */
+ 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */
+ 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */
+ 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */
+ 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */
+ 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */
+ 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */
+ 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */
+ 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */
+ 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */
+ 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */
+ 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */
+ 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */
+ 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */
+ 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */
+ 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */
+ 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */
+ 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */
+ 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */
+ 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */
+ 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */
+ 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */
+ 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */
+ 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */
+ 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */
+ 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */
+ 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */
+ 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */
+ 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */
+ 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */
+ 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */
+ 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */
+ 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */
+ 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */
+ 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */
+ 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */
+ 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */
+ 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */
+ 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */
+ 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */
+ 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */
+ 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */
+ 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */
+ 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */
+ 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */
+ 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */
+ 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */
+ 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */
+ 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */
+ 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */
+ 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */
+ 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */
+ 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */
+ 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */
+ 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */
+ 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */
+ 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */
+ 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */
+ 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */
+ 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */
+ 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */
+ 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */
+ 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */
+ 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */
+ 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */
+ 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */
+ 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */
+ 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */
+ 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */
+ 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */
+ 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */
+ 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */
+ 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */
+ 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */
+ 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */
+ 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */
+ 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */
+ 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */
+ 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */
+ 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */
+ 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */
+ 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */
+ 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */
+ 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */
+ 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */
+ 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */
+ 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */
+ 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */
+ 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */
+ 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */
+ 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */
+ 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */
+ 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */
+};
+
+
+static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data)
+{
+ unsigned short mask = 0x8000;
+ /* activate access to codec registers */
+ PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ);
+
+ while (mask) {
+ PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
+ data & mask ? PCXHR_DATA_CODEC : 0);
+ mask >>= 1;
+ }
+ /* termiate access to codec registers */
+ PCXHR_INPB(mgr, PCXHR_XLX_RUER);
+}
+
+
+static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr,
+ int idx, int level)
+{
+ unsigned short cmd;
+ if (idx > 1 ||
+ level < 0 ||
+ level >= ARRAY_SIZE(g_hr222_p_level))
+ return -EINVAL;
+
+ if (idx == 0)
+ cmd = AKM_LEFT_LEVEL_CMD;
+ else
+ cmd = AKM_RIGHT_LEVEL_CMD;
+
+ /* conversion from PmBoardCodedLevel to AKM nonlinear programming */
+ cmd += g_hr222_p_level[level];
+
+ hr222_config_akm(mgr, cmd);
+ return 0;
+}
+
+
+static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr,
+ int level_l, int level_r, int level_mic)
+{
+ /* program all input levels at the same time */
+ unsigned int data;
+ int i;
+
+ if (!mgr->capture_chips)
+ return -EINVAL; /* no PCX22 */
+
+ data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */
+ data |= ((level_mic & 0xff) << 16); /* level on both channels */
+ data |= ((level_r & 0xff) << 8); /* line input right channel */
+ data |= (level_l & 0xff); /* line input left channel */
+
+ PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */
+ /* send 32 bits (4 x 8 bits) */
+ for (i = 0; i < 32; i++, data <<= 1) {
+ PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
+ (data & 0x80000000) ? PCXHR_DATA_CODEC : 0);
+ }
+ PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */
+ return 0;
+}
+
+static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level);
+
+int hr222_sub_init(struct pcxhr_mgr *mgr)
+{
+ unsigned char reg;
+
+ mgr->board_has_analog = 1; /* analog always available */
+ mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK;
+
+ reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
+ if (reg & PCXHR_STAT_MIC_CAPS)
+ mgr->board_has_mic = 1; /* microphone available */
+ snd_printdd("MIC input available = %d\n", mgr->board_has_mic);
+
+ /* reset codec */
+ PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
+ PCXHR_DSP_RESET_DSP);
+ msleep(5);
+ PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
+ PCXHR_DSP_RESET_DSP |
+ PCXHR_DSP_RESET_MUTE |
+ PCXHR_DSP_RESET_CODEC);
+ msleep(5);
+
+ /* config AKM */
+ hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD);
+ hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
+ hr222_config_akm(mgr, AKM_UNMUTE_CMD);
+ hr222_config_akm(mgr, AKM_RESET_OFF_CMD);
+
+ /* init micro boost */
+ hr222_micro_boost(mgr, 0);
+
+ return 0;
+}
+
+
+/* calc PLL register */
+/* TODO : there is a very similar fct in pcxhr.c */
+static int hr222_pll_freq_register(unsigned int freq,
+ unsigned int *pllreg,
+ unsigned int *realfreq)
+{
+ unsigned int reg;
+
+ if (freq < 6900 || freq > 219000)
+ return -EINVAL;
+ reg = (28224000 * 2) / freq;
+ reg = (reg - 1) / 2;
+ if (reg < 0x100)
+ *pllreg = reg + 0xC00;
+ else if (reg < 0x200)
+ *pllreg = reg + 0x800;
+ else if (reg < 0x400)
+ *pllreg = reg & 0x1ff;
+ else if (reg < 0x800) {
+ *pllreg = ((reg >> 1) & 0x1ff) + 0x200;
+ reg &= ~1;
+ } else {
+ *pllreg = ((reg >> 2) & 0x1ff) + 0x400;
+ reg &= ~3;
+ }
+ if (realfreq)
+ *realfreq = (28224000 / (reg + 1));
+ return 0;
+}
+
+int hr222_sub_set_clock(struct pcxhr_mgr *mgr,
+ unsigned int rate,
+ int *changed)
+{
+ unsigned int speed, pllreg = 0;
+ int err;
+ unsigned realfreq = rate;
+
+ switch (mgr->use_clock_type) {
+ case HR22_CLOCK_TYPE_INTERNAL:
+ err = hr222_pll_freq_register(rate, &pllreg, &realfreq);
+ if (err)
+ return err;
+
+ mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK |
+ PCXHR_CFG_CLOCK_UER1_SEL_MASK);
+ break;
+ case HR22_CLOCK_TYPE_AES_SYNC:
+ mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK;
+ mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK;
+ break;
+ case HR22_CLOCK_TYPE_AES_1:
+ if (!mgr->board_has_aes1)
+ return -EINVAL;
+
+ mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK |
+ PCXHR_CFG_CLOCK_UER1_SEL_MASK);
+ break;
+ default:
+ return -EINVAL;
+ }
+ hr222_config_akm(mgr, AKM_MUTE_CMD);
+
+ if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) {
+ PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8);
+ PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff);
+ }
+
+ /* set clock source */
+ PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg);
+
+ /* codec speed modes */
+ speed = rate < 55000 ? 0 : 1;
+ if (mgr->codec_speed != speed) {
+ mgr->codec_speed = speed;
+ if (speed == 0)
+ hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
+ else
+ hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD);
+ }
+
+ mgr->sample_rate_real = realfreq;
+ mgr->cur_clock_type = mgr->use_clock_type;
+
+ if (changed)
+ *changed = 1;
+
+ hr222_config_akm(mgr, AKM_UNMUTE_CMD);
+
+ snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n",
+ rate, realfreq, pllreg);
+ return 0;
+}
+
+int hr222_get_external_clock(struct pcxhr_mgr *mgr,
+ enum pcxhr_clock_type clock_type,
+ int *sample_rate)
+{
+ int rate, calc_rate = 0;
+ unsigned int ticks;
+ unsigned char mask, reg;
+
+ if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) {
+
+ mask = (PCXHR_SUER_CLOCK_PRESENT_MASK |
+ PCXHR_SUER_DATA_PRESENT_MASK);
+ reg = PCXHR_STAT_FREQ_SYNC_MASK;
+
+ } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) {
+
+ mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK |
+ PCXHR_SUER1_DATA_PRESENT_MASK);
+ reg = PCXHR_STAT_FREQ_UER1_MASK;
+
+ } else {
+ snd_printdd("get_external_clock : type %d not supported\n",
+ clock_type);
+ return -EINVAL; /* other clocks not supported */
+ }
+
+ if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) {
+ snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type);
+ *sample_rate = 0;
+ return 0; /* no external clock locked */
+ }
+
+ PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */
+
+ /* save the measured clock frequency */
+ reg |= PCXHR_STAT_FREQ_SAVE_MASK;
+
+ if (mgr->last_reg_stat != reg) {
+ udelay(500); /* wait min 2 cycles of lowest freq (8000) */
+ mgr->last_reg_stat = reg;
+ }
+
+ PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */
+
+ /* get the frequency */
+ ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG);
+ ticks = (ticks & 0x03) << 8;
+ ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET);
+
+ if (ticks != 0)
+ calc_rate = 28224000 / ticks;
+ /* rounding */
+ if (calc_rate > 184200)
+ rate = 192000;
+ else if (calc_rate > 152200)
+ rate = 176400;
+ else if (calc_rate > 112000)
+ rate = 128000;
+ else if (calc_rate > 92100)
+ rate = 96000;
+ else if (calc_rate > 76100)
+ rate = 88200;
+ else if (calc_rate > 56000)
+ rate = 64000;
+ else if (calc_rate > 46050)
+ rate = 48000;
+ else if (calc_rate > 38050)
+ rate = 44100;
+ else if (calc_rate > 28000)
+ rate = 32000;
+ else if (calc_rate > 23025)
+ rate = 24000;
+ else if (calc_rate > 19025)
+ rate = 22050;
+ else if (calc_rate > 14000)
+ rate = 16000;
+ else if (calc_rate > 11512)
+ rate = 12000;
+ else if (calc_rate > 9512)
+ rate = 11025;
+ else if (calc_rate > 7000)
+ rate = 8000;
+ else
+ rate = 0;
+
+ snd_printdd("External clock is at %d Hz (measured %d Hz)\n",
+ rate, calc_rate);
+ *sample_rate = rate;
+ return 0;
+}
+
+
+int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
+ int is_capture, int channel)
+{
+ snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n",
+ is_capture ? "capture" : "playback", channel);
+ if (is_capture) {
+ int level_l, level_r, level_mic;
+ /* we have to update all levels */
+ if (chip->analog_capture_active) {
+ level_l = chip->analog_capture_volume[0];
+ level_r = chip->analog_capture_volume[1];
+ } else {
+ level_l = HR222_LINE_CAPTURE_LEVEL_MIN;
+ level_r = HR222_LINE_CAPTURE_LEVEL_MIN;
+ }
+ if (chip->mic_active)
+ level_mic = chip->mic_volume;
+ else
+ level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN;
+ return hr222_set_hw_capture_level(chip->mgr,
+ level_l, level_r, level_mic);
+ } else {
+ int vol;
+ if (chip->analog_playback_active[channel])
+ vol = chip->analog_playback_volume[channel];
+ else
+ vol = HR222_LINE_PLAYBACK_LEVEL_MIN;
+ return hr222_set_hw_playback_level(chip->mgr, channel, vol);
+ }
+}
+
+
+/*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/
+#define SOURCE_LINE 0
+#define SOURCE_DIGITAL 1
+#define SOURCE_DIGISRC 2
+#define SOURCE_MIC 3
+#define SOURCE_LINEMIC 4
+
+int hr222_set_audio_source(struct snd_pcxhr *chip)
+{
+ int digital = 0;
+ /* default analog source */
+ chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK |
+ PCXHR_CFG_DATAIN_SEL_MASK |
+ PCXHR_CFG_DATA_UER1_SEL_MASK);
+
+ if (chip->audio_capture_source == SOURCE_DIGISRC) {
+ chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK;
+ digital = 1;
+ } else {
+ if (chip->audio_capture_source == SOURCE_DIGITAL)
+ digital = 1;
+ }
+ if (digital) {
+ chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK;
+ if (chip->mgr->board_has_aes1) {
+ /* get data from the AES1 plug */
+ chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK;
+ }
+ /* chip->mic_active = 0; */
+ /* chip->analog_capture_active = 0; */
+ } else {
+ int update_lvl = 0;
+ chip->analog_capture_active = 0;
+ chip->mic_active = 0;
+ if (chip->audio_capture_source == SOURCE_LINE ||
+ chip->audio_capture_source == SOURCE_LINEMIC) {
+ if (chip->analog_capture_active == 0)
+ update_lvl = 1;
+ chip->analog_capture_active = 1;
+ }
+ if (chip->audio_capture_source == SOURCE_MIC ||
+ chip->audio_capture_source == SOURCE_LINEMIC) {
+ if (chip->mic_active == 0)
+ update_lvl = 1;
+ chip->mic_active = 1;
+ }
+ if (update_lvl) {
+ /* capture: update all 3 mutes/unmutes with one call */
+ hr222_update_analog_audio_level(chip, 1, 0);
+ }
+ }
+ /* set the source infos (max 3 bits modified) */
+ PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg);
+ return 0;
+}
+
+
+int hr222_iec958_capture_byte(struct snd_pcxhr *chip,
+ int aes_idx, unsigned char *aes_bits)
+{
+ unsigned char idx = (unsigned char)(aes_idx * 8);
+ unsigned char temp = 0;
+ unsigned char mask = chip->mgr->board_has_aes1 ?
+ PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK;
+ int i;
+ for (i = 0; i < 8; i++) {
+ PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */
+ temp <<= 1;
+ if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask)
+ temp |= 1;
+ }
+ snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+ chip->chip_idx, aes_idx, temp);
+ *aes_bits = temp;
+ return 0;
+}
+
+
+int hr222_iec958_update_byte(struct snd_pcxhr *chip,
+ int aes_idx, unsigned char aes_bits)
+{
+ int i;
+ unsigned char new_bits = aes_bits;
+ unsigned char old_bits = chip->aes_bits[aes_idx];
+ unsigned char idx = (unsigned char)(aes_idx * 8);
+ for (i = 0; i < 8; i++) {
+ if ((old_bits & 0x01) != (new_bits & 0x01)) {
+ /* idx < 192 */
+ PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx);
+ /* write C and U bit */
+ PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ?
+ PCXHR_SUER_BIT_C_WRITE_MASK : 0);
+ }
+ idx++;
+ old_bits >>= 1;
+ new_bits >>= 1;
+ }
+ chip->aes_bits[aes_idx] = aes_bits;
+ return 0;
+}
+
+static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level)
+{
+ unsigned char boost_mask;
+ boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET);
+ if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK))
+ return; /* only values form 0 to 3 accepted */
+
+ mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK;
+ mgr->xlx_selmic |= boost_mask;
+
+ PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
+
+ snd_printdd("hr222_micro_boost : set %x\n", boost_mask);
+}
+
+static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
+{
+ if (power)
+ mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM;
+ else
+ mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM;
+
+ PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
+
+ snd_printdd("hr222_phantom_power : set %d\n", power);
+}
+
+
+/* mic level */
+static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650);
+
+static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */
+ /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */
+ uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */
+ return 0;
+}
+
+static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ mutex_lock(&chip->mgr->mixer_mutex);
+ ucontrol->value.integer.value[0] = chip->mic_volume;
+ mutex_unlock(&chip->mgr->mixer_mutex);
+ return 0;
+}
+
+static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ mutex_lock(&chip->mgr->mixer_mutex);
+ if (chip->mic_volume != ucontrol->value.integer.value[0]) {
+ changed = 1;
+ chip->mic_volume = ucontrol->value.integer.value[0];
+ hr222_update_analog_audio_level(chip, 1, 0);
+ }
+ mutex_unlock(&chip->mgr->mixer_mutex);
+ return changed;
+}
+
+static struct snd_kcontrol_new hr222_control_mic_level = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Mic Capture Volume",
+ .info = hr222_mic_vol_info,
+ .get = hr222_mic_vol_get,
+ .put = hr222_mic_vol_put,
+ .tlv = { .p = db_scale_mic_hr222 },
+};
+
+
+/* mic boost level */
+static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400);
+
+static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0; /* 0 dB */
+ uinfo->value.integer.max = 3; /* 54 dB */
+ return 0;
+}
+
+static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ mutex_lock(&chip->mgr->mixer_mutex);
+ ucontrol->value.integer.value[0] = chip->mic_boost;
+ mutex_unlock(&chip->mgr->mixer_mutex);
+ return 0;
+}
+
+static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ mutex_lock(&chip->mgr->mixer_mutex);
+ if (chip->mic_boost != ucontrol->value.integer.value[0]) {
+ changed = 1;
+ chip->mic_boost = ucontrol->value.integer.value[0];
+ hr222_micro_boost(chip->mgr, chip->mic_boost);
+ }
+ mutex_unlock(&chip->mgr->mixer_mutex);
+ return changed;
+}
+
+static struct snd_kcontrol_new hr222_control_mic_boost = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "MicBoost Capture Volume",
+ .info = hr222_mic_boost_info,
+ .get = hr222_mic_boost_get,
+ .put = hr222_mic_boost_put,
+ .tlv = { .p = db_scale_micboost_hr222 },
+};
+
+
+/******************* Phantom power switch *******************/
+#define hr222_phantom_power_info snd_ctl_boolean_mono_info
+
+static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ mutex_lock(&chip->mgr->mixer_mutex);
+ ucontrol->value.integer.value[0] = chip->phantom_power;
+ mutex_unlock(&chip->mgr->mixer_mutex);
+ return 0;
+}
+
+static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ int power, changed = 0;
+
+ mutex_lock(&chip->mgr->mixer_mutex);
+ power = !!ucontrol->value.integer.value[0];
+ if (chip->phantom_power != power) {
+ hr222_phantom_power(chip->mgr, power);
+ chip->phantom_power = power;
+ changed = 1;
+ }
+ mutex_unlock(&chip->mgr->mixer_mutex);
+ return changed;
+}
+
+static struct snd_kcontrol_new hr222_phantom_power_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Phantom Power Switch",
+ .info = hr222_phantom_power_info,
+ .get = hr222_phantom_power_get,
+ .put = hr222_phantom_power_put,
+};
+
+
+int hr222_add_mic_controls(struct snd_pcxhr *chip)
+{
+ int err;
+ if (!chip->mgr->board_has_mic)
+ return 0;
+
+ /* controls */
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level,
+ chip));
+ if (err < 0)
+ return err;
+
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost,
+ chip));
+ if (err < 0)
+ return err;
+
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch,
+ chip));
+ return err;
+}
diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h
new file mode 100644
index 000000000000..6b318b2f0100
--- /dev/null
+++ b/sound/pci/pcxhr/pcxhr_mix22.h
@@ -0,0 +1,56 @@
+/*
+ * Driver for Digigram pcxhr compatible soundcards
+ *
+ * low level interface with interrupt ans message handling
+ *
+ * Copyright (c) 2004 by Digigram <alsa@digigram.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SOUND_PCXHR_MIX22_H
+#define __SOUND_PCXHR_MIX22_H
+
+struct pcxhr_mgr;
+
+int hr222_sub_init(struct pcxhr_mgr *mgr);
+int hr222_sub_set_clock(struct pcxhr_mgr *mgr, unsigned int rate,
+ int *changed);
+int hr222_get_external_clock(struct pcxhr_mgr *mgr,
+ enum pcxhr_clock_type clock_type,
+ int *sample_rate);
+
+#define HR222_LINE_PLAYBACK_LEVEL_MIN 0 /* -25.5 dB */
+#define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */
+#define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */
+
+#define HR222_LINE_CAPTURE_LEVEL_MIN 0 /* -111.5 dB */
+#define HR222_LINE_CAPTURE_ZERO_LEVEL 223 /* 0.0 dB */
+#define HR222_LINE_CAPTURE_LEVEL_MAX 255 /* +16 dB */
+#define HR222_MICRO_CAPTURE_LEVEL_MIN 0 /* -98.5 dB */
+#define HR222_MICRO_CAPTURE_LEVEL_MAX 210 /* +6.5 dB */
+
+int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
+ int is_capture,
+ int channel);
+int hr222_set_audio_source(struct snd_pcxhr *chip);
+int hr222_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx,
+ unsigned char *aes_bits);
+int hr222_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx,
+ unsigned char aes_bits);
+
+int hr222_add_mic_controls(struct snd_pcxhr *chip);
+
+#endif /* __SOUND_PCXHR_MIX22_H */
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index aabc7bc5321e..2436e374586f 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -33,20 +33,24 @@
#include <sound/tlv.h>
#include <sound/asoundef.h>
#include "pcxhr_mixer.h"
+#include "pcxhr_mix22.h"
+#define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */
+#define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */
+#define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */
-#define PCXHR_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB */
-#define PCXHR_ANALOG_CAPTURE_LEVEL_MAX 255 /* +31.5 dB */
-#define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL 224 /* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */
+#define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */
+#define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */
+#define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */
-#define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -128.0 dB */
-#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */
-#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
-
-static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550);
static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400);
-static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
+static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600);
+static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400);
+
+static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip,
+ int is_capture, int channel)
{
int err, vol;
struct pcxhr_rmh rmh;
@@ -60,15 +64,17 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur
if (chip->analog_playback_active[channel])
vol = chip->analog_playback_volume[channel];
else
- vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN;
- rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol; /* playback analog levels are inversed */
+ vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN;
+ /* playback analog levels are inversed */
+ rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol;
}
rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */
rmh.cmd_len = 3;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) "
- "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err);
+ snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)"
+ " is_capture(%d) err(%x)\n",
+ chip->chip_idx, is_capture, err);
return -EINVAL;
}
return 0;
@@ -80,14 +86,34 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur
static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
if (kcontrol->private_value == 0) { /* playback */
- uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; /* -128 dB */
- uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */
+ if (chip->mgr->is_hr_stereo) {
+ uinfo->value.integer.min =
+ HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */
+ uinfo->value.integer.max =
+ HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */
+ } else {
+ uinfo->value.integer.min =
+ PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */
+ uinfo->value.integer.max =
+ PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */
+ }
} else { /* capture */
- uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */
- uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */
+ if (chip->mgr->is_hr_stereo) {
+ uinfo->value.integer.min =
+ HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */
+ uinfo->value.integer.max =
+ HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */
+ } else {
+ uinfo->value.integer.min =
+ PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */
+ uinfo->value.integer.max =
+ PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */
+ }
}
return 0;
}
@@ -98,11 +124,11 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol,
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
mutex_lock(&chip->mgr->mixer_mutex);
if (kcontrol->private_value == 0) { /* playback */
- ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
- ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
+ ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
+ ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
} else { /* capture */
- ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
- ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
+ ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
+ ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
}
mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
@@ -123,18 +149,35 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol,
&chip->analog_capture_volume[i] :
&chip->analog_playback_volume[i];
if (is_capture) {
- if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN ||
- new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX)
- continue;
+ if (chip->mgr->is_hr_stereo) {
+ if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN ||
+ new_volume > HR222_LINE_CAPTURE_LEVEL_MAX)
+ continue;
+ } else {
+ if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN ||
+ new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX)
+ continue;
+ }
} else {
- if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN ||
- new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX)
- continue;
+ if (chip->mgr->is_hr_stereo) {
+ if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN ||
+ new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX)
+ continue;
+ } else {
+ if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN ||
+ new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX)
+ continue;
+ }
}
if (*stored_volume != new_volume) {
*stored_volume = new_volume;
changed = 1;
- pcxhr_update_analog_audio_level(chip, is_capture, i);
+ if (chip->mgr->is_hr_stereo)
+ hr222_update_analog_audio_level(chip,
+ is_capture, i);
+ else
+ pcxhr_update_analog_audio_level(chip,
+ is_capture, i);
}
}
mutex_unlock(&chip->mgr->mixer_mutex);
@@ -153,6 +196,7 @@ static struct snd_kcontrol_new pcxhr_control_analog_level = {
};
/* shared */
+
#define pcxhr_sw_info snd_ctl_boolean_stereo_info
static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol,
@@ -180,7 +224,10 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol,
!!ucontrol->value.integer.value[i];
changed = 1;
/* update playback levels */
- pcxhr_update_analog_audio_level(chip, 0, i);
+ if (chip->mgr->is_hr_stereo)
+ hr222_update_analog_audio_level(chip, 0, i);
+ else
+ pcxhr_update_analog_audio_level(chip, 0, i);
}
}
mutex_unlock(&chip->mgr->mixer_mutex);
@@ -251,7 +298,8 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx)
#define VALID_AUDIO_IO_MUTE_LEVEL 0x000004
#define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008
-static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel)
+static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip,
+ int capture, int channel)
{
int err;
struct pcxhr_rmh rmh;
@@ -264,18 +312,20 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in
pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST);
/* add channel mask */
- pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio));
- /* TODO : if mask (3 << pipe->first_audio) is used, left and right channel
- * will be programmed to the same params
- */
+ pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0,
+ 1 << (channel + pipe->first_audio));
+ /* TODO : if mask (3 << pipe->first_audio) is used, left and right
+ * channel will be programmed to the same params */
if (capture) {
rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL;
- /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */
+ /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled
+ * (capture pipe level) */
rmh.cmd[2] = chip->digital_capture_volume[channel];
} else {
- rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1;
- /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet
- * handled (playback pipe level)
+ rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL |
+ VALID_AUDIO_IO_MUTE_MONITOR_1;
+ /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL
+ * not yet handled (playback pipe level)
*/
rmh.cmd[2] = chip->monitoring_volume[channel] << 10;
if (chip->monitoring_active[channel] == 0)
@@ -284,8 +334,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in
rmh.cmd_len = 3;
err = pcxhr_send_msg(chip->mgr, &rmh);
- if(err<0) {
- snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n",
+ if (err < 0) {
+ snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n",
chip->chip_idx, err);
return -EINVAL;
}
@@ -309,15 +359,15 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+ int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
int *stored_volume;
int is_capture = kcontrol->private_value;
mutex_lock(&chip->mgr->mixer_mutex);
- if (is_capture)
- stored_volume = chip->digital_capture_volume; /* digital capture */
- else
- stored_volume = chip->digital_playback_volume[idx]; /* digital playback */
+ if (is_capture) /* digital capture */
+ stored_volume = chip->digital_capture_volume;
+ else /* digital playback */
+ stored_volume = chip->digital_playback_volume[idx];
ucontrol->value.integer.value[0] = stored_volume[0];
ucontrol->value.integer.value[1] = stored_volume[1];
mutex_unlock(&chip->mgr->mixer_mutex);
@@ -328,7 +378,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+ int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
int changed = 0;
int is_capture = kcontrol->private_value;
int *stored_volume;
@@ -384,7 +434,8 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
@@ -444,8 +495,8 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol,
if (chip->monitoring_volume[i] !=
ucontrol->value.integer.value[i]) {
chip->monitoring_volume[i] =
- !!ucontrol->value.integer.value[i];
- if(chip->monitoring_active[i])
+ ucontrol->value.integer.value[i];
+ if (chip->monitoring_active[i])
/* update monitoring volume and mute */
/* do only when monitoring is unmuted */
pcxhr_update_audio_pipe_level(chip, 0, i);
@@ -460,7 +511,7 @@ static struct snd_kcontrol_new pcxhr_control_monitor_vol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- .name = "Monitoring Volume",
+ .name = "Monitoring Playback Volume",
.info = pcxhr_digital_vol_info, /* shared */
.get = pcxhr_monitor_vol_get,
.put = pcxhr_monitor_vol_put,
@@ -511,7 +562,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new pcxhr_control_monitor_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Monitoring Switch",
+ .name = "Monitoring Playback Switch",
.info = pcxhr_sw_info, /* shared */
.get = pcxhr_monitor_sw_get,
.put = pcxhr_monitor_sw_put
@@ -533,7 +584,7 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip)
struct pcxhr_rmh rmh;
unsigned int mask, reg;
unsigned int codec;
- int err, use_src, changed;
+ int err, changed;
switch (chip->chip_idx) {
case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break;
@@ -542,13 +593,10 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip)
case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break;
default: return -EINVAL;
}
- reg = 0; /* audio source from analog plug */
- use_src = 0; /* do not activate codec SRC */
-
if (chip->audio_capture_source != 0) {
reg = mask; /* audio source from digital plug */
- if (chip->audio_capture_source == 2)
- use_src = 1;
+ } else {
+ reg = 0; /* audio source from analog plug */
}
/* set the input source */
pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed);
@@ -560,29 +608,61 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip)
if (err)
return err;
}
- pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */
- rmh.cmd_len = 3;
- rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
- rmh.cmd[1] = codec;
- rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54);
- err = pcxhr_send_msg(chip->mgr, &rmh);
- if(err)
- return err;
- rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49);
- err = pcxhr_send_msg(chip->mgr, &rmh);
+ if (chip->mgr->board_aes_in_192k) {
+ int i;
+ unsigned int src_config = 0xC0;
+ /* update all src configs with one call */
+ for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) {
+ if (chip->mgr->chip[i]->audio_capture_source == 2)
+ src_config |= (1 << (3 - i));
+ }
+ /* set codec SRC on off */
+ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
+ rmh.cmd_len = 2;
+ rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC;
+ rmh.cmd[1] = src_config;
+ err = pcxhr_send_msg(chip->mgr, &rmh);
+ } else {
+ int use_src = 0;
+ if (chip->audio_capture_source == 2)
+ use_src = 1;
+ /* set codec SRC on off */
+ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
+ rmh.cmd_len = 3;
+ rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
+ rmh.cmd[1] = codec;
+ rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) |
+ (use_src ? 0x41 : 0x54));
+ err = pcxhr_send_msg(chip->mgr, &rmh);
+ if (err)
+ return err;
+ rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) |
+ (use_src ? 0x41 : 0x49));
+ err = pcxhr_send_msg(chip->mgr, &rmh);
+ }
return err;
}
static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"Analog", "Digital", "Digi+SRC"};
+ static const char *texts[5] = {
+ "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"
+ };
+ int i;
+ struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+ i = 2; /* no SRC, no Mic available */
+ if (chip->mgr->board_has_aes1) {
+ i = 3; /* SRC available */
+ if (chip->mgr->board_has_mic)
+ i = 5; /* Mic and MicroMix available */
+ }
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
+ uinfo->value.enumerated.items = i;
+ if (uinfo->value.enumerated.item > (i-1))
+ uinfo->value.enumerated.item = i-1;
strcpy(uinfo->value.enumerated.name,
texts[uinfo->value.enumerated.item]);
return 0;
@@ -601,13 +681,21 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol,
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int ret = 0;
-
- if (ucontrol->value.enumerated.item[0] >= 3)
+ int i = 2; /* no SRC, no Mic available */
+ if (chip->mgr->board_has_aes1) {
+ i = 3; /* SRC available */
+ if (chip->mgr->board_has_mic)
+ i = 5; /* Mic and MicroMix available */
+ }
+ if (ucontrol->value.enumerated.item[0] >= i)
return -EINVAL;
mutex_lock(&chip->mgr->mixer_mutex);
if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) {
chip->audio_capture_source = ucontrol->value.enumerated.item[0];
- pcxhr_set_audio_source(chip);
+ if (chip->mgr->is_hr_stereo)
+ hr222_set_audio_source(chip);
+ else
+ pcxhr_set_audio_source(chip);
ret = 1;
}
mutex_unlock(&chip->mgr->mixer_mutex);
@@ -626,25 +714,46 @@ static struct snd_kcontrol_new pcxhr_control_audio_src = {
/*
* clock type selection
* enum pcxhr_clock_type {
- * PCXHR_CLOCK_TYPE_INTERNAL = 0,
- * PCXHR_CLOCK_TYPE_WORD_CLOCK,
- * PCXHR_CLOCK_TYPE_AES_SYNC,
- * PCXHR_CLOCK_TYPE_AES_1,
- * PCXHR_CLOCK_TYPE_AES_2,
- * PCXHR_CLOCK_TYPE_AES_3,
- * PCXHR_CLOCK_TYPE_AES_4,
- * };
+ * PCXHR_CLOCK_TYPE_INTERNAL = 0,
+ * PCXHR_CLOCK_TYPE_WORD_CLOCK,
+ * PCXHR_CLOCK_TYPE_AES_SYNC,
+ * PCXHR_CLOCK_TYPE_AES_1,
+ * PCXHR_CLOCK_TYPE_AES_2,
+ * PCXHR_CLOCK_TYPE_AES_3,
+ * PCXHR_CLOCK_TYPE_AES_4,
+ * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4,
+ * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL,
+ * HR22_CLOCK_TYPE_AES_SYNC,
+ * HR22_CLOCK_TYPE_AES_1,
+ * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1,
+ * };
*/
static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[7] = {
- "Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4"
+ static const char *textsPCXHR[7] = {
+ "Internal", "WordClock", "AES Sync",
+ "AES 1", "AES 2", "AES 3", "AES 4"
+ };
+ static const char *textsHR22[3] = {
+ "Internal", "AES Sync", "AES 1"
};
+ const char **texts;
struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
- int clock_items = 3 + mgr->capture_chips;
-
+ int clock_items = 2; /* at least Internal and AES Sync clock */
+ if (mgr->board_has_aes1) {
+ clock_items += mgr->capture_chips; /* add AES x */
+ if (!mgr->is_hr_stereo)
+ clock_items += 1; /* add word clock */
+ }
+ if (mgr->is_hr_stereo) {
+ texts = textsHR22;
+ snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1));
+ } else {
+ texts = textsPCXHR;
+ snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1));
+ }
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = clock_items;
@@ -667,9 +776,13 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
- unsigned int clock_items = 3 + mgr->capture_chips;
int rate, ret = 0;
-
+ unsigned int clock_items = 2; /* at least Internal and AES Sync clock */
+ if (mgr->board_has_aes1) {
+ clock_items += mgr->capture_chips; /* add AES x */
+ if (!mgr->is_hr_stereo)
+ clock_items += 1; /* add word clock */
+ }
if (ucontrol->value.enumerated.item[0] >= clock_items)
return -EINVAL;
mutex_lock(&mgr->mixer_mutex);
@@ -677,7 +790,8 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
mutex_lock(&mgr->setup_mutex);
mgr->use_clock_type = ucontrol->value.enumerated.item[0];
if (mgr->use_clock_type)
- pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate);
+ pcxhr_get_external_clock(mgr, mgr->use_clock_type,
+ &rate);
else
rate = mgr->sample_rate;
if (rate) {
@@ -686,7 +800,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
mgr->sample_rate = rate;
}
mutex_unlock(&mgr->setup_mutex);
- ret = 1; /* return 1 even if the set was not done. ok ? */
+ ret = 1; /* return 1 even if the set was not done. ok ? */
}
mutex_unlock(&mgr->mixer_mutex);
return ret;
@@ -747,14 +861,16 @@ static struct snd_kcontrol_new pcxhr_control_clock_rate = {
/*
* IEC958 status bits
*/
-static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
-static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits)
+static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip,
+ int aes_idx, unsigned char *aes_bits)
{
int i, err;
unsigned char temp;
@@ -763,39 +879,61 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsign
pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
switch (chip->chip_idx) {
- case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */
+ /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */
+ case 0: rmh.cmd[1] = CS8420_01_CS; break;
case 1: rmh.cmd[1] = CS8420_23_CS; break;
case 2: rmh.cmd[1] = CS8420_45_CS; break;
case 3: rmh.cmd[1] = CS8420_67_CS; break;
default: return -EINVAL;
}
- switch (aes_idx) {
- case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */
- case 1: rmh.cmd[2] = CS8420_CSB1; break;
- case 2: rmh.cmd[2] = CS8420_CSB2; break;
- case 3: rmh.cmd[2] = CS8420_CSB3; break;
- case 4: rmh.cmd[2] = CS8420_CSB4; break;
- default: return -EINVAL;
+ if (chip->mgr->board_aes_in_192k) {
+ switch (aes_idx) {
+ case 0: rmh.cmd[2] = CS8416_CSB0; break;
+ case 1: rmh.cmd[2] = CS8416_CSB1; break;
+ case 2: rmh.cmd[2] = CS8416_CSB2; break;
+ case 3: rmh.cmd[2] = CS8416_CSB3; break;
+ case 4: rmh.cmd[2] = CS8416_CSB4; break;
+ default: return -EINVAL;
+ }
+ } else {
+ switch (aes_idx) {
+ /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */
+ case 0: rmh.cmd[2] = CS8420_CSB0; break;
+ case 1: rmh.cmd[2] = CS8420_CSB1; break;
+ case 2: rmh.cmd[2] = CS8420_CSB2; break;
+ case 3: rmh.cmd[2] = CS8420_CSB3; break;
+ case 4: rmh.cmd[2] = CS8420_CSB4; break;
+ default: return -EINVAL;
+ }
}
- rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */
- rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */
+ /* size and code the chip id for the fpga */
+ rmh.cmd[1] &= 0x0fffff;
+ /* chip signature + map for spi read */
+ rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI;
rmh.cmd_len = 3;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
return err;
- temp = 0;
- for (i = 0; i < 8; i++) {
- /* attention : reversed bit order (not with CS8416_01_CS) */
- temp <<= 1;
- if (rmh.stat[1] & (1 << i))
- temp |= 1;
+
+ if (chip->mgr->board_aes_in_192k) {
+ temp = (unsigned char)rmh.stat[1];
+ } else {
+ temp = 0;
+ /* reversed bit order (not with CS8416_01_CS) */
+ for (i = 0; i < 8; i++) {
+ temp <<= 1;
+ if (rmh.stat[1] & (1 << i))
+ temp |= 1;
+ }
}
- snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp);
+ snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+ chip->chip_idx, aes_idx, temp);
*aes_bits = temp;
return 0;
}
-static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
unsigned char aes_bits;
@@ -806,7 +944,12 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
if (kcontrol->private_value == 0) /* playback */
aes_bits = chip->aes_bits[i];
else { /* capture */
- err = pcxhr_iec958_capture_byte(chip, i, &aes_bits);
+ if (chip->mgr->is_hr_stereo)
+ err = hr222_iec958_capture_byte(chip, i,
+ &aes_bits);
+ else
+ err = pcxhr_iec958_capture_byte(chip, i,
+ &aes_bits);
if (err)
break;
}
@@ -825,7 +968,8 @@ static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits)
+static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip,
+ int aes_idx, unsigned char aes_bits)
{
int i, err, cmd;
unsigned char new_bits = aes_bits;
@@ -834,12 +978,12 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigne
for (i = 0; i < 8; i++) {
if ((old_bits & 0x01) != (new_bits & 0x01)) {
- cmd = chip->chip_idx & 0x03; /* chip index 0..3 */
- if(chip->chip_idx > 3)
+ cmd = chip->chip_idx & 0x03; /* chip index 0..3 */
+ if (chip->chip_idx > 3)
/* new bit used if chip_idx>3 (PCX1222HR) */
cmd |= 1 << 22;
- cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */
- cmd |= (new_bits & 0x01) << 23; /* add bit value */
+ cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */
+ cmd |= (new_bits & 0x01) << 23; /* add bit value */
pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
rmh.cmd[0] |= IO_NUM_REG_CUER;
rmh.cmd[1] = cmd;
@@ -867,7 +1011,12 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol,
mutex_lock(&chip->mgr->mixer_mutex);
for (i = 0; i < 5; i++) {
if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) {
- pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]);
+ if (chip->mgr->is_hr_stereo)
+ hr222_iec958_update_byte(chip, i,
+ ucontrol->value.iec958.status[i]);
+ else
+ pcxhr_iec958_update_byte(chip, i,
+ ucontrol->value.iec958.status[i]);
changed = 1;
}
}
@@ -917,29 +1066,53 @@ static void pcxhr_init_audio_levels(struct snd_pcxhr *chip)
/* at boot time the digital volumes are unmuted 0dB */
for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) {
chip->digital_playback_active[j][i] = 1;
- chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL;
+ chip->digital_playback_volume[j][i] =
+ PCXHR_DIGITAL_ZERO_LEVEL;
}
- /* after boot, only two bits are set on the uer interface */
- chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000;
-/* only for test purpose, remove later */
+ /* after boot, only two bits are set on the uer
+ * interface
+ */
+ chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL |
+ IEC958_AES0_PRO_FS_48000);
#ifdef CONFIG_SND_DEBUG
- /* analog volumes for playback (is LEVEL_MIN after boot) */
+ /* analog volumes for playback
+ * (is LEVEL_MIN after boot)
+ */
chip->analog_playback_active[i] = 1;
- chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL;
- pcxhr_update_analog_audio_level(chip, 0, i);
+ if (chip->mgr->is_hr_stereo)
+ chip->analog_playback_volume[i] =
+ HR222_LINE_PLAYBACK_ZERO_LEVEL;
+ else {
+ chip->analog_playback_volume[i] =
+ PCXHR_LINE_PLAYBACK_ZERO_LEVEL;
+ pcxhr_update_analog_audio_level(chip, 0, i);
+ }
#endif
-/* test end */
+ /* stereo cards need to be initialised after boot */
+ if (chip->mgr->is_hr_stereo)
+ hr222_update_analog_audio_level(chip, 0, i);
}
if (chip->nb_streams_capt) {
/* at boot time the digital volumes are unmuted 0dB */
- chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL;
-/* only for test purpose, remove later */
+ chip->digital_capture_volume[i] =
+ PCXHR_DIGITAL_ZERO_LEVEL;
+ chip->analog_capture_active = 1;
#ifdef CONFIG_SND_DEBUG
- /* analog volumes for playback (is LEVEL_MIN after boot) */
- chip->analog_capture_volume[i] = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL;
- pcxhr_update_analog_audio_level(chip, 1, i);
+ /* analog volumes for playback
+ * (is LEVEL_MIN after boot)
+ */
+ if (chip->mgr->is_hr_stereo)
+ chip->analog_capture_volume[i] =
+ HR222_LINE_CAPTURE_ZERO_LEVEL;
+ else {
+ chip->analog_capture_volume[i] =
+ PCXHR_LINE_CAPTURE_ZERO_LEVEL;
+ pcxhr_update_analog_audio_level(chip, 1, i);
+ }
#endif
-/* test end */
+ /* stereo cards need to be initialised after boot */
+ if (chip->mgr->is_hr_stereo)
+ hr222_update_analog_audio_level(chip, 1, i);
}
}
@@ -963,90 +1136,125 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr)
temp = pcxhr_control_analog_level;
temp.name = "Master Playback Volume";
temp.private_value = 0; /* playback */
- temp.tlv.p = db_scale_analog_playback;
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+ if (mgr->is_hr_stereo)
+ temp.tlv.p = db_scale_a_hr222_playback;
+ else
+ temp.tlv.p = db_scale_analog_playback;
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&temp, chip));
+ if (err < 0)
return err;
+
/* output mute controls */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_output_switch,
- chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_output_switch,
+ chip));
+ if (err < 0)
return err;
-
+
temp = snd_pcxhr_pcm_vol;
temp.name = "PCM Playback Volume";
temp.count = PCXHR_PLAYBACK_STREAMS;
temp.private_value = 0; /* playback */
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&temp, chip));
+ if (err < 0)
return err;
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_pcm_switch,
- chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_pcm_switch, chip));
+ if (err < 0)
return err;
/* IEC958 controls */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_playback_iec958_mask,
- chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_playback_iec958_mask,
+ chip));
+ if (err < 0)
return err;
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_playback_iec958,
- chip))) < 0)
+
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_playback_iec958,
+ chip));
+ if (err < 0)
return err;
}
if (chip->nb_streams_capt) {
- /* analog input level control only on first two chips !*/
+ /* analog input level control */
temp = pcxhr_control_analog_level;
- temp.name = "Master Capture Volume";
+ temp.name = "Line Capture Volume";
temp.private_value = 1; /* capture */
- temp.tlv.p = db_scale_analog_capture;
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+ if (mgr->is_hr_stereo)
+ temp.tlv.p = db_scale_a_hr222_capture;
+ else
+ temp.tlv.p = db_scale_analog_capture;
+
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&temp, chip));
+ if (err < 0)
return err;
temp = snd_pcxhr_pcm_vol;
temp.name = "PCM Capture Volume";
temp.count = 1;
temp.private_value = 1; /* capture */
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&temp, chip));
+ if (err < 0)
return err;
+
/* Audio source */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_audio_src,
- chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_audio_src, chip));
+ if (err < 0)
return err;
+
/* IEC958 controls */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_capture_iec958_mask,
- chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_capture_iec958_mask,
+ chip));
+ if (err < 0)
return err;
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_capture_iec958,
- chip))) < 0)
+
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_capture_iec958,
+ chip));
+ if (err < 0)
return err;
+
+ if (mgr->is_hr_stereo) {
+ err = hr222_add_mic_controls(chip);
+ if (err < 0)
+ return err;
+ }
}
/* monitoring only if playback and capture device available */
if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) {
/* monitoring */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_monitor_vol,
- chip))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_monitor_vol, chip));
+ if (err < 0)
return err;
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_monitor_sw,
- chip))) < 0)
+
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_monitor_sw, chip));
+ if (err < 0)
return err;
}
if (i == 0) {
/* clock mode only one control per pcxhr */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_clock_type,
- mgr))) < 0)
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_clock_type, mgr));
+ if (err < 0)
return err;
- /* non standard control used to scan the external clock presence/frequencies */
- if ((err = snd_ctl_add(chip->card,
- snd_ctl_new1(&pcxhr_control_clock_rate,
- mgr))) < 0)
+ /* non standard control used to scan
+ * the external clock presence/frequencies
+ */
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&pcxhr_control_clock_rate, mgr));
+ if (err < 0)
return err;
}
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 736246f98acc..fdd3be5b439d 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1452,7 +1452,7 @@ static int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int i
if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0)
return -1;
- sprintf (hdsp->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1);
+ sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1);
hdsp->midi[id].rmidi->private_data = &hdsp->midi[id];
snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 98762f909d64..dc5c4baa1e64 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1293,7 +1293,7 @@ static int __devinit snd_hdspm_create_midi (struct snd_card *card,
if (err < 0)
return err;
- sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1);
+ sprintf(hdspm->midi[id].rmidi->name, "HDSPM MIDI %d", id+1);
hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index a38c0c790d2b..af76ee862d27 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -1033,7 +1033,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
}
if (of_device_is_compatible(sound, "tumbler")) {
chip->model = PMAC_TUMBLER;
- chip->can_capture = 0; /* no capture */
+ chip->can_capture = machine_is_compatible("PowerMac4,2");
chip->can_duplex = 0;
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index f746e15b8481..3eb223385416 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -875,7 +875,8 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = {
.put = tumbler_put_master_switch
},
DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
- DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
+ /* Alternative PCM is assigned to Mic analog loopback on iBook G4 */
+ DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2),
DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c
index 798ca124da58..ccd763dd7167 100644
--- a/sound/usb/caiaq/caiaq-control.c
+++ b/sound/usb/caiaq/caiaq-control.c
@@ -247,69 +247,56 @@ static struct caiaq_controller a8dj_controller[] = {
{ "Software lock", 40 }
};
-int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
+static int __devinit add_controls(struct caiaq_controller *c, int num,
+ struct snd_usb_caiaqdev *dev)
{
- int i;
+ int i, ret;
struct snd_kcontrol *kc;
+ for (i = 0; i < num; i++, c++) {
+ kcontrol_template.name = c->name;
+ kcontrol_template.private_value = c->index;
+ kc = snd_ctl_new1(&kcontrol_template, dev);
+ ret = snd_ctl_add(dev->chip.card, kc);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
+{
+ int ret = 0;
+
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
- for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) {
- struct caiaq_controller *c = ak1_controller + i;
- kcontrol_template.name = c->name;
- kcontrol_template.private_value = c->index;
- kc = snd_ctl_new1(&kcontrol_template, dev);
- snd_ctl_add(dev->chip.card, kc);
- }
-
+ ret = add_controls(ak1_controller,
+ ARRAY_SIZE(ak1_controller), dev);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
- for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) {
- struct caiaq_controller *c = rk2_controller + i;
- kcontrol_template.name = c->name;
- kcontrol_template.private_value = c->index;
- kc = snd_ctl_new1(&kcontrol_template, dev);
- snd_ctl_add(dev->chip.card, kc);
- }
-
+ ret = add_controls(rk2_controller,
+ ARRAY_SIZE(rk2_controller), dev);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
- for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) {
- struct caiaq_controller *c = rk3_controller + i;
- kcontrol_template.name = c->name;
- kcontrol_template.private_value = c->index;
- kc = snd_ctl_new1(&kcontrol_template, dev);
- snd_ctl_add(dev->chip.card, kc);
- }
-
+ ret = add_controls(rk3_controller,
+ ARRAY_SIZE(rk3_controller), dev);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
- for (i = 0; i < ARRAY_SIZE(kore_controller); i++) {
- struct caiaq_controller *c = kore_controller + i;
- kcontrol_template.name = c->name;
- kcontrol_template.private_value = c->index;
- kc = snd_ctl_new1(&kcontrol_template, dev);
- snd_ctl_add(dev->chip.card, kc);
- }
-
+ ret = add_controls(kore_controller,
+ ARRAY_SIZE(kore_controller), dev);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
- for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) {
- struct caiaq_controller *c = a8dj_controller + i;
- kcontrol_template.name = c->name;
- kcontrol_template.private_value = c->index;
- kc = snd_ctl_new1(&kcontrol_template, dev);
- snd_ctl_add(dev->chip.card, kc);
- }
-
+ ret = add_controls(a8dj_controller,
+ ARRAY_SIZE(a8dj_controller), dev);
break;
}
- return 0;
+ return ret;
}
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c
index 83175083e50f..b143ef7152f7 100644
--- a/sound/usb/caiaq/caiaq-device.c
+++ b/sound/usb/caiaq/caiaq-device.c
@@ -42,7 +42,7 @@
#endif
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.9");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, RigKontrol3},"