summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/compress_offload.c26
-rw-r--r--sound/core/control.c1
-rw-r--r--sound/core/info.c7
-rw-r--r--sound/core/info_oss.c3
-rw-r--r--sound/core/oss/mixer_oss.c2
-rw-r--r--sound/core/pcm.c4
-rw-r--r--sound/core/pcm_lib.c214
-rw-r--r--sound/core/pcm_memory.c26
-rw-r--r--sound/core/seq/seq_device.c2
-rw-r--r--sound/core/sgbuf.c27
-rw-r--r--sound/core/sound.c3
-rw-r--r--sound/drivers/opl4/opl4_synth.c9
-rw-r--r--sound/isa/Kconfig12
-rw-r--r--sound/isa/Makefile2
-rw-r--r--sound/isa/ad1816a/ad1816a.c64
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c38
-rw-r--r--sound/isa/cmi8328.c483
-rw-r--r--sound/isa/gus/interwave.c5
-rw-r--r--sound/isa/opti9xx/miro.c15
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c14
-rw-r--r--sound/isa/sb/emu8000.c15
-rw-r--r--sound/last.c1
-rw-r--r--sound/pci/ac97/ac97_patch.c24
-rw-r--r--sound/pci/ali5451/ali5451.c10
-rw-r--r--sound/pci/als300.c2
-rw-r--r--sound/pci/als4000.c4
-rw-r--r--sound/pci/asihpi/asihpi.c2
-rw-r--r--sound/pci/atiixp.c15
-rw-r--r--sound/pci/atiixp_modem.c6
-rw-r--r--sound/pci/azt3328.c6
-rw-r--r--sound/pci/ca0106/ca0106.h4
-rw-r--r--sound/pci/ca0106/ca0106_main.c30
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c4
-rw-r--r--sound/pci/cmipci.c12
-rw-r--r--sound/pci/cs4281.c6
-rw-r--r--sound/pci/cs46xx/cs46xx.c2
-rw-r--r--sound/pci/cs46xx/cs46xx.h2
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c8
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.h2
-rw-r--r--sound/pci/cs46xx/dsp_spos.c8
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c2
-rw-r--r--sound/pci/cs5530.c3
-rw-r--r--sound/pci/cs5535audio/Makefile2
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c2
-rw-r--r--sound/pci/ctxfi/ctatc.c4
-rw-r--r--sound/pci/ctxfi/ctatc.h2
-rw-r--r--sound/pci/ctxfi/cthardware.h2
-rw-r--r--sound/pci/ctxfi/cthw20k1.c4
-rw-r--r--sound/pci/ctxfi/cthw20k2.c4
-rw-r--r--sound/pci/ctxfi/ctmixer.c4
-rw-r--r--sound/pci/ctxfi/ctmixer.h2
-rw-r--r--sound/pci/ctxfi/ctpcm.c52
-rw-r--r--sound/pci/ctxfi/xfi.c2
-rw-r--r--sound/pci/echoaudio/echoaudio.c12
-rw-r--r--sound/pci/echoaudio/echoaudio.h2
-rw-r--r--sound/pci/emu10k1/emu10k1.c4
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c8
-rw-r--r--sound/pci/emu10k1/emu10k1x.c21
-rw-r--r--sound/pci/emu10k1/emufx.c2
-rw-r--r--sound/pci/emu10k1/memory.c4
-rw-r--r--sound/pci/emu10k1/p16v.c2
-rw-r--r--sound/pci/ens1370.c70
-rw-r--r--sound/pci/es1938.c6
-rw-r--r--sound/pci/es1968.c12
-rw-r--r--sound/pci/fm801.c13
-rw-r--r--sound/pci/hda/Kconfig10
-rw-r--r--sound/pci/hda/hda_auto_parser.c7
-rw-r--r--sound/pci/hda/hda_codec.c270
-rw-r--r--sound/pci/hda/hda_codec.h82
-rw-r--r--sound/pci/hda/hda_generic.c8
-rw-r--r--sound/pci/hda/hda_hwdep.c43
-rw-r--r--sound/pci/hda/hda_intel.c306
-rw-r--r--sound/pci/hda/hda_jack.c5
-rw-r--r--sound/pci/hda/hda_local.h2
-rw-r--r--sound/pci/hda/hda_proc.c9
-rw-r--r--sound/pci/hda/hda_trace.h26
-rw-r--r--sound/pci/hda/patch_analog.c90
-rw-r--r--sound/pci/hda/patch_cirrus.c225
-rw-r--r--sound/pci/hda/patch_conexant.c31
-rw-r--r--sound/pci/hda/patch_hdmi.c407
-rw-r--r--sound/pci/hda/patch_realtek.c19
-rw-r--r--sound/pci/hda/patch_sigmatel.c95
-rw-r--r--sound/pci/hda/patch_via.c37
-rw-r--r--sound/pci/ice1712/aureon.c4
-rw-r--r--sound/pci/ice1712/ice1712.h2
-rw-r--r--sound/pci/ice1712/ice1724.c4
-rw-r--r--sound/pci/ice1712/juli.c4
-rw-r--r--sound/pci/ice1712/prodigy_hifi.c4
-rw-r--r--sound/pci/intel8x0.c24
-rw-r--r--sound/pci/intel8x0m.c4
-rw-r--r--sound/pci/korg1212/korg1212.c4
-rw-r--r--sound/pci/maestro3.c10
-rw-r--r--sound/pci/nm256/nm256.c4
-rw-r--r--sound/pci/oxygen/oxygen.c2
-rw-r--r--sound/pci/oxygen/oxygen.h2
-rw-r--r--sound/pci/oxygen/oxygen_lib.c4
-rw-r--r--sound/pci/oxygen/virtuoso.c2
-rw-r--r--sound/pci/pcxhr/pcxhr.c24
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c6
-rw-r--r--sound/pci/riptide/riptide.c6
-rw-r--r--sound/pci/sis7019.c6
-rw-r--r--sound/pci/trident/trident.c2
-rw-r--r--sound/pci/trident/trident_main.c4
-rw-r--r--sound/pci/via82xx.c33
-rw-r--r--sound/pci/via82xx_modem.c4
-rw-r--r--sound/pci/vx222/vx222.c2
-rw-r--r--sound/pci/ymfpci/ymfpci.c2
-rw-r--r--sound/pci/ymfpci/ymfpci.h2
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c26
-rw-r--r--sound/soc/soc-dmaengine-pcm.c6
-rw-r--r--sound/usb/6fire/firmware.c5
-rw-r--r--sound/usb/card.c2
-rw-r--r--sound/usb/card.h7
-rw-r--r--sound/usb/endpoint.c39
-rw-r--r--sound/usb/endpoint.h5
-rw-r--r--sound/usb/helper.c5
-rw-r--r--sound/usb/mixer.c7
-rw-r--r--sound/usb/pcm.c126
-rw-r--r--sound/usb/quirks-table.h53
-rw-r--r--sound/usb/quirks.c24
-rw-r--r--sound/usb/quirks.h10
121 files changed, 2750 insertions, 763 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index eb60cb8dbb8..c40ae573346 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -425,6 +425,26 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
return 0;
}
+static int snd_compress_check_input(struct snd_compr_params *params)
+{
+ /* first let's check the buffer parameter's */
+ if (params->buffer.fragment_size == 0 ||
+ params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
+ return -EINVAL;
+
+ /* now codec parameters */
+ if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
+ return -EINVAL;
+
+ if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
+ return -EINVAL;
+
+ if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
+ return -EINVAL;
+
+ return 0;
+}
+
static int
snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
{
@@ -443,11 +463,17 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
retval = -EFAULT;
goto out;
}
+
+ retval = snd_compress_check_input(params);
+ if (retval)
+ goto out;
+
retval = snd_compr_allocate_buffer(stream, params);
if (retval) {
retval = -ENOMEM;
goto out;
}
+
retval = stream->ops->set_params(stream, params);
if (retval)
goto out;
diff --git a/sound/core/control.c b/sound/core/control.c
index 2487a6bb1c5..7e86a5b9f3b 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -246,6 +246,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
kctl.count = ncontrol->count ? ncontrol->count : 1;
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
(ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE|
SNDRV_CTL_ELEM_ACCESS_INACTIVE|
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
diff --git a/sound/core/info.c b/sound/core/info.c
index c1e611c65c8..6b368d25073 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -28,7 +28,7 @@
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
-#include <sound/version.h>
+#include <linux/utsname.h>
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <stdarg.h>
@@ -986,9 +986,8 @@ static struct snd_info_entry *snd_info_version_entry;
static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
snd_iprintf(buffer,
- "Advanced Linux Sound Architecture Driver Version "
- CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
- );
+ "Advanced Linux Sound Architecture Driver Version k%s.\n",
+ init_utsname()->release);
}
static int __init snd_info_version_init(void)
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index cf42ab5080e..83c29dbff9c 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -26,7 +26,6 @@
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
-#include <sound/version.h>
#include <linux/utsname.h>
#include <linux/mutex.h>
@@ -94,7 +93,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
static void snd_sndstat_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
+ snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA emulation code)\n");
snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
init_utsname()->sysname,
init_utsname()->nodename,
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 18297f7f2c5..29f6ded0255 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1046,6 +1046,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
if (kctl->info(kctl, uinfo)) {
up_read(&mixer->card->controls_rwsem);
+ kfree(uinfo);
return 0;
}
strcpy(str, ptr->name);
@@ -1061,6 +1062,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
uinfo->value.enumerated.item = slot.capture_item;
if (kctl->info(kctl, uinfo)) {
up_read(&mixer->card->controls_rwsem);
+ kfree(uinfo);
return 0;
}
if (!strcmp(uinfo->value.enumerated.name, str)) {
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 1a3070b4e5b..f2991940b27 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1105,6 +1105,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
break;
}
snd_unregister_device(devtype, pcm->card, pcm->device);
+ if (pcm->streams[cidx].chmap_kctl) {
+ snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
+ pcm->streams[cidx].chmap_kctl = NULL;
+ }
}
unlock:
mutex_unlock(&register_mutex);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 7ae67192339..f42c10a4331 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -26,6 +26,7 @@
#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -2302,3 +2303,216 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL(snd_pcm_lib_readv);
+
+/*
+ * standard channel mapping helpers
+ */
+
+/* default channel maps for multi-channel playbacks, up to 8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+ { .channels = 8,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
+
+/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 8,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
+
+static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
+{
+ if (ch > info->max_channels)
+ return false;
+ return !info->channel_mask || (info->channel_mask & (1U << ch));
+}
+
+static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 0;
+ uinfo->count = info->max_channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+ return 0;
+}
+
+/* get callback for channel map ctl element
+ * stores the channel position firstly matching with the current channels
+ */
+static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ const struct snd_pcm_chmap_elem *map;
+
+ if (snd_BUG_ON(!info->chmap))
+ return -EINVAL;
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+ for (map = info->chmap; map->channels; map++) {
+ int i;
+ if (map->channels == substream->runtime->channels &&
+ valid_chmap_channels(info, map->channels)) {
+ for (i = 0; i < map->channels; i++)
+ ucontrol->value.integer.value[i] = map->map[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/* tlv callback for channel map ctl element
+ * expands the pre-defined channel maps in a form of TLV
+ */
+static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ const struct snd_pcm_chmap_elem *map;
+ unsigned int __user *dst;
+ int c, count = 0;
+
+ if (snd_BUG_ON(!info->chmap))
+ return -EINVAL;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+ return -EFAULT;
+ size -= 8;
+ dst = tlv + 2;
+ for (map = info->chmap; map->channels; map++) {
+ int chs_bytes = map->channels * 4;
+ if (!valid_chmap_channels(info, map->channels))
+ continue;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
+ put_user(chs_bytes, dst + 1))
+ return -EFAULT;
+ dst += 2;
+ size -= 8;
+ count += 8;
+ if (size < chs_bytes)
+ return -ENOMEM;
+ size -= chs_bytes;
+ count += chs_bytes;
+ for (c = 0; c < map->channels; c++) {
+ if (put_user(map->map[c], dst))
+ return -EFAULT;
+ dst++;
+ }
+ }
+ if (put_user(count, tlv + 1))
+ return -EFAULT;
+ return 0;
+}
+
+static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ info->pcm->streams[info->stream].chmap_kctl = NULL;
+ kfree(info);
+}
+
+/**
+ * snd_pcm_add_chmap_ctls - create channel-mapping control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @chmap: channel map elements (for query)
+ * @max_channels: the max number of channels for the stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_chmap instance if non-NULL
+ *
+ * Create channel-mapping control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_chmap_elem *chmap,
+ int max_channels,
+ unsigned long private_value,
+ struct snd_pcm_chmap **info_ret)
+{
+ struct snd_pcm_chmap *info;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = pcm_chmap_ctl_info,
+ .get = pcm_chmap_ctl_get,
+ .tlv.c = pcm_chmap_ctl_tlv,
+ };
+ int err;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pcm = pcm;
+ info->stream = stream;
+ info->chmap = chmap;
+ info->max_channels = max_channels;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ knew.name = "Playback Channel Map";
+ else
+ knew.name = "Capture Channel Map";
+ knew.device = pcm->device;
+ knew.count = pcm->streams[stream].substream_count;
+ knew.private_value = private_value;
+ info->kctl = snd_ctl_new1(&knew, info);
+ if (!info->kctl) {
+ kfree(info);
+ return -ENOMEM;
+ }
+ info->kctl->private_free = pcm_chmap_ctl_private_free;
+ err = snd_ctl_add(pcm->card, info->kctl);
+ if (err < 0)
+ return err;
+ pcm->streams[stream].chmap_kctl = info->kctl;
+ if (info_ret)
+ *info_ret = info;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 957131366dd..69e01c4fc32 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -327,32 +327,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
}
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-
-/*
- * compute the max chunk size with continuous pages on sg-buffer
- */
-unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
- unsigned int ofs, unsigned int size)
-{
- struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
- unsigned int start, end, pg;
-
- start = ofs >> PAGE_SHIFT;
- end = (ofs + size - 1) >> PAGE_SHIFT;
- /* check page continuity */
- pg = sg->table[start].addr >> PAGE_SHIFT;
- for (;;) {
- start++;
- if (start > end)
- break;
- pg++;
- if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
- return (start << PAGE_SHIFT) - ofs;
- }
- /* ok, all on continuous pages */
- return size;
-}
-EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);
#endif /* CONFIG_SND_DMA_SGBUF */
/**
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 5cf8d65ed5e..60e8fc1b344 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -569,5 +569,7 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers);
EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
+#ifdef CONFIG_MODULES
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
+#endif
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index d0f00356fc1..0a418503ec4 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
+#include <linux/export.h>
#include <sound/memalloc.h>
@@ -136,3 +137,29 @@ void *snd_malloc_sgbuf_pages(struct device *device,
snd_free_sgbuf_pages(dmab); /* free the table */
return NULL;
}
+
+/*
+ * compute the max chunk size with continuous pages on sg-buffer
+ */
+unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
+ unsigned int ofs, unsigned int size)
+{
+ struct snd_sg_buf *sg = dmab->private_data;
+ unsigned int start, end, pg;
+
+ start = ofs >> PAGE_SHIFT;
+ end = (ofs + size - 1) >> PAGE_SHIFT;
+ /* check page continuity */
+ pg = sg->table[start].addr >> PAGE_SHIFT;
+ for (;;) {
+ start++;
+ if (start > end)
+ break;
+ pg++;
+ if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
+ return (start << PAGE_SHIFT) - ofs;
+ }
+ /* ok, all on continuous pages */
+ return size;
+}
+EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 28f35593a75..643976000ce 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -27,7 +27,6 @@
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
-#include <sound/version.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <linux/kmod.h>
@@ -468,7 +467,7 @@ static int __init alsa_sound_init(void)
}
snd_info_minor_register();
#ifndef MODULE
- printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
+ printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");
#endif
return 0;
}
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 49b9e240915..4b91adc0238 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -504,8 +504,7 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0; i < voices; i++) {
voice[i] = snd_opl4_get_voice(opl4);
- list_del(&voice[i]->list);
- list_add_tail(&voice[i]->list, &opl4->on_voices);
+ list_move_tail(&voice[i]->list, &opl4->on_voices);
voice[i]->chan = chan;
voice[i]->note = note;
voice[i]->velocity = vel & 0x7f;
@@ -555,8 +554,7 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
- list_del(&voice->list);
- list_add_tail(&voice->list, &opl4->off_voices);
+ list_move_tail(&voice->list, &opl4->off_voices);
voice->reg_misc &= ~OPL4_KEY_ON_BIT;
snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
@@ -571,8 +569,7 @@ void snd_opl4_note_off(void *private_data, int note, int vel, struct snd_midi_ch
static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
- list_del(&voice->list);
- list_add_tail(&voice->list, &opl4->off_voices);
+ list_move_tail(&voice->list, &opl4->off_voices);
voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;
snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 52064cfa91f..a38d9643e9d 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -117,6 +117,18 @@ config SND_AZT2320
To compile this driver as a module, choose M here: the module
will be called snd-azt2320.
+config SND_CMI8328
+ tristate "C-Media CMI8328"
+ select SND_WSS_LIB
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
+ help
+ Say Y here to include support for soundcards based on the
+ C-Media CMI8328 chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-cmi8328.
+
config SND_CMI8330
tristate "C-Media CMI8330"
select SND_WSS_LIB
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 8d781e419e2..9a15f1497b1 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -6,6 +6,7 @@
snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
+snd-cmi8328-objs := cmi8328.o
snd-cmi8330-objs := cmi8330.o
snd-es18xx-objs := es18xx.o
snd-opl3sa2-objs := opl3sa2.o
@@ -16,6 +17,7 @@ snd-sscape-objs := sscape.o
obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
+obj-$(CONFIG_SND_CMI8328) += snd-cmi8328.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 94b83b6e46a..2c2f829c3fd 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -63,11 +63,6 @@ MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard.");
module_param_array(clockfreq, int, NULL, 0444);
MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
-struct snd_card_ad1816a {
- struct pnp_dev *dev;
- struct pnp_dev *devmpu;
-};
-
static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
/* Analog Devices AD1815 */
{ .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } },
@@ -99,25 +94,16 @@ MODULE_DEVICE_TABLE(pnp_card, snd_ad1816a_pnpids);
#define DRIVER_NAME "snd-card-ad1816a"
-static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acard,
- struct pnp_card_link *card,
+static int __devinit snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
int err;
- acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL)
+ pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (pdev == NULL)
return -EBUSY;
- acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
- if (acard->devmpu == NULL) {
- mpu_port[dev] = -1;
- snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
- }
-
- pdev = acard->dev;
-
err = pnp_activate_dev(pdev);
if (err < 0) {
printk(KERN_ERR PFX "AUDIO PnP configure failure\n");
@@ -130,16 +116,17 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- if (acard->devmpu == NULL)
+ pdev = pnp_request_card_device(card, id->devs[1].id, NULL);
+ if (pdev == NULL) {
+ mpu_port[dev] = -1;
+ snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
return 0;
-
- pdev = acard->devmpu;
+ }
err = pnp_activate_dev(pdev);
if (err < 0) {
printk(KERN_ERR PFX "MPU401 PnP configure failure\n");
mpu_port[dev] = -1;
- acard->devmpu = NULL;
} else {
mpu_port[dev] = pnp_port_start(pdev, 0);
mpu_irq[dev] = pnp_irq(pdev, 0);
@@ -153,18 +140,17 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
{
int error;
struct snd_card *card;
- struct snd_card_ad1816a *acard;
struct snd_ad1816a *chip;
struct snd_opl3 *opl3;
struct snd_timer *timer;
error = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_ad1816a), &card);
+ sizeof(struct snd_ad1816a), &card);
if (error < 0)
return error;
- acard = card->private_data;
+ chip = card->private_data;
- if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
+ if ((error = snd_card_ad1816a_pnp(dev, pcard, pid))) {
snd_card_free(card);
return error;
}
@@ -174,7 +160,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
irq[dev],
dma1[dev],
dma2[dev],
- &chip)) < 0) {
+ chip)) < 0) {
snd_card_free(card);
return error;
}
@@ -258,13 +244,37 @@ static void __devexit snd_ad1816a_pnp_remove(struct pnp_card_link * pcard)
pnp_set_card_drvdata(pcard, NULL);
}
+#ifdef CONFIG_PM
+static int snd_ad1816a_pnp_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_ad1816a_suspend(card->private_data);
+ return 0;
+}
+
+static int snd_ad1816a_pnp_resume(struct pnp_card_link *pcard)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+ snd_ad1816a_resume(card->private_data);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
static struct pnp_card_driver ad1816a_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "ad1816a",
.id_table = snd_ad1816a_pnpids,
.probe = snd_ad1816a_pnp_detect,
.remove = __devexit_p(snd_ad1816a_pnp_remove),
- /* FIXME: suspend/resume */
+#ifdef CONFIG_PM
+ .suspend = snd_ad1816a_pnp_suspend,
+ .resume = snd_ad1816a_pnp_resume,
+#endif
};
static int __init alsa_card_ad1816a_init(void)
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 177eed3271b..db64df6023e 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -491,7 +491,7 @@ static int snd_ad1816a_capture_close(struct snd_pcm_substream *substream)
}
-static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
+static void snd_ad1816a_init(struct snd_ad1816a *chip)
{
unsigned long flags;
@@ -511,6 +511,32 @@ static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
spin_unlock_irqrestore(&chip->lock, flags);
}
+#ifdef CONFIG_PM
+void snd_ad1816a_suspend(struct snd_ad1816a *chip)
+{
+ int reg;
+ unsigned long flags;
+
+ snd_pcm_suspend_all(chip->pcm);
+ spin_lock_irqsave(&chip->lock, flags);
+ for (reg = 0; reg < 48; reg++)
+ chip->image[reg] = snd_ad1816a_read(chip, reg);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+void snd_ad1816a_resume(struct snd_ad1816a *chip)
+{
+ int reg;
+ unsigned long flags;
+
+ snd_ad1816a_init(chip);
+ spin_lock_irqsave(&chip->lock, flags);
+ for (reg = 0; reg < 48; reg++)
+ snd_ad1816a_write(chip, reg, chip->image[reg]);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+#endif
+
static int __devinit snd_ad1816a_probe(struct snd_ad1816a *chip)
{
unsigned long flags;
@@ -548,7 +574,6 @@ static int snd_ad1816a_free(struct snd_ad1816a *chip)
snd_dma_disable(chip->dma2);
free_dma(chip->dma2);
}
- kfree(chip);
return 0;
}
@@ -573,19 +598,13 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
int __devinit snd_ad1816a_create(struct snd_card *card,
unsigned long port, int irq, int dma1, int dma2,
- struct snd_ad1816a **rchip)
+ struct snd_ad1816a *chip)
{
static struct snd_device_ops ops = {
.dev_free = snd_ad1816a_dev_free,
};
int error;
- struct snd_ad1816a *chip;
-
- *rchip = NULL;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
chip->irq = -1;
chip->dma1 = -1;
chip->dma2 = -1;
@@ -631,7 +650,6 @@ int __devinit snd_ad1816a_create(struct snd_card *card,
return error;
}
- *rchip = chip;
return 0;
}
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
new file mode 100644
index 00000000000..bde60139bb9
--- /dev/null
+++ b/sound/isa/cmi8328.c
@@ -0,0 +1,483 @@
+/*
+ * Driver for C-Media CMI8328-based soundcards, such as AudioExcel AV500
+ * Copyright (c) 2012 Ondrej Zary
+ *
+ * AudioExcel AV500 card consists of:
+ * - CMI8328 - main chip (SB Pro emulation, gameport, OPL3, MPU401, CD-ROM)
+ * - CS4231A - WSS codec
+ * - Dream SAM9233+GMS950400+RAM+ROM: Wavetable MIDI, connected to MPU401
+ */
+
+#include <linux/init.h>
+#include <linux/isa.h>
+#include <linux/module.h>
+#include <linux/gameport.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>");
+MODULE_DESCRIPTION("C-Media CMI8328");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#define SUPPORT_JOYSTICK 1
+#endif
+
+/* I/O port is configured by jumpers on the card to one of these */
+static int cmi8328_ports[] = { 0x530, 0xe80, 0xf40, 0x604 };
+#define CMI8328_MAX ARRAY_SIZE(cmi8328_ports)
+
+static int index[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = -1};
+static char *id[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = NULL};
+static long port[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int irq[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+static int dma1[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static int dma2[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static long mpuport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int mpuirq[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+#ifdef SUPPORT_JOYSTICK
+static bool gameport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = true};
+#endif
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for CMI8328 soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for CMI8328 soundcard.");
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for CMI8328 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for CMI8328 driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "DMA1 for CMI8328 driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "DMA2 for CMI8328 driver.");
+
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8328 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8328 MPU-401 port.");
+#ifdef SUPPORT_JOYSTICK
+module_param_array(gameport, bool, NULL, 0444);
+MODULE_PARM_DESC(gameport, "Enable gameport.");
+#endif
+
+struct snd_cmi8328 {
+ u16 port;
+ u8 cfg[3];
+ u8 wss_cfg;
+ struct snd_card *card;
+ struct snd_wss *wss;
+#ifdef SUPPORT_JOYSTICK
+ struct gameport *gameport;
+#endif
+};
+
+/* CMI8328 configuration registers */
+#define CFG1 0x61
+#define CFG1_SB_DISABLE (1 << 0)
+#define CFG1_GAMEPORT (1 << 1)
+/*
+ * bit 0: SB: 0=enabled, 1=disabled
+ * bit 1: gameport: 0=disabled, 1=enabled
+ * bits 2-4: SB IRQ: 001=3, 010=5, 011=7, 100=9, 101=10, 110=11
+ * bits 5-6: SB DMA: 00=disabled (when SB disabled), 01=DMA0, 10=DMA1, 11=DMA3
+ * bit 7: SB port: 0=0x220, 1=0x240
+ */
+#define CFG2 0x62
+#define CFG2_MPU_ENABLE (1 << 2)
+/*
+ * bits 0-1: CD-ROM mode: 00=disabled, 01=Panasonic, 10=Sony/Mitsumi/Wearnes,
+ 11=IDE
+ * bit 2: MPU401: 0=disabled, 1=enabled
+ * bits 3-4: MPU401 IRQ: 00=3, 01=5, 10=7, 11=9,
+ * bits 5-7: MPU401 port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x332,
+ 101=0x334, 110=0x336
+ */
+#define CFG3 0x63
+/*
+ * bits 0-2: CD-ROM IRQ: 000=disabled, 001=3, 010=5, 011=7, 100=9, 101=10,
+ 110=11
+ * bits 3-4: CD-ROM DMA: 00=disabled, 01=DMA0, 10=DMA1, 11=DMA3
+ * bits 5-7: CD-ROM port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x340,
+ 101=0x350, 110=0x360, 111=0x370
+ */
+
+static u8 snd_cmi8328_cfg_read(u16 port, u8 reg)
+{
+ outb(0x43, port + 3);
+ outb(0x21, port + 3);
+ outb(reg, port + 3);
+ return inb(port);
+}
+
+static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val)
+{
+ outb(0x43, port + 3);
+ outb(0x21, port + 3);
+ outb(reg, port + 3);
+ outb(val, port + 3); /* yes, value goes to the same port as index */
+}
+
+static void snd_cmi8328_cfg_save(u16 port, u8 cfg[])
+{
+ cfg[0] = snd_cmi8328_cfg_read(port, CFG1);
+ cfg[1] = snd_cmi8328_cfg_read(port, CFG2);
+ cfg[2] = snd_cmi8328_cfg_read(port, CFG3);
+}
+
+static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[])
+{
+ snd_cmi8328_cfg_write(port, CFG1, cfg[0]);
+ snd_cmi8328_cfg_write(port, CFG2, cfg[1]);
+ snd_cmi8328_cfg_write(port, CFG3, cfg[2]);
+}
+
+static int __devinit snd_cmi8328_mixer(struct snd_wss *chip)
+{
+ struct snd_card *card;
+ struct snd_ctl_elem_id id1, id2;
+ int err;
+
+ card = chip->card;
+
+ memset(&id1, 0, sizeof(id1));
+ memset(&id2, 0, sizeof(id2));
+ id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ /* rename AUX0 switch to CD */
+ strcpy(id1.name, "Aux Playback Switch");
+ strcpy(id2.name, "CD Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+ /* rename AUX0 volume to CD */
+ strcpy(id1.name, "Aux Playback Volume");
+ strcpy(id2.name, "CD Playback Volume");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+ /* rename AUX1 switch to Synth */
+ strcpy(id1.name, "Aux Playback Switch");
+ id1.index = 1;
+ strcpy(id2.name, "Synth Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+ /* rename AUX1 volume to Synth */
+ strcpy(id1.name, "Aux Playback Volume");
+ id1.index = 1;
+ strcpy(id2.name, "Synth Playback Volume");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+
+ return 0;
+}
+
+/* find index of an item in "-1"-ended array */
+int array_find(int array[], int item)
+{
+ int i;
+
+ for (i = 0; array[i] != -1; i++)
+ if (array[i] == item)
+ return i;
+
+ return -1;
+}
+/* the same for long */
+int array_find_l(long array[], long item)
+{
+ int i;
+
+ for (i = 0; array[i] != -1; i++)
+ if (array[i] == item)
+ return i;
+
+ return -1;
+}
+
+static int __devinit snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+ struct snd_cmi8328 *cmi;
+#ifdef SUPPORT_JOYSTICK
+ struct resource *res;
+#endif
+ int err, pos;
+ static long mpu_ports[] = { 0x330, 0x300, 0x310, 0x320, 0x332, 0x334,
+ 0x336, -1 };
+ static u8 mpu_port_bits[] = { 3, 0, 1, 2, 4, 5, 6 };
+ static int mpu_irqs[] = { 9, 7, 5, 3, -1 };
+ static u8 mpu_irq_bits[] = { 3, 2, 1, 0 };
+ static int irqs[] = { 9, 10, 11, 7, -1 };
+ static u8 irq_bits[] = { 2, 3, 4, 1 };
+ static int dma1s[] = { 3, 1, 0, -1 };
+ static u8 dma_bits[] = { 3, 2, 1 };
+ static int dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, {0, -1} };
+ u16 port = cmi8328_ports[ndev];
+ u8 val;
+
+ /* 0xff is invalid configuration (but settable - hope it isn't set) */
+ if (snd_cmi8328_cfg_read(port, CFG1) == 0xff)
+ return -ENODEV;
+ /* the SB disable bit must NEVER EVER be cleared or the WSS dies */
+ snd_cmi8328_cfg_write(port, CFG1, CFG1_SB_DISABLE);
+ if (snd_cmi8328_cfg_read(port, CFG1) != CFG1_SB_DISABLE)
+ return -ENODEV;
+ /* disable everything first */
+ snd_cmi8328_cfg_write(port, CFG2, 0); /* disable CDROM and MPU401 */
+ snd_cmi8328_cfg_write(port, CFG3, 0); /* disable CDROM IRQ and DMA */
+
+ if (irq[ndev] == SNDRV_AUTO_IRQ) {
+ irq[ndev] = snd_legacy_find_free_irq(irqs);
+ if (irq[ndev] < 0) {
+ snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (dma1[ndev] == SNDRV_AUTO_DMA) {
+ dma1[ndev] = snd_legacy_find_free_dma(dma1s);
+ if (dma1[ndev] < 0) {
+ snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ return -EBUSY;
+ }
+ }
+ if (dma2[ndev] == SNDRV_AUTO_DMA) {
+ dma2[ndev] = snd_legacy_find_free_dma(dma2s[dma1[ndev] % 4]);
+ if (dma2[ndev] < 0) {
+ snd_printk(KERN_WARNING "unable to find a free DMA2, full-duplex will not work\n");
+ dma2[ndev] = -1;
+ }
+ }
+ /* configure WSS IRQ... */
+ pos = array_find(irqs, irq[ndev]);
+ if (pos < 0) {
+ snd_printk(KERN_ERR "invalid IRQ %d\n", irq[ndev]);
+ return -EINVAL;
+ }
+ val = irq_bits[pos] << 3;
+ /* ...and DMA... */
+ pos = array_find(dma1s, dma1[ndev]);
+ if (pos < 0) {
+ snd_printk(KERN_ERR "invalid DMA1 %d\n", dma1[ndev]);
+ return -EINVAL;
+ }
+ val |= dma_bits[pos];
+ /* ...and DMA2 */
+ if (dma2[ndev] >= 0 && dma1[ndev] != dma2[ndev]) {
+ pos = array_find(dma2s[dma1[ndev]], dma2[ndev]);
+ if (pos < 0) {
+ snd_printk(KERN_ERR "invalid DMA2 %d\n", dma2[ndev]);
+ return -EINVAL;
+ }
+ val |= 0x04; /* enable separate capture DMA */
+ }
+ outb(val, port);
+
+ err = snd_card_create(index[ndev], id[ndev], THIS_MODULE,
+ sizeof(struct snd_cmi8328), &card);
+ if (err < 0)
+ return err;
+ cmi = card->private_data;
+ cmi->card = card;
+ cmi->port = port;
+ cmi->wss_cfg = val;
+ snd_card_set_dev(card, pdev);
+
+ err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev],
+ dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_pcm(cmi->wss, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_mixer(cmi->wss);
+ if (err < 0)
+ goto error;
+ err = snd_cmi8328_mixer(cmi->wss);
+ if (err < 0)
+ goto error;
+
+ if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+ snd_printk(KERN_WARNING "error initializing WSS timer\n");
+
+ if (mpuport[ndev] == SNDRV_AUTO_PORT) {
+ mpuport[ndev] = snd_legacy_find_free_ioport(mpu_ports, 2);
+ if (mpuport[ndev] < 0)
+ snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+ }
+ if (mpuirq[ndev] == SNDRV_AUTO_IRQ) {
+ mpuirq[ndev] = snd_legacy_find_free_irq(mpu_irqs);
+ if (mpuirq[ndev] < 0)
+ snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+ }
+ /* enable and configure MPU401 */
+ if (mpuport[ndev] > 0 && mpuirq[ndev] > 0) {
+ val = CFG2_MPU_ENABLE;
+ pos = array_find_l(mpu_ports, mpuport[ndev]);
+ if (pos < 0)
+ snd_printk(KERN_WARNING "invalid MPU401 port 0x%lx\n",
+ mpuport[ndev]);
+ else {
+ val |= mpu_port_bits[pos] << 5;
+ pos = array_find(mpu_irqs, mpuirq[ndev]);
+ if (pos < 0)
+ snd_printk(KERN_WARNING "invalid MPU401 IRQ %d\n",
+ mpuirq[ndev]);
+ else {
+ val |= mpu_irq_bits[pos] << 3;
+ snd_cmi8328_cfg_write(port, CFG2, val);
+ if (snd_mpu401_uart_new(card, 0,
+ MPU401_HW_MPU401, mpuport[ndev],
+ 0, mpuirq[ndev], NULL) < 0)
+ snd_printk(KERN_ERR "error initializing MPU401\n");
+ }
+ }
+ }
+ /* OPL3 is hardwired to 0x388 and cannot be disabled */
+ if (snd_opl3_create(card, 0x388, 0x38a, OPL3_HW_AUTO, 0, &opl3) < 0)
+ snd_printk(KERN_ERR "error initializing OPL3\n");
+ else
+ if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0)
+ snd_printk(KERN_WARNING "error initializing OPL3 hwdep\n");
+
+ strcpy(card->driver, "CMI8328");
+ strcpy(card->shortname, "C-Media CMI8328");
+ sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d",
+ card->shortname, cmi->wss->port, irq[ndev], dma1[ndev],
+ (dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]);
+
+ dev_set_drvdata(pdev, card);
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+#ifdef SUPPORT_JOYSTICK
+ if (!gameport[ndev])
+ return 0;
+ /* gameport is hardwired to 0x200 */
+ res = request_region(0x200, 8, "CMI8328 gameport");
+ if (!res)
+ snd_printk(KERN_WARNING "unable to allocate gameport I/O port\n");
+ else {
+ struct gameport *gp = cmi->gameport = gameport_allocate_port();
+ if (!cmi->gameport)
+ release_and_free_resource(res);
+ else {
+ gameport_set_name(gp, "CMI8328 Gameport");
+ gameport_set_phys(gp, "%s/gameport0", dev_name(pdev));
+ gameport_set_dev_parent(gp, pdev);
+ gp->io = 0x200;
+ gameport_set_port_data(gp, res);
+ /* Enable gameport */
+ snd_cmi8328_cfg_write(port, CFG1,
+ CFG1_SB_DISABLE | CFG1_GAMEPORT);
+ gameport_register_port(gp);
+ }
+ }
+#endif
+ return 0;
+error:
+ snd_card_free(card);
+
+ return err;
+}
+
+static int __devexit snd_cmi8328_remove(struct device *pdev, unsigned int dev)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_cmi8328 *cmi = card->private_data;
+
+#ifdef SUPPORT_JOYSTICK
+ if (cmi->gameport) {
+ struct resource *res = gameport_get_port_data(cmi->gameport);
+ gameport_unregister_port(cmi->gameport);
+ release_and_free_resource(res);
+ }
+#endif
+ /* disable everything */
+ snd_cmi8328_cfg_write(cmi->port, CFG1, CFG1_SB_DISABLE);
+ snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
+ snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
+ snd_card_free(card);
+ dev_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_cmi8328_suspend(struct device *pdev, unsigned int n,
+ pm_message_t state)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_cmi8328 *cmi;
+
+ if (!card) /* ignore absent devices */
+ return 0;
+ cmi = card->private_data;
+ snd_cmi8328_cfg_save(cmi->port, cmi->cfg);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(cmi->wss->pcm);
+ cmi->wss->suspend(cmi->wss);
+
+ return 0;
+}
+
+static int snd_cmi8328_resume(struct device *pdev, unsigned int n)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_cmi8328 *cmi;
+
+ if (!card) /* ignore absent devices */
+ return 0;
+ cmi = card->private_data;
+ snd_cmi8328_cfg_restore(cmi->port, cmi->cfg);
+ outb(cmi->wss_cfg, cmi->port);
+ cmi->wss->resume(cmi->wss);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+#endif
+
+static struct isa_driver snd_cmi8328_driver = {
+ .probe = snd_cmi8328_probe,
+ .remove = __devexit_p(snd_cmi8328_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_cmi8328_suspend,
+ .resume = snd_cmi8328_resume,
+#endif
+ .driver = {
+ .name = "cmi8328"
+ },
+};
+
+static int __init alsa_card_cmi8328_init(void)
+{
+ return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX);
+}
+
+static void __exit alsa_card_cmi8328_exit(void)
+{
+ isa_unregister_driver(&snd_cmi8328_driver);
+}
+
+module_init(alsa_card_cmi8328_init)
+module_exit(alsa_card_cmi8328_exit)
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index a76bc8d27c1..3fc8b66fd16 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -443,9 +443,8 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
for (i = 0; i < 8; ++i)
iwave[i] = snd_gf1_peek(gus, bank_pos + i);
#ifdef CONFIG_SND_DEBUG_ROM
- printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
- iwave[0], iwave[1], iwave[2], iwave[3],
- iwave[4], iwave[5], iwave[6], iwave[7]);
+ printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
+ 8, iwave);
#endif
if (strncmp(iwave, "INTRWAVE", 8))
continue; /* first check */
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index c24594c866f..3d1afb612b3 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -37,6 +37,7 @@
#include <sound/opl4.h>
#include <sound/control.h>
#include <sound/info.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
@@ -770,20 +771,6 @@ static int __devinit snd_miro_mixer(struct snd_card *card,
return 0;
}
-static long snd_legacy_find_free_ioport(long *port_table, long size)
-{
- while (*port_table != -1) {
- struct resource *res;
- if ((res = request_region(*port_table, size,
- "ALSA test")) != NULL) {
- release_and_free_resource(res);
- return *port_table;
- }
- port_table++;
- }
- return -1;
-}
-
static int __devinit snd_miro_init(struct snd_miro *chip,
unsigned short hardware)
{
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index f8fbe22515c..2899c9fd1ce 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -39,6 +39,7 @@
#ifndef OPTi93X
#include <sound/opl4.h>
#endif
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
@@ -185,19 +186,6 @@ static char * snd_opti9xx_names[] = {
"82C930", "82C931", "82C933"
};
-
-static long __devinit snd_legacy_find_free_ioport(long *port_table, long size)
-{
- while (*port_table != -1) {
- if (request_region(*port_table, size, "ALSA test")) {
- release_region(*port_table, size);
- return *port_table;
- }
- port_table++;
- }
- return -1;
-}
-
static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
unsigned short hardware)
{
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index 71887874679..2aae6a0efbc 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -417,9 +417,6 @@ size_dram(struct snd_emu8000 *emu)
EMU8000_SMLD_READ(emu); /* discard stale data */
if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
break; /* no memory at this address */
-
- detected_size = size;
-
snd_emu8000_read_wait(emu);
/*
@@ -432,6 +429,18 @@ size_dram(struct snd_emu8000 *emu)
if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
break; /* we must have wrapped around */
snd_emu8000_read_wait(emu);
+
+ /* Otherwise, it's valid memory. */
+ detected_size = size + 512 * 1024;
+ }
+
+ /* Distinguish 512 KiB from 0. */
+ if (detected_size == 0) {
+ snd_emu8000_read_wait(emu);
+ EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
+ EMU8000_SMLD_READ(emu); /* discard stale data */
+ if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1)
+ detected_size = 512 * 1024;
}
/* wait until FULL bit in SMAxW register is false */
diff --git a/sound/last.c b/sound/last.c
index 7ffc182e084..43f22282503 100644
--- a/sound/last.c
+++ b/sound/last.c
@@ -19,7 +19,6 @@
*
*/
-#define SNDRV_MAIN_OBJECT_FILE
#include <linux/init.h>
#include <sound/core.h>
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index a872d0a8297..66a3bc95fb8 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -2595,6 +2595,21 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)
shared ? 0 : 0x100);
}
+static int alc650_swap_surround_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_chmap *map = ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK];
+
+ if (map) {
+ if (ucontrol->value.integer.value[0])
+ map->chmap = snd_pcm_std_chmaps;
+ else
+ map->chmap = snd_pcm_alt_chmaps;
+ }
+ return snd_ac97_put_volsw(kcontrol, ucontrol);
+}
+
static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {
AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
@@ -2608,7 +2623,14 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {
/* 9: Line-In/Surround share */
/* 10: Mic/CLFE share */
/* 11-13: in IEC958 controls */
- AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Swap Surround Slot",
+ .info = snd_ac97_info_volsw,
+ .get = snd_ac97_get_volsw,
+ .put = alc650_swap_surround_put,
+ .private_value = AC97_SINGLE_VALUE(AC97_ALC650_MULTICH, 14, 1, 0),
+ },
#if 0 /* always set in patch_alc650 */
AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index ee895f3c860..c7e3c533316 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -270,7 +270,7 @@ struct snd_ali {
spinlock_t reg_lock;
spinlock_t voice_alloc;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
struct snd_ali_image *image;
#endif
};
@@ -1883,7 +1883,7 @@ static int __devinit snd_ali_mixer(struct snd_ali * codec)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ali_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -1989,7 +1989,7 @@ static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
#define ALI_PM_OPS &ali_pm
#else
#define ALI_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int snd_ali_free(struct snd_ali * codec)
{
@@ -2000,7 +2000,7 @@ static int snd_ali_free(struct snd_ali * codec)
if (codec->port)
pci_release_regions(codec->pci);
pci_disable_device(codec->pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
kfree(codec->image);
#endif
pci_dev_put(codec->pci_m1533);
@@ -2232,7 +2232,7 @@ static int __devinit snd_ali_create(struct snd_card *card,
return err;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
if (!codec->image)
snd_printk(KERN_WARNING "can't allocate apm buffer\n");
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 68c4469c6d1..00f157a2cf6 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -765,7 +765,7 @@ static int __devinit snd_als300_create(struct snd_card *card,
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_als300_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 0eeca49c575..feb2a143683 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -987,7 +987,7 @@ static void __devexit snd_card_als4000_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_als4000_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -1040,7 +1040,7 @@ static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume
#define SND_ALS4000_PM_OPS &snd_als4000_pm
#else
#define SND_ALS4000_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver als4000_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index e8de831f98b..a51e3ce3c80 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -2968,7 +2968,7 @@ static struct pci_driver driver = {
.id_table = asihpi_pci_tbl,
.probe = snd_asihpi_probe,
.remove = __devexit_p(snd_asihpi_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* .suspend = snd_asihpi_suspend,
.resume = snd_asihpi_resume, */
#endif
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 31020d2a868..368df8b0853 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -535,7 +535,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_atiixp_aclink_down(struct atiixp *chip)
{
// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1250,6 +1250,7 @@ static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {
static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)
{
struct snd_pcm *pcm;
+ struct snd_pcm_chmap *chmap;
struct snd_ac97_bus *pbus = chip->ac97_bus;
int err, i, num_pcms;
@@ -1293,6 +1294,14 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)
snd_dma_pci_data(chip->pci),
64*1024, 128*1024);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, chip->max_channels, 0,
+ &chmap);
+ if (err < 0)
+ return err;
+ chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+ chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
/* no SPDIF support on codec? */
if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates)
return 0;
@@ -1458,7 +1467,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1533,7 +1542,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
#define SND_ATIIXP_PM_OPS &snd_atiixp_pm
#else
#define SND_ATIIXP_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PROC_FS
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 79e204ec623..6fc03d9f2cf 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -511,7 +511,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
{
// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1113,7 +1113,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1169,7 +1169,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
#define SND_ATIIXP_PM_OPS &snd_atiixp_pm
#else
#define SND_ATIIXP_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PROC_FS
/*
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 4dddd871548..c03b66b784a 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -365,7 +365,7 @@ struct snd_azf3328 {
* CONFIG_PM register storage below, but that's slightly difficult. */
u16 shadow_reg_ctrl_6AH;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* register value containers for power management
* Note: not always full I/O range preserved (similar to Win driver!) */
u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
@@ -2729,7 +2729,7 @@ snd_azf3328_remove(struct pci_dev *pci)
snd_azf3328_dbgcallleave();
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static inline void
snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
{
@@ -2866,7 +2866,7 @@ static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume
#define SND_AZF3328_PM_OPS &snd_azf3328_pm
#else
#define SND_AZF3328_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver azf3328_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index e8e8ccc9640..04402c14cb2 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -710,7 +710,7 @@ struct snd_ca0106 {
u16 spi_dac_reg[16];
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
#define NUM_SAVED_VOLUMES 9
unsigned int saved_vol[NUM_SAVED_VOLUMES];
#endif
@@ -733,7 +733,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value);
int snd_ca0106_spi_write(struct snd_ca0106 * emu,
unsigned int data);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip);
void snd_ca0106_mixer_resume(struct snd_ca0106 *chip);
#else
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 83277b747b3..65c55910566 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1334,10 +1334,29 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static const struct snd_pcm_chmap_elem surround_map[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+ { }
+};
+
+static const struct snd_pcm_chmap_elem side_map[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+
static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
+ const struct snd_pcm_chmap_elem *map = NULL;
int err;
err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm);
@@ -1350,18 +1369,22 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
case 0:
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops);
+ map = snd_pcm_std_chmaps;
break;
case 1:
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops);
+ map = surround_map;
break;
case 2:
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops);
+ map = clfe_map;
break;
case 3:
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops);
+ map = side_map;
break;
}
@@ -1388,6 +1411,11 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
return err;
}
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+ 1 << 2, NULL);
+ if (err < 0)
+ return err;
+
emu->pcm[device] = pcm;
return 0;
@@ -1871,7 +1899,7 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_ca0106_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 84f3f92436b..68eacf7002d 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -907,7 +907,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
struct ca0106_vol_tbl {
unsigned int channel_id;
unsigned int reg;
@@ -953,4 +953,4 @@ void snd_ca0106_mixer_resume(struct snd_ca0106 *chip)
if (chip->details->i2c_adc)
ca0106_set_capture_mic_line_in(chip);
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index b7d6f2b886e..22122ff26e3 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -504,7 +504,7 @@ struct cmipci {
spinlock_t reg_lock;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
unsigned int saved_regs[0x20];
unsigned char saved_mixers[0x20];
#endif
@@ -1962,6 +1962,12 @@ static int __devinit snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, cm->max_channels, 0,
+ NULL);
+ if (err < 0)
+ return err;
+
return 0;
}
@@ -3315,7 +3321,7 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci)
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -3403,7 +3409,7 @@ static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
#define SND_CMIPCI_PM_OPS &snd_cmipci_pm
#else
#define SND_CMIPCI_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver cmipci_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 45a8317085f..8e86ec0031f 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -486,7 +486,7 @@ struct cs4281 {
struct gameport *gameport;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 suspend_regs[SUSPEND_REGISTERS];
#endif
@@ -1977,7 +1977,7 @@ static void __devexit snd_cs4281_remove(struct pci_dev *pci)
/*
* Power Management
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int saved_regs[SUSPEND_REGISTERS] = {
BA0_JSCTL,
@@ -2089,7 +2089,7 @@ static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
#define CS4281_PM_OPS &cs4281_pm
#else
#define CS4281_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver cs4281_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 1e007c736a8..575bed0836f 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -166,7 +166,7 @@ static struct pci_driver cs46xx_driver = {
.id_table = snd_cs46xx_ids,
.probe = snd_card_cs46xx_probe,
.remove = __devexit_p(snd_card_cs46xx_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &snd_cs46xx_pm,
},
diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h
index 29d8a8da1ba..fc339ef0a0a 100644
--- a/sound/pci/cs46xx/cs46xx.h
+++ b/sound/pci/cs46xx/cs46xx.h
@@ -1721,7 +1721,7 @@ struct snd_cs46xx {
unsigned int play_ctl;
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 *saved_regs;
#endif
};
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index a71d1c14a0f..a2bb8c91ebe 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2797,7 +2797,7 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
}
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
kfree(chip->saved_regs);
#endif
@@ -3590,7 +3590,7 @@ static struct cs_card_type __devinitdata cards[] = {
/*
* APM support
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static unsigned int saved_regs[] = {
BA0_ACOSV,
/*BA0_ASER_FADDR,*/
@@ -3711,7 +3711,7 @@ static int snd_cs46xx_resume(struct device *dev)
}
SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/*
@@ -3868,7 +3868,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
snd_cs46xx_proc_init(card, chip);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
ARRAY_SIZE(saved_regs), GFP_KERNEL);
if (!chip->saved_regs) {
diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
index b5189495d58..86f14620f81 100644
--- a/sound/pci/cs46xx/cs46xx_lib.h
+++ b/sound/pci/cs46xx/cs46xx_lib.h
@@ -90,7 +90,7 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int cs46xx_dsp_resume(struct snd_cs46xx * chip);
#endif
struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 56fec0bc0ef..1686b4f4c44 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -287,7 +287,7 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
kfree(ins->scbs[i].data);
#endif
}
@@ -1019,7 +1019,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
{
struct dsp_scb_descriptor * desc;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* copy the data for resume */
scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
if (!scb_data)
@@ -1032,7 +1032,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
_dsp_create_scb(chip,scb_data,dest);
} else {
snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
kfree(scb_data);
#endif
}
@@ -1937,7 +1937,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int cs46xx_dsp_resume(struct snd_cs46xx * chip)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index c2c695b07f8..409e8764fbe 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -203,7 +203,7 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
remove_symbol (chip,scb->scb_symbol);
ins->scbs[scb->index].deleted = 1;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
kfree(ins->scbs[scb->index].data);
ins->scbs[scb->index].data = NULL;
#endif
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index f1e4229993a..d1cca283157 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -142,8 +142,7 @@ static int __devinit snd_cs5530_create(struct snd_card *card,
mem = pci_ioremap_bar(pci, 0);
if (mem == NULL) {
- kfree(chip);
- pci_disable_device(pci);
+ snd_cs5530_free(chip);
return -EBUSY;
}
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
index ccc642269b9..a8f75f8dfda 100644
--- a/sound/pci/cs5535audio/Makefile
+++ b/sound/pci/cs5535audio/Makefile
@@ -3,7 +3,7 @@
#
snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
-snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
+snd-cs5535audio-$(CONFIG_PM_SLEEP) += cs5535audio_pm.o
snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o
# Toplevel Module Dependency
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 51f64ba5fac..4915efa551f 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -399,7 +399,7 @@ static struct pci_driver cs5535audio_driver = {
.id_table = snd_cs5535audio_ids,
.probe = snd_cs5535audio_probe,
.remove = __devexit_p(snd_cs5535audio_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &snd_cs5535audio_pm,
},
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 2f6e9c762d3..a2f997a9977 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -1536,7 +1536,7 @@ static void atc_connect_resources(struct ct_atc *atc)
}
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int atc_suspend(struct ct_atc *atc)
{
int i;
@@ -1647,7 +1647,7 @@ static struct ct_atc atc_preset __devinitdata = {
.output_switch_put = atc_output_switch_put,
.mic_source_switch_get = atc_mic_source_switch_get,
.mic_source_switch_put = atc_mic_source_switch_put,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = atc_suspend,
.resume = atc_resume,
#endif
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 653e813ad14..69b51f9d345 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -143,7 +143,7 @@ struct ct_atc {
struct ct_timer *timer;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int (*suspend)(struct ct_atc *atc);
int (*resume)(struct ct_atc *atc);
#define NUM_PCMS (NUM_CTALSADEVS - 1)
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index c56fe533b3f..5977e9a24b5 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -72,7 +72,7 @@ struct hw {
int (*card_init)(struct hw *hw, struct card_conf *info);
int (*card_stop)(struct hw *hw);
int (*pll_init)(struct hw *hw, unsigned int rsr);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int (*suspend)(struct hw *hw);
int (*resume)(struct hw *hw, struct card_conf *info);
#endif
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index dc1969bc67d..4507f7088b2 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -2085,7 +2085,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int hw_suspend(struct hw *hw)
{
struct pci_dev *pci = hw->pci;
@@ -2180,7 +2180,7 @@ static struct hw ct20k1_preset __devinitdata = {
.is_adc_source_selected = hw_is_adc_input_selected,
.select_adc_source = hw_adc_input_select,
.capabilities = hw_capabilities,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = hw_suspend,
.resume = hw_resume,
#endif
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 9d1231dc4ae..b9c9349058b 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -2201,7 +2201,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int hw_suspend(struct hw *hw)
{
struct pci_dev *pci = hw->pci;
@@ -2250,7 +2250,7 @@ static struct hw ct20k2_preset __devinitdata = {
.output_switch_put = hw_output_switch_put,
.mic_source_switch_get = hw_mic_source_switch_get,
.mic_source_switch_put = hw_mic_source_switch_put,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = hw_suspend,
.resume = hw_resume,
#endif
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index 0cc13eeef8d..48fe0e39c2b 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -1118,7 +1118,7 @@ mixer_set_input_right(struct ct_mixer *mixer,
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mixer_resume(struct ct_mixer *mixer)
{
int i, state;
@@ -1188,7 +1188,7 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
mixer->get_output_ports = mixer_get_output_ports;
mixer->set_input_left = mixer_set_input_left;
mixer->set_input_right = mixer_set_input_right;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
mixer->resume = mixer_resume;
#endif
diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h
index b009e989e77..be881c639fe 100644
--- a/sound/pci/ctxfi/ctmixer.h
+++ b/sound/pci/ctxfi/ctmixer.h
@@ -56,7 +56,7 @@ struct ct_mixer {
enum MIXER_PORT_T type, struct rsc *rsc);
int (*set_input_right)(struct ct_mixer *mixer,
enum MIXER_PORT_T type, struct rsc *rsc);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int (*resume)(struct ct_mixer *mixer);
#endif
};
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index 2c8622617c8..e8a4feb1ed8 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -395,12 +395,38 @@ static struct snd_pcm_ops ct_pcm_capture_ops = {
.page = snd_pcm_sgbuf_ops_page,
};
+static const struct snd_pcm_chmap_elem surround_map[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+ { }
+};
+
+static const struct snd_pcm_chmap_elem side_map[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+
/* Create ALSA pcm device */
int ct_alsa_pcm_create(struct ct_atc *atc,
enum CTALSADEVS device,
const char *device_name)
{
struct snd_pcm *pcm;
+ const struct snd_pcm_chmap_elem *map;
+ int chs;
int err;
int playback_count, capture_count;
@@ -427,7 +453,31 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
-#ifdef CONFIG_PM
+ chs = 2;
+ switch (device) {
+ case FRONT:
+ chs = 8;
+ map = snd_pcm_std_chmaps;
+ break;
+ case SURROUND:
+ map = surround_map;
+ break;
+ case CLFE:
+ map = clfe_map;
+ break;
+ case SIDE:
+ map = side_map;
+ break;
+ default:
+ map = snd_pcm_std_chmaps;
+ break;
+ }
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, chs,
+ 0, NULL);
+ if (err < 0)
+ return err;
+
+#ifdef CONFIG_PM_SLEEP
atc->pcms[device] = pcm;
#endif
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index e002183ef8b..07c07d752fd 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -125,7 +125,7 @@ static void __devexit ct_card_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ct_card_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 0ff754f180d..abb0b86c41c 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -46,7 +46,7 @@ static int get_firmware(const struct firmware **fw_entry,
int err;
char name[30];
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
if (chip->fw_cache[fw_index]) {
DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
*fw_entry = chip->fw_cache[fw_index];
@@ -59,7 +59,7 @@ static int get_firmware(const struct firmware **fw_entry,
err = request_firmware(fw_entry, name, pci_device(chip));
if (err < 0)
snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
else
chip->fw_cache[fw_index] = *fw_entry;
#endif
@@ -70,7 +70,7 @@ static int get_firmware(const struct firmware **fw_entry,
static void free_firmware(const struct firmware *fw_entry)
{
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
DE_ACT(("firmware not released (kept in cache)\n"));
#else
release_firmware(fw_entry);
@@ -82,7 +82,7 @@ static void free_firmware(const struct firmware *fw_entry)
static void free_firmware_cache(struct echoaudio *chip)
{
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int i;
for (i = 0; i < 8 ; i++)
@@ -2203,7 +2203,7 @@ ctl_error:
-#if defined(CONFIG_PM)
+#if defined(CONFIG_PM_SLEEP)
static int snd_echo_suspend(struct device *dev)
{
@@ -2313,7 +2313,7 @@ static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
#define SND_ECHO_PM_OPS &snd_echo_pm
#else
#define SND_ECHO_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static void __devexit snd_echo_remove(struct pci_dev *pci)
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index 1df974dcb5f..e158369f5fa 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -449,7 +449,7 @@ struct echoaudio {
volatile u32 __iomem *dsp_registers; /* DSP's register base */
u32 active_mask; /* Chs. active mask or
* punks out */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
const struct firmware *fw_cache[8]; /* Cached firmwares */
#endif
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index ddac4e6d660..b7c1875ba90 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -206,7 +206,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_emu10k1_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -268,7 +268,7 @@ static SIMPLE_DEV_PM_OPS(snd_emu10k1_pm, snd_emu10k1_suspend, snd_emu10k1_resume
#define SND_EMU10K1_PM_OPS &snd_emu10k1_pm
#else
#define SND_EMU10K1_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver emu10k1_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 754924081d0..bed4485f34f 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1241,7 +1241,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
* Create the EMU10K1 instance
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int alloc_pm_buffer(struct snd_emu10k1 *emu);
static void free_pm_buffer(struct snd_emu10k1 *emu);
#endif
@@ -1275,7 +1275,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
snd_dma_free_pages(&emu->ptb_pages);
vfree(emu->page_ptr_table);
vfree(emu->page_addr_table);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
free_pm_buffer(emu);
#endif
if (emu->port)
@@ -1971,7 +1971,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
err = snd_emu10k1_init(emu, enable_ir, 0);
if (err < 0)
goto error;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
err = alloc_pm_buffer(emu);
if (err < 0)
goto error;
@@ -2000,7 +2000,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
return err;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static unsigned char saved_regs[] = {
CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,
FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL,
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 5c8978b2c4d..556fd6f456e 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -830,9 +830,22 @@ static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static const struct snd_pcm_chmap_elem surround_map[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+ { }
+};
+
static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)
{
struct snd_pcm *pcm;
+ const struct snd_pcm_chmap_elem *map = NULL;
int err;
int capture = 0;
@@ -861,12 +874,15 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s
switch(device) {
case 0:
strcpy(pcm->name, "EMU10K1X Front");
+ map = snd_pcm_std_chmaps;
break;
case 1:
strcpy(pcm->name, "EMU10K1X Rear");
+ map = surround_map;
break;
case 2:
strcpy(pcm->name, "EMU10K1X Center/LFE");
+ map = clfe_map;
break;
}
emu->pcm = pcm;
@@ -875,6 +891,11 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s
snd_dma_pci_data(emu->pci),
32*1024, 32*1024);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+ 1 << 2, NULL);
+ if (err < 0)
+ return err;
+
if (rpcm)
*rpcm = pcm;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index dae4050ede5..52419959178 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -2646,7 +2646,7 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
{
int len;
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 0a436626182..ae709c1ab3a 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -263,8 +263,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b
spin_lock_irqsave(&emu->memblk_lock, flags);
if (blk->mapped_page >= 0) {
/* update order link */
- list_del(&blk->mapped_order_link);
- list_add_tail(&blk->mapped_order_link, &emu->mapped_order_link_head);
+ list_move_tail(&blk->mapped_order_link,
+ &emu->mapped_order_link_head);
spin_unlock_irqrestore(&emu->memblk_lock, flags);
return 0;
}
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index a81dc44228e..88cec6b7dd4 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -893,7 +893,7 @@ int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
#define NUM_CHS 1 /* up to 4, but only first channel is used */
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index f7e6f73186e..5674cc31653 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -55,8 +55,10 @@
#ifdef CHIP1370
#define DRIVER_NAME "ENS1370"
+#define CHIP_NAME "ES1370" /* it can be ENS but just to keep compatibility... */
#else
#define DRIVER_NAME "ENS1371"
+#define CHIP_NAME "ES1371"
#endif
@@ -1258,6 +1260,14 @@ static struct snd_pcm_ops snd_ensoniq_capture_ops = {
.pointer = snd_ensoniq_capture_pointer,
};
+static const struct snd_pcm_chmap_elem surround_map[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { }
+};
+
static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
struct snd_pcm ** rpcm)
{
@@ -1266,11 +1276,7 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
if (rpcm)
*rpcm = NULL;
-#ifdef CHIP1370
- err = snd_pcm_new(ensoniq->card, "ES1370/1", device, 1, 1, &pcm);
-#else
- err = snd_pcm_new(ensoniq->card, "ES1371/1", device, 1, 1, &pcm);
-#endif
+ err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -1283,16 +1289,22 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
pcm->private_data = ensoniq;
pcm->info_flags = 0;
-#ifdef CHIP1370
- strcpy(pcm->name, "ES1370 DAC2/ADC");
-#else
- strcpy(pcm->name, "ES1371 DAC2/ADC");
-#endif
+ strcpy(pcm->name, CHIP_NAME " DAC2/ADC");
ensoniq->pcm1 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
+#ifdef CHIP1370
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ surround_map, 2, 0, NULL);
+#else
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_std_chmaps, 2, 0, NULL);
+#endif
+ if (err < 0)
+ return err;
+
if (rpcm)
*rpcm = pcm;
return 0;
@@ -1306,11 +1318,7 @@ static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device,
if (rpcm)
*rpcm = NULL;
-#ifdef CHIP1370
- err = snd_pcm_new(ensoniq->card, "ES1370/2", device, 1, 0, &pcm);
-#else
- err = snd_pcm_new(ensoniq->card, "ES1371/2", device, 1, 0, &pcm);
-#endif
+ err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);
if (err < 0)
return err;
@@ -1321,16 +1329,22 @@ static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device,
#endif
pcm->private_data = ensoniq;
pcm->info_flags = 0;
-#ifdef CHIP1370
- strcpy(pcm->name, "ES1370 DAC1");
-#else
- strcpy(pcm->name, "ES1371 DAC1");
-#endif
+ strcpy(pcm->name, CHIP_NAME " DAC1");
ensoniq->pcm2 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
+#ifdef CHIP1370
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_std_chmaps, 2, 0, NULL);
+#else
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ surround_map, 2, 0, NULL);
+#endif
+ if (err < 0)
+ return err;
+
if (rpcm)
*rpcm = pcm;
return 0;
@@ -1885,11 +1899,7 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry,
{
struct ensoniq *ensoniq = entry->private_data;
-#ifdef CHIP1370
- snd_iprintf(buffer, "Ensoniq AudioPCI ES1370\n\n");
-#else
- snd_iprintf(buffer, "Ensoniq AudioPCI ES1371\n\n");
-#endif
+ snd_iprintf(buffer, "Ensoniq AudioPCI " CHIP_NAME "\n\n");
snd_iprintf(buffer, "Joystick enable : %s\n",
ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off");
#ifdef CHIP1370
@@ -2032,7 +2042,7 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
synchronize_irq(ensoniq->irq);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_ensoniq_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -2094,7 +2104,7 @@ static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume
#define SND_ENSONIQ_PM_OPS &snd_ensoniq_pm
#else
#define SND_ENSONIQ_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int __devinit snd_ensoniq_create(struct snd_card *card,
struct pci_dev *pci,
@@ -2361,11 +2371,7 @@ static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device,
*rrawmidi = NULL;
if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)
return err;
-#ifdef CHIP1370
- strcpy(rmidi->name, "ES1370");
-#else
- strcpy(rmidi->name, "ES1371");
-#endif
+ strcpy(rmidi->name, CHIP_NAME);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_ensoniq_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index dbb81807bc1..394c5d41353 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -236,7 +236,7 @@ struct es1938 {
#ifdef SUPPORT_JOYSTICK
struct gameport *gameport;
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
unsigned char saved_regs[SAVED_REG_SIZE];
#endif
};
@@ -1456,7 +1456,7 @@ static void snd_es1938_chip_init(struct es1938 *chip)
outb(0, SLDM_REG(chip, DMACLEAR));
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* PM support
*/
@@ -1536,7 +1536,7 @@ static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
#define ES1938_PM_OPS &es1938_pm
#else
#define ES1938_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef SUPPORT_JOYSTICK
static int __devinit snd_es1938_create_gameport(struct es1938 *chip)
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index fb4c90b99c0..5d0e568fdea 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -491,7 +491,7 @@ struct esschan {
/* linked list */
struct list_head list;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u16 wc_map[4];
#endif
};
@@ -544,7 +544,7 @@ struct es1968 {
struct list_head substream_list;
spinlock_t substream_lock;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u16 apu_map[NR_APUS][NR_APU_REGS];
#endif
@@ -706,7 +706,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
{
if (snd_BUG_ON(channel >= NR_APUS))
return;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
chip->apu_map[channel][reg] = data;
#endif
reg |= (channel << 4);
@@ -993,7 +993,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es
/* set the wavecache control reg */
wave_set_register(chip, es->apu[channel] << 3, tmpval);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
es->wc_map[channel] = tmpval;
#endif
}
@@ -2377,7 +2377,7 @@ static void snd_es1968_start_irq(struct es1968 *chip)
outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* PM support
*/
@@ -2461,7 +2461,7 @@ static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
#define ES1968_PM_OPS &es1968_pm
#else
#define ES1968_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef SUPPORT_JOYSTICK
#define JOYSTICK_ADDR 0x200
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 522c8706f24..cc2e91d1553 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -205,7 +205,7 @@ struct fm801 {
struct snd_tea575x tea;
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u16 saved_regs[0x20];
#endif
};
@@ -711,6 +711,13 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc
snd_dma_pci_data(chip->pci),
chip->multichannel ? 128*1024 : 64*1024, 128*1024);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps,
+ chip->multichannel ? 6 : 2, 0,
+ NULL);
+ if (err < 0)
+ return err;
+
if (rpcm)
*rpcm = pcm;
return 0;
@@ -1361,7 +1368,7 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static unsigned char saved_regs[] = {
FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,
FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2,
@@ -1421,7 +1428,7 @@ static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
#define SND_FM801_PM_OPS &snd_fm801_pm
#else
#define SND_FM801_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver fm801_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 194d625c1f8..7105c3de1bc 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -228,17 +228,9 @@ config SND_HDA_GENERIC
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 PM
- 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
+ depends on PM
default 0
help
The default time-out value in seconds for HD-audio automatic
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 4f7d2dfcef7..a98e25ebfd6 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -141,7 +141,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
memset(sequences_hp, 0, sizeof(sequences_hp));
assoc_line_out = 0;
- codec->ignore_misc_bit = true;
end_nid = codec->start_nid + codec->num_nodes;
for (nid = codec->start_nid; nid < end_nid; nid++) {
unsigned int wid_caps = get_wcaps(codec, nid);
@@ -157,9 +156,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
continue;
def_conf = snd_hda_codec_get_pincfg(codec, nid);
- if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
- AC_DEFCFG_MISC_NO_PRESENCE))
- codec->ignore_misc_bit = false;
conn = get_defcfg_connect(def_conf);
if (conn == AC_JACK_PORT_NONE)
continue;
@@ -739,7 +735,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
for (q = quirk; q->subvendor; q++) {
unsigned int vendorid =
q->subdevice | (q->subvendor << 16);
- if (vendorid == codec->subsystem_id) {
+ unsigned int mask = 0xffff0000 | q->subdevice_mask;
+ if ((codec->subsystem_id & mask) == (vendorid & mask)) {
id = q->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name = q->name;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 1c65cc5e3a3..960800b862a 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -94,13 +94,19 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
}
EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static void hda_power_work(struct work_struct *work);
static void hda_keep_power_on(struct hda_codec *codec);
#define hda_codec_is_power_on(codec) ((codec)->power_on)
+static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up)
+{
+ if (bus->ops.pm_notify)
+ bus->ops.pm_notify(bus, power_up);
+}
#else
static inline void hda_keep_power_on(struct hda_codec *codec) {}
#define hda_codec_is_power_on(codec) 1
+#define hda_call_pm_notify(bus, state) {}
#endif
/**
@@ -808,7 +814,7 @@ find_codec_preset(struct hda_codec *codec)
{
struct hda_codec_preset_list *tbl;
const struct hda_codec_preset *preset;
- int mod_requested = 0;
+ unsigned int mod_requested = 0;
if (is_generic_config(codec))
return NULL; /* use the generic parser */
@@ -1186,7 +1192,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
return;
snd_hda_jack_tbl_clear(codec);
restore_init_pincfgs(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
cancel_delayed_work(&codec->power_work);
flush_workqueue(codec->bus->workq);
#endif
@@ -1199,6 +1205,10 @@ static void snd_hda_codec_free(struct hda_codec *codec)
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
+#ifdef CONFIG_PM
+ if (!codec->pm_down_notified) /* cancel leftover refcounts */
+ hda_call_pm_notify(codec->bus, false);
+#endif
module_put(codec->owner);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
@@ -1212,7 +1222,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
hda_nid_t fg, unsigned int power_state);
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state);
/**
@@ -1229,6 +1239,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
{
struct hda_codec *codec;
char component[31];
+ hda_nid_t fg;
int err;
if (snd_BUG_ON(!bus))
@@ -1263,7 +1274,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spin_lock_init(&codec->power_lock);
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
@@ -1271,6 +1282,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
* phase.
*/
hda_keep_power_on(codec);
+ hda_call_pm_notify(bus, true);
#endif
if (codec->bus->modelname) {
@@ -1304,7 +1316,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
goto error;
}
- err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg);
+ fg = codec->afg ? codec->afg : codec->mfg;
+ err = read_widget_caps(codec, fg);
if (err < 0) {
snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
goto error;
@@ -1314,20 +1327,22 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
goto error;
if (!codec->subsystem_id) {
- hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
codec->subsystem_id =
- snd_hda_codec_read(codec, nid, 0,
+ snd_hda_codec_read(codec, fg, 0,
AC_VERB_GET_SUBSYSTEM_ID, 0);
}
- codec->epss = snd_hda_codec_get_supported_ps(codec,
- codec->afg ? codec->afg : codec->mfg,
+#ifdef CONFIG_PM
+ codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg,
+ AC_PWRST_CLKSTOP);
+ if (!codec->d3_stop_clk)
+ bus->power_keep_link_on = 1;
+#endif
+ codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
AC_PWRST_EPSS);
/* power-up all before initialization */
- hda_set_power_state(codec,
- codec->afg ? codec->afg : codec->mfg,
- AC_PWRST_D0);
+ hda_set_power_state(codec, AC_PWRST_D0);
snd_hda_codec_proc_new(codec);
@@ -2335,7 +2350,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
/* OK, let it free */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
cancel_delayed_work_sync(&codec->power_work);
codec->power_on = 0;
codec->power_transition = 0;
@@ -3500,20 +3515,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
power_state);
}
-
- if (power_state == AC_PWRST_D0) {
- unsigned long end_time;
- int state;
- /* wait until the codec reachs to D0 */
- end_time = jiffies + msecs_to_jiffies(500);
- do {
- state = snd_hda_codec_read(codec, fg, 0,
- AC_VERB_GET_POWER_STATE, 0);
- if (state == power_state)
- break;
- msleep(1);
- } while (time_after_eq(end_time, jiffies));
- }
}
EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
@@ -3534,18 +3535,40 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg
}
/*
- * set power state of the codec
+ * wait until the state is reached, returns the current state
*/
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state)
+static unsigned int hda_sync_power_state(struct hda_codec *codec,
+ hda_nid_t fg,
+ unsigned int power_state)
{
- int count;
- unsigned int state;
+ unsigned long end_time = jiffies + msecs_to_jiffies(500);
+ unsigned int state, actual_state;
- if (codec->patch_ops.set_power_state) {
- codec->patch_ops.set_power_state(codec, fg, power_state);
- return;
+ for (;;) {
+ state = snd_hda_codec_read(codec, fg, 0,
+ AC_VERB_GET_POWER_STATE, 0);
+ if (state & AC_PWRST_ERROR)
+ break;
+ actual_state = (state >> 4) & 0x0f;
+ if (actual_state == power_state)
+ break;
+ if (time_after_eq(jiffies, end_time))
+ break;
+ /* wait until the codec reachs to the target state */
+ msleep(1);
}
+ return state;
+}
+
+/*
+ * set power state of the codec, and return the power state
+ */
+static unsigned int hda_set_power_state(struct hda_codec *codec,
+ unsigned int power_state)
+{
+ hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
+ int count;
+ unsigned int state;
/* this delay seems necessary to avoid click noise at power-down */
if (power_state == AC_PWRST_D3) {
@@ -3555,14 +3578,22 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
/* repeat power states setting at most 10 times*/
for (count = 0; count < 10; count++) {
- snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
- power_state);
- snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
- state = snd_hda_codec_read(codec, fg, 0,
- AC_VERB_GET_POWER_STATE, 0);
+ if (codec->patch_ops.set_power_state)
+ codec->patch_ops.set_power_state(codec, fg,
+ power_state);
+ else {
+ snd_hda_codec_read(codec, fg, 0,
+ AC_VERB_SET_POWER_STATE,
+ power_state);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state,
+ true);
+ }
+ state = hda_sync_power_state(codec, fg, power_state);
if (!(state & AC_PWRST_ERROR))
break;
}
+
+ return state;
}
#ifdef CONFIG_SND_HDA_HWDEP
@@ -3579,16 +3610,16 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
#ifdef CONFIG_PM
/*
* call suspend and power-down; used both from PM and power-save
+ * this function returns the power state in the end
*/
-static void hda_call_codec_suspend(struct hda_codec *codec)
+static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
{
+ unsigned int state;
+
if (codec->patch_ops.suspend)
codec->patch_ops.suspend(codec);
hda_cleanup_all_streams(codec);
- hda_set_power_state(codec,
- codec->afg ? codec->afg : codec->mfg,
- AC_PWRST_D3);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+ state = hda_set_power_state(codec, AC_PWRST_D3);
cancel_delayed_work(&codec->power_work);
spin_lock(&codec->power_lock);
snd_hda_update_power_acct(codec);
@@ -3597,7 +3628,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
codec->power_transition = 0;
codec->power_jiffies = jiffies;
spin_unlock(&codec->power_lock);
-#endif
+ return state;
}
/*
@@ -3609,9 +3640,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
* in the resume / power-save sequence
*/
hda_keep_power_on(codec);
- hda_set_power_state(codec,
- codec->afg ? codec->afg : codec->mfg,
- AC_PWRST_D0);
+ hda_set_power_state(codec, AC_PWRST_D0);
restore_pincfgs(codec); /* restore all current pin configs */
restore_shutup_pins(codec);
hda_exec_init_verbs(codec);
@@ -3624,6 +3653,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
}
+ snd_hda_jack_report_sync(codec);
snd_hda_power_down(codec); /* flag down before returning */
}
#endif /* CONFIG_PM */
@@ -3658,6 +3688,36 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
}
EXPORT_SYMBOL_HDA(snd_hda_build_controls);
+/*
+ * add standard channel maps if not specified
+ */
+static int add_std_chmaps(struct hda_codec *codec)
+{
+ int i, str, err;
+
+ for (i = 0; i < codec->num_pcms; i++) {
+ for (str = 0; str < 2; str++) {
+ struct snd_pcm *pcm = codec->pcm_info[i].pcm;
+ struct hda_pcm_stream *hinfo =
+ &codec->pcm_info[i].stream[str];
+ struct snd_pcm_chmap *chmap;
+
+ if (codec->pcm_info[i].own_chmap)
+ continue;
+ if (!pcm || !hinfo->substreams)
+ continue;
+ err = snd_pcm_add_chmap_ctls(pcm, str,
+ snd_pcm_std_chmaps,
+ hinfo->channels_max,
+ 0, &chmap);
+ if (err < 0)
+ return err;
+ chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+ }
+ }
+ return 0;
+}
+
int snd_hda_codec_build_controls(struct hda_codec *codec)
{
int err = 0;
@@ -3669,6 +3729,13 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
err = codec->patch_ops.build_controls(codec);
if (err < 0)
return err;
+
+ /* we create chmaps here instead of build_pcms */
+ err = add_std_chmaps(codec);
+ if (err < 0)
+ return err;
+
+ snd_hda_jack_report_sync(codec); /* call at the last init point */
return 0;
}
@@ -4211,7 +4278,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
*
* This function returns 0 if successful, or a negative error code.
*/
-int __devinit snd_hda_build_pcms(struct hda_bus *bus)
+int snd_hda_build_pcms(struct hda_bus *bus)
{
struct hda_codec *codec;
@@ -4391,12 +4458,13 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
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;
+ unsigned int state;
spin_lock(&codec->power_lock);
if (codec->power_transition > 0) { /* during power-up sequence? */
@@ -4410,9 +4478,12 @@ static void hda_power_work(struct work_struct *work)
}
spin_unlock(&codec->power_lock);
- hda_call_codec_suspend(codec);
- if (bus->ops.pm_notify)
- bus->ops.pm_notify(bus);
+ state = hda_call_codec_suspend(codec);
+ codec->pm_down_notified = 0;
+ if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
+ codec->pm_down_notified = 1;
+ hda_call_pm_notify(bus, false);
+ }
}
static void hda_keep_power_on(struct hda_codec *codec)
@@ -4438,19 +4509,16 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
/* Transition to powered up, if wait_power_down then wait for a pending
* transition to D3 to complete. A pending D3 transition is indicated
* with power_transition == -1. */
+/* call this with codec->power_lock held! */
static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
{
struct hda_bus *bus = codec->bus;
- spin_lock(&codec->power_lock);
- codec->power_count++;
/* Return if power_on or transitioning to power_on, unless currently
* powering down. */
if ((codec->power_on || codec->power_transition > 0) &&
- !(wait_power_down && codec->power_transition < 0)) {
- spin_unlock(&codec->power_lock);
+ !(wait_power_down && codec->power_transition < 0))
return;
- }
spin_unlock(&codec->power_lock);
cancel_delayed_work_sync(&codec->power_work);
@@ -4462,9 +4530,9 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
if (codec->power_on) {
if (codec->power_transition < 0)
codec->power_transition = 0;
- spin_unlock(&codec->power_lock);
return;
}
+
trace_hda_power_up(codec);
snd_hda_update_power_acct(codec);
codec->power_on = 1;
@@ -4472,71 +4540,54 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
codec->power_transition = 1; /* avoid reentrance */
spin_unlock(&codec->power_lock);
- if (bus->ops.pm_notify)
- bus->ops.pm_notify(bus);
+ if (codec->pm_down_notified) {
+ codec->pm_down_notified = 0;
+ hda_call_pm_notify(bus, true);
+ }
+
hda_call_codec_resume(codec);
spin_lock(&codec->power_lock);
codec->power_transition = 0;
- spin_unlock(&codec->power_lock);
-}
-
-/**
- * snd_hda_power_up - Power-up the codec
- * @codec: HD-audio codec
- *
- * Increment the power-up counter and power up the hardware really when
- * not turned on yet.
- */
-void snd_hda_power_up(struct hda_codec *codec)
-{
- __snd_hda_power_up(codec, false);
}
-EXPORT_SYMBOL_HDA(snd_hda_power_up);
-
-/**
- * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
- * D3 transition to complete. This differs from snd_hda_power_up() when
- * power_transition == -1. snd_hda_power_up sees this case as a nop,
- * snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
- * back up.
- * @codec: HD-audio codec
- *
- * Cancel any power down operation hapenning on the work queue, then power up.
- */
-void snd_hda_power_up_d3wait(struct hda_codec *codec)
-{
- /* This will cancel and wait for pending power_work to complete. */
- __snd_hda_power_up(codec, true);
-}
-EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait);
#define power_save(codec) \
((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
-/**
- * snd_hda_power_down - Power-down the codec
- * @codec: HD-audio codec
- *
- * Decrement the power-up counter and schedules the power-off work if
- * the counter rearches to zero.
- */
-void snd_hda_power_down(struct hda_codec *codec)
+/* Transition to powered down */
+static void __snd_hda_power_down(struct hda_codec *codec)
{
- spin_lock(&codec->power_lock);
- --codec->power_count;
- if (!codec->power_on || codec->power_count || codec->power_transition) {
- spin_unlock(&codec->power_lock);
+ if (!codec->power_on || codec->power_count || codec->power_transition)
return;
- }
+
if (power_save(codec)) {
codec->power_transition = -1; /* avoid reentrance */
queue_delayed_work(codec->bus->workq, &codec->power_work,
msecs_to_jiffies(power_save(codec) * 1000));
}
+}
+
+/**
+ * snd_hda_power_save - Power-up/down/sync the codec
+ * @codec: HD-audio codec
+ * @delta: the counter delta to change
+ *
+ * Change the power-up counter via @delta, and power up or down the hardware
+ * appropriately. For the power-down, queue to the delayed action.
+ * Passing zero to @delta means to synchronize the power state.
+ */
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
+{
+ spin_lock(&codec->power_lock);
+ codec->power_count += delta;
+ trace_hda_power_count(codec);
+ if (delta > 0)
+ __snd_hda_power_up(codec, d3wait);
+ else
+ __snd_hda_power_down(codec);
spin_unlock(&codec->power_lock);
}
-EXPORT_SYMBOL_HDA(snd_hda_power_down);
+EXPORT_SYMBOL_HDA(snd_hda_power_save);
/**
* snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5087,9 +5138,6 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend);
* @bus: the HDA bus
*
* Returns 0 if successful.
- *
- * This function is defined only when POWER_SAVE isn't set.
- * In the power-save mode, the codec is resumed dynamically.
*/
int snd_hda_resume(struct hda_bus *bus)
{
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index e5a7e19a807..507fe8a917b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -386,6 +386,10 @@ enum {
/* DIGITAL2 bits */
#define AC_DIG2_CC (0x7f<<0)
+/* DIGITAL3 bits */
+#define AC_DIG3_ICT (0xf<<0)
+#define AC_DIG3_KAE (1<<7)
+
/* Pin widget control - 8bit */
#define AC_PINCTL_EPT (0x3<<0)
#define AC_PINCTL_EPT_NATIVE 0
@@ -610,9 +614,9 @@ struct hda_bus_ops {
struct hda_pcm *pcm);
/* reset bus for retry verb */
void (*bus_reset)(struct hda_bus *bus);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
/* notify power-up/down from codec to controller */
- void (*pm_notify)(struct hda_bus *bus);
+ void (*pm_notify)(struct hda_bus *bus, bool power_up);
#endif
};
@@ -708,8 +712,6 @@ struct hda_codec_ops {
#ifdef CONFIG_PM
int (*suspend)(struct hda_codec *codec);
int (*resume)(struct hda_codec *codec);
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
#endif
void (*reboot_notify)(struct hda_codec *codec);
@@ -774,6 +776,7 @@ struct hda_pcm {
unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */
int device; /* device number to assign */
struct snd_pcm *pcm; /* assigned PCM instance */
+ bool own_chmap; /* codec driver provides own channel maps */
};
/* codec information */
@@ -859,12 +862,13 @@ struct hda_codec {
unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
- unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
unsigned int no_jack_detect:1; /* Machine has no jack-detection */
unsigned int pcm_format_first:1; /* PCM format must be set first */
unsigned int epss:1; /* supporting EPSS? */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
unsigned int power_on :1; /* current (global) power-state */
+ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
+ unsigned int pm_down_notified:1; /* PM notified to controller */
int power_transition; /* power-state in transition */
int power_count; /* current (global) power refcount */
struct delayed_work power_work; /* delayed task for powerdown */
@@ -1042,7 +1046,7 @@ int snd_hda_resume(struct hda_bus *bus);
static inline
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
if (codec->patch_ops.check_power_status)
return codec->patch_ops.check_power_status(codec, nid);
#endif
@@ -1059,22 +1063,70 @@ 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_up_d3wait(struct hda_codec *codec);
-void snd_hda_power_down(struct hda_codec *codec);
+#ifdef CONFIG_PM
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
void snd_hda_update_power_acct(struct hda_codec *codec);
#else
-static inline void snd_hda_power_up(struct hda_codec *codec) {}
-static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {}
-static inline void snd_hda_power_down(struct hda_codec *codec) {}
+static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
+ bool d3wait) {}
#endif
+/**
+ * snd_hda_power_up - Power-up the codec
+ * @codec: HD-audio codec
+ *
+ * Increment the power-up counter and power up the hardware really when
+ * not turned on yet.
+ */
+static inline void snd_hda_power_up(struct hda_codec *codec)
+{
+ snd_hda_power_save(codec, 1, false);
+}
+
+/**
+ * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
+ * D3 transition to complete. This differs from snd_hda_power_up() when
+ * power_transition == -1. snd_hda_power_up sees this case as a nop,
+ * snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
+ * back up.
+ * @codec: HD-audio codec
+ *
+ * Cancel any power down operation hapenning on the work queue, then power up.
+ */
+static inline void snd_hda_power_up_d3wait(struct hda_codec *codec)
+{
+ snd_hda_power_save(codec, 1, true);
+}
+
+/**
+ * snd_hda_power_down - Power-down the codec
+ * @codec: HD-audio codec
+ *
+ * Decrement the power-up counter and schedules the power-off work if
+ * the counter rearches to zero.
+ */
+static inline void snd_hda_power_down(struct hda_codec *codec)
+{
+ snd_hda_power_save(codec, -1, false);
+}
+
+/**
+ * snd_hda_power_sync - Synchronize the power-save status
+ * @codec: HD-audio codec
+ *
+ * Synchronize the actual power state with the power account;
+ * called when power_save parameter is changed
+ */
+static inline void snd_hda_power_sync(struct hda_codec *codec)
+{
+ snd_hda_power_save(codec, 0, false);
+}
+
#ifdef CONFIG_SND_HDA_PATCH_LOADER
/*
* patch firmware
*/
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
+int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
#endif
/*
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 431bf868711..b81d3d0b952 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -70,7 +70,7 @@ struct hda_gspec {
struct list_head nid_list; /* list of widgets */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
#define MAX_LOOPBACK_AMPS 7
struct hda_loopback_check loopback;
int num_loopbacks;
@@ -654,7 +654,7 @@ static int parse_input(struct hda_codec *codec)
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx)
{
@@ -1028,7 +1028,7 @@ static int build_generic_pcms(struct hda_codec *codec)
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_gspec *spec = codec->spec;
@@ -1043,7 +1043,7 @@ static struct hda_codec_ops generic_patch_ops = {
.build_controls = build_generic_controls,
.build_pcms = build_generic_pcms,
.free = snd_hda_generic_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
.check_power_status = generic_check_power_status,
#endif
};
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 6b2efb8cb1f..1af86d40eb2 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -25,7 +25,6 @@
#include <linux/mutex.h>
#include <linux/ctype.h>
#include <linux/string.h>
-#include <linux/firmware.h>
#include <linux/export.h>
#include <sound/core.h>
#include "hda_codec.h"
@@ -156,7 +155,7 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static ssize_t power_on_acct_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -192,7 +191,7 @@ int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
hwdep->device, &power_attrs[i]);
return 0;
}
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#endif /* CONFIG_PM */
#ifdef CONFIG_SND_HDA_RECONFIG
@@ -747,18 +746,21 @@ static int parse_line_mode(char *buf, struct hda_bus *bus)
*
* the spaces at the beginning and the end of the line are stripped
*/
-static int get_line_from_fw(char *buf, int size, struct firmware *fw)
+static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
+ const void **fw_data_p)
{
int len;
- const char *p = fw->data;
- while (isspace(*p) && fw->size) {
+ size_t fw_size = *fw_size_p;
+ const char *p = *fw_data_p;
+
+ while (isspace(*p) && fw_size) {
p++;
- fw->size--;
+ fw_size--;
}
- if (!fw->size)
+ if (!fw_size)
return 0;
- for (len = 0; len < fw->size; len++) {
+ for (len = 0; len < fw_size; len++) {
if (!*p)
break;
if (*p == '\n') {
@@ -770,8 +772,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
*buf++ = *p++;
}
*buf = 0;
- fw->size -= len;
- fw->data = p;
+ *fw_size_p = fw_size - len;
+ *fw_data_p = p;
remove_trail_spaces(buf);
return 1;
}
@@ -779,29 +781,15 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
/*
* load a "patch" firmware file and parse it
*/
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
+int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
{
- int err;
- const struct firmware *fw;
- struct firmware tmp;
char buf[128];
struct hda_codec *codec;
int line_mode;
- struct device *dev = bus->card->dev;
-
- if (snd_BUG_ON(!dev))
- return -ENODEV;
- err = request_firmware(&fw, patch, dev);
- if (err < 0) {
- printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
- patch);
- return err;
- }
- tmp = *fw;
line_mode = LINE_MODE_NONE;
codec = NULL;
- while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
+ while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
if (!*buf || *buf == '#' || *buf == '\n')
continue;
if (*buf == '[')
@@ -810,7 +798,6 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
(codec || !patch_items[line_mode].need_codec))
patch_items[line_mode].parser(buf, bus, &codec);
}
- release_firmware(fw);
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_load_patch);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c4763c52eaf..f09ff6c1404 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -46,6 +46,7 @@
#include <linux/mutex.h>
#include <linux/reboot.h>
#include <linux/io.h>
+#include <linux/pm_runtime.h>
#ifdef CONFIG_X86
/* for snoop control */
#include <asm/pgtable.h>
@@ -55,6 +56,7 @@
#include <sound/initval.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
+#include <linux/firmware.h>
#include "hda_codec.h"
@@ -62,7 +64,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static char *model[SNDRV_CARDS];
-static int position_fix[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_only[SNDRV_CARDS];
@@ -86,7 +88,7 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
- "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
+ "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
@@ -108,9 +110,16 @@ MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
"(0=off, 1=on) (default=1).");
#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
+static int param_set_xint(const char *val, const struct kernel_param *kp);
+static struct kernel_param_ops param_ops_xint = {
+ .set = param_set_xint,
+ .get = param_get_int,
+};
+#define param_check_xint param_check_int
+
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-module_param(power_save, int, 0644);
+module_param(power_save, xint, 0644);
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
"(in second, 0 = disable).");
@@ -121,7 +130,7 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
static bool power_save_controller = 1;
module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
-#endif
+#endif /* CONFIG_PM */
static int align_buffer_size = -1;
module_param(align_buffer_size, bint, 0644);
@@ -406,6 +415,7 @@ struct azx_dev {
*/
unsigned int insufficient :1;
unsigned int wc_marked:1;
+ unsigned int no_period_wakeup:1;
};
/* CORB/RIRB */
@@ -471,6 +481,10 @@ struct azx {
struct snd_dma_buffer rb;
struct snd_dma_buffer posbuf;
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ const struct firmware *fw;
+#endif
+
/* flags */
int position_fix[2]; /* for both playback/capture streams */
int poll_count;
@@ -498,6 +512,9 @@ struct azx {
/* reboot notifier (for mysterious hangup problem at power-down) */
struct notifier_block reboot_notifier;
+
+ /* card list (for power_save trigger) */
+ struct list_head list;
};
/* driver types */
@@ -538,6 +555,7 @@ enum {
#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
#define AZX_DCAPS_POSFIX_COMBO (1 << 24) /* Use COMBO as default */
+#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
@@ -560,13 +578,17 @@ enum {
* VGA-switcher support
*/
#ifdef SUPPORT_VGA_SWITCHEROO
+#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo)
+#else
+#define use_vga_switcheroo(chip) 0
+#endif
+
+#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER)
#define DELAYED_INIT_MARK
#define DELAYED_INITDATA_MARK
-#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo)
#else
#define DELAYED_INIT_MARK __devinit
#define DELAYED_INITDATA_MARK __devinitdata
-#define use_vga_switcheroo(chip) 0
#endif
static char *driver_short_names[] DELAYED_INITDATA_MARK = {
@@ -1012,8 +1034,8 @@ static unsigned int azx_get_response(struct hda_bus *bus,
return azx_rirb_get_response(bus, addr);
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void azx_power_notify(struct hda_bus *bus);
+#ifdef CONFIG_PM
+static void azx_power_notify(struct hda_bus *bus, bool power_up);
#endif
/* reset codec link */
@@ -1269,6 +1291,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
u8 sd_status;
int i, ok;
+#ifdef CONFIG_PM_RUNTIME
+ if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
+ return IRQ_NONE;
+#endif
+
spin_lock(&chip->reg_lock);
if (chip->disabled) {
@@ -1394,7 +1421,7 @@ static int azx_setup_periods(struct azx *chip,
ofs = 0;
azx_dev->frags = 0;
pos_adj = bdl_pos_adj[chip->dev_index];
- if (pos_adj > 0) {
+ if (!azx_dev->no_period_wakeup && pos_adj > 0) {
struct snd_pcm_runtime *runtime = substream->runtime;
int pos_align = pos_adj;
pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
@@ -1410,8 +1437,7 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0;
} else {
ofs = setup_bdle(chip, substream, azx_dev,
- &bdl, ofs, pos_adj,
- !substream->runtime->no_period_wakeup);
+ &bdl, ofs, pos_adj, true);
if (ofs < 0)
goto error;
}
@@ -1424,7 +1450,7 @@ static int azx_setup_periods(struct azx *chip,
else
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
period_bytes,
- !substream->runtime->no_period_wakeup);
+ !azx_dev->no_period_wakeup);
if (ofs < 0)
goto error;
}
@@ -1580,7 +1606,7 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode
bus_temp.ops.get_response = azx_get_response;
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
bus_temp.ops.bus_reset = azx_bus_reset;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify;
#endif
@@ -1897,10 +1923,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
if (bufsize != azx_dev->bufsize ||
period_bytes != azx_dev->period_bytes ||
- format_val != azx_dev->format_val) {
+ format_val != azx_dev->format_val ||
+ runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
azx_dev->bufsize = bufsize;
azx_dev->period_bytes = period_bytes;
azx_dev->format_val = format_val;
+ azx_dev->no_period_wakeup = runtime->no_period_wakeup;
err = azx_setup_periods(chip, substream, azx_dev);
if (err < 0)
return err;
@@ -1959,14 +1987,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
spin_lock(&chip->reg_lock);
- if (nsync > 1) {
- /* first, set SYNC bits of corresponding streams */
- if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
- azx_writel(chip, OLD_SSYNC,
- azx_readl(chip, OLD_SSYNC) | sbits);
- else
- azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
- }
+
+ /* first, set SYNC bits of corresponding streams */
+ if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+ azx_writel(chip, OLD_SSYNC,
+ azx_readl(chip, OLD_SSYNC) | sbits);
+ else
+ azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
+
snd_pcm_group_for_each_entry(s, substream) {
if (s->pcm->card != substream->pcm->card)
continue;
@@ -1984,8 +2012,6 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
spin_unlock(&chip->reg_lock);
if (start) {
- if (nsync == 1)
- return 0;
/* wait until all FIFOs get ready */
for (timeout = 5000; timeout; timeout--) {
nwait = 0;
@@ -2018,16 +2044,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
cpu_relax();
}
}
- if (nsync > 1) {
- spin_lock(&chip->reg_lock);
- /* reset SYNC bits */
- if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
- azx_writel(chip, OLD_SSYNC,
- azx_readl(chip, OLD_SSYNC) & ~sbits);
- else
- azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
- spin_unlock(&chip->reg_lock);
- }
+ spin_lock(&chip->reg_lock);
+ /* reset SYNC bits */
+ if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+ azx_writel(chip, OLD_SSYNC,
+ azx_readl(chip, OLD_SSYNC) & ~sbits);
+ else
+ azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
+ spin_unlock(&chip->reg_lock);
return 0;
}
@@ -2120,6 +2144,27 @@ static unsigned int azx_get_position(struct azx *chip,
if (pos >= azx_dev->bufsize)
pos = 0;
+
+ /* calculate runtime delay from LPIB */
+ if (azx_dev->substream->runtime &&
+ chip->position_fix[stream] == POS_FIX_POSBUF &&
+ (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
+ unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
+ int delay;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ delay = pos - lpib_pos;
+ else
+ delay = lpib_pos - pos;
+ if (delay < 0)
+ delay += azx_dev->bufsize;
+ if (delay >= azx_dev->period_bytes) {
+ snd_printdd("delay %d > period_bytes %d\n",
+ delay, azx_dev->period_bytes);
+ delay = 0; /* something is wrong */
+ }
+ azx_dev->substream->runtime->delay =
+ bytes_to_frames(azx_dev->substream->runtime, delay);
+ }
return pos;
}
@@ -2379,33 +2424,65 @@ static void azx_stop_chip(struct azx *chip)
chip->initialized = 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
/* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus)
+static void azx_power_notify(struct hda_bus *bus, bool power_up)
{
struct azx *chip = bus->private_data;
+
+ if (power_up)
+ pm_runtime_get_sync(&chip->pci->dev);
+ else
+ pm_runtime_put_sync(&chip->pci->dev);
+}
+
+static DEFINE_MUTEX(card_list_lock);
+static LIST_HEAD(card_list);
+
+static void azx_add_card_list(struct azx *chip)
+{
+ mutex_lock(&card_list_lock);
+ list_add(&chip->list, &card_list);
+ mutex_unlock(&card_list_lock);
+}
+
+static void azx_del_card_list(struct azx *chip)
+{
+ mutex_lock(&card_list_lock);
+ list_del_init(&chip->list);
+ mutex_unlock(&card_list_lock);
+}
+
+/* trigger power-save check at writing parameter */
+static int param_set_xint(const char *val, const struct kernel_param *kp)
+{
+ struct azx *chip;
struct hda_codec *c;
- int power_on = 0;
+ int prev = power_save;
+ int ret = param_set_int(val, kp);
- list_for_each_entry(c, &bus->codec_list, list) {
- if (c->power_on) {
- power_on = 1;
- break;
- }
+ if (ret || prev == power_save)
+ return ret;
+
+ mutex_lock(&card_list_lock);
+ list_for_each_entry(chip, &card_list, list) {
+ if (!chip->bus || chip->disabled)
+ continue;
+ list_for_each_entry(c, &chip->bus->codec_list, list)
+ snd_hda_power_sync(c);
}
- if (power_on)
- azx_init_chip(chip, 1);
- else if (chip->running && power_save_controller &&
- !bus->power_keep_link_on)
- azx_stop_chip(chip);
+ mutex_unlock(&card_list_lock);
+ return 0;
}
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#else
+#define azx_add_card_list(chip) /* NOP */
+#define azx_del_card_list(chip) /* NOP */
+#endif /* CONFIG_PM */
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)
/*
* power management
*/
-
static int azx_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -2460,11 +2537,41 @@ static int azx_resume(struct device *dev)
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
-static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume);
+#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */
+
+#ifdef CONFIG_PM_RUNTIME
+static int azx_runtime_suspend(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+
+ if (!power_save_controller)
+ return -EAGAIN;
+
+ azx_stop_chip(chip);
+ azx_clear_irq_pending(chip);
+ return 0;
+}
+
+static int azx_runtime_resume(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+
+ azx_init_pci(chip);
+ azx_init_chip(chip, 1);
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops azx_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
+ SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL)
+};
+
#define AZX_PM_OPS &azx_pm
#else
-#define azx_suspend(dev)
-#define azx_resume(dev)
#define AZX_PM_OPS NULL
#endif /* CONFIG_PM */
@@ -2599,6 +2706,8 @@ static int azx_free(struct azx *chip)
{
int i;
+ azx_del_card_list(chip);
+
azx_notifier_unregister(chip);
if (use_vga_switcheroo(chip)) {
@@ -2640,6 +2749,10 @@ static int azx_free(struct azx *chip)
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip->azx_dev);
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ if (chip->fw)
+ release_firmware(chip->fw);
+#endif
kfree(chip);
return 0;
@@ -2719,6 +2832,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
const struct snd_pci_quirk *q;
switch (fix) {
+ case POS_FIX_AUTO:
case POS_FIX_LPIB:
case POS_FIX_POSBUF:
case POS_FIX_VIACOMBO:
@@ -2904,6 +3018,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->dev_index = dev;
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
INIT_LIST_HEAD(&chip->pcm_list);
+ INIT_LIST_HEAD(&chip->list);
init_vga_switcheroo(chip);
chip->position_fix[0] = chip->position_fix[1] =
@@ -3138,7 +3253,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip)
static void power_down_all_codecs(struct azx *chip)
{
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
/* The codecs were powered up in snd_hda_codec_new().
* Now all initialization done, so turn them down if possible
*/
@@ -3149,12 +3264,40 @@ static void power_down_all_codecs(struct azx *chip)
#endif
}
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+/* callback from request_firmware_nowait() */
+static void azx_firmware_cb(const struct firmware *fw, void *context)
+{
+ struct snd_card *card = context;
+ struct azx *chip = card->private_data;
+ struct pci_dev *pci = chip->pci;
+
+ if (!fw) {
+ snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n");
+ goto error;
+ }
+
+ chip->fw = fw;
+ if (!chip->disabled) {
+ /* continue probing */
+ if (azx_probe_continue(chip))
+ goto error;
+ }
+ return; /* OK */
+
+ error:
+ snd_card_free(card);
+ pci_set_drvdata(pci, NULL);
+}
+#endif
+
static int __devinit azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
static int dev;
struct snd_card *card;
struct azx *chip;
+ bool probe_now;
int err;
if (dev >= SNDRV_CARDS)
@@ -3170,15 +3313,28 @@ static int __devinit azx_probe(struct pci_dev *pci,
return err;
}
- /* set this here since it's referred in snd_hda_load_patch() */
snd_card_set_dev(card, &pci->dev);
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
if (err < 0)
goto out_free;
card->private_data = chip;
+ probe_now = !chip->disabled;
- if (!chip->disabled) {
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ if (patch[dev] && *patch[dev]) {
+ snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
+ patch[dev]);
+ err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
+ &pci->dev, GFP_KERNEL, card,
+ azx_firmware_cb);
+ if (err < 0)
+ goto out_free;
+ probe_now = false; /* continued in azx_firmware_cb() */
+ }
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+
+ if (probe_now) {
err = azx_probe_continue(chip);
if (err < 0)
goto out_free;
@@ -3186,6 +3342,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
pci_set_drvdata(pci, card);
+ if (pci_dev_run_wake(pci))
+ pm_runtime_put_noidle(&pci->dev);
+
dev++;
return 0;
@@ -3208,12 +3367,13 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
if (err < 0)
goto out_free;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (patch[dev] && *patch[dev]) {
- snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
- patch[dev]);
- err = snd_hda_load_patch(chip->bus, patch[dev]);
+ if (chip->fw) {
+ err = snd_hda_load_patch(chip->bus, chip->fw->size,
+ chip->fw->data);
if (err < 0)
goto out_free;
+ release_firmware(chip->fw); /* no longer needed */
+ chip->fw = NULL;
}
#endif
if ((probe_only[dev] & 1) == 0) {
@@ -3239,6 +3399,7 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
chip->running = 1;
power_down_all_codecs(chip);
azx_notifier_register(chip);
+ azx_add_card_list(chip);
return 0;
@@ -3250,6 +3411,10 @@ out_free:
static void __devexit azx_remove(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
+
+ if (pci_dev_run_wake(pci))
+ pm_runtime_get_noresume(&pci->dev);
+
if (card)
snd_card_free(card);
pci_set_drvdata(pci, NULL);
@@ -3260,7 +3425,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* CPT */
{ PCI_DEVICE(0x8086, 0x1c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
/* PBG */
{ PCI_DEVICE(0x8086, 0x1d20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
@@ -3268,23 +3433,30 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0c0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ { PCI_DEVICE(0x8086, 0x0d0c),
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ /* 5 Series/3400 */
+ { PCI_DEVICE(0x8086, 0x3b56),
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
/* SCH */
{ PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index aaccc0236bd..c9333c9688f 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -26,9 +26,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
return false;
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
return false;
- if (!codec->ignore_misc_bit &&
- (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
- AC_DEFCFG_MISC_NO_PRESENCE))
+ if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+ AC_DEFCFG_MISC_NO_PRESENCE)
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
return false;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 1b4c12941ba..09dbdc37f78 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -529,7 +529,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
#endif
-#if defined(CONFIG_SND_HDA_POWER_SAVE) && defined(CONFIG_SND_HDA_HWDEP)
+#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP)
int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
#else
static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 6894ec66258..045e5d32f5d 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -402,6 +402,9 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
{
unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_DIGI_CONVERT_1, 0);
+ unsigned char digi2 = digi1 >> 8;
+ unsigned char digi3 = digi1 >> 16;
+
snd_iprintf(buffer, " Digital:");
if (digi1 & AC_DIG1_ENABLE)
snd_iprintf(buffer, " Enabled");
@@ -419,9 +422,13 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
snd_iprintf(buffer, " Pro");
if (digi1 & AC_DIG1_LEVEL)
snd_iprintf(buffer, " GenLevel");
+ if (digi3 & AC_DIG3_KAE)
+ snd_iprintf(buffer, " KAE");
snd_iprintf(buffer, "\n");
snd_iprintf(buffer, " Digital category: 0x%x\n",
- (digi1 >> 8) & AC_DIG2_CC);
+ digi2 & AC_DIG2_CC);
+ snd_iprintf(buffer, " IEC Coding Type: 0x%x\n",
+ digi3 & AC_DIG3_ICT);
}
static const char *get_pwr_state(u32 state)
diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h
index 9884871ddb0..3a1c63161eb 100644
--- a/sound/pci/hda/hda_trace.h
+++ b/sound/pci/hda/hda_trace.h
@@ -58,6 +58,7 @@ TRACE_EVENT(hda_bus_reset,
TP_printk("[%d]", __entry->card)
);
+#ifdef CONFIG_PM
DECLARE_EVENT_CLASS(hda_power,
TP_PROTO(struct hda_codec *codec),
@@ -87,6 +88,31 @@ DEFINE_EVENT(hda_power, hda_power_up,
TP_ARGS(codec)
);
+TRACE_EVENT(hda_power_count,
+ TP_PROTO(struct hda_codec *codec),
+ TP_ARGS(codec),
+ TP_STRUCT__entry(
+ __field( unsigned int, card )
+ __field( unsigned int, addr )
+ __field( int, power_count )
+ __field( int, power_on )
+ __field( int, power_transition )
+ ),
+
+ TP_fast_assign(
+ __entry->card = (codec)->bus->card->number;
+ __entry->addr = (codec)->addr;
+ __entry->power_count = (codec)->power_count;
+ __entry->power_on = (codec)->power_on;
+ __entry->power_transition = (codec)->power_transition;
+ ),
+
+ TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d",
+ __entry->card, __entry->addr, __entry->power_count,
+ __entry->power_on, __entry->power_transition)
+);
+#endif /* CONFIG_PM */
+
TRACE_EVENT(hda_unsol_event,
TP_PROTO(struct hda_bus *bus, u32 res, u32 res_ex),
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 0208fa121e5..cdd43eadbc6 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -85,7 +85,7 @@ struct ad198x_spec {
unsigned int analog_beep: 1; /* analog beep input present */
unsigned int avoid_init_slave_vol:1;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
struct hda_loopback_check loopback;
#endif
/* for virtual master */
@@ -269,7 +269,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
struct ad198x_spec *spec = codec->spec;
@@ -654,10 +654,8 @@ static const struct hda_codec_ops ad198x_patch_ops = {
.build_pcms = ad198x_build_pcms,
.init = ad198x_init,
.free = ad198x_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- .check_power_status = ad198x_check_power_status,
-#endif
#ifdef CONFIG_PM
+ .check_power_status = ad198x_check_power_status,
.suspend = ad198x_suspend,
#endif
.reboot_notify = ad198x_shutup,
@@ -1231,7 +1229,7 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
{}
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1986a_loopbacks[] = {
{ 0x13, HDA_OUTPUT, 0 }, /* Mic */
{ 0x14, HDA_OUTPUT, 0 }, /* Phone */
@@ -1278,7 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
spec->mixers[0] = ad1986a_mixers;
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1986a_init_verbs;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1986a_loopbacks;
#endif
spec->vmaster_nid = 0x1b;
@@ -1537,7 +1535,7 @@ static const struct hda_verb ad1983_init_verbs[] = {
{ } /* end */
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1983_loopbacks[] = {
{ 0x12, HDA_OUTPUT, 0 }, /* Mic */
{ 0x13, HDA_OUTPUT, 0 }, /* Line */
@@ -1576,7 +1574,7 @@ static int patch_ad1983(struct hda_codec *codec)
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1983_init_verbs;
spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1983_loopbacks;
#endif
spec->vmaster_nid = 0x05;
@@ -1704,7 +1702,7 @@ static const struct hda_verb ad1981_init_verbs[] = {
{ } /* end */
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1981_loopbacks[] = {
{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
{ 0x13, HDA_OUTPUT, 0 }, /* Line */
@@ -1812,7 +1810,7 @@ static const struct hda_input_mux ad1981_hp_capture_source = {
.num_items = 3,
.items = {
{ "Mic", 0x0 },
- { "Docking-Station", 0x1 },
+ { "Dock Mic", 0x1 },
{ "Mix", 0x2 },
},
};
@@ -1836,8 +1834,8 @@ static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
*/
HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
/* FIXME: does this laptop have analog CD connection? */
@@ -1982,7 +1980,7 @@ static int patch_ad1981(struct hda_codec *codec)
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1981_init_verbs;
spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1981_loopbacks;
#endif
spec->vmaster_nid = 0x05;
@@ -2807,7 +2805,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1988_loopbacks[] = {
{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
{ 0x20, HDA_INPUT, 1 }, /* Line */
@@ -3399,7 +3397,7 @@ static int patch_ad1988(struct hda_codec *codec)
codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
break;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1988_loopbacks;
#endif
spec->vmaster_nid = 0x04;
@@ -3555,7 +3553,7 @@ static const struct hda_verb ad1884_init_verbs[] = {
{ } /* end */
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1884_loopbacks[] = {
{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
{ 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -3567,7 +3565,7 @@ static const struct hda_amp_list ad1884_loopbacks[] = {
static const char * const ad1884_slave_vols[] = {
"PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
- "Internal Mic", "Docking Mic", /* "Beep", */ "IEC958",
+ "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
NULL
};
@@ -3602,7 +3600,7 @@ static int patch_ad1884(struct hda_codec *codec)
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1884_init_verbs;
spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1884_loopbacks;
#endif
spec->vmaster_nid = 0x04;
@@ -3628,7 +3626,7 @@ static const struct hda_input_mux ad1984_thinkpad_capture_source = {
{ "Mic", 0x0 },
{ "Internal Mic", 0x1 },
{ "Mix", 0x3 },
- { "Docking-Station", 0x4 },
+ { "Dock Mic", 0x4 },
},
};
@@ -3657,8 +3655,8 @@ static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
- HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
@@ -3994,7 +3992,7 @@ static const struct hda_verb ad1884a_init_verbs[] = {
{ } /* end */
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1884a_loopbacks[] = {
{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
{ 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -4602,7 +4600,7 @@ static int patch_ad1884a(struct hda_codec *codec)
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1884a_init_verbs;
spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1884a_loopbacks;
#endif
codec->patch_ops = ad198x_patch_ops;
@@ -4814,6 +4812,32 @@ static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
{ } /* end */
};
+/* simple auto-mute control for AD1882 3-stack board */
+#define AD1882_HP_EVENT 0x01
+
+static void ad1882_3stack_automute(struct hda_codec *codec)
+{
+ bool mute = snd_hda_jack_detect(codec, 0x11);
+ snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ mute ? 0 : PIN_OUT);
+}
+
+static int ad1882_3stack_automute_init(struct hda_codec *codec)
+{
+ ad198x_init(codec);
+ ad1882_3stack_automute(codec);
+ return 0;
+}
+
+static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ switch (res >> 26) {
+ case AD1882_HP_EVENT:
+ ad1882_3stack_automute(codec);
+ break;
+ }
+}
+
static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
@@ -4928,7 +4952,12 @@ static const struct hda_verb ad1882_init_verbs[] = {
{ } /* end */
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_verb ad1882_3stack_automute_verbs[] = {
+ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
+ { } /* end */
+};
+
+#ifdef CONFIG_PM
static const struct hda_amp_list ad1882_loopbacks[] = {
{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
{ 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -4942,12 +4971,14 @@ static const struct hda_amp_list ad1882_loopbacks[] = {
enum {
AD1882_3STACK,
AD1882_6STACK,
+ AD1882_3STACK_AUTOMUTE,
AD1882_MODELS
};
static const char * const ad1882_models[AD1986A_MODELS] = {
[AD1882_3STACK] = "3stack",
[AD1882_6STACK] = "6stack",
+ [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
};
@@ -4989,7 +5020,7 @@ static int patch_ad1882(struct hda_codec *codec)
spec->num_init_verbs = 1;
spec->init_verbs[0] = ad1882_init_verbs;
spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->loopback.amplist = ad1882_loopbacks;
#endif
spec->vmaster_nid = 0x04;
@@ -5002,6 +5033,7 @@ static int patch_ad1882(struct hda_codec *codec)
switch (board_config) {
default:
case AD1882_3STACK:
+ case AD1882_3STACK_AUTOMUTE:
spec->num_mixers = 3;
spec->mixers[2] = ad1882_3stack_mixers;
spec->channel_mode = ad1882_modes;
@@ -5009,6 +5041,12 @@ static int patch_ad1882(struct hda_codec *codec)
spec->need_dac_fix = 1;
spec->multiout.max_channels = 2;
spec->multiout.num_dacs = 1;
+ if (board_config != AD1882_3STACK) {
+ spec->init_verbs[spec->num_init_verbs++] =
+ ad1882_3stack_automute_verbs;
+ codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
+ codec->patch_ops.init = ad1882_3stack_automute_init;
+ }
break;
case AD1882_6STACK:
spec->num_mixers = 3;
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 0c4c1a61b37..fcfc9f0a056 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -34,7 +34,8 @@
*/
struct cs_spec {
- int board_config;
+ struct hda_gen_spec gen;
+
struct auto_pin_cfg autocfg;
struct hda_multi_out multiout;
struct snd_kcontrol *vmaster_sw;
@@ -80,16 +81,20 @@ enum {
CS420X_MBP53,
CS420X_MBP55,
CS420X_IMAC27,
- CS420X_IMAC27_122,
- CS420X_APPLE,
+ CS420X_GPIO_13,
+ CS420X_GPIO_23,
+ CS420X_MBP101,
+ CS420X_MBP101_COEF,
CS420X_AUTO,
- CS420X_MODELS
+ /* aliases */
+ CS420X_IMAC27_122 = CS420X_GPIO_23,
+ CS420X_APPLE = CS420X_GPIO_13,
};
/* CS421x boards */
enum {
CS421X_CDB4210,
- CS421X_MODELS
+ CS421X_SENSE_B,
};
/* Vendor-specific processing widget */
@@ -1157,6 +1162,14 @@ static const struct hda_verb cs_errata_init_verbs[] = {
{} /* terminator */
};
+static const struct hda_verb mbp101_init_verbs[] = {
+ {0x11, AC_VERB_SET_COEF_INDEX, 0x0002},
+ {0x11, AC_VERB_SET_PROC_COEF, 0x100a},
+ {0x11, AC_VERB_SET_COEF_INDEX, 0x0004},
+ {0x11, AC_VERB_SET_PROC_COEF, 0x000f},
+ {}
+};
+
/* SPDIF setup */
static void init_digital(struct hda_codec *codec)
{
@@ -1193,7 +1206,6 @@ static int cs_init(struct hda_codec *codec)
init_output(codec);
init_input(codec);
init_digital(codec);
- snd_hda_jack_report_sync(codec);
return 0;
}
@@ -1279,38 +1291,32 @@ static int cs_parse_auto_config(struct hda_codec *codec)
return 0;
}
-static const char * const cs420x_models[CS420X_MODELS] = {
- [CS420X_MBP53] = "mbp53",
- [CS420X_MBP55] = "mbp55",
- [CS420X_IMAC27] = "imac27",
- [CS420X_IMAC27_122] = "imac27_122",
- [CS420X_APPLE] = "apple",
- [CS420X_AUTO] = "auto",
+static const struct hda_model_fixup cs420x_models[] = {
+ { .id = CS420X_MBP53, .name = "mbp53" },
+ { .id = CS420X_MBP55, .name = "mbp55" },
+ { .id = CS420X_IMAC27, .name = "imac27" },
+ { .id = CS420X_IMAC27_122, .name = "imac27_122" },
+ { .id = CS420X_APPLE, .name = "apple" },
+ { .id = CS420X_MBP101, .name = "mbp101" },
+ {}
};
-
-static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
/* this conflicts with too many other models */
/*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
- {} /* terminator */
-};
-static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
+ /* codec SSID */
SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
+ SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
{} /* terminator */
};
-struct cs_pincfg {
- hda_nid_t nid;
- u32 val;
-};
-
-static const struct cs_pincfg mbp53_pincfgs[] = {
+static const struct hda_pintbl mbp53_pincfgs[] = {
{ 0x09, 0x012b4050 },
{ 0x0a, 0x90100141 },
{ 0x0b, 0x90100140 },
@@ -1324,7 +1330,7 @@ static const struct cs_pincfg mbp53_pincfgs[] = {
{} /* terminator */
};
-static const struct cs_pincfg mbp55_pincfgs[] = {
+static const struct hda_pintbl mbp55_pincfgs[] = {
{ 0x09, 0x012b4030 },
{ 0x0a, 0x90100121 },
{ 0x0b, 0x90100120 },
@@ -1338,7 +1344,7 @@ static const struct cs_pincfg mbp55_pincfgs[] = {
{} /* terminator */
};
-static const struct cs_pincfg imac27_pincfgs[] = {
+static const struct hda_pintbl imac27_pincfgs[] = {
{ 0x09, 0x012b4050 },
{ 0x0a, 0x90100140 },
{ 0x0b, 0x90100142 },
@@ -1352,22 +1358,78 @@ static const struct cs_pincfg imac27_pincfgs[] = {
{} /* terminator */
};
-static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
- [CS420X_MBP53] = mbp53_pincfgs,
- [CS420X_MBP55] = mbp55_pincfgs,
- [CS420X_IMAC27] = imac27_pincfgs,
+static const struct hda_pintbl mbp101_pincfgs[] = {
+ { 0x0d, 0x40ab90f0 },
+ { 0x0e, 0x90a600f0 },
+ { 0x12, 0x50a600f0 },
+ {} /* terminator */
};
-static void fix_pincfg(struct hda_codec *codec, int model,
- const struct cs_pincfg **pin_configs)
+static void cs420x_fixup_gpio_13(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
{
- const struct cs_pincfg *cfg = pin_configs[model];
- if (!cfg)
- return;
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct cs_spec *spec = codec->spec;
+ spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
+ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+ spec->gpio_mask = spec->gpio_dir =
+ spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+ }
}
+static void cs420x_fixup_gpio_23(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct cs_spec *spec = codec->spec;
+ spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
+ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+ spec->gpio_mask = spec->gpio_dir =
+ spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+ }
+}
+
+static const struct hda_fixup cs420x_fixups[] = {
+ [CS420X_MBP53] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = mbp53_pincfgs,
+ .chained = true,
+ .chain_id = CS420X_APPLE,
+ },
+ [CS420X_MBP55] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = mbp55_pincfgs,
+ .chained = true,
+ .chain_id = CS420X_GPIO_13,
+ },
+ [CS420X_IMAC27] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = imac27_pincfgs,
+ .chained = true,
+ .chain_id = CS420X_GPIO_13,
+ },
+ [CS420X_GPIO_13] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs420x_fixup_gpio_13,
+ },
+ [CS420X_GPIO_23] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs420x_fixup_gpio_23,
+ },
+ [CS420X_MBP101] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = mbp101_pincfgs,
+ .chained = true,
+ .chain_id = CS420X_MBP101_COEF,
+ },
+ [CS420X_MBP101_COEF] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = mbp101_init_verbs,
+ .chained = true,
+ .chain_id = CS420X_GPIO_13,
+ },
+};
+
static int patch_cs420x(struct hda_codec *codec)
{
struct cs_spec *spec;
@@ -1380,33 +1442,9 @@ static int patch_cs420x(struct hda_codec *codec)
spec->vendor_nid = CS420X_VENDOR_NID;
- spec->board_config =
- snd_hda_check_board_config(codec, CS420X_MODELS,
- cs420x_models, cs420x_cfg_tbl);
- if (spec->board_config < 0)
- spec->board_config =
- snd_hda_check_board_codec_sid_config(codec,
- CS420X_MODELS, NULL, cs420x_codec_cfg_tbl);
- if (spec->board_config >= 0)
- fix_pincfg(codec, spec->board_config, cs_pincfgs);
-
- switch (spec->board_config) {
- case CS420X_IMAC27:
- case CS420X_MBP53:
- case CS420X_MBP55:
- case CS420X_APPLE:
- spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
- spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
- spec->gpio_mask = spec->gpio_dir =
- spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
- break;
- case CS420X_IMAC27_122:
- spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
- spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
- spec->gpio_mask = spec->gpio_dir =
- spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
- break;
- }
+ snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
+ cs420x_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = cs_parse_auto_config(codec);
if (err < 0)
@@ -1414,6 +1452,8 @@ static int patch_cs420x(struct hda_codec *codec)
codec->patch_ops = cs_patch_ops;
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
return 0;
error:
@@ -1431,11 +1471,12 @@ static int patch_cs420x(struct hda_codec *codec)
*/
/* CS4210 board names */
-static const char *cs421x_models[CS421X_MODELS] = {
- [CS421X_CDB4210] = "cdb4210",
+static const struct hda_model_fixup cs421x_models[] = {
+ { .id = CS421X_CDB4210, .name = "cdb4210" },
+ {}
};
-static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs421x_fixup_tbl[] = {
/* Test Intel board + CDB2410 */
SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
{} /* terminator */
@@ -1443,7 +1484,7 @@ static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
/* CS4210 board pinconfigs */
/* Default CS4210 (CDB4210)*/
-static const struct cs_pincfg cdb4210_pincfgs[] = {
+static const struct hda_pintbl cdb4210_pincfgs[] = {
{ 0x05, 0x0321401f },
{ 0x06, 0x90170010 },
{ 0x07, 0x03813031 },
@@ -1453,8 +1494,26 @@ static const struct cs_pincfg cdb4210_pincfgs[] = {
{} /* terminator */
};
-static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = {
- [CS421X_CDB4210] = cdb4210_pincfgs,
+/* Setup GPIO/SENSE for each board (if used) */
+static void cs421x_fixup_sense_b(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct cs_spec *spec = codec->spec;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->sense_b = 1;
+}
+
+static const struct hda_fixup cs421x_fixups[] = {
+ [CS421X_CDB4210] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cdb4210_pincfgs,
+ .chained = true,
+ .chain_id = CS421X_SENSE_B,
+ },
+ [CS421X_SENSE_B] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs421x_fixup_sense_b,
+ }
};
static const struct hda_verb cs421x_coef_init_verbs[] = {
@@ -1643,7 +1702,6 @@ static int cs421x_init(struct hda_codec *codec)
init_output(codec);
init_input(codec);
init_cs421x_digital(codec);
- snd_hda_jack_report_sync(codec);
return 0;
}
@@ -1937,26 +1995,9 @@ static int patch_cs4210(struct hda_codec *codec)
spec->vendor_nid = CS4210_VENDOR_NID;
- spec->board_config =
- snd_hda_check_board_config(codec, CS421X_MODELS,
- cs421x_models, cs421x_cfg_tbl);
- if (spec->board_config >= 0)
- fix_pincfg(codec, spec->board_config, cs421x_pincfgs);
- /*
- Setup GPIO/SENSE for each board (if used)
- */
- switch (spec->board_config) {
- case CS421X_CDB4210:
- snd_printd("CS4210 board: %s\n",
- cs421x_models[spec->board_config]);
-/* spec->gpio_mask = 3;
- spec->gpio_dir = 3;
- spec->gpio_data = 3;
-*/
- spec->sense_b = 1;
-
- break;
- }
+ snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
+ cs421x_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
/*
Update the GPIO/DMIC/SENSE_B pinmux before the configuration
@@ -1971,6 +2012,8 @@ static int patch_cs4210(struct hda_codec *codec)
codec->patch_ops = cs421x_patch_ops;
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
return 0;
error:
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 5e22a8f43d2..c03d3b8e42b 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -553,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec)
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static int conexant_suspend(struct hda_codec *codec)
{
snd_hda_shutup_pins(codec);
@@ -567,7 +567,7 @@ static const struct hda_codec_ops conexant_patch_ops = {
.init = conexant_init,
.free = conexant_free,
.set_power_state = conexant_set_power,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
.suspend = conexant_suspend,
#endif
.reboot_notify = snd_hda_shutup_pins,
@@ -1710,8 +1710,8 @@ static const struct snd_kcontrol_new cxt5051_capture_mixers[] = {
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
- HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT),
+ HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT),
{}
};
@@ -3540,8 +3540,9 @@ static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t pin, hda_nid_t *srcp,
bool do_select, int depth)
{
+ struct conexant_spec *spec = codec->spec;
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int i, nums;
+ int startidx, i, nums;
switch (get_wcaps_type(get_wcaps(codec, mux))) {
case AC_WID_AUD_IN:
@@ -3565,14 +3566,25 @@ static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
depth++;
if (depth == 2)
return -1;
+
+ /* Try to rotate around connections to avoid one boost controlling
+ another input path as well */
+ startidx = 0;
+ for (i = 0; i < spec->private_imux.num_items; i++)
+ if (spec->imux_info[i].pin == pin) {
+ startidx = i;
+ break;
+ }
+
for (i = 0; i < nums; i++) {
- int ret = __select_input_connection(codec, conn[i], pin, srcp,
+ int j = (i + startidx) % nums;
+ int ret = __select_input_connection(codec, conn[j], pin, srcp,
do_select, depth);
if (ret >= 0) {
if (do_select)
snd_hda_codec_write(codec, mux, 0,
- AC_VERB_SET_CONNECT_SEL, i);
- return i;
+ AC_VERB_SET_CONNECT_SEL, j);
+ return j;
}
}
return -1;
@@ -4061,7 +4073,6 @@ static int cx_auto_init(struct hda_codec *codec)
cx_auto_init_output(codec);
cx_auto_init_input(codec);
cx_auto_init_digital(codec);
- snd_hda_jack_report_sync(codec);
snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
return 0;
}
@@ -4396,7 +4407,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
.init = cx_auto_init,
.free = conexant_free,
.unsol_event = cx_auto_unsol_event,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
.suspend = conexant_suspend,
#endif
.reboot_notify = snd_hda_shutup_pins,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8f23374fa64..71555cc54db 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -34,6 +34,8 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
+#include <sound/asoundef.h>
+#include <sound/tlv.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_jack.h"
@@ -71,6 +73,9 @@ struct hdmi_spec_per_pin {
struct hdmi_eld sink_eld;
struct delayed_work work;
int repoll_count;
+ bool non_pcm;
+ bool chmap_set; /* channel-map override by ALSA API? */
+ unsigned char chmap[8]; /* ALSA API channel-map */
};
struct hdmi_spec {
@@ -80,6 +85,7 @@ struct hdmi_spec {
int num_pins;
struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
struct hda_pcm pcm_rec[MAX_HDMI_PINS];
+ unsigned int channels_max; /* max over all cvts */
/*
* Non-generic ATI/NVIDIA specific
@@ -469,6 +475,17 @@ static void init_channel_allocations(void)
}
}
+static int get_channel_allocation_order(int ca)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channel_allocations[i].ca_index == ca)
+ break;
+ }
+ return i;
+}
+
/*
* The transformation takes two steps:
*
@@ -535,24 +552,36 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
}
-static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid,
+ bool non_pcm,
int ca)
{
int i;
int err;
+ int order;
+ int non_pcm_mapping[8];
+
+ order = get_channel_allocation_order(ca);
if (hdmi_channel_mapping[ca][1] == 0) {
- for (i = 0; i < channel_allocations[ca].channels; i++)
+ for (i = 0; i < channel_allocations[order].channels; i++)
hdmi_channel_mapping[ca][i] = i | (i << 4);
for (; i < 8; i++)
hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
}
+ if (non_pcm) {
+ for (i = 0; i < channel_allocations[order].channels; i++)
+ non_pcm_mapping[i] = i | (i << 4);
+ for (; i < 8; i++)
+ non_pcm_mapping[i] = 0xf | (i << 4);
+ }
+
for (i = 0; i < 8; i++) {
err = snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_HDMI_CHAN_SLOT,
- hdmi_channel_mapping[ca][i]);
+ non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]);
if (err) {
snd_printdd(KERN_NOTICE
"HDMI: channel mapping failed\n");
@@ -563,6 +592,136 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
hdmi_debug_channel_mapping(codec, pin_nid);
}
+struct channel_map_table {
+ unsigned char map; /* ALSA API channel map position */
+ unsigned char cea_slot; /* CEA slot value */
+ int spk_mask; /* speaker position bit mask */
+};
+
+static struct channel_map_table map_tables[] = {
+ { SNDRV_CHMAP_FL, 0x00, FL },
+ { SNDRV_CHMAP_FR, 0x01, FR },
+ { SNDRV_CHMAP_RL, 0x04, RL },
+ { SNDRV_CHMAP_RR, 0x05, RR },
+ { SNDRV_CHMAP_LFE, 0x02, LFE },
+ { SNDRV_CHMAP_FC, 0x03, FC },
+ { SNDRV_CHMAP_RLC, 0x06, RLC },
+ { SNDRV_CHMAP_RRC, 0x07, RRC },
+ {} /* terminator */
+};
+
+/* from ALSA API channel position to speaker bit mask */
+static int to_spk_mask(unsigned char c)
+{
+ struct channel_map_table *t = map_tables;
+ for (; t->map; t++) {
+ if (t->map == c)
+ return t->spk_mask;
+ }
+ return 0;
+}
+
+/* from ALSA API channel position to CEA slot */
+static int to_cea_slot(unsigned char c)
+{
+ struct channel_map_table *t = map_tables;
+ for (; t->map; t++) {
+ if (t->map == c)
+ return t->cea_slot;
+ }
+ return 0x0f;
+}
+
+/* from CEA slot to ALSA API channel position */
+static int from_cea_slot(unsigned char c)
+{
+ struct channel_map_table *t = map_tables;
+ for (; t->map; t++) {
+ if (t->cea_slot == c)
+ return t->map;
+ }
+ return 0;
+}
+
+/* from speaker bit mask to ALSA API channel position */
+static int spk_to_chmap(int spk)
+{
+ struct channel_map_table *t = map_tables;
+ for (; t->map; t++) {
+ if (t->spk_mask == spk)
+ return t->map;
+ }
+ return 0;
+}
+
+/* get the CA index corresponding to the given ALSA API channel map */
+static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
+{
+ int i, spks = 0, spk_mask = 0;
+
+ for (i = 0; i < chs; i++) {
+ int mask = to_spk_mask(map[i]);
+ if (mask) {
+ spk_mask |= mask;
+ spks++;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if ((chs == channel_allocations[i].channels ||
+ spks == channel_allocations[i].channels) &&
+ (spk_mask & channel_allocations[i].spk_mask) ==
+ channel_allocations[i].spk_mask)
+ return channel_allocations[i].ca_index;
+ }
+ return -1;
+}
+
+/* set up the channel slots for the given ALSA API channel map */
+static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
+ hda_nid_t pin_nid,
+ int chs, unsigned char *map)
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+ int val, err;
+ if (i < chs)
+ val = to_cea_slot(map[i]);
+ else
+ val = 0xf;
+ val |= (i << 4);
+ err = snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_HDMI_CHAN_SLOT, val);
+ if (err)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* store ALSA API channel map from the current default map */
+static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (i < channel_allocations[ca].channels)
+ map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f);
+ else
+ map[i] = 0;
+ }
+}
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+ hda_nid_t pin_nid, bool non_pcm, int ca,
+ int channels, unsigned char *map)
+{
+ if (!non_pcm && map) {
+ hdmi_manual_setup_channel_mapping(codec, pin_nid,
+ channels, map);
+ } else {
+ hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca);
+ hdmi_setup_fake_chmap(map, ca);
+ }
+}
/*
* Audio InfoFrame routines
@@ -686,7 +845,8 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
}
static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
- struct snd_pcm_substream *substream)
+ bool non_pcm,
+ struct snd_pcm_substream *substream)
{
struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
@@ -700,7 +860,12 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
if (!eld->monitor_present)
return;
- ca = hdmi_channel_allocation(eld, channels);
+ if (!non_pcm && per_pin->chmap_set)
+ ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
+ else
+ ca = hdmi_channel_allocation(eld, channels);
+ if (ca < 0)
+ ca = 0;
memset(&ai, 0, sizeof(ai));
if (eld->conn_type == 0) { /* HDMI */
@@ -737,12 +902,21 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
"pin=%d channels=%d\n",
pin_nid,
channels);
- hdmi_setup_channel_mapping(codec, pin_nid, ca);
+ hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+ channels, per_pin->chmap);
hdmi_stop_infoframe_trans(codec, pin_nid);
hdmi_fill_audio_infoframe(codec, pin_nid,
ai.bytes, sizeof(ai));
hdmi_start_infoframe_trans(codec, pin_nid);
+ } else {
+ /* For non-pcm audio switch, setup new channel mapping
+ * accordingly */
+ if (per_pin->non_pcm != non_pcm)
+ hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+ channels, per_pin->chmap);
}
+
+ per_pin->non_pcm = non_pcm;
}
@@ -1035,6 +1209,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
per_pin = &spec->pins[pin_idx];
per_pin->pin_nid = pin_nid;
+ per_pin->non_pcm = false;
err = hdmi_read_pin_conn(codec, pin_idx);
if (err < 0)
@@ -1064,8 +1239,11 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
per_cvt->cvt_nid = cvt_nid;
per_cvt->channels_min = 2;
- if (chans <= 16)
+ if (chans <= 16) {
per_cvt->channels_max = chans;
+ if (chans > spec->channels_max)
+ spec->channels_max = chans;
+ }
err = snd_hda_query_supported_pcm(codec, cvt_nid,
&per_cvt->rates,
@@ -1115,7 +1293,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
* can be lost and presence sense verb will become inaccurate if the
* HDA link is powered off at hot plug or hw initialization time.
*/
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
AC_PWRST_EPSS))
codec->bus->power_keep_link_on = 1;
@@ -1133,6 +1311,19 @@ static char *get_hdmi_pcm_name(int idx)
return &names[idx][0];
}
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+ struct hda_spdif_out *spdif;
+ bool non_pcm;
+
+ mutex_lock(&codec->spdif_mutex);
+ spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
+ non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
+ mutex_unlock(&codec->spdif_mutex);
+ return non_pcm;
+}
+
+
/*
* HDMI callbacks
*/
@@ -1148,10 +1339,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
int pin_idx = hinfo_to_pin_index(spec, hinfo);
hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
int pinctl;
+ bool non_pcm;
+
+ non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
- hdmi_setup_audio_infoframe(codec, pin_idx, substream);
+ hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1200,7 +1394,10 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
AC_VERB_SET_PIN_WIDGET_CONTROL,
pinctl & ~PIN_OUT);
snd_hda_spdif_ctls_unassign(codec, pin_idx);
+ per_pin->chmap_set = false;
+ memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
}
+
return 0;
}
@@ -1211,6 +1408,135 @@ static const struct hda_pcm_ops generic_ops = {
.cleanup = generic_hdmi_playback_pcm_cleanup,
};
+/*
+ * ALSA API channel-map control callbacks
+ */
+static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct hda_codec *codec = info->private_data;
+ struct hdmi_spec *spec = codec->spec;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = spec->channels_max;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+ return 0;
+}
+
+static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct hda_codec *codec = info->private_data;
+ struct hdmi_spec *spec = codec->spec;
+ const unsigned int valid_mask =
+ FL | FR | RL | RR | LFE | FC | RLC | RRC;
+ unsigned int __user *dst;
+ int chs, count = 0;
+
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+ return -EFAULT;
+ size -= 8;
+ dst = tlv + 2;
+ for (chs = 2; chs <= spec->channels_max; chs++) {
+ int i, c;
+ struct cea_channel_speaker_allocation *cap;
+ cap = channel_allocations;
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
+ int chs_bytes = chs * 4;
+ if (cap->channels != chs)
+ continue;
+ if (cap->spk_mask & ~valid_mask)
+ continue;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) ||
+ put_user(chs_bytes, dst + 1))
+ return -EFAULT;
+ dst += 2;
+ size -= 8;
+ count += 8;
+ if (size < chs_bytes)
+ return -ENOMEM;
+ size -= chs_bytes;
+ count += chs_bytes;
+ for (c = 7; c >= 0; c--) {
+ int spk = cap->speakers[c];
+ if (!spk)
+ continue;
+ if (put_user(spk_to_chmap(spk), dst))
+ return -EFAULT;
+ dst++;
+ }
+ }
+ }
+ if (put_user(count, tlv + 1))
+ return -EFAULT;
+ return 0;
+}
+
+static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct hda_codec *codec = info->private_data;
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx = kcontrol->private_value;
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
+ ucontrol->value.integer.value[i] = per_pin->chmap[i];
+ return 0;
+}
+
+static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct hda_codec *codec = info->private_data;
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx = kcontrol->private_value;
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ unsigned int ctl_idx;
+ struct snd_pcm_substream *substream;
+ unsigned char chmap[8];
+ int i, ca, prepared = 0;
+
+ ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ substream = snd_pcm_chmap_substream(info, ctl_idx);
+ if (!substream || !substream->runtime)
+ return -EBADFD;
+ switch (substream->runtime->status->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_SETUP:
+ break;
+ case SNDRV_PCM_STATE_PREPARED:
+ prepared = 1;
+ break;
+ default:
+ return -EBUSY;
+ }
+ memset(chmap, 0, sizeof(chmap));
+ for (i = 0; i < ARRAY_SIZE(chmap); i++)
+ chmap[i] = ucontrol->value.integer.value[i];
+ if (!memcmp(chmap, per_pin->chmap, sizeof(chmap)))
+ return 0;
+ ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
+ if (ca < 0)
+ return -EINVAL;
+ per_pin->chmap_set = true;
+ memcpy(per_pin->chmap, chmap, sizeof(chmap));
+ if (prepared)
+ hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
+ substream);
+
+ return 0;
+}
+
static int generic_hdmi_build_pcms(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
@@ -1223,6 +1549,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
info = &spec->pcm_rec[pin_idx];
info->name = get_hdmi_pcm_name(pin_idx);
info->pcm_type = HDA_PCM_TYPE_HDMI;
+ info->own_chmap = true;
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
pstr->substreams = 1;
@@ -1280,6 +1607,27 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
hdmi_present_sense(per_pin, 0);
}
+ /* add channel maps */
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct snd_pcm_chmap *chmap;
+ struct snd_kcontrol *kctl;
+ int i;
+ err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
+ SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 0, pin_idx, &chmap);
+ if (err < 0)
+ return err;
+ /* override handlers */
+ chmap->private_data = codec;
+ kctl = chmap->kctl;
+ for (i = 0; i < kctl->count; i++)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ kctl->info = hdmi_chmap_ctl_info;
+ kctl->get = hdmi_chmap_ctl_get;
+ kctl->put = hdmi_chmap_ctl_put;
+ kctl->tlv.c = hdmi_chmap_ctl_tlv;
+ }
+
return 0;
}
@@ -1311,7 +1659,6 @@ static int generic_hdmi_init(struct hda_codec *codec)
hdmi_init_pin(codec, pin_nid);
snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
}
- snd_hda_jack_report_sync(codec);
return 0;
}
@@ -1428,7 +1775,6 @@ static int simple_playback_init(struct hda_codec *codec)
snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
snd_hda_jack_detect_enable(codec, pin, pin);
- snd_hda_jack_report_sync(codec);
return 0;
}
@@ -1809,6 +2155,43 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
return 0;
}
+static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int err = simple_playback_build_pcms(codec);
+ spec->pcm_rec[0].own_chmap = true;
+ return err;
+}
+
+static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_pcm_chmap *chmap;
+ int err;
+
+ err = simple_playback_build_controls(codec);
+ if (err < 0)
+ return err;
+
+ /* add channel maps */
+ err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm,
+ SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, 8, 0, &chmap);
+ if (err < 0)
+ return err;
+ switch (codec->preset->id) {
+ case 0x10de0002:
+ case 0x10de0003:
+ case 0x10de0005:
+ case 0x10de0006:
+ chmap->channel_mask = (1U << 2) | (1U << 8);
+ break;
+ case 0x10de0007:
+ chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
+ }
+ return 0;
+}
+
static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
{
struct hdmi_spec *spec;
@@ -1819,6 +2202,8 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
spec->multiout.max_channels = 8;
spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
codec->patch_ops.init = nvhdmi_7x_init_8ch;
+ codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
+ codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
/* Initialize the audio infoframe channel mask and checksum to something
* valid */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4f81dd44c83..3d440fc7c20 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -174,7 +174,7 @@ struct alc_spec {
/* hooks */
void (*init_hook)(struct hda_codec *codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
void (*power_hook)(struct hda_codec *codec);
#endif
void (*shutup)(struct hda_codec *codec);
@@ -215,7 +215,7 @@ struct alc_spec {
/* for virtual master */
hda_nid_t vmaster_nid;
struct hda_vmaster_mute_hook vmaster_mute;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
struct hda_loopback_check loopback;
int num_loopbacks;
struct hda_amp_list loopback_list[8];
@@ -2053,13 +2053,11 @@ static int alc_init(struct hda_codec *codec)
alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
- snd_hda_jack_report_sync(codec);
-
hda_call_check_power_status(codec, 0x01);
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
struct alc_spec *spec = codec->spec;
@@ -2289,6 +2287,8 @@ static int alc_build_pcms(struct hda_codec *codec)
p = &alc_pcm_analog_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
}
if (spec->adc_nids) {
p = spec->stream_analog_capture;
@@ -2437,7 +2437,7 @@ static void alc_free(struct hda_codec *codec)
snd_hda_detach_beep_device(codec);
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static void alc_power_eapd(struct hda_codec *codec)
{
alc_auto_setup_eapd(codec, false);
@@ -2477,7 +2477,7 @@ static const struct hda_codec_ops alc_patch_ops = {
#ifdef CONFIG_PM
.resume = alc_resume,
#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
.suspend = alc_suspend,
.check_power_status = alc_check_power_status,
#endif
@@ -2633,7 +2633,7 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
return channel_name[ch];
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
/* add the powersave loopback-list entry */
static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)
{
@@ -6189,6 +6189,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
@@ -6503,7 +6504,7 @@ static int patch_alc861(struct hda_codec *codec)
}
codec->patch_ops = alc_patch_ops;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
spec->power_hook = alc_power_eapd;
#endif
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 3d4722f0a1c..bb6c50e7b5d 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -103,6 +103,7 @@ enum {
STAC_HP_ZEPHYR,
STAC_92HD83XXX_HP_LED,
STAC_92HD83XXX_HP_INV_LED,
+ STAC_92HD83XXX_HP_MIC_LED,
STAC_92HD83XXX_MODELS
};
@@ -215,6 +216,9 @@ struct sigmatel_spec {
unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
unsigned int vref_led;
+ unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
+ bool mic_mute_led_on; /* current mic mute state */
+
/* stream */
unsigned int stream_delay;
@@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
[STAC_HP_ZEPHYR] = "hp-zephyr",
[STAC_92HD83XXX_HP_LED] = "hp-led",
[STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led",
+ [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led",
};
static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
+ "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
@@ -2791,18 +2798,27 @@ stac_control_new(struct sigmatel_spec *spec,
return knew;
}
-static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
- const struct snd_kcontrol_new *ktemp,
- int idx, const char *name,
- unsigned long val)
+static struct snd_kcontrol_new *
+add_control_temp(struct sigmatel_spec *spec,
+ const struct snd_kcontrol_new *ktemp,
+ int idx, const char *name,
+ unsigned long val)
{
struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
HDA_SUBDEV_AMP_FLAG);
if (!knew)
- return -ENOMEM;
+ return NULL;
knew->index = idx;
knew->private_value = val;
- return 0;
+ return knew;
+}
+
+static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
+ const struct snd_kcontrol_new *ktemp,
+ int idx, const char *name,
+ unsigned long val)
+{
+ return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;
}
static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
@@ -3226,9 +3242,12 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
idx = i;
break;
case AUTO_PIN_SPEAKER_OUT:
- name = "Speaker";
- idx = i;
- break;
+ if (num_outs <= 1) {
+ name = "Speaker";
+ idx = i;
+ break;
+ }
+ /* Fall through in case of multi speaker outs */
default:
name = chname[i];
idx = 0;
@@ -3242,18 +3261,56 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
return 0;
}
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+ unsigned int dir_mask, unsigned int data);
+
+/* hook for controlling mic-mute LED GPIO */
+static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ int err;
+ bool mute;
+
+ err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+ if (err <= 0)
+ return err;
+ mute = !(ucontrol->value.integer.value[0] &&
+ ucontrol->value.integer.value[1]);
+ if (spec->mic_mute_led_on != mute) {
+ spec->mic_mute_led_on = mute;
+ if (mute)
+ spec->gpio_data |= spec->mic_mute_led_gpio;
+ else
+ spec->gpio_data &= ~spec->mic_mute_led_gpio;
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data);
+ }
+ return err;
+}
+
static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
unsigned long sw, int idx)
{
+ struct sigmatel_spec *spec = codec->spec;
+ struct snd_kcontrol_new *knew;
int err;
+
err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
"Capture Volume", vol);
if (err < 0)
return err;
- err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
- "Capture Switch", sw);
- if (err < 0)
- return err;
+
+ knew = add_control_temp(spec,
+ &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE],
+ idx, "Capture Switch", sw);
+ if (!knew)
+ return -ENOMEM;
+ /* add a LED hook for some HP laptops */
+ if (spec->mic_mute_led_gpio)
+ knew->put = stac92xx_capture_sw_put_led;
+
return 0;
}
@@ -4418,8 +4475,6 @@ static int stac92xx_init(struct hda_codec *codec)
stac_toggle_power_map(codec, nid, 0);
}
- snd_hda_jack_report_sync(codec);
-
/* sync mute LED */
if (spec->gpio_led) {
if (spec->vmaster_mute.hook)
@@ -5578,6 +5633,9 @@ again:
case STAC_92HD83XXX_HP_INV_LED:
default_polarity = 1;
break;
+ case STAC_92HD83XXX_HP_MIC_LED:
+ spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+ break;
}
if (find_mute_led_cfg(codec, default_polarity))
@@ -5596,6 +5654,13 @@ again:
}
}
+ if (spec->mic_mute_led_gpio) {
+ spec->gpio_mask |= spec->mic_mute_led_gpio;
+ spec->gpio_dir |= spec->mic_mute_led_gpio;
+ spec->mic_mute_led_on = true;
+ spec->gpio_data |= spec->mic_mute_led_gpio;
+ }
+
err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 43077177691..5a45a912aed 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1672,7 +1672,8 @@ static void via_hp_automute(struct hda_codec *codec)
struct via_spec *spec = codec->spec;
if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] &&
- (spec->codec_type != VT1708 || spec->vt1708_jack_detect))
+ (spec->codec_type != VT1708 || spec->vt1708_jack_detect) &&
+ is_jack_detectable(codec, spec->autocfg.hp_pins[0]))
present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
if (spec->smart51_enabled)
@@ -1764,7 +1765,7 @@ static int via_suspend(struct hda_codec *codec)
}
#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
struct via_spec *spec = codec->spec;
@@ -1785,8 +1786,6 @@ static const struct hda_codec_ops via_patch_ops = {
.unsol_event = via_unsol_event,
#ifdef CONFIG_PM
.suspend = via_suspend,
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
.check_power_status = via_check_power_status,
#endif
};
@@ -2815,7 +2814,6 @@ static int via_init(struct hda_codec *codec)
via_hp_automute(codec);
vt1708_update_hp_work(spec);
- snd_hda_jack_report_sync(codec);
return 0;
}
@@ -3669,6 +3667,32 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
update_power_state(codec, 0x21, AC_PWRST_D3);
}
+/*
+ * pin fix-up
+ */
+enum {
+ VIA_FIXUP_INTMIC_BOOST,
+};
+
+static void via_fixup_intmic_boost(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ override_mic_boost(codec, 0x30, 0, 2, 40);
+}
+
+static const struct hda_fixup via_fixups[] = {
+ [VIA_FIXUP_INTMIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = via_fixup_intmic_boost,
+ },
+};
+
+static const struct snd_pci_quirk vt2002p_fixups[] = {
+ SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
+ {}
+};
+
/* patch for vt2002P */
static int patch_vt2002P(struct hda_codec *codec)
{
@@ -3685,6 +3709,9 @@ static int patch_vt2002P(struct hda_codec *codec)
override_mic_boost(codec, 0x29, 0, 3, 40);
add_secret_dac_path(codec);
+ snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
if (err < 0) {
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 3e4f8c12ffc..20bcddea2ea 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -2103,7 +2103,7 @@ static int aureon_reset(struct snd_ice1712 *ice)
/*
* suspend/resume
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int aureon_resume(struct snd_ice1712 *ice)
{
struct aureon_spec *spec = ice->spec;
@@ -2160,7 +2160,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
ice->pm_resume = aureon_resume;
ice->pm_suspend_enabled = 1;
#endif
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 0da778a69ef..d0e7d87f09f 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -384,7 +384,7 @@ struct snd_ice1712 {
char **ext_clock_names;
int ext_clock_count;
void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int (*pm_suspend)(struct snd_ice1712 *);
int (*pm_resume)(struct snd_ice1712 *);
unsigned int pm_suspend_enabled:1;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index bed9f34f4ef..3050a527925 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2792,7 +2792,7 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_vt1724_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -2878,7 +2878,7 @@ static SIMPLE_DEV_PM_OPS(snd_vt1724_pm, snd_vt1724_suspend, snd_vt1724_resume);
#define SND_VT1724_PM_OPS &snd_vt1724_pm
#else
#define SND_VT1724_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver vt1724_driver = {
.name = KBUILD_MODNAME,
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 98bc3b7681b..14fd536b645 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -486,7 +486,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
* suspend/resume
* */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int juli_resume(struct snd_ice1712 *ice)
{
struct snd_akm4xxx *ak = ice->akm;
@@ -652,7 +652,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
ice->spdif.ops.open = juli_spdif_in_open;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
ice->pm_resume = juli_resume;
ice->pm_suspend = juli_suspend;
ice->pm_suspend_enabled = 1;
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index 075d5aa1fee..7bf093c51ce 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -1100,7 +1100,7 @@ static void ak4396_init(struct snd_ice1712 *ice)
ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int prodigy_hd2_resume(struct snd_ice1712 *ice)
{
/* initialize ak4396 codec and restore previous mixer volumes */
@@ -1141,7 +1141,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
return -ENOMEM;
ice->spec = spec;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
ice->pm_resume = &prodigy_hd2_resume;
ice->pm_suspend_enabled = 1;
#endif
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index cd553f592e2..848102e5d86 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -1541,6 +1541,26 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
snd_dma_pci_data(chip->pci),
rec->prealloc_size, rec->prealloc_max_size);
+ if (rec->ac97_idx == ICHD_PCMOUT && rec->playback_ops) {
+ struct snd_pcm_chmap *chmap;
+ int chs = 2;
+ if (rec->ac97_idx == ICHD_PCMOUT) {
+ if (chip->multi8)
+ chs = 8;
+ else if (chip->multi6)
+ chs = 6;
+ else if (chip->multi4)
+ chs = 4;
+ }
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, chs, 0,
+ &chmap);
+ if (err < 0)
+ return err;
+ chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+ chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+ }
+
return 0;
}
@@ -2620,7 +2640,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -2741,7 +2761,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
#define INTEL8X0_PM_OPS &intel8x0_pm
#else
#define INTEL8X0_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index da44bb3f8e7..4d551736531 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1008,7 +1008,7 @@ static int snd_intel8x0m_free(struct intel8x0m *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1067,7 +1067,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
#define INTEL8X0M_PM_OPS &intel8x0m_pm
#else
#define INTEL8X0M_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PROC_FS
static void snd_intel8x0m_proc_read(struct snd_info_entry * entry,
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index e69ce5f9c31..8a67ce95f24 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -196,8 +196,8 @@ enum MonitorModeSelector {
#define K1212_ADAT_BUF_SIZE (K1212_ADAT_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
#define K1212_MAX_BUF_SIZE (K1212_ANALOG_BUF_SIZE + K1212_ADAT_BUF_SIZE)
-#define k1212MinADCSens 0x7f
-#define k1212MaxADCSens 0x00
+#define k1212MinADCSens 0x00
+#define k1212MaxADCSens 0x7f
#define k1212MaxVolume 0x7fff
#define k1212MaxWaveVolume 0xffff
#define k1212MinVolume 0x0000
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index c85d1ffcc95..eb3cd3a4315 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -789,7 +789,7 @@ struct snd_m3 {
unsigned int in_suspend;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u16 *suspend_mem;
#endif
@@ -2368,7 +2368,7 @@ static int snd_m3_free(struct snd_m3 *chip)
outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
vfree(chip->suspend_mem);
#endif
@@ -2390,7 +2390,7 @@ static int snd_m3_free(struct snd_m3 *chip)
/*
* APM support
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int m3_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -2485,7 +2485,7 @@ static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
#define M3_PM_OPS &m3_pm
#else
#define M3_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_SND_MAESTRO3_INPUT
static int __devinit snd_m3_input_register(struct snd_m3 *chip)
@@ -2656,7 +2656,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
}
chip->irq = pci->irq;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
if (chip->suspend_mem == NULL)
snd_printk(KERN_WARNING "can't allocate apm buffer\n");
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 465cff25b14..e80e9a1e84a 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1377,7 +1377,7 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* APM event handler, so the card is properly reinitialized after a power
* event.
@@ -1441,7 +1441,7 @@ static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
#define NM256_PM_OPS &nm256_pm
#else
#define NM256_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int snd_nm256_free(struct nm256 *chip)
{
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 37520a2b4dc..2becae155a4 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -872,7 +872,7 @@ static struct pci_driver oxygen_driver = {
.id_table = oxygen_ids,
.probe = generic_oxygen_probe,
.remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &oxygen_pci_pm,
},
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 7112a89fb8b..09a24b24958 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -161,7 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
)
);
void oxygen_pci_remove(struct pci_dev *pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops oxygen_pci_pm;
#endif
void oxygen_pci_shutdown(struct pci_dev *pci);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index ab8738e21ad..25697584b94 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -726,7 +726,7 @@ void oxygen_pci_remove(struct pci_dev *pci)
}
EXPORT_SYMBOL(oxygen_pci_remove);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int oxygen_pci_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -824,7 +824,7 @@ static int oxygen_pci_resume(struct device *dev)
SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
EXPORT_SYMBOL(oxygen_pci_pm);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
void oxygen_pci_shutdown(struct pci_dev *pci)
{
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index d3b606b69f3..3d71423b23b 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -93,7 +93,7 @@ static struct pci_driver xonar_driver = {
.id_table = xonar_ids,
.probe = xonar_probe,
.remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &oxygen_pci_pm,
},
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index e3ac1f768ff..be4f1456009 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -91,6 +91,14 @@ enum {
PCI_ID_PCX924E,
PCI_ID_PCX924HRMIC,
PCI_ID_PCX924E_MIC,
+ PCI_ID_VX442HR,
+ PCI_ID_PCX442HR,
+ PCI_ID_VX442E,
+ PCI_ID_PCX442E,
+ PCI_ID_VX822HR,
+ PCI_ID_PCX822HR,
+ PCI_ID_VX822E,
+ PCI_ID_PCX822E,
PCI_ID_LAST
};
@@ -121,6 +129,14 @@ static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = {
{ 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, },
+ { 0x10b5, 0x9656, 0x1369, 0xd001, 0, 0, PCI_ID_VX442HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xd101, 0, 0, PCI_ID_PCX442HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xd021, 0, 0, PCI_ID_VX442E, },
+ { 0x10b5, 0x9056, 0x1369, 0xd121, 0, 0, PCI_ID_PCX442E, },
+ { 0x10b5, 0x9656, 0x1369, 0xd201, 0, 0, PCI_ID_VX822HR, },
+ { 0x10b5, 0x9656, 0x1369, 0xd301, 0, 0, PCI_ID_PCX822HR, },
+ { 0x10b5, 0x9056, 0x1369, 0xd221, 0, 0, PCI_ID_VX822E, },
+ { 0x10b5, 0x9056, 0x1369, 0xd321, 0, 0, PCI_ID_PCX822E, },
{ 0, }
};
@@ -160,6 +176,14 @@ static struct board_parameters pcxhr_board_params[] = {
[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 },
+[PCI_ID_VX442HR] = { "VX442HR", 2, 2, 0, 41 },
+[PCI_ID_PCX442HR] = { "PCX442HR", 2, 2, 0, 41 },
+[PCI_ID_VX442E] = { "VX442e", 2, 2, 1, 41 },
+[PCI_ID_PCX442E] = { "PCX442e", 2, 2, 1, 41 },
+[PCI_ID_VX822HR] = { "VX822HR", 4, 1, 2, 42 },
+[PCI_ID_PCX822HR] = { "PCX822HR", 4, 1, 2, 42 },
+[PCI_ID_VX822E] = { "VX822e", 4, 1, 3, 42 },
+[PCI_ID_PCX822E] = { "PCX822e", 4, 1, 3, 42 },
};
/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index ec1587cddb0..bf207e317f7 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -66,10 +66,10 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
err = pcxhr_send_msg(mgr, &rmh);
if (err)
return err;
- /* test 8 or 12 phys out */
- if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
+ /* test 4, 8 or 12 phys out */
+ if ((rmh.stat[0] & MASK_FIRST_FIELD) < mgr->playback_chips * 2)
return -EINVAL;
- /* test 8 or 2 phys in */
+ /* test 4, 8 or 2 phys in */
if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
mgr->capture_chips * 2)
return -EINVAL;
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 760ee467cd9..7d291542c5b 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -464,7 +464,7 @@ struct snd_riptide {
unsigned long received_irqs;
unsigned long handled_irqs;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
int in_suspend;
#endif
};
@@ -1150,7 +1150,7 @@ static void riptide_handleirq(unsigned long dev_id)
}
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int riptide_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -1193,7 +1193,7 @@ static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
#define RIPTIDE_PM_OPS &riptide_pm
#else
#define RIPTIDE_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
{
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 805ab6e9a78..51e43407ebc 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -103,7 +103,7 @@ struct voice {
* we're not doing power management, we still need to allocate a page
* for the silence buffer.
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
#define SIS_SUSPEND_PAGES 4
#else
#define SIS_SUSPEND_PAGES 1
@@ -1208,7 +1208,7 @@ static int sis_chip_init(struct sis7019 *sis)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sis_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -1305,7 +1305,7 @@ static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
#define SIS_PM_OPS &sis_pm
#else
#define SIS_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int sis_alloc_suspend(struct sis7019 *sis)
{
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index d36e6ca147e..8a6f1f76e87 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -177,7 +177,7 @@ static struct pci_driver trident_driver = {
.id_table = snd_trident_ids,
.probe = snd_trident_probe,
.remove = __devexit_p(snd_trident_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &snd_trident_pm,
},
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 94011dcae73..06b10d1a76e 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3919,7 +3919,7 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor
}
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_trident_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -3983,4 +3983,4 @@ static int snd_trident_resume(struct device *dev)
}
SIMPLE_DEV_PM_OPS(snd_trident_pm, snd_trident_suspend, snd_trident_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 0eb7245dd36..f0b4efdb483 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -362,7 +362,7 @@ struct via82xx {
unsigned char old_legacy;
unsigned char old_legacy_cfg;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
unsigned char legacy_saved;
unsigned char legacy_cfg_saved;
unsigned char spdif_ctrl_saved;
@@ -1440,6 +1440,7 @@ static void init_viadev(struct via82xx *chip, int idx, unsigned int reg_offset,
static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
{
struct snd_pcm *pcm;
+ struct snd_pcm_chmap *chmap;
int i, err;
chip->playback_devno = 0; /* x 4 */
@@ -1467,6 +1468,12 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
snd_dma_pci_data(chip->pci),
64*1024, VIA_MAX_BUFSIZE);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_std_chmaps, 2, 0,
+ &chmap);
+ if (err < 0)
+ return err;
+
/* PCM #1: multi-channel playback and 2nd capture */
err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
if (err < 0)
@@ -1484,6 +1491,14 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
64*1024, VIA_MAX_BUFSIZE);
+
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, 6, 0,
+ &chmap);
+ if (err < 0)
+ return err;
+ chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
return 0;
}
@@ -1493,6 +1508,7 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
{
struct snd_pcm *pcm;
+ struct snd_pcm_chmap *chmap;
int err;
chip->multi_devno = 0;
@@ -1519,6 +1535,13 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
snd_dma_pci_data(chip->pci),
64*1024, VIA_MAX_BUFSIZE);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, 6, 0,
+ &chmap);
+ if (err < 0)
+ return err;
+ chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
/* SPDIF supported? */
if (! ac97_can_spdif(chip->ac97))
return 0;
@@ -2038,7 +2061,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
if (mpu_port >= 0x200) { /* force MIDI */
mpu_port &= 0xfffc;
pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
chip->mpu_port_saved = mpu_port;
#endif
} else {
@@ -2090,7 +2113,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
snd_via686_create_gameport(chip, &legacy);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
chip->legacy_saved = legacy;
chip->legacy_cfg_saved = legacy_cfg;
#endif
@@ -2238,7 +2261,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -2313,7 +2336,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume
#define SND_VIA82XX_PM_OPS &snd_via82xx_pm
#else
#define SND_VIA82XX_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int snd_via82xx_free(struct via82xx *chip)
{
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index e886bc16999..8e0efc416f2 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1019,7 +1019,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1076,7 +1076,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume
#define SND_VIA82XX_PM_OPS &snd_via82xx_pm
#else
#define SND_VIA82XX_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static int snd_via82xx_free(struct via82xx_modem *chip)
{
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index b89e7a86e9d..fdfbaf85723 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -257,7 +257,7 @@ static void __devexit snd_vx222_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int snd_vx222_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 4810356b97b..e01fe34db9e 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -355,7 +355,7 @@ static struct pci_driver ymfpci_driver = {
.id_table = snd_ymfpci_ids,
.probe = snd_card_ymfpci_probe,
.remove = __devexit_p(snd_card_ymfpci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &snd_ymfpci_pm,
},
diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h
index bddc4052286..4631a234891 100644
--- a/sound/pci/ymfpci/ymfpci.h
+++ b/sound/pci/ymfpci/ymfpci.h
@@ -363,7 +363,7 @@ struct snd_ymfpci {
const struct firmware *dsp_microcode;
const struct firmware *controller_microcode;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 *saved_regs;
u32 saved_ydsxgr_mode;
u16 saved_dsxg_legacy;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 62b23635b75..3a6f03f9b02 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1166,6 +1166,11 @@ int __devinit snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_std_chmaps, 2, 0, NULL);
+ if (err < 0)
+ return err;
+
if (rpcm)
*rpcm = pcm;
return 0;
@@ -1257,6 +1262,14 @@ static struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {
.pointer = snd_ymfpci_playback_pointer,
};
+static const struct snd_pcm_chmap_elem surround_map[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { }
+};
+
int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm)
{
struct snd_pcm *pcm;
@@ -1278,6 +1291,11 @@ int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ surround_map, 2, 0, NULL);
+ if (err < 0)
+ return err;
+
if (rpcm)
*rpcm = pcm;
return 0;
@@ -2242,7 +2260,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
pci_set_power_state(chip->pci, 3);
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
vfree(chip->saved_regs);
#endif
if (chip->irq >= 0)
@@ -2272,7 +2290,7 @@ static int snd_ymfpci_dev_free(struct snd_device *device)
return snd_ymfpci_free(chip);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int saved_regs_index[] = {
/* spdif */
YDSXGR_SPDIFOUTCTRL,
@@ -2374,7 +2392,7 @@ static int snd_ymfpci_resume(struct device *dev)
}
SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
int __devinit snd_ymfpci_create(struct snd_card *card,
struct pci_dev * pci,
@@ -2452,7 +2470,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
return err;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32));
if (chip->saved_regs == NULL) {
snd_ymfpci_free(chip);
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index 5df529eda25..bbc125748a3 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -140,14 +140,18 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
struct dma_chan *chan = prtd->dma_chan;
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction direction;
+ unsigned long flags = DMA_CTRL_ACK;
direction = snd_pcm_substream_to_dma_direction(substream);
+ if (!substream->runtime->no_period_wakeup)
+ flags |= DMA_PREP_INTERRUPT;
+
prtd->pos = 0;
desc = dmaengine_prep_dma_cyclic(chan,
substream->runtime->dma_addr,
snd_pcm_lib_buffer_bytes(substream),
- snd_pcm_lib_period_bytes(substream), direction);
+ snd_pcm_lib_period_bytes(substream), direction, flags);
if (!desc)
return -ENOMEM;
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 56ad923bf6b..a1d9b0792a1 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -346,11 +346,10 @@ static int usb6fire_fw_check(u8 *version)
if (!memcmp(version, known_fw_versions + i, 4))
return 0;
- snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
- "%02x %02x %02x %02x. "
+ snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "
"please reconnect to power. if this failure "
"still happens, check your firmware installation.",
- version[0], version[1], version[2], version[3]);
+ 4, version);
return -EINVAL;
}
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4a469f0cb6d..561bb74fd36 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -646,6 +646,8 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
list_for_each(p, &chip->pcm_list) {
as = list_entry(p, struct snd_usb_stream, list);
snd_pcm_suspend_all(as->pcm);
+ as->substream[0].need_setup_ep =
+ as->substream[1].need_setup_ep = true;
}
}
} else {
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 2b9fffff23b..afa4f9e9b27 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -92,6 +92,8 @@ struct snd_usb_endpoint {
unsigned char silence_value;
unsigned int stride;
int iface, alt_idx;
+ int skip_packets; /* quirks for devices to ignore the first n packets
+ in a stream */
spinlock_t lock;
struct list_head list;
@@ -105,6 +107,8 @@ struct snd_usb_substream {
int interface; /* current interface */
int endpoint; /* assigned endpoint */
struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
+ snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */
+ unsigned int channels; /* current number of channels (for hw_params callback) */
unsigned int cur_rate; /* current rate (for hw_params callback) */
unsigned int period_bytes; /* current period bytes (for hw_params callback) */
unsigned int altset_idx; /* USB data format: index of alternate setting */
@@ -115,14 +119,13 @@ struct snd_usb_substream {
unsigned int hwptr_done; /* processed byte position in the buffer */
unsigned int transfer_done; /* processed frames since last period update */
- unsigned long active_mask; /* bitmask of active urbs */
- unsigned long unlink_mask; /* bitmask of unlinked urbs */
/* data and sync endpoints for this stream */
unsigned int ep_num; /* the endpoint number */
struct snd_usb_endpoint *data_endpoint;
struct snd_usb_endpoint *sync_endpoint;
unsigned long flags;
+ bool need_setup_ep; /* (re)configure EP at prepare? */
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index d6e2bb49c59..152bfd48a31 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -31,6 +31,7 @@
#include "card.h"
#include "endpoint.h"
#include "pcm.h"
+#include "quirks.h"
#define EP_FLAG_ACTIVATED 0
#define EP_FLAG_RUNNING 1
@@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
{
struct urb *urb = urb_ctx->urb;
+ if (unlikely(ep->skip_packets > 0)) {
+ ep->skip_packets--;
+ return;
+ }
+
if (ep->sync_slave)
snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
@@ -561,20 +567,19 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)
* configure a data endpoint
*/
static int data_ep_set_params(struct snd_usb_endpoint *ep,
- struct snd_pcm_hw_params *hw_params,
+ snd_pcm_format_t pcm_format,
+ unsigned int channels,
+ unsigned int period_bytes,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep)
{
unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
- int period_bytes = params_period_bytes(hw_params);
- int format = params_format(hw_params);
int is_playback = usb_pipeout(ep->pipe);
- int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
- params_channels(hw_params);
+ int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
ep->datainterval = fmt->datainterval;
ep->stride = frame_bits >> 3;
- ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
+ ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
/* calculate max. frequency */
if (ep->maxpacksize) {
@@ -687,7 +692,6 @@ out_of_memory:
* configure a sync endpoint
*/
static int sync_ep_set_params(struct snd_usb_endpoint *ep,
- struct snd_pcm_hw_params *hw_params,
struct audioformat *fmt)
{
int i;
@@ -730,7 +734,10 @@ out_of_memory:
* snd_usb_endpoint_set_params: configure an snd_usb_endpoint
*
* @ep: the snd_usb_endpoint to configure
- * @hw_params: the hardware parameters
+ * @pcm_format: the audio fomat.
+ * @channels: the number of audio channels.
+ * @period_bytes: the number of bytes in one alsa period.
+ * @rate: the frame rate.
* @fmt: the USB audio format information
* @sync_ep: the sync endpoint to use, if any
*
@@ -739,7 +746,10 @@ out_of_memory:
* An endpoint that is already running can not be reconfigured.
*/
int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
- struct snd_pcm_hw_params *hw_params,
+ snd_pcm_format_t pcm_format,
+ unsigned int channels,
+ unsigned int period_bytes,
+ unsigned int rate,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep)
{
@@ -759,9 +769,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);
if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
- ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+ ep->freqn = get_usb_full_speed_rate(rate);
else
- ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+ ep->freqn = get_usb_high_speed_rate(rate);
/* calculate the frequency in 16.16 format */
ep->freqm = ep->freqn;
@@ -771,10 +781,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
switch (ep->type) {
case SND_USB_ENDPOINT_TYPE_DATA:
- err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+ err = data_ep_set_params(ep, pcm_format, channels,
+ period_bytes, fmt, sync_ep);
break;
case SND_USB_ENDPOINT_TYPE_SYNC:
- err = sync_ep_set_params(ep, hw_params, fmt);
+ err = sync_ep_set_params(ep, fmt);
break;
default:
err = -EINVAL;
@@ -822,6 +833,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
ep->unlink_mask = 0;
ep->phase = 0;
+ snd_usb_endpoint_start_quirk(ep);
+
/*
* If this endpoint has a data endpoint as implicit feedback source,
* don't start the urbs here. Instead, mark them all as available,
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index cbbbdf226d6..6376ccf10fd 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -9,7 +9,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
int ep_num, int direction, int type);
int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
- struct snd_pcm_hw_params *hw_params,
+ snd_pcm_format_t pcm_format,
+ unsigned int channels,
+ unsigned int period_bytes,
+ unsigned int rate,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep);
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index 9eed8f40b17..c1db28f874c 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -21,6 +21,7 @@
#include "usbaudio.h"
#include "helper.h"
+#include "quirks.h"
/*
* combine bytes and get an integer value
@@ -97,6 +98,10 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
memcpy(data, buf, size);
kfree(buf);
}
+
+ snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
+ value, index, data, size);
+
return err;
}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 4f40ba82316..fe56c9da38e 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1267,6 +1267,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
/* disable non-functional volume control */
master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
break;
+ case USB_ID(0x1130, 0xf211):
+ snd_printk(KERN_INFO
+ "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
+ /* disable non-functional volume control */
+ channels = 0;
+ break;
+
}
if (channels > 0)
first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index f782ce19bf5..55e19e1b80e 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -82,8 +82,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
/*
* find a matching audio format
*/
-static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format,
- unsigned int rate, unsigned int channels)
+static struct audioformat *find_format(struct snd_usb_substream *subs)
{
struct list_head *p;
struct audioformat *found = NULL;
@@ -92,16 +91,17 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned
list_for_each(p, &subs->fmt_list) {
struct audioformat *fp;
fp = list_entry(p, struct audioformat, list);
- if (!(fp->formats & (1uLL << format)))
+ if (!(fp->formats & (1uLL << subs->pcm_format)))
continue;
- if (fp->channels != channels)
+ if (fp->channels != subs->channels)
continue;
- if (rate < fp->rate_min || rate > fp->rate_max)
+ if (subs->cur_rate < fp->rate_min ||
+ subs->cur_rate > fp->rate_max)
continue;
if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
unsigned int i;
for (i = 0; i < fp->nr_rates; i++)
- if (fp->rate_table[i] == rate)
+ if (fp->rate_table[i] == subs->cur_rate)
break;
if (i >= fp->nr_rates)
continue;
@@ -436,6 +436,42 @@ add_sync_ep:
}
/*
+ * configure endpoint params
+ *
+ * called during initial setup and upon resume
+ */
+static int configure_endpoint(struct snd_usb_substream *subs)
+{
+ int ret;
+
+ mutex_lock(&subs->stream->chip->shutdown_mutex);
+ /* format changed */
+ stop_endpoints(subs, 0, 0, 0);
+ ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+ subs->pcm_format,
+ subs->channels,
+ subs->period_bytes,
+ subs->cur_rate,
+ subs->cur_audiofmt,
+ subs->sync_endpoint);
+ if (ret < 0)
+ goto unlock;
+
+ if (subs->sync_endpoint)
+ ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+ subs->pcm_format,
+ subs->channels,
+ subs->period_bytes,
+ subs->cur_rate,
+ subs->cur_audiofmt,
+ NULL);
+
+unlock:
+ mutex_unlock(&subs->stream->chip->shutdown_mutex);
+ return ret;
+}
+
+/*
* hw_params callback
*
* allocate a buffer and set the given audio format.
@@ -450,63 +486,33 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
{
struct snd_usb_substream *subs = substream->runtime->private_data;
struct audioformat *fmt;
- unsigned int channels, rate, format;
- int ret, changed;
+ int ret;
ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (ret < 0)
return ret;
- format = params_format(hw_params);
- rate = params_rate(hw_params);
- channels = params_channels(hw_params);
- fmt = find_format(subs, format, rate, channels);
+ subs->pcm_format = params_format(hw_params);
+ subs->period_bytes = params_period_bytes(hw_params);
+ subs->channels = params_channels(hw_params);
+ subs->cur_rate = params_rate(hw_params);
+
+ fmt = find_format(subs);
if (!fmt) {
snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
- format, rate, channels);
+ subs->pcm_format, subs->cur_rate, subs->channels);
return -EINVAL;
}
- changed = subs->cur_audiofmt != fmt ||
- subs->period_bytes != params_period_bytes(hw_params) ||
- subs->cur_rate != rate;
if ((ret = set_format(subs, fmt)) < 0)
return ret;
- if (subs->cur_rate != rate) {
- struct usb_host_interface *alts;
- struct usb_interface *iface;
- iface = usb_ifnum_to_if(subs->dev, fmt->iface);
- alts = &iface->altsetting[fmt->altset_idx];
- ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate);
- if (ret < 0)
- return ret;
- subs->cur_rate = rate;
- }
-
- if (changed) {
- mutex_lock(&subs->stream->chip->shutdown_mutex);
- /* format changed */
- stop_endpoints(subs, 0, 0, 0);
- ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
- subs->sync_endpoint);
- if (ret < 0)
- goto unlock;
+ subs->interface = fmt->iface;
+ subs->altset_idx = fmt->altset_idx;
+ subs->need_setup_ep = true;
- if (subs->sync_endpoint)
- ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
- hw_params, fmt, NULL);
-unlock:
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
- }
-
- if (ret == 0) {
- subs->interface = fmt->iface;
- subs->altset_idx = fmt->altset_idx;
- }
-
- return ret;
+ return 0;
}
/*
@@ -537,6 +543,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_usb_substream *subs = runtime->private_data;
+ struct usb_host_interface *alts;
+ struct usb_interface *iface;
+ int ret;
if (! subs->cur_audiofmt) {
snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
@@ -546,6 +555,27 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
if (snd_BUG_ON(!subs->data_endpoint))
return -EIO;
+ ret = set_format(subs, subs->cur_audiofmt);
+ if (ret < 0)
+ return ret;
+
+ iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
+ alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
+ ret = snd_usb_init_sample_rate(subs->stream->chip,
+ subs->cur_audiofmt->iface,
+ alts,
+ subs->cur_audiofmt,
+ subs->cur_rate);
+ if (ret < 0)
+ return ret;
+
+ if (subs->need_setup_ep) {
+ ret = configure_endpoint(subs);
+ if (ret < 0)
+ return ret;
+ subs->need_setup_ep = false;
+ }
+
/* some unit conversions in runtime */
subs->data_endpoint->maxframesize =
bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 79780fa57a4..d73ac9bc427 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2781,6 +2781,59 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
+/* Microsoft XboxLive Headset/Xbox Communicator */
+{
+ USB_DEVICE(0x045e, 0x0283),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .vendor_name = "Microsoft",
+ .product_name = "XboxLive Headset/Xbox Communicator",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = &(const struct snd_usb_audio_quirk[]) {
+ {
+ /* playback */
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 1,
+ .iface = 0,
+ .altsetting = 0,
+ .altset_idx = 0,
+ .attributes = 0,
+ .endpoint = 0x04,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 22050,
+ .rate_max = 22050
+ }
+ },
+ {
+ /* capture */
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels = 1,
+ .iface = 1,
+ .altsetting = 0,
+ .altset_idx = 0,
+ .attributes = 0,
+ .endpoint = 0x85,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 16000,
+ .rate_max = 16000
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+
{
/*
* Some USB MIDI devices don't have an audio control interface,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 27817266867..0f58b4b6d70 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -761,3 +761,27 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
}
}
+void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
+{
+ /*
+ * "Playback Design" products send bogus feedback data at the start
+ * of the stream. Ignore them.
+ */
+ if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) &&
+ ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
+ ep->skip_packets = 4;
+}
+
+void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+ __u8 request, __u8 requesttype, __u16 value,
+ __u16 index, void *data, __u16 size)
+{
+ /*
+ * "Playback Design" products need a 20ms delay after each
+ * class compliant request
+ */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
+ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ mdelay(20);
+}
+
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 03e5e94098c..0ca9e91067a 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -1,6 +1,10 @@
#ifndef __USBAUDIO_QUIRKS_H
#define __USBAUDIO_QUIRKS_H
+struct audioformat;
+struct snd_usb_endpoint;
+struct snd_usb_substream;
+
int snd_usb_create_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
struct usb_driver *driver,
@@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
struct audioformat *fp);
+void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
+
+void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+ __u8 request, __u8 requesttype, __u16 value,
+ __u16 index, void *data, __u16 size);
+
#endif /* __USBAUDIO_QUIRKS_H */