summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2004-06-16 15:59:16 +0200
committerJaroslav Kysela <perex@suse.cz>2004-06-16 15:59:16 +0200
commit976b3e534966a952304354f7e004b3ebcfda45fa (patch)
treed416aedf21f19be0faa6bdf7c76f73760d03fb59
parentadf791bd0c2829aa41a66b218617937d0e059e14 (diff)
parenta6c7717d44417a1622f0233be531309a868d3520 (diff)
Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5
into suse.cz:/home/perex/bk/linux-sound/linux-sound
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt5
-rw-r--r--include/sound/ac97_codec.h6
-rw-r--r--include/sound/core.h4
-rw-r--r--include/sound/seq_kernel.h3
-rw-r--r--include/sound/version.h4
-rw-r--r--include/sound/vx_core.h8
-rw-r--r--sound/core/memalloc.c4
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c2
-rw-r--r--sound/core/seq/seq.c1
-rw-r--r--sound/core/seq/seq_clientmgr.c18
-rw-r--r--sound/drivers/vx/vx_core.c3
-rw-r--r--sound/drivers/vx/vx_mixer.c51
-rw-r--r--sound/drivers/vx/vx_pcm.c13
-rw-r--r--sound/drivers/vx/vx_uer.c15
-rw-r--r--sound/isa/wavefront/wavefront_synth.c6
-rw-r--r--sound/parisc/harmony.c44
-rw-r--r--sound/pci/ac97/ac97_codec.c244
-rw-r--r--sound/pci/ac97/ac97_id.h7
-rw-r--r--sound/pci/ac97/ac97_local.h14
-rw-r--r--sound/pci/ac97/ac97_patch.c249
-rw-r--r--sound/pci/ac97/ac97_patch.h1
-rw-r--r--sound/pci/ac97/ac97_proc.c10
-rw-r--r--sound/pci/atiixp.c16
-rw-r--r--sound/pci/ice1712/Makefile2
-rw-r--r--sound/pci/ice1712/ice1724.c29
-rw-r--r--sound/pci/ice1712/vt1720_mobo.c97
-rw-r--r--sound/pci/ice1712/vt1720_mobo.h35
-rw-r--r--sound/pci/via82xx.c54
28 files changed, 693 insertions, 252 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 10c5bed26b1c..1edf8cb98d7c 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -613,7 +613,7 @@ Module parameters
model - Use the given board model, one of the following:
delta1010, dio2496, delta66, delta44, audiophile, delta410,
delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d,
- dmx6fire, dsp24, dsp24_71, ez8
+ dmx6fire, dsp24, dsp24_value, dsp24_71, ez8
omni - Omni I/O support for MidiMan M-Audio Delta44/66
cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever)
in msec resolution, default value is 500 (0.5 sec)
@@ -631,7 +631,8 @@ Module parameters
* TerraTec Aureon Sky-5.1, Space-7.1
model - Use the given board model, one of the following:
- revo71, amp2000, prodigy71, aureon51, aureon71
+ revo71, amp2000, prodigy71, aureon51, aureon71,
+ k8x800
Module supports up to 8 cards and autoprobe.
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 3629059ad262..ee64dd0bf169 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -441,6 +441,7 @@ struct _snd_ac97 {
unsigned short subsystem_vendor;
unsigned short subsystem_device;
spinlock_t reg_lock;
+ struct semaphore mutex; /* mutex for AD18xx multi-codecs and paging (2.3) */
unsigned short num; /* number of codec: 0 = primary, 1 = secondary */
unsigned short addr; /* physical address of codec [0-3] */
unsigned int id; /* identification of codec */
@@ -461,7 +462,6 @@ struct _snd_ac97 {
unsigned short id[3]; // codec IDs (lower 16-bit word)
unsigned short pcmreg[3]; // PCM registers
unsigned short codec_cfg[3]; // CODEC_CFG bits
- struct semaphore mutex;
} ad18xx;
unsigned int dev_flags; /* device specific */
} spec;
@@ -484,6 +484,10 @@ static inline int ac97_can_amap(ac97_t * ac97)
{
return (ac97->ext_id & AC97_EI_AMAP) != 0;
}
+static inline int ac97_can_spdif(ac97_t * ac97)
+{
+ return (ac97->ext_id & AC97_EI_SPDIF) != 0;
+}
/* functions */
int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus); /* create new AC97 bus */
diff --git a/include/sound/core.h b/include/sound/core.h
index caf1b3c859d3..e8e56cef2ec9 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -211,12 +211,14 @@ int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
void *private_data);
#define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data)
+#ifdef CONFIG_PCI
#ifndef SND_PCI_PM_CALLBACKS
int snd_card_pci_suspend(struct pci_dev *dev, u32 state);
int snd_card_pci_resume(struct pci_dev *dev);
#define SND_PCI_PM_CALLBACKS \
.suspend = snd_card_pci_suspend, .resume = snd_card_pci_resume
#endif
+#endif
#else
#define snd_power_lock(card) do { (void)(card); } while (0)
#define snd_power_unlock(card) do { (void)(card); } while (0)
@@ -226,8 +228,10 @@ static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct fi
#define snd_card_set_pm_callback(card,suspend,resume,data) -EINVAL
#define snd_card_set_dev_pm_callback(card,suspend,resume,data) -EINVAL
#define snd_card_set_isa_pm_callback(card,suspend,resume,data) -EINVAL
+#ifdef CONFIG_PCI
#define SND_PCI_PM_CALLBACKS
#endif
+#endif
/* device.c */
diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h
index d0b69fbef924..5af1f35b04fe 100644
--- a/include/sound/seq_kernel.h
+++ b/include/sound/seq_kernel.h
@@ -168,6 +168,9 @@ typedef int (*snd_seq_dump_func_t)(void *ptr, void *buf, int count);
int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf, int in_kernel, int size_aligned);
int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t func, void *private_data);
+/* interface for OSS emulation */
+int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo);
+
/* port callback routines */
void snd_port_init_callback(snd_seq_port_callback_t *p);
snd_seq_port_callback_t *snd_port_alloc_callback(void);
diff --git a/include/sound/version.h b/include/sound/version.h
index 9f7d0e930064..90a79d6148c4 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h. Generated by configure. */
-#define CONFIG_SND_VERSION "1.0.4"
-#define CONFIG_SND_DATE " (Mon May 17 14:31:44 2004 UTC)"
+#define CONFIG_SND_VERSION "1.0.5"
+#define CONFIG_SND_DATE " (Sun May 30 10:49:40 2004 UTC)"
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index 5609f5420ac0..d3d90e1f25fd 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -182,6 +182,7 @@ struct snd_vx_core {
/* clock and audio sources */
unsigned int audio_source; /* current audio input source */
unsigned int audio_source_target;
+ unsigned int clock_mode; /* clock mode (VX_CLOCK_MODE_XXX) */
unsigned int clock_source; /* current clock source (INTERNAL_QUARTZ or UER_SYNC) */
unsigned int freq; /* current frequency */
unsigned int freq_detected; /* detected frequency from digital in */
@@ -364,6 +365,13 @@ enum {
UER_SYNC
};
+/* clock mode */
+enum {
+ VX_CLOCK_MODE_AUTO, /* depending on the current audio source */
+ VX_CLOCK_MODE_INTERNAL, /* fixed to internal quartz */
+ VX_CLOCK_MODE_EXTERNAL /* fixed to UER sync */
+};
+
/* SPDIF/UER type */
enum {
VX_UER_MODE_CONSUMER,
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 3cf0917741d6..e562950c9824 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -45,10 +45,14 @@ MODULE_LICENSE("GPL");
#ifndef SNDRV_CARDS
#define SNDRV_CARDS 8
#endif
+
+/* FIXME: so far only some PCI devices have the preallocation table */
+#ifdef CONFIG_PCI
static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
static int boot_devs;
module_param_array(enable, bool, boot_devs, 0444);
MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
+#endif
/*
*/
diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
index b0d72a883eeb..d3976147a0fd 100644
--- a/sound/core/seq/oss/seq_oss_timer.c
+++ b/sound/core/seq/oss/seq_oss_timer.c
@@ -168,7 +168,7 @@ snd_seq_oss_timer_start(seq_oss_timer_t *timer)
tmprec.queue = dp->queue;
tmprec.ppq = timer->ppq;
tmprec.tempo = timer->tempo;
- snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, &tmprec);
+ snd_seq_set_queue_tempo(dp->cseq, &tmprec);
send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0);
timer->running = 1;
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 5f8beb4a2037..0559bc89060f 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -133,6 +133,7 @@ EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
+EXPORT_SYMBOL(snd_seq_set_queue_tempo);
/* seq_memory.c */
EXPORT_SYMBOL(snd_seq_expand_var_event);
EXPORT_SYMBOL(snd_seq_dump_var_event);
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 9e67d06da3c2..4c6d56614bb1 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1694,6 +1694,13 @@ static int snd_seq_ioctl_get_queue_tempo(client_t * client, void __user *arg)
/* SET_QUEUE_TEMPO ioctl() */
+int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo)
+{
+ if (!snd_seq_queue_check_access(tempo->queue, client))
+ return -EPERM;
+ return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
+}
+
static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
{
int result;
@@ -1702,15 +1709,8 @@ static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
if (copy_from_user(&tempo, arg, sizeof(tempo)))
return -EFAULT;
- if (snd_seq_queue_check_access(tempo.queue, client->number)) {
- result = snd_seq_queue_timer_set_tempo(tempo.queue, client->number, &tempo);
- if (result < 0)
- return result;
- } else {
- return -EPERM;
- }
-
- return 0;
+ result = snd_seq_set_queue_tempo(client->number, &tempo);
+ return result < 0 ? result : 0;
}
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 31a94efd6534..2ba233df3286 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -572,6 +572,7 @@ static void vx_reset_board(vx_core_t *chip, int cold_reset)
if (cold_reset) {
chip->audio_source_target = chip->audio_source;
chip->clock_source = INTERNAL_QUARTZ;
+ chip->clock_mode = VX_CLOCK_MODE_AUTO;
chip->freq = 48000;
chip->uer_detected = VX_UER_MODE_NOT_PRESENT;
chip->uer_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
@@ -606,6 +607,7 @@ static void vx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
vx_core_t *chip = snd_magic_cast(vx_core_t, entry->private_data, return);
static char *audio_src_vxp[] = { "Line", "Mic", "Digital" };
static char *audio_src_vx2[] = { "Analog", "Analog", "Digital" };
+ static char *clock_mode[] = { "Auto", "Internal", "External" };
static char *clock_src[] = { "Internal", "External" };
static char *uer_type[] = { "Consumer", "Professional", "Not Present" };
@@ -629,6 +631,7 @@ static void vx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
snd_iprintf(buffer, "Input Source: %s\n", vx_is_pcmcia(chip) ?
audio_src_vxp[chip->audio_source] :
audio_src_vx2[chip->audio_source]);
+ snd_iprintf(buffer, "Clock Mode: %s\n", clock_mode[chip->clock_mode]);
snd_iprintf(buffer, "Clock Source: %s\n", clock_src[chip->clock_source]);
snd_iprintf(buffer, "Frequency: %d\n", chip->freq);
snd_iprintf(buffer, "Detected Frequency: %d\n", chip->freq_detected);
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 52cfb80b5b3c..cbffed79278c 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -524,6 +524,54 @@ static snd_kcontrol_new_t vx_control_audio_src = {
};
/*
+ * clock mode selection
+ */
+static int vx_clock_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[3] = {
+ "Auto", "Internal", "External"
+ };
+
+ 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;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int vx_clock_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ vx_core_t *chip = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.enumerated.item[0] = chip->clock_mode;
+ return 0;
+}
+
+static int vx_clock_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ vx_core_t *chip = snd_kcontrol_chip(kcontrol);
+ down(&chip->mixer_mutex);
+ if (chip->clock_mode != ucontrol->value.enumerated.item[0]) {
+ chip->clock_mode = ucontrol->value.enumerated.item[0];
+ vx_set_clock(chip, chip->freq);
+ up(&chip->mixer_mutex);
+ return 1;
+ }
+ up(&chip->mixer_mutex);
+ return 0;
+}
+
+static snd_kcontrol_new_t vx_control_clock_mode = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Mode",
+ .info = vx_clock_mode_info,
+ .get = vx_clock_mode_get,
+ .put = vx_clock_mode_put,
+};
+
+/*
* Audio Gain
*/
static int vx_audio_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -913,6 +961,9 @@ int snd_vx_mixer_new(vx_core_t *chip)
/* Audio source */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0)
return err;
+ /* clock mode */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0)
+ return err;
/* IEC958 controls */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0)
return err;
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 9ee1c80efb6a..9ae96b949d65 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -48,6 +48,7 @@
#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/delay.h>
#include <sound/core.h>
#include <sound/asoundef.h>
#include <sound/pcm.h>
@@ -381,7 +382,7 @@ static int vx_send_irqa(vx_core_t *chip)
*/
static int vx_toggle_pipe(vx_core_t *chip, vx_pipe_t *pipe, int state)
{
- int err, i, cur_state, delay;
+ int err, i, cur_state;
/* Check the pipe is not already in the requested state */
if (vx_get_pipe_state(chip, pipe, &cur_state) < 0)
@@ -394,17 +395,14 @@ static int vx_toggle_pipe(vx_core_t *chip, vx_pipe_t *pipe, int state)
* enough sound buffer for this pipe)
*/
if (state) {
- int delay = CAN_START_DELAY;
for (i = 0 ; i < MAX_WAIT_FOR_DSP; i++) {
- snd_vx_delay(chip, delay);
err = vx_pipe_can_start(chip, pipe);
if (err > 0)
break;
/* Wait for a few, before asking again
* to avoid flooding the DSP with our requests
*/
- if ((i % 4 ) == 0)
- delay <<= 1;
+ mdelay(1);
}
}
@@ -418,15 +416,12 @@ static int vx_toggle_pipe(vx_core_t *chip, vx_pipe_t *pipe, int state)
* reaching the expected state before returning
* Check one pipe only (since they are synchronous)
*/
- delay = WAIT_STATE_DELAY;
for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
- snd_vx_delay(chip, delay);
err = vx_get_pipe_state(chip, pipe, &cur_state);
if (err < 0 || cur_state == state)
break;
err = -EIO;
- if ((i % 4 ) == 0)
- delay <<= 1;
+ mdelay(1);
}
return err < 0 ? -EIO : 0;
}
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index 54609aac8a14..5db41f136d64 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -263,17 +263,17 @@ int vx_set_clock(vx_core_t *chip, unsigned int freq)
/* change the audio source if possible */
vx_sync_audio_source(chip);
- switch (chip->audio_source) {
- case VX_AUDIO_SRC_DIGITAL:
+ if (chip->clock_mode == VX_CLOCK_MODE_EXTERNAL ||
+ (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
+ chip->audio_source == VX_AUDIO_SRC_DIGITAL)) {
if (chip->clock_source != UER_SYNC) {
vx_change_clock_source(chip, UER_SYNC);
mdelay(6);
src_changed = 1;
}
- if (chip->freq == freq)
- return 0;
- break;
- default:
+ } else if (chip->clock_mode == VX_CLOCK_MODE_INTERNAL ||
+ (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
+ chip->audio_source != VX_AUDIO_SRC_DIGITAL)) {
if (chip->clock_source != INTERNAL_QUARTZ) {
vx_change_clock_source(chip, INTERNAL_QUARTZ);
src_changed = 1;
@@ -283,8 +283,9 @@ int vx_set_clock(vx_core_t *chip, unsigned int freq)
vx_set_internal_clock(chip, freq);
if (src_changed)
vx_modify_board_inputs(chip);
- break;
}
+ if (chip->freq == freq)
+ return 0;
chip->freq = freq;
vx_modify_board_clock(chip, 1);
return 0;
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 9b65db0b1941..04ecfa030af3 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1961,6 +1961,12 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
break;
}
+ if (section_length < 0 || section_length > WF_SECTION_MAX) {
+ snd_printk ("invalid firmware section length %d\n",
+ section_length);
+ goto failure;
+ }
+
if (sys_read (fd, section, section_length) != section_length) {
snd_printk ("firmware section "
"read error.\n");
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 423ab05c0480..90bd82a6e842 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -556,7 +556,7 @@ static int snd_card_harmony_playback_prepare(snd_pcm_substream_t * substream)
harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
/* data format */
- harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format);
+ harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format);
/* number of channels */
if (runtime->channels == 2)
@@ -587,7 +587,7 @@ static int snd_card_harmony_capture_prepare(snd_pcm_substream_t * substream)
harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
/* data format */
- harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format);
+ harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format);
/* number of channels */
if (runtime->channels == 1)
@@ -751,6 +751,8 @@ static int snd_card_harmony_hw_params(snd_pcm_substream_t *substream,
int err;
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+ if (err > 0 && substream->dma_device.type == SNDRV_DMA_TYPE_CONTINUOUS)
+ substream->runtime->dma_addr = __pa(substream->runtime->dma_area);
DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err,
(unsigned long)substream->runtime->dma_addr);
return err;
@@ -784,7 +786,7 @@ static snd_pcm_ops_t snd_card_harmony_capture_ops = {
.pointer = snd_card_harmony_capture_pointer,
};
-static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony, int device)
+static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony)
{
snd_pcm_t *pcm;
int err;
@@ -797,7 +799,7 @@ static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony, int device)
snd_harmony_disable_interrupts(harmony);
- if ((err = snd_pcm_new(harmony->card, "Harmony", device, 1, 1, &pcm)) < 0)
+ if ((err = snd_pcm_new(harmony->card, "Harmony", 0, 1, 1, &pcm)) < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_harmony_playback_ops);
@@ -813,26 +815,46 @@ static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony, int device)
harmony->dma_dev.dev = &harmony->pa_dev->dev;
err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
&harmony->graveyard_dma);
- if (err < 0)
+ if (err == -ENOMEM) {
+ /* use continuous buffers */
+ harmony->dma_dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+ harmony->dma_dev.dev = snd_dma_continuous_data(GFP_KERNEL);
+ err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
+ &harmony->graveyard_dma);
+ }
+ if (err < 0) {
+ printk(KERN_ERR PFX "can't allocate graveyard buffer\n");
return err;
+ }
harmony->graveyard_count = 0;
/* initialize silence buffers */
err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*SILENCE_BUFS,
&harmony->silence_dma);
- if (err < 0)
+ if (err < 0) {
+ printk(KERN_ERR PFX "can't allocate silence buffer\n");
return err;
+ }
harmony->silence_count = 0;
+ if (harmony->dma_dev.type == SNDRV_DMA_TYPE_CONTINUOUS) {
+ harmony->graveyard_dma.addr = __pa(harmony->graveyard_dma.area);
+ harmony->silence_dma.addr = __pa(harmony->silence_dma.area);
+ }
+
harmony->ply_stopped = harmony->cap_stopped = 1;
harmony->playback_substream = NULL;
harmony->capture_substream = NULL;
harmony->graveyard_count = 0;
-
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- &harmony->pa_dev->dev,
- MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
+
+ err = snd_pcm_lib_preallocate_pages_for_all(pcm, harmony->dma_dev.type,
+ harmony->dma_dev.dev,
+ MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
+ if (err < 0) {
+ printk(KERN_ERR PFX "buffer allocation error %d\n", err);
+ // return err;
+ }
return 0;
}
@@ -1037,7 +1059,7 @@ static int __init snd_card_harmony_probe(struct parisc_device *pa_dev)
snd_card_free(card);
return err;
}
- if ((err = snd_card_harmony_pcm_init(chip, dev)) < 0) {
+ if ((err = snd_card_harmony_pcm_init(chip)) < 0) {
printk(KERN_ERR PFX "PCM Init failed\n");
snd_card_free(card);
return err;
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 8f43dd60dd1b..54a4fda87e37 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -108,12 +108,13 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL },
{ 0x414c4300, 0xffffff00, "ALC100/100P", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200/200P", NULL, NULL },
+{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */
+{ 0x414c4722, 0xffffffff, "ALC650E", NULL, NULL }, /* already patched */
+{ 0x414c4723, 0xffffffff, "ALC650F", NULL, NULL }, /* already patched */
{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL },
-{ 0x414c4721, 0xfffffff0, "ALC650D", patch_alc650, NULL },
-{ 0x414c4722, 0xfffffff0, "ALC650E", patch_alc650, NULL },
-{ 0x414c4723, 0xfffffff0, "ALC650F", patch_alc650, NULL },
{ 0x414c4760, 0xfffffff0, "ALC655", patch_alc655, NULL },
{ 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL },
+{ 0x414c4790, 0xfffffff0, "ALC850", patch_alc850, NULL },
{ 0x414c4730, 0xffffffff, "ALC101", NULL, NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL },
@@ -274,7 +275,7 @@ void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value)
{
if (!snd_ac97_valid_reg(ac97, reg))
return;
- if ((ac97->id & 0xffffff00) == 0x414c4300) {
+ if ((ac97->id & 0xffffff00) == AC97_ID_ALC100) {
/* Fix H/W bug of ALC100/100P */
if (reg == AC97_MASTER || reg == AC97_HEADPHONE)
ac97->bus->write(ac97, AC97_RESET, 0); /* reset audio codec */
@@ -398,7 +399,7 @@ static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned sho
int change;
unsigned short old, new, cfg;
- down(&ac97->spec.ad18xx.mutex);
+ down(&ac97->mutex);
spin_lock(&ac97->reg_lock);
old = ac97->spec.ad18xx.pcmreg[codec];
new = (old & ~mask) | value;
@@ -418,7 +419,7 @@ static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned sho
cfg | 0x7000);
} else
spin_unlock(&ac97->reg_lock);
- up(&ac97->spec.ad18xx.mutex);
+ up(&ac97->mutex);
return change;
}
@@ -545,7 +546,7 @@ int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontr
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0x01;
ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask;
if (invert)
@@ -559,7 +560,7 @@ int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontr
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0x01;
unsigned short val;
val = (ucontrol->value.integer.value[0] & mask);
@@ -625,6 +626,40 @@ static int snd_ac97_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
(val1 << shift_left) | (val2 << shift_right));
}
+int snd_ac97_getput_page(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol,
+ int (*func)(snd_kcontrol_t *, snd_ctl_elem_value_t *))
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int err;
+
+ if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
+ (reg >= 0x60 && reg < 0x70)) {
+ unsigned short page_save;
+ unsigned short page = (kcontrol->private_value >> 25) & 0x0f;
+ down(&ac97->mutex); /* lock paging */
+ page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
+ err = func(kcontrol, ucontrol);
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
+ up(&ac97->mutex); /* unlock paging */
+ } else
+ err = func(kcontrol, ucontrol);
+ return err;
+}
+
+/* for rev2.3 paging */
+int snd_ac97_page_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_get_single);
+}
+
+/* for rev2.3 paging */
+int snd_ac97_page_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_put_single);
+}
+
static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = {
AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1)
@@ -1120,6 +1155,7 @@ static void snd_ac97_change_volume_params1(ac97_t * ac97, int reg, unsigned char
snd_ac97_write_cache(ac97, reg, 0x8000);
}
+/* check the volume resolution of center/lfe */
static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max)
{
unsigned short val, val1;
@@ -1135,6 +1171,7 @@ static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, un
snd_ac97_write_cache(ac97, reg, 0x8080);
}
+/* check whether the volume resolution is 4 or 5 bits */
static void snd_ac97_change_volume_params3(ac97_t * ac97, int reg, unsigned char *max)
{
unsigned short val, val1;
@@ -1150,6 +1187,18 @@ static void snd_ac97_change_volume_params3(ac97_t * ac97, int reg, unsigned char
snd_ac97_write_cache(ac97, reg, 0x8000);
}
+/* check whether the volume is mono or stereo */
+static int snd_ac97_is_stereo_vol(ac97_t *ac97, int reg)
+{
+ unsigned short val, val1, val2;
+ val = snd_ac97_read(ac97, reg);
+ val1 = val | 0x8000 | (0x01 << 8);
+ snd_ac97_write(ac97, reg, val1);
+ val2 = snd_ac97_read(ac97, reg);
+ snd_ac97_write(ac97, reg, val); /* restore */
+ return val1 == val2;
+}
+
static inline int printable(unsigned int x)
{
x &= 0xff;
@@ -1239,6 +1288,8 @@ static int snd_ac97_cmix_new(snd_card_t *card, const char *pfx, int reg, int che
}
+static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97);
+
static int snd_ac97_mixer_build(ac97_t * ac97)
{
snd_card_t *card = ac97->bus->card;
@@ -1293,11 +1344,8 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
/* build headphone controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE) || ac97->id == AC97_ID_STAC9708) {
- const char *name = ac97->id == AC97_ID_STAC9708 ?
- "Sigmatel Surround Playback" :
- "Headphone Playback";
- if ((err = snd_ac97_cmix_new(card, name, AC97_HEADPHONE, 1, ac97)) < 0)
+ if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
+ if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, 1, ac97)) < 0)
return err;
}
@@ -1332,7 +1380,8 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
return err;
- snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
+ snd_ac97_write_cache(ac97, AC97_PC_BEEP,
+ snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e);
}
/* build Phone controls */
@@ -1349,15 +1398,26 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
/* build MIC controls */
snd_ac97_change_volume_params3(ac97, AC97_MIC, &max);
- for (idx = 0; idx < 3; idx++) {
- if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)
+ if (snd_ac97_is_stereo_vol(ac97, AC97_MIC)) {
+ /* build stereo mic */
+ if ((err = snd_ac97_cmute_new(card, "Mic Playback Switch", AC97_MIC, ac97)) < 0)
return err;
- if (idx == 1) { // volume
- kctl->private_value &= ~(0xff << 16);
- kctl->private_value |= (int)max << 16;
+ if ((err = snd_ac97_cvol_new(card, "Mic Playback Volume", AC97_MIC, max, ac97)) < 0)
+ return err;
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic[2], ac97))) < 0)
+ return err;
+ } else {
+ /* build mono mic */
+ for (idx = 0; idx < 3; idx++) {
+ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)
+ return err;
+ if (idx == 1) { // volume
+ kctl->private_value &= ~(0xff << 16);
+ kctl->private_value |= (int)max << 16;
+ }
}
+ snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);
}
- snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);
/* build Line controls */
if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, 0, ac97)) < 0)
@@ -1410,9 +1470,7 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
if ((err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97)) < 0)
return err;
/* FIXME: C-Media chips have no PCM volume!! */
- if (/*ac97->id == 0x434d4941 ||*/
- ac97->id == 0x434d4942 ||
- ac97->id == 0x434d4961)
+ if (ac97->id == AC97_ID_CM9739)
snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f);
else {
if ((err = snd_ac97_cvol_new(card, "PCM Playback Volume", AC97_PCM, 31, ac97)) < 0)
@@ -1520,6 +1578,7 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
/* set default PCM S/PDIF params */
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20);
+ ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97);
}
ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
}
@@ -1675,7 +1734,7 @@ static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem)
if (snd_ac97_read(ac97, AC97_REC_GAIN) == 0x8a05)
return 0;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/100);
+ schedule_timeout(1);
} while (time_after_eq(end_time, jiffies));
return -ENODEV;
}
@@ -1774,6 +1833,7 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
ac97->bus = bus;
bus->codec[ac97->num] = ac97;
spin_lock_init(&ac97->reg_lock);
+ init_MUTEX(&ac97->mutex);
if (ac97->pci) {
pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor);
@@ -1789,8 +1849,14 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
bus->wait(ac97);
else {
udelay(50);
- if (ac97_reset_wait(ac97, HZ/2, 0) < 0 &&
- ac97_reset_wait(ac97, HZ/2, 1) < 0) {
+ if (ac97->scaps & AC97_SCAP_SKIP_AUDIO)
+ err = ac97_reset_wait(ac97, HZ/2, 1);
+ else {
+ err = ac97_reset_wait(ac97, HZ/2, 0);
+ if (err < 0)
+ err = ac97_reset_wait(ac97, 0, 1);
+ }
+ if (err < 0) {
snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num);
/* proceed anyway - it's often non-critical */
}
@@ -1803,20 +1869,6 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
snd_ac97_free(ac97);
return -EIO;
}
- /* AC97 audio codec chip revision detection. */
- /* Currently only Realtek ALC650 detection implemented. */
- switch(ac97->id & 0xfffffff0) {
- case 0x414c4720: /* ALC650 */
- reg = snd_ac97_read(ac97, AC97_ALC650_REVISION);
- if (((reg & 0x3f) >= 0) && ((reg & 0x3f) < 3))
- ac97->id = 0x414c4720; /* Old version */
- else if (((reg & 0x3f) >= 3) && ((reg & 0x3f) < 0x10))
- ac97->id = 0x414c4721; /* D version */
- else if ((reg&0x30) == 0x10)
- ac97->id = 0x414c4722; /* E version */
- else if ((reg&0x30) == 0x20)
- ac97->id = 0x414c4723; /* F version */
- }
/* test for AC'97 */
if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) {
@@ -1865,9 +1917,9 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
goto __ready_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/10);
+ schedule_timeout(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "AC'97 %d analog subsections not ready\n", ac97->num);
+ snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num);
}
/* FIXME: add powerdown control */
@@ -1898,9 +1950,9 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
goto __ready_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/10);
+ schedule_timeout(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
+ snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
}
__ready_ok:
@@ -1919,12 +1971,7 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
}
if (ac97->ext_id & AC97_EI_SPDIF) {
/* codec specific code (patch) should override these values */
- if (ac97->flags & AC97_CS_SPDIF)
- ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100;
- else if (ac97->id == AC97_ID_CM9739)
- ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000;
- else
- ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97);
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000;
}
if (ac97->ext_id & AC97_EI_VRM) { /* MIC VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);
@@ -1942,8 +1989,8 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
/* additional initializations */
if (bus->init)
bus->init(ac97);
- snd_ac97_get_name(ac97, ac97->id, name, 0);
- snd_ac97_get_name(NULL, ac97->id, name, 0); // ac97->id might be changed in the special setup code
+ snd_ac97_get_name(ac97, ac97->id, name, !ac97_is_audio(ac97));
+ snd_ac97_get_name(NULL, ac97->id, name, !ac97_is_audio(ac97)); // ac97->id might be changed in the special setup code
if (ac97_is_audio(ac97)) {
if (card->mixername[0] == '\0') {
strcpy(card->mixername, name);
@@ -2066,18 +2113,28 @@ void snd_ac97_resume(ac97_t *ac97)
snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0);
snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
- ac97->bus->write(ac97, AC97_MASTER, 0x8101);
- for (i = 0; i < 10; i++) {
- if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
- break;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
- /* FIXME: extra delay */
- ac97->bus->write(ac97, AC97_MASTER, 0x8000);
- if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ if (ac97_is_audio(ac97)) {
+ ac97->bus->write(ac97, AC97_MASTER, 0x8101);
+ for (i = HZ/10; i >= 0; i--) {
+ if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+ /* FIXME: extra delay */
+ ac97->bus->write(ac97, AC97_MASTER, 0x8000);
+ if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/4);
+ }
+ } else {
+ for (i = HZ/10; i >= 0; i--) {
+ unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+ if (val != 0xffff && (val & 1) != 0)
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
}
__reset_ready:
@@ -2151,42 +2208,57 @@ __reset_ready:
/*
*/
-int snd_ac97_remove_ctl(ac97_t *ac97, const char *name)
+static void set_ctl_name(char *dst, const char *src, const char *suffix)
+{
+ if (suffix)
+ sprintf(dst, "%s %s", src, suffix);
+ else
+ strcpy(dst, src);
+}
+
+int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix)
{
snd_ctl_elem_id_t id;
memset(&id, 0, sizeof(id));
- strcpy(id.name, name);
+ set_ctl_name(id.name, name, suffix);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(ac97->bus->card, &id);
}
-static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name)
+static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name, const char *suffix)
{
snd_ctl_elem_id_t sid;
memset(&sid, 0, sizeof(sid));
- strcpy(sid.name, name);
+ set_ctl_name(sid.name, name, suffix);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(ac97->bus->card, &sid);
}
-int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst)
+int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix)
{
- snd_kcontrol_t *kctl = ctl_find(ac97, src);
+ snd_kcontrol_t *kctl = ctl_find(ac97, src, suffix);
if (kctl) {
- strcpy(kctl->id.name, dst);
+ set_ctl_name(kctl->id.name, dst, suffix);
return 0;
}
return -ENOENT;
}
-int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2)
+/* rename both Volume and Switch controls - don't check the return value */
+void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst)
+{
+ snd_ac97_rename_ctl(ac97, src, dst, "Switch");
+ snd_ac97_rename_ctl(ac97, src, dst, "Volume");
+}
+
+int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix)
{
snd_kcontrol_t *kctl1, *kctl2;
- kctl1 = ctl_find(ac97, s1);
- kctl2 = ctl_find(ac97, s2);
+ kctl1 = ctl_find(ac97, s1, suffix);
+ kctl2 = ctl_find(ac97, s2, suffix);
if (kctl1 && kctl2) {
- strcpy(kctl1->id.name, s2);
- strcpy(kctl2->id.name, s1);
+ set_ctl_name(kctl1->id.name, s2, suffix);
+ set_ctl_name(kctl2->id.name, s1, suffix);
return 0;
}
return -ENOENT;
@@ -2194,26 +2266,22 @@ int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2)
static int swap_headphone(ac97_t *ac97, int remove_master)
{
- /* FIXME: error checks.. */
if (remove_master) {
- if (ctl_find(ac97, "Headphone Playback Switch") == NULL)
+ if (ctl_find(ac97, "Headphone Playback Switch", NULL) == NULL)
return 0;
- snd_ac97_remove_ctl(ac97, "Master Playback Switch");
- snd_ac97_remove_ctl(ac97, "Master Playback Volume");
- } else {
- snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch");
- snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume");
- }
- snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
- snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
+ snd_ac97_remove_ctl(ac97, "Master Playback", "Switch");
+ snd_ac97_remove_ctl(ac97, "Master Playback", "Volume");
+ } else
+ snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Line-Out Playback");
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
return 0;
}
static int swap_surround(ac97_t *ac97)
{
/* FIXME: error checks.. */
- snd_ac97_swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch");
- snd_ac97_swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume");
+ snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Switch");
+ snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Volume");
return 0;
}
diff --git a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h
index fa75c06fde9a..24a9f6cc3ea4 100644
--- a/sound/pci/ac97/ac97_id.h
+++ b/sound/pci/ac97/ac97_id.h
@@ -45,7 +45,14 @@
#define AC97_ID_CS4201 0x43525948
#define AC97_ID_CS4205 0x43525958
#define AC97_ID_CS_MASK 0xfffffff8 /* bit 0-2: rev */
+#define AC97_ID_ALC100 0x414c4300
#define AC97_ID_ALC650 0x414c4720
+#define AC97_ID_ALC650D 0x414c4721
+#define AC97_ID_ALC650E 0x414c4722
+#define AC97_ID_ALC650F 0x414c4723
+#define AC97_ID_ALC655 0x414c4760
+#define AC97_ID_ALC658 0x414c4780
+#define AC97_ID_ALC850 0x414c4790
#define AC97_ID_YMF753 0x594d4803
#define AC97_ID_VT1616 0x49434551
#define AC97_ID_CM9738 0x434d4941
diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h
index 838656f76177..27d3236eed63 100644
--- a/sound/pci/ac97/ac97_local.h
+++ b/sound/pci/ac97/ac97_local.h
@@ -23,10 +23,15 @@
*/
#define AC97_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24))
+#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) | ((page) << 25))
#define AC97_SINGLE(xname, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
.get = snd_ac97_get_single, .put = snd_ac97_put_single, \
.private_value = AC97_SINGLE_VALUE(reg, shift, mask, invert) }
+#define AC97_PAGE_SINGLE(xname, reg, shift, mask, invert, page) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
+ .get = snd_ac97_page_get_single, .put = snd_ac97_page_put_single, \
+ .private_value = AC97_PAGE_SINGLE_VALUE(reg, shift, mask, invert, page) }
/* ac97_codec.c */
extern const char *snd_ac97_stereo_enhancements[];
@@ -37,10 +42,13 @@ void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem);
int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_page_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_page_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit);
-int snd_ac97_remove_ctl(ac97_t *ac97, const char *name);
-int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst);
-int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2);
+int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix);
+int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix);
+int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix);
+void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst);
/* ac97_proc.c */
void snd_ac97_bus_proc_init(ac97_bus_t * ac97);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 85124051ef70..0db027495571 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -51,6 +51,21 @@ static int patch_build_controls(ac97_t * ac97, const snd_kcontrol_new_t *control
return 0;
}
+/* set to the page, update bits and restore the page */
+static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page)
+{
+ unsigned short page_save;
+ int ret;
+
+ down(&ac97->mutex);
+ page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
+ ret = snd_ac97_update_bits(ac97, reg, mask, value);
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
+ up(&ac97->mutex); /* unlock paging */
+ return ret;
+}
+
/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */
@@ -204,7 +219,7 @@ static int patch_yamaha_ymf753_3d(ac97_t * ac97)
if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control - Wide");
- kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);
+ kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0)
return err;
@@ -315,7 +330,7 @@ static int patch_sigmatel_stac9700_3d(ac97_t * ac97)
if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
- kctl->private_value = AC97_3D_CONTROL | (3 << 16);
+ kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
return 0;
}
@@ -328,11 +343,11 @@ static int patch_sigmatel_stac9708_3d(ac97_t * ac97)
if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
- kctl->private_value = AC97_3D_CONTROL | (3 << 16);
+ kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 0, 3, 0);
if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
- kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16);
+ kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
return 0;
}
@@ -373,17 +388,23 @@ static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
.build_specific = patch_sigmatel_stac97xx_specific
};
-static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
- .build_3d = patch_sigmatel_stac9708_3d,
- .build_specific = patch_sigmatel_stac97xx_specific
-};
-
int patch_sigmatel_stac9700(ac97_t * ac97)
{
ac97->build_ops = &patch_sigmatel_stac9700_ops;
return 0;
}
+static int patch_sigmatel_stac9708_specific(ac97_t *ac97)
+{
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
+ return patch_sigmatel_stac97xx_specific(ac97);
+}
+
+static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
+ .build_3d = patch_sigmatel_stac9708_3d,
+ .build_specific = patch_sigmatel_stac9708_specific
+};
+
int patch_sigmatel_stac9708(ac97_t * ac97)
{
unsigned int codec72, codec6c;
@@ -467,11 +488,11 @@ static int snd_ac97_stac9758_output_jack_get(snd_kcontrol_t *kcontrol, snd_ctl_e
int shift = kcontrol->private_value;
unsigned short val;
- val = ac97->regs[AC97_SIGMATEL_OUTSEL];
- if (!((val >> shift) & 4))
+ val = ac97->regs[AC97_SIGMATEL_OUTSEL] >> shift;
+ if (!(val & 4))
ucontrol->value.enumerated.item[0] = 0;
else
- ucontrol->value.enumerated.item[0] = 1 + ((val >> shift) & 3);
+ ucontrol->value.enumerated.item[0] = 1 + (val & 3);
return 0;
}
@@ -480,6 +501,7 @@ static int snd_ac97_stac9758_output_jack_put(snd_kcontrol_t *kcontrol, snd_ctl_e
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
int shift = kcontrol->private_value;
unsigned short val;
+ int ret;
if (ucontrol->value.enumerated.item[0] > 4)
return -EINVAL;
@@ -487,8 +509,10 @@ static int snd_ac97_stac9758_output_jack_put(snd_kcontrol_t *kcontrol, snd_ctl_e
val = 0;
else
val = 4 | (ucontrol->value.enumerated.item[0] - 1);
- return snd_ac97_update_bits(ac97, AC97_SIGMATEL_OUTSEL,
- 7 << shift, val << shift);
+ ret = snd_ac97_update_bits(ac97, AC97_SIGMATEL_OUTSEL,
+ 7 << shift, val << shift);
+ up(&ac97->mutex);
+ return ret;
}
static int snd_ac97_stac9758_input_jack_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -521,8 +545,8 @@ static int snd_ac97_stac9758_input_jack_put(snd_kcontrol_t *kcontrol, snd_ctl_el
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
int shift = kcontrol->private_value;
- return snd_ac97_update_bits(ac97, AC97_SIGMATEL_INSEL, 7 << shift,
- ucontrol->value.enumerated.item[0] << shift);
+ return ac97_update_bits_page(ac97, AC97_SIGMATEL_INSEL, 7 << shift,
+ ucontrol->value.enumerated.item[0] << shift, 0);
}
static int snd_ac97_stac9758_phonesel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -550,8 +574,8 @@ static int snd_ac97_stac9758_phonesel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- return snd_ac97_update_bits(ac97, AC97_SIGMATEL_IOMISC, 3,
- ucontrol->value.enumerated.item[0]);
+ return ac97_update_bits_page(ac97, AC97_SIGMATEL_IOMISC, 3,
+ ucontrol->value.enumerated.item[0], 0);
}
#define STAC9758_OUTPUT_JACK(xname, shift) \
@@ -596,6 +620,14 @@ static int patch_sigmatel_stac9758_specific(ac97_t *ac97)
ARRAY_SIZE(snd_ac97_sigmatel_stac9758_controls));
if (err < 0)
return err;
+ /* DAC-A direct */
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Front Playback");
+ /* DAC-A to Mix = PCM */
+ /* DAC-B direct = Surround */
+ /* DAC-B to Mix */
+ snd_ac97_rename_vol_ctl(ac97, "Video Playback", "Surround Mix Playback");
+ /* DAC-C direct = Center/LFE */
+
return 0;
}
@@ -613,16 +645,16 @@ int patch_sigmatel_stac9758(ac97_t * ac97)
AC97_SIGMATEL_VARIOUS
};
static unsigned short def_regs[4] = {
- /* OUTSEL */ 0xd794,
+ /* OUTSEL */ 0xd794, /* CL:CL, SR:SR, LO:MX, LI:DS, MI:DS */
/* IOMISC */ 0x2001,
- /* INSEL */ 0x0201,
+ /* INSEL */ 0x0201, /* LI:LI, MI:M1 */
/* VARIOUS */ 0x0040
};
static unsigned short m675_regs[4] = {
- /* OUTSEL */ 0x9040,
- /* IOMISC */ 0x2102,
- /* INSEL */ 0x0203,
- /* VARIOUS */ 0x0041
+ /* OUTSEL */ 0xfc70, /* CL:MX, SR:MX, LO:DS, LI:MX, MI:DS */
+ /* IOMISC */ 0x2102, /* HP amp on */
+ /* INSEL */ 0x0203, /* LI:LI, MI:FR */
+ /* VARIOUS */ 0x0041 /* stereo mic */
};
unsigned short *pregs = def_regs;
int i;
@@ -635,6 +667,8 @@ int patch_sigmatel_stac9758(ac97_t * ac97)
// patch for SigmaTel
ac97->build_ops = &patch_sigmatel_stac9758_ops;
+ /* FIXME: assume only page 0 for writing cache */
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
for (i = 0; i < 4; i++)
snd_ac97_write_cache(ac97, regs[i], pregs[i]);
@@ -654,8 +688,10 @@ static int patch_cirrus_build_spdif(ac97_t * ac97)
{
int err;
+ /* con mask, pro mask, default */
if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)
return err;
+ /* switch, spsa */
if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0)
return err;
switch (ac97->id & AC97_ID_CS_MASK) {
@@ -714,8 +750,10 @@ static int patch_conexant_build_spdif(ac97_t * ac97)
{
int err;
+ /* con mask, pro mask, default */
if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)
return err;
+ /* switch */
if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0)
return err;
/* set default PCM S/PDIF params */
@@ -734,6 +772,7 @@ int patch_conexant(ac97_t * ac97)
ac97->build_ops = &patch_conexant_ops;
ac97->flags |= AC97_CX_SPDIF;
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
return 0;
}
@@ -821,8 +860,6 @@ int patch_ad1881(ac97_t * ac97)
unsigned short val;
int idx, num;
- init_MUTEX(&ac97->spec.ad18xx.mutex);
-
val = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, val);
codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
@@ -1114,10 +1151,8 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
static int patch_ad1888_specific(ac97_t *ac97)
{
/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
- snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch");
- snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume");
- snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
- snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
+ snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Master Surround Playback");
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
}
@@ -1213,7 +1248,7 @@ int patch_ad1985(ac97_t * ac97)
}
/*
- * realtek ALC65x codecs
+ * realtek ALC65x/850 codecs
*/
static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
{
@@ -1303,6 +1338,17 @@ int patch_alc650(ac97_t * ac97)
ac97->build_ops = &patch_alc650_ops;
+ /* determine the revision */
+ val = snd_ac97_read(ac97, AC97_ALC650_REVISION) & 0x3f;
+ if (val < 3)
+ ac97->id = 0x414c4720; /* Old version */
+ else if (val < 0x10)
+ ac97->id = 0x414c4721; /* D version */
+ else if (val < 0x20)
+ ac97->id = 0x414c4722; /* E version */
+ else if (val < 0x30)
+ ac97->id = 0x414c4723; /* F version */
+
/* revision E or F */
/* FIXME: what about revision D ? */
ac97->spec.dev_flags = (ac97->id == 0x414c4722 ||
@@ -1351,20 +1397,19 @@ static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- int change;
/* misc control; vrefout disable */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
ucontrol->value.integer.value[0] ? (1 << 12) : 0);
- change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
- ucontrol->value.integer.value[0] ? (1 << 10) : 0);
- return change;
+ return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10,
+ ucontrol->value.integer.value[0] ? (1 << 10) : 0,
+ 0);
}
static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
- AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
- AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
+ AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
+ AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mic As Center/LFE",
@@ -1391,7 +1436,6 @@ static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_
texts_658[uinfo->value.enumerated.item] :
texts_655[uinfo->value.enumerated.item]);
return 0;
-
}
static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
@@ -1410,13 +1454,15 @@ static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12,
- (unsigned short)ucontrol->value.enumerated.item[0]);
+
+ return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 3 << 12,
+ (unsigned short)ucontrol->value.enumerated.item[0],
+ 0);
}
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {
- AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
- AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0),
+ AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0),
+ AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Route",
@@ -1451,6 +1497,9 @@ int patch_alc655(ac97_t * ac97)
ac97->build_ops = &patch_alc655_ops;
+ /* assume only page 0 for writing cache */
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
+
/* adjust default values */
val = snd_ac97_read(ac97, 0x7a); /* misc control */
val |= (1 << 1); /* spdif input pin */
@@ -1469,6 +1518,120 @@ int patch_alc655(ac97_t * ac97)
return 0;
}
+
+#define AC97_ALC850_JACK_SELECT 0x76
+#define AC97_ALC850_MISC1 0x7a
+
+static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2;
+ return 0;
+}
+
+static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+ /* SURR 1kOhm (bit4), Amp (bit5) */
+ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
+ ucontrol->value.integer.value[0] ? (1<<5) : (1<<4));
+ /* LINE-IN = 0, SURROUND = 2 */
+ return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
+ ucontrol->value.integer.value[0] ? (2<<12) : (0<<12));
+}
+
+static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2;
+ return 0;
+}
+
+static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+ /* Vref disable (bit12), 1kOhm (bit13) */
+ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
+ ucontrol->value.integer.value[0] ? (1<<12) : (1<<13));
+ /* MIC-IN = 1, CENTER-LFE = 2 */
+ return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
+ ucontrol->value.integer.value[0] ? (2<<4) : (1<<4));
+}
+
+static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = {
+ AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line-In As Surround",
+ .info = snd_ac97_info_single,
+ .get = ac97_alc850_surround_get,
+ .put = ac97_alc850_surround_put,
+ .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic As Center/LFE",
+ .info = snd_ac97_info_single,
+ .get = ac97_alc850_mic_get,
+ .put = ac97_alc850_mic_put,
+ .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+ },
+
+};
+
+static int patch_alc850_specific(ac97_t *ac97)
+{
+ int err;
+
+ if ((err = patch_build_controls(ac97, snd_ac97_controls_alc850, ARRAY_SIZE(snd_ac97_controls_alc850))) < 0)
+ return err;
+ if (ac97->ext_id & AC97_EI_SPDIF) {
+ if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0)
+ return err;
+ }
+ return 0;
+}
+
+static struct snd_ac97_build_ops patch_alc850_ops = {
+ .build_specific = patch_alc850_specific
+};
+
+int patch_alc850(ac97_t *ac97)
+{
+ ac97->build_ops = &patch_alc850_ops;
+
+ ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */
+
+ /* assume only page 0 for writing cache */
+ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
+
+ /* adjust default values */
+ /* set default: spdif-in enabled,
+ spdif-in monitor off, spdif-in PCM off
+ center on mic off, surround on line-in off
+ duplicate front off
+ */
+ snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15);
+ /* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off
+ * Front Amp: on, Vref: enable, Center 1kOhm: on, Mix: on
+ */
+ snd_ac97_write_cache(ac97, 0x7a, (1<<1)|(1<<4)|(0<<5)|(1<<6)|
+ (1<<7)|(0<<12)|(1<<13)|(0<<14));
+ /* detection UIO2,3: all path floating, UIO3: MIC, Vref2: disable,
+ * UIO1: FRONT, Vref3: disable, UIO3: LINE, Front-Mic: mute
+ */
+ snd_ac97_write_cache(ac97, 0x76, (0<<0)|(0<<2)|(1<<4)|(1<<7)|(2<<8)|
+ (1<<11)|(0<<12)|(1<<15));
+
+ /* full DAC volume */
+ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808);
+ return 0;
+}
+
+
/*
* C-Media CM97xx codecs
*/
@@ -1599,8 +1762,10 @@ int patch_cm9739(ac97_t * ac97)
/* enable spdif in */
snd_ac97_write_cache(ac97, AC97_CM9739_SPDIF_CTRL,
snd_ac97_read(ac97, AC97_CM9739_SPDIF_CTRL) | 0x01);
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
} else {
ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */
+ ac97->rates[AC97_RATES_SPDIF] = 0;
}
/* set-up multi channel */
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 3e78799c593a..a619d7276057 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -49,6 +49,7 @@ int patch_ad1981b(ac97_t * ac97);
int patch_ad1985(ac97_t * ac97);
int patch_alc650(ac97_t * ac97);
int patch_alc655(ac97_t * ac97);
+int patch_alc850(ac97_t * ac97);
int patch_cm9738(ac97_t * ac97);
int patch_cm9739(ac97_t * ac97);
int patch_vt1616(ac97_t * ac97);
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
index 40b3e9fd8f5b..0a5865066018 100644
--- a/sound/pci/ac97/ac97_proc.c
+++ b/sound/pci/ac97/ac97_proc.c
@@ -292,9 +292,9 @@ static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buff
{
ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
+ down(&ac97->mutex);
if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86
int idx;
- down(&ac97->spec.ad18xx.mutex);
for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) {
/* select single codec */
@@ -305,7 +305,6 @@ static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buff
}
/* select all codecs */
snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
- up(&ac97->spec.ad18xx.mutex);
snd_iprintf(buffer, "\nAD18XX configuration\n");
snd_iprintf(buffer, "Unchained : 0x%04x,0x%04x,0x%04x\n",
@@ -319,6 +318,7 @@ static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buff
} else {
snd_ac97_proc_read_main(ac97, buffer, 0);
}
+ up(&ac97->mutex);
}
#ifdef CONFIG_SND_DEBUG
@@ -328,6 +328,7 @@ static void snd_ac97_proc_regs_write(snd_info_entry_t *entry, snd_info_buffer_t
ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
char line[64];
unsigned int reg, val;
+ down(&ac97->mutex);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
@@ -335,6 +336,7 @@ static void snd_ac97_proc_regs_write(snd_info_entry_t *entry, snd_info_buffer_t
if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff)
snd_ac97_write_cache(ac97, reg, val);
}
+ up(&ac97->mutex);
}
#endif
@@ -353,10 +355,10 @@ static void snd_ac97_proc_regs_read(snd_info_entry_t *entry,
{
ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
+ down(&ac97->mutex);
if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86
int idx;
- down(&ac97->spec.ad18xx.mutex);
for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx]) {
/* select single codec */
@@ -366,10 +368,10 @@ static void snd_ac97_proc_regs_read(snd_info_entry_t *entry,
}
/* select all codecs */
snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
- up(&ac97->spec.ad18xx.mutex);
} else {
snd_ac97_proc_regs_read_main(ac97, buffer, 0);
}
+ up(&ac97->mutex);
}
void snd_ac97_proc_init(ac97_t * ac97)
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 8869e7a68a27..a561b6625f1d 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1,5 +1,5 @@
/*
- * ALSA driver for ATI IXP 150/200/250 AC97 controllers
+ * ALSA driver for ATI IXP 150/200/250/300 AC97 controllers
*
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
*
@@ -1387,17 +1387,9 @@ static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock)
ac97.num = i;
ac97.scaps = AC97_SCAP_SKIP_MODEM;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
- if (chip->codec_not_ready_bits)
- /* codec(s) was detected but not available.
- * return the error
- */
- return err;
- else {
- /* codec(s) was NOT detected, so just ignore here */
- chip->ac97[i] = NULL; /* to be sure */
- snd_printd("atiixp: codec %d not found\n", i);
- continue;
- }
+ chip->ac97[i] = NULL; /* to be sure */
+ snd_printdd("atiixp: codec %d not available for audio\n", i);
+ continue;
}
codec_count++;
}
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index f1e417ca036d..1ac1659237b6 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
snd-ice17xx-ak4xxx-objs := ak4xxx.o
snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index a7a55a98bac1..26719f6ed5a7 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -44,6 +44,7 @@
#include "amp.h"
#include "revo.h"
#include "aureon.h"
+#include "vt1720_mobo.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -54,6 +55,7 @@ MODULE_DEVICES("{"
REVO_DEVICE_DESC
AMP_AUDIO2000_DEVICE_DESC
AUREON_DEVICE_DESC
+ VT1720_MOBO_DEVICE_DESC
"{VIA,VT1720},"
"{VIA,VT1724},"
"{ICEnsemble,Generic ICE1724},"
@@ -419,7 +421,7 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force
ice->cur_rate = rate;
/* check MT02 */
- if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) {
+ if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
val = old = inb(ICEMT1724(ice, I2S_FORMAT));
if (rate > 96000)
val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
@@ -446,15 +448,6 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force
if (ice->akm[i].ops.set_rate_val)
ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
}
-
- /* set up AC97 registers if needed */
- if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) && ice->ac97) {
- snd_ac97_set_rate(ice->ac97, AC97_PCM_FRONT_DAC_RATE, rate);
- snd_ac97_set_rate(ice->ac97, AC97_PCM_SURR_DAC_RATE, rate);
- snd_ac97_set_rate(ice->ac97, AC97_PCM_LFE_DAC_RATE, rate);
- snd_ac97_set_rate(ice->ac97, AC97_SPDIF, rate);
- snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, rate);
- }
}
static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream,
@@ -698,7 +691,7 @@ static snd_pcm_hardware_t snd_vt1724_2ch_stereo =
static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) {
+ if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
/* I2S */
if (ice->eeprom.data[ICE_EEP2_I2S] & 0x08)
return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
@@ -714,15 +707,9 @@ static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream)
ratec = AC97_RATES_FRONT_DAC;
else
ratec = AC97_RATES_ADC;
- runtime->hw.rates = ice->ac97->rates[ratec];
runtime->hw.rate_max = 48000;
- if (runtime->hw.rates == SNDRV_PCM_RATE_48000) {
- runtime->hw.rate_min = 48000;
- return 0;
- } else {
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
- return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48);
- }
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
+ return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48);
}
return 0;
}
@@ -1815,6 +1802,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_revo_cards,
snd_vt1724_amp_cards,
snd_vt1724_aureon_cards,
+ snd_vt1720_mobo_cards,
0,
};
@@ -1930,9 +1918,6 @@ static int __devinit snd_vt1724_chip_init(ice1712_t *ice)
outb(0, ICEREG1724(ice, POWERDOWN));
- /* read back to check the availability of SPDIF out */
- ice->eeprom.data[ICE_EEP2_SPDIF] = inb(ICEREG1724(ice, SPDIF_CFG));
-
return 0;
}
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
new file mode 100644
index 000000000000..5986f3561521
--- /dev/null
+++ b/sound/pci/ice1712/vt1720_mobo.c
@@ -0,0 +1,97 @@
+/*
+ * ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT)
+ *
+ * Lowlevel functions for VT1720-based motherboards
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ * 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 <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "vt1720_mobo.h"
+
+
+static int __devinit k8x800_init(ice1712_t *ice)
+{
+ ice->vt1720 = 1;
+
+ /* VT1616 codec */
+ ice->num_total_dacs = 6;
+ ice->num_total_adcs = 2;
+
+ /* WM8728 codec */
+ /* FIXME: TODO */
+
+ return 0;
+}
+
+static int __devinit k8x800_add_controls(ice1712_t *ice)
+{
+ /* FIXME: needs some quirks for VT1616? */
+ return 0;
+}
+
+/* EEPROM image */
+
+static unsigned char k8x800_eeprom[] __devinitdata = {
+ 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */
+ 0x02, /* ACLINK: ACLINK, packed */
+ 0x00, /* I2S: - */
+ 0x00, /* SPDIF: - */
+ 0xff, /* GPIO_DIR */
+ 0xff, /* GPIO_DIR1 */
+ 0x00, /* - */
+ 0xff, /* GPIO_MASK */
+ 0xff, /* GPIO_MASK1 */
+ 0x00, /* - */
+ 0x00, /* GPIO_STATE */
+ 0x00, /* GPIO_STATE1 */
+ 0x00, /* - */
+};
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
+ {
+ .subvendor = VT1720_SUBDEVICE_K8X800,
+ .name = "Albatron K8X800 Pro II",
+ .model = "k8x800",
+ .chip_init = k8x800_init,
+ .build_controls = k8x800_add_controls,
+ .eeprom_size = sizeof(k8x800_eeprom),
+ .eeprom_data = k8x800_eeprom,
+ },
+ {
+ .subvendor = VT1720_SUBDEVICE_ZNF3_150,
+ .name = "Chaintech ZNF3-150",
+ /* identical with k8x800 */
+ .chip_init = k8x800_init,
+ .build_controls = k8x800_add_controls,
+ .eeprom_size = sizeof(k8x800_eeprom),
+ .eeprom_data = k8x800_eeprom,
+ },
+ { } /* terminator */
+};
+
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
new file mode 100644
index 000000000000..aba19bb780de
--- /dev/null
+++ b/sound/pci/ice1712/vt1720_mobo.h
@@ -0,0 +1,35 @@
+#ifndef __SOUND_VT1720_MOBO_H
+#define __SOUND_VT1720_MOBO_H
+
+/*
+ * ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT)
+ *
+ * Lowlevel functions for VT1720-based motherboards
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ * 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
+ *
+ */
+
+#define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\
+ "{Chaintech,ZNF3-150},"
+
+#define VT1720_SUBDEVICE_K8X800 0xf217052c
+#define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6
+
+extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[];
+
+#endif /* __SOUND_VT1720_MOBO_H */
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 67e5edd5b5c2..f69510f54c48 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1060,19 +1060,6 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst
int err;
unsigned long flags;
struct via_rate_lock *ratep;
- struct ratetbl {
- int rate;
- unsigned int bit;
- } ratebits[] = {
- {8000, SNDRV_PCM_RATE_8000},
- {11025, SNDRV_PCM_RATE_11025},
- {16000, SNDRV_PCM_RATE_16000},
- {22050, SNDRV_PCM_RATE_22050},
- {32000, SNDRV_PCM_RATE_32000},
- {44100, SNDRV_PCM_RATE_44100},
- {48000, SNDRV_PCM_RATE_48000},
- };
- int i;
runtime->hw = snd_via82xx_hw;
@@ -1080,10 +1067,10 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst
ratep = &chip->rates[viadev->direction];
spin_lock_irqsave(&ratep->lock, flags);
ratep->used++;
- if (chip->spdif_on) {
- runtime->hw.rates = SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000;
- runtime->hw.rate_min = 32000;
- runtime->hw.rate_max = 48000;
+ if (chip->spdif_on && viadev->reg_offset == 0x30) {
+ /* DXS#3 and spdif is on */
+ runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF];
+ snd_pcm_limit_hw_rates(runtime);
} else if (chip->dxs_fixed && viadev->reg_offset < 0x40) {
/* fixed DXS playback rate */
runtime->hw.rates = SNDRV_PCM_RATE_48000;
@@ -1091,27 +1078,10 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst
} else if (! ratep->rate) {
int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
runtime->hw.rates = chip->ac97->rates[idx];
- for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) {
- if (runtime->hw.rates & ratebits[i].bit) {
- runtime->hw.rate_min = ratebits[i].rate;
- break;
- }
- }
- for (i = ARRAY_SIZE(ratebits) - 1; i >= 0; i--) {
- if (runtime->hw.rates & ratebits[i].bit) {
- runtime->hw.rate_max = ratebits[i].rate;
- break;
- }
- }
+ snd_pcm_limit_hw_rates(runtime);
} else {
/* a fixed rate */
runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
- for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) {
- if (ratep->rate == ratebits[i].rate) {
- runtime->hw.rates = ratebits[i].bit;
- break;
- }
- }
runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate;
}
spin_unlock_irqrestore(&ratep->lock, flags);
@@ -1363,6 +1333,10 @@ static int __devinit snd_via8233a_pcm_new(via82xx_t *chip)
snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
return err;
+ /* SPDIF supported? */
+ if (! ac97_can_spdif(chip->ac97))
+ return 0;
+
/* PCM #1: DXS3 playback (for spdif) */
err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 0, &pcm);
if (err < 0)
@@ -1660,9 +1634,11 @@ static int snd_via8233_init_misc(via82xx_t *chip, int dev)
if (err < 0)
return err;
}
- err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip));
- if (err < 0)
- return err;
+ if (ac97_can_spdif(chip->ac97)) {
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip));
+ if (err < 0)
+ return err;
+ }
if (chip->chip_type != TYPE_VIA8233A) {
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip));
if (err < 0)
@@ -1672,6 +1648,7 @@ static int snd_via8233_init_misc(via82xx_t *chip, int dev)
/* select spdif data slot 10/11 */
pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &val);
val = (val & ~VIA8233_SPDIF_SLOT_MASK) | VIA8233_SPDIF_SLOT_1011;
+ val &= ~VIA8233_SPDIF_DX3; /* SPDIF off as default */
pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, val);
return 0;
@@ -2114,6 +2091,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
{ .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
{ .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
+ { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
{ .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
{ .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
{ .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */