Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-07-28 00:02:19 +0200
committerTakashi Iwai <tiwai@suse.de>2009-07-28 00:02:19 +0200
commit8779c0dd4c135b0a3b55234b89cfc89d78f55bd1 (patch)
tree868870444f81be9f54cbdf3c7b66f21783a724c9
parent0c9903a476c9db3c86e12d6dc585ffb627d5fedb (diff)
- patches.drivers/alsa-pcm-*: ALSA PCM fixes
- Fix/enhancement patches backported from ALSA tree * patches.drivers/alsa-core-Add-new-TLV-types-for-dBwith-min-max: ALSA: Add new TLV types for dBwith min/max (for usb). * patches.drivers/alsa-ctxfi-*: SB X-Fi support (FATE#306935). * patches.drivers/alsa-hda-*: More HD-audio fixes * patches.drivers/alsa-ice-*: ICE17xx fixes * patches.drivers/alsa-midi-*: MIDI fixes * patches.drivers/alsa-usb-*: USB-audio/MIDI fixes - Remove obsoleted patches: patches.drivers/alsa-ad1984a-hp-quirks, patches.drivers/alsa-ca0106-capture-bufsize-fix, patches.drivers/alsa-ctxfi - Update config files.
-rw-r--r--config/i386/debug1
-rw-r--r--config/i386/default1
-rw-r--r--config/i386/desktop1
-rw-r--r--config/i386/pae1
-rw-r--r--config/i386/trace1
-rw-r--r--config/ia64/debug1
-rw-r--r--config/ia64/default1
-rw-r--r--config/ia64/trace1
-rw-r--r--config/x86_64/debug1
-rw-r--r--config/x86_64/default1
-rw-r--r--config/x86_64/desktop1
-rw-r--r--config/x86_64/trace1
-rw-r--r--kernel-source.changes17
-rw-r--r--patches.drivers/alsa-ad1984a-hp-quirks40
-rw-r--r--patches.drivers/alsa-ca0106-capture-bufsize-fix33
-rw-r--r--patches.drivers/alsa-core-Add-new-TLV-types-for-dBwith-min-max75
-rw-r--r--patches.drivers/alsa-ctxfi13300
-rw-r--r--patches.drivers/alsa-ctxfi-01-Native-timer-support-for-emu20k2128
-rw-r--r--patches.drivers/alsa-ctxfi-02-Fix-uninitialized-error-checks76
-rw-r--r--patches.drivers/alsa-ctxfi-03-Simple-code-clean-up858
-rw-r--r--patches.drivers/alsa-hda-01-Don-t-call-snd_hda_codec_configure129
-rw-r--r--patches.drivers/alsa-hda-02-Add-patch-module-option427
-rw-r--r--patches.drivers/alsa-hda-03-Check-beep-hint36
-rw-r--r--patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc8832416
-rw-r--r--patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883...old2244
-rw-r--r--patches.drivers/alsa-hda-05-Fix-input-pinctl-for-ALC882-auto-mode39
-rw-r--r--patches.drivers/alsa-hda-06-Allow-FLOAT-PCM-format36
-rw-r--r--patches.drivers/alsa-hda-07-Add-missing-mixer-amp-initialization34
-rw-r--r--patches.drivers/alsa-hda-08-Manually-expand-alc882_init_verbs101
-rw-r--r--patches.drivers/alsa-hda-09-Don-t-override-maxbps-for-FLOAT40
-rw-r--r--patches.drivers/alsa-hda-10-Add-quirks-for-RTL888-RV630-M7632
-rw-r--r--patches.drivers/alsa-hda-11-Fix-the-merge-error27
-rw-r--r--patches.drivers/alsa-hda-12-Check-codec-errors-in-connections46
-rw-r--r--patches.drivers/alsa-hda-13-Add-CX20582-and-OLPC-XO-1.5-support538
-rw-r--r--patches.drivers/alsa-hda-14-Add-support-for-new-AMD-HD-audio-devices36
-rw-r--r--patches.drivers/alsa-hda-15-add-bounds-checking-for-the-codec-cmds50
-rw-r--r--patches.drivers/alsa-hda-16-Fix-the-previous-sanity-check29
-rw-r--r--patches.drivers/alsa-hda-17-Fix-ALC268-parser-for-mono-speaker121
-rw-r--r--patches.drivers/alsa-hda-18-Reduce-click-noise-at-power-saving62
-rw-r--r--patches.drivers/alsa-hda-19-Fix-ALC861-auto-mode-parser295
-rw-r--r--patches.drivers/alsa-hda-20-do-not-read-connections-for-widged50
-rw-r--r--patches.drivers/alsa-hda-21-use-AC_WCAP_CONN_LIST28
-rw-r--r--patches.drivers/alsa-hda-22-Use-snprintf-to-be-safer27
-rw-r--r--patches.drivers/alsa-hda-23-Cleanups-for-widget-connection-list88
-rw-r--r--patches.drivers/alsa-hda-24-Restore-GPIO1-properly-at-resume34
-rw-r--r--patches.drivers/alsa-hda-25-Add-better-Intel-IbexPeak-platform-support356
-rw-r--r--patches.drivers/alsa-hda-26-Fix-mute-control-with-some-ALC262-models84
-rw-r--r--patches.drivers/alsa-hda-27-Introduce-get_wcaps_type-macro219
-rw-r--r--patches.drivers/alsa-hda-28-Add-exception-for-volume-knob35
-rw-r--r--patches.drivers/alsa-ice-01-Patch-for-suspend-resume-for-Audiotrak284
-rw-r--r--patches.drivers/alsa-ice-02-Fix-section-mismatch27
-rw-r--r--patches.drivers/alsa-midi-01-always-log-message-on-output-overrun31
-rw-r--r--patches.drivers/alsa-midi-02-do-not-send-MIDI-reset-when-closing36
-rw-r--r--patches.drivers/alsa-midi-03-disable-active-sensing-on-close-by-def41
-rw-r--r--patches.drivers/alsa-midi-04-oss-remove-magic-numbers54
-rw-r--r--patches.drivers/alsa-pcm-01-Fix-regressions-with-VMware52
-rw-r--r--patches.drivers/alsa-pcm-02-Add-logging-of-hwptr-updates63
-rw-r--r--patches.drivers/alsa-pcm-03-Fix-warnings-in-debug-loggings55
-rw-r--r--patches.drivers/alsa-pcm-04-Fix-hwptr-buffer-size-overlap-bug29
-rw-r--r--patches.drivers/alsa-usb-01-Use-the-new-TLV_DB_MINMAX-type35
-rw-r--r--patches.drivers/alsa-usb-02-Correct-bogus-volume-dB-information35
-rw-r--r--patches.drivers/alsa-usb-03-Xonar-U1-digital-output-support100
-rw-r--r--patches.drivers/alsa-usb-04-use-multiple-input-URBs194
-rw-r--r--patches.drivers/alsa-usb-05-use-multiple-output-URBs382
-rw-r--r--patches.drivers/alsa-usb-06-add-MIDI-drain-callback164
-rw-r--r--patches.drivers/alsa-usb-07-Volume-control-quirk-for-QuickCam-E-364
-rw-r--r--patches.drivers/alsa-usb-08-add-support-for-Audio2DJ80
-rw-r--r--series.conf57
68 files changed, 10607 insertions, 13374 deletions
diff --git a/config/i386/debug b/config/i386/debug
index a116ae8adb..ed5c84c7e9 100644
--- a/config/i386/debug
+++ b/config/i386/debug
@@ -3722,6 +3722,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/i386/default b/config/i386/default
index 3571353846..59067900db 100644
--- a/config/i386/default
+++ b/config/i386/default
@@ -3695,6 +3695,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/i386/desktop b/config/i386/desktop
index ceb2685d95..76132e95e7 100644
--- a/config/i386/desktop
+++ b/config/i386/desktop
@@ -3522,6 +3522,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/i386/pae b/config/i386/pae
index 158e2727b9..98dfda8d20 100644
--- a/config/i386/pae
+++ b/config/i386/pae
@@ -3538,6 +3538,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/i386/trace b/config/i386/trace
index d3079f0a91..b8a20a6fa9 100644
--- a/config/i386/trace
+++ b/config/i386/trace
@@ -3538,6 +3538,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/ia64/debug b/config/ia64/debug
index fac31bf660..d6bf4cb3fa 100644
--- a/config/ia64/debug
+++ b/config/ia64/debug
@@ -3058,6 +3058,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/ia64/default b/config/ia64/default
index 440444c375..344b408423 100644
--- a/config/ia64/default
+++ b/config/ia64/default
@@ -3039,6 +3039,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/ia64/trace b/config/ia64/trace
index 993f0abe08..fe8d0ffcc5 100644
--- a/config/ia64/trace
+++ b/config/ia64/trace
@@ -3046,6 +3046,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/x86_64/debug b/config/x86_64/debug
index 912cef8749..ad3ac090e5 100644
--- a/config/x86_64/debug
+++ b/config/x86_64/debug
@@ -3474,6 +3474,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/x86_64/default b/config/x86_64/default
index e63234944d..d53982d314 100644
--- a/config/x86_64/default
+++ b/config/x86_64/default
@@ -3465,6 +3465,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/x86_64/desktop b/config/x86_64/desktop
index 6caef61f89..e4dcd2a851 100644
--- a/config/x86_64/desktop
+++ b/config/x86_64/desktop
@@ -3449,6 +3449,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/config/x86_64/trace b/config/x86_64/trace
index da19063c5c..55c2a76b20 100644
--- a/config/x86_64/trace
+++ b/config/x86_64/trace
@@ -3465,6 +3465,7 @@ CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
diff --git a/kernel-source.changes b/kernel-source.changes
index f162d78f35..79520de6b3 100644
--- a/kernel-source.changes
+++ b/kernel-source.changes
@@ -1,4 +1,21 @@
-------------------------------------------------------------------
+Mon Jul 27 23:57:31 CEST 2009 - tiwai@suse.de
+
+- patches.drivers/alsa-pcm-*: ALSA PCM fixes
+- Fix/enhancement patches backported from ALSA tree
+ * patches.drivers/alsa-core-Add-new-TLV-types-for-dBwith-min-max:
+ ALSA: Add new TLV types for dBwith min/max (for usb).
+ * patches.drivers/alsa-ctxfi-*: SB X-Fi support (FATE#306935).
+ * patches.drivers/alsa-hda-*: More HD-audio fixes
+ * patches.drivers/alsa-ice-*: ICE17xx fixes
+ * patches.drivers/alsa-midi-*: MIDI fixes
+ * patches.drivers/alsa-usb-*: USB-audio/MIDI fixes
+- Remove obsoleted patches: patches.drivers/alsa-ad1984a-hp-quirks,
+ patches.drivers/alsa-ca0106-capture-bufsize-fix,
+ patches.drivers/alsa-ctxfi
+- Update config files.
+
+-------------------------------------------------------------------
Mon Jul 27 17:06:11 CEST 2009 - mmarek@suse.cz
- rpm/kernel-source.spec.in, scripts/tar-up.sh: really drop
diff --git a/patches.drivers/alsa-ad1984a-hp-quirks b/patches.drivers/alsa-ad1984a-hp-quirks
deleted file mode 100644
index 5f5269256f..0000000000
--- a/patches.drivers/alsa-ad1984a-hp-quirks
+++ /dev/null
@@ -1,40 +0,0 @@
-From: Takashi Iwai <tiwai@suse.de>
-Subject: ALSA: update HP quirks for Zenith & co
-Patch-mainline:
-References: bnc#472789, bnc#479617, bnc#502425, bnc#503101
-
-Added model=laptop or model=mobile for HP laptops with AD1984A codec.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
- sound/pci/hda/patch_analog.c | 15 +++++++++++++++
- 1 file changed, 15 insertions(+)
-
---- a/sound/pci/hda/patch_analog.c
-+++ b/sound/pci/hda/patch_analog.c
-@@ -3978,9 +3978,24 @@ static struct snd_pci_quirk ad1884a_cfg_
- SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
- SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
- SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3072, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3073, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3074, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3075, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3076, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3077, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3078, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x3079, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK(0x103c, 0x307a, "HP", AD1884A_MOBILE),
- SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
- SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK(0x103c, 0x30e1, "HP 2530p", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
- SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK(0x103c, 0x360d, "HP 6530b", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK(0x103c, 0x3632, "HP", AD1884A_MOBILE),
- SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
- {}
- };
diff --git a/patches.drivers/alsa-ca0106-capture-bufsize-fix b/patches.drivers/alsa-ca0106-capture-bufsize-fix
deleted file mode 100644
index 89e9305981..0000000000
--- a/patches.drivers/alsa-ca0106-capture-bufsize-fix
+++ /dev/null
@@ -1,33 +0,0 @@
-From 34fdeb2d07102e07ecafe79dec170bd6733f2e56 Mon Sep 17 00:00:00 2001
-From: Takashi Iwai <tiwai@suse.de>
-Subject: ALSA: ca0106 - Fix the max capture buffer size
-Patch-mainline:
-References: bnc#521890
-
-The capture buffer size with 64kB seems broken with CA0106.
-At least, either the update timing or the DMA position is wrong,
-and this screws up pulseaudio badly.
-
-This patch restricts the max buffer size less than that to make life
-a bit easier.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
- sound/pci/ca0106/ca0106_main.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/sound/pci/ca0106/ca0106_main.c
-+++ b/sound/pci/ca0106/ca0106_main.c
-@@ -325,9 +325,9 @@
- .rate_max = 192000,
- .channels_min = 2,
- .channels_max = 2,
-- .buffer_bytes_max = ((65536 - 64) * 8),
-+ .buffer_bytes_max = 65536 - 128,
- .period_bytes_min = 64,
-- .period_bytes_max = (65536 - 64),
-+ .period_bytes_max = 32768 - 64,
- .periods_min = 2,
- .periods_max = 2,
- .fifo_size = 0,
diff --git a/patches.drivers/alsa-core-Add-new-TLV-types-for-dBwith-min-max b/patches.drivers/alsa-core-Add-new-TLV-types-for-dBwith-min-max
new file mode 100644
index 0000000000..64f864eb2a
--- /dev/null
+++ b/patches.drivers/alsa-core-Add-new-TLV-types-for-dBwith-min-max
@@ -0,0 +1,75 @@
+From 085f30654175a91c28d2b66b9ea6cceab627fed0 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 16 Jun 2009 13:57:07 +0200
+Subject: ALSA: Add new TLV types for dBwith min/max
+Patch-mainline:
+References:
+
+Add new types for TLV dB scale specified with min/max values instead
+of min/step since the resolution can't match always with the one
+a device provides. For example, usb audio devices give 1/256 dB
+resolution while ALSA TLV is based on 1/100 dB resolution.
+The new min/max types have less problems because the possible
+rounding error happens only at min/max.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ include/sound/tlv.h | 14 ++++++++++++++
+ sound/core/vmaster.c | 8 ++++++--
+ 2 files changed, 20 insertions(+), 2 deletions(-)
+
+--- a/include/sound/tlv.h
++++ b/include/sound/tlv.h
+@@ -35,6 +35,8 @@
+ #define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
+ #define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
+ #define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
++#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
++#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
+
+ #define TLV_DB_SCALE_ITEM(min, step, mute) \
+ SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
+@@ -42,6 +44,18 @@
+ #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
+ unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
+
++/* dB scale specified with min/max values instead of step */
++#define TLV_DB_MINMAX_ITEM(min_dB, max_dB) \
++ SNDRV_CTL_TLVT_DB_MINMAX, 2 * sizeof(unsigned int), \
++ (min_dB), (max_dB)
++#define TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \
++ SNDRV_CTL_TLVT_DB_MINMAX_MUTE, 2 * sizeof(unsigned int), \
++ (min_dB), (max_dB)
++#define DECLARE_TLV_DB_MINMAX(name, min_dB, max_dB) \
++ unsigned int name[] = { TLV_DB_MINMAX_ITEM(min_dB, max_dB) }
++#define DECLARE_TLV_DB_MINMAX_MUTE(name, min_dB, max_dB) \
++ unsigned int name[] = { TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) }
++
+ /* linear volume between min_dB and max_dB (.01dB unit) */
+ #define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \
+ SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
+--- a/sound/core/vmaster.c
++++ b/sound/core/vmaster.c
+@@ -353,7 +353,8 @@
+ *
+ * The optional argument @tlv can be used to specify the TLV information
+ * for dB scale of the master control. It should be a single element
+- * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB.
++ * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
++ * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
+ */
+ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+ const unsigned int *tlv)
+@@ -384,7 +385,10 @@
+ kctl->private_free = master_free;
+
+ /* additional (constant) TLV read */
+- if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
++ if (tlv &&
++ (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE ||
++ tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX ||
++ tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) {
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ memcpy(master->tlv, tlv, sizeof(master->tlv));
+ kctl->tlv.p = master->tlv;
diff --git a/patches.drivers/alsa-ctxfi b/patches.drivers/alsa-ctxfi
deleted file mode 100644
index ad841befd2..0000000000
--- a/patches.drivers/alsa-ctxfi
+++ /dev/null
@@ -1,13300 +0,0 @@
-From: Takashi Iwai <tiwai@suse.de>
-Subject: Add SoundBlaster X-Fi support
-Patch-mainline:
-References: FATE#306935
-
-Backported from the latest ALSA tree.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
- include/linux/pci_ids.h | 7
- sound/pci/Kconfig | 10
- sound/pci/Makefile | 1
- sound/pci/ctxfi/Makefile | 5
- sound/pci/ctxfi/ct20k1reg.h | 636 +++++++++++
- sound/pci/ctxfi/ct20k2reg.h | 88 +
- sound/pci/ctxfi/ctamixer.c | 486 +++++++++
- sound/pci/ctxfi/ctamixer.h | 96 +
- sound/pci/ctxfi/ctatc.c | 1712 ++++++++++++++++++++++++++++++++
- sound/pci/ctxfi/ctatc.h | 154 ++
- sound/pci/ctxfi/ctdaio.c | 769 ++++++++++++++
- sound/pci/ctxfi/ctdaio.h | 122 ++
- sound/pci/ctxfi/cthardware.c | 91 +
- sound/pci/ctxfi/cthardware.h | 203 +++
- sound/pci/ctxfi/cthw20k1.c | 2297 +++++++++++++++++++++++++++++++++++++++++++
- sound/pci/ctxfi/cthw20k1.h | 26
- sound/pci/ctxfi/cthw20k2.c | 2219 +++++++++++++++++++++++++++++++++++++++++
- sound/pci/ctxfi/cthw20k2.h | 26
- sound/pci/ctxfi/ctimap.c | 112 ++
- sound/pci/ctxfi/ctimap.h | 40
- sound/pci/ctxfi/ctmixer.c | 1157 +++++++++++++++++++++
- sound/pci/ctxfi/ctmixer.h | 70 +
- sound/pci/ctxfi/ctpcm.c | 430 ++++++++
- sound/pci/ctxfi/ctpcm.h | 27
- sound/pci/ctxfi/ctresource.c | 301 +++++
- sound/pci/ctxfi/ctresource.h | 72 +
- sound/pci/ctxfi/ctsrc.c | 885 ++++++++++++++++
- sound/pci/ctxfi/ctsrc.h | 149 ++
- sound/pci/ctxfi/cttimer.c | 443 ++++++++
- sound/pci/ctxfi/cttimer.h | 29
- sound/pci/ctxfi/ctvmem.c | 250 ++++
- sound/pci/ctxfi/ctvmem.h | 61 +
- sound/pci/ctxfi/xfi.c | 164 +++
- 33 files changed, 13138 insertions(+)
-
---- a/include/linux/pci_ids.h
-+++ b/include/linux/pci_ids.h
-@@ -1314,6 +1314,13 @@
-
- #define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */
- #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
-+#define PCI_DEVICE_ID_CREATIVE_20K1 0x0005
-+#define PCI_DEVICE_ID_CREATIVE_20K2 0x000b
-+#define PCI_SUBDEVICE_ID_CREATIVE_SB0760 0x0024
-+#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041
-+#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042
-+#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043
-+#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000
-
- #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */
- #define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
---- a/sound/pci/Kconfig
-+++ b/sound/pci/Kconfig
-@@ -275,6 +275,16 @@
- To compile this driver as a module, choose M here: the module
- will be called snd-cs5535audio.
-
-+config SND_CTXFI
-+ tristate "Creative Sound Blaster X-Fi"
-+ select SND_PCM
-+ help
-+ If you want to use soundcards based on Creative Sound Blastr X-Fi
-+ boards with 20k1 or 20k2 chips, say Y here.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called snd-ctxfi.
-+
- config SND_DARLA20
- tristate "(Echoaudio) Darla20"
- select FW_LOADER
---- a/sound/pci/Makefile
-+++ b/sound/pci/Makefile
-@@ -59,6 +59,7 @@
- ali5451/ \
- au88x0/ \
- aw2/ \
-+ ctxfi/ \
- ca0106/ \
- cs46xx/ \
- cs5535audio/ \
---- /dev/null
-+++ b/sound/pci/ctxfi/Makefile
-@@ -0,0 +1,5 @@
-+snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
-+ ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \
-+ cthw20k2.o cthw20k1.o
-+
-+obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
---- /dev/null
-+++ b/sound/pci/ctxfi/ct20k1reg.h
-@@ -0,0 +1,636 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ */
-+
-+#ifndef CT20K1REG_H
-+#define CT20k1REG_H
-+
-+/* 20k1 registers */
-+#define DSPXRAM_START 0x000000
-+#define DSPXRAM_END 0x013FFC
-+#define DSPAXRAM_START 0x020000
-+#define DSPAXRAM_END 0x023FFC
-+#define DSPYRAM_START 0x040000
-+#define DSPYRAM_END 0x04FFFC
-+#define DSPAYRAM_START 0x020000
-+#define DSPAYRAM_END 0x063FFC
-+#define DSPMICRO_START 0x080000
-+#define DSPMICRO_END 0x0B3FFC
-+#define DSP0IO_START 0x100000
-+#define DSP0IO_END 0x101FFC
-+#define AUDIORINGIPDSP0_START 0x100000
-+#define AUDIORINGIPDSP0_END 0x1003FC
-+#define AUDIORINGOPDSP0_START 0x100400
-+#define AUDIORINGOPDSP0_END 0x1007FC
-+#define AUDPARARINGIODSP0_START 0x100800
-+#define AUDPARARINGIODSP0_END 0x100BFC
-+#define DSP0LOCALHWREG_START 0x100C00
-+#define DSP0LOCALHWREG_END 0x100C3C
-+#define DSP0XYRAMAGINDEX_START 0x100C40
-+#define DSP0XYRAMAGINDEX_END 0x100C5C
-+#define DSP0XYRAMAGMDFR_START 0x100C60
-+#define DSP0XYRAMAGMDFR_END 0x100C7C
-+#define DSP0INTCONTLVEC_START 0x100C80
-+#define DSP0INTCONTLVEC_END 0x100CD8
-+#define INTCONTLGLOBALREG_START 0x100D1C
-+#define INTCONTLGLOBALREG_END 0x100D3C
-+#define HOSTINTFPORTADDRCONTDSP0 0x100D40
-+#define HOSTINTFPORTDATADSP0 0x100D44
-+#define TIME0PERENBDSP0 0x100D60
-+#define TIME0COUNTERDSP0 0x100D64
-+#define TIME1PERENBDSP0 0x100D68
-+#define TIME1COUNTERDSP0 0x100D6C
-+#define TIME2PERENBDSP0 0x100D70
-+#define TIME2COUNTERDSP0 0x100D74
-+#define TIME3PERENBDSP0 0x100D78
-+#define TIME3COUNTERDSP0 0x100D7C
-+#define XRAMINDOPERREFNOUP_STARTDSP0 0x100D80
-+#define XRAMINDOPERREFNOUP_ENDDSP0 0x100D9C
-+#define XRAMINDOPERREFUP_STARTDSP0 0x100DA0
-+#define XRAMINDOPERREFUP_ENDDSP0 0x100DBC
-+#define YRAMINDOPERREFNOUP_STARTDSP0 0x100DC0
-+#define YRAMINDOPERREFNOUP_ENDDSP0 0x100DDC
-+#define YRAMINDOPERREFUP_STARTDSP0 0x100DE0
-+#define YRAMINDOPERREFUP_ENDDSP0 0x100DFC
-+#define DSP0CONDCODE 0x100E00
-+#define DSP0STACKFLAG 0x100E04
-+#define DSP0PROGCOUNTSTACKPTREG 0x100E08
-+#define DSP0PROGCOUNTSTACKDATAREG 0x100E0C
-+#define DSP0CURLOOPADDRREG 0x100E10
-+#define DSP0CURLOOPCOUNT 0x100E14
-+#define DSP0TOPLOOPCOUNTSTACK 0x100E18
-+#define DSP0TOPLOOPADDRSTACK 0x100E1C
-+#define DSP0LOOPSTACKPTR 0x100E20
-+#define DSP0STASSTACKDATAREG 0x100E24
-+#define DSP0STASSTACKPTR 0x100E28
-+#define DSP0PROGCOUNT 0x100E2C
-+#define GLOBDSPDEBGREG 0x100E30
-+#define GLOBDSPBREPTRREG 0x100E30
-+#define DSP0XYRAMBASE_START 0x100EA0
-+#define DSP0XYRAMBASE_END 0x100EBC
-+#define DSP0XYRAMLENG_START 0x100EC0
-+#define DSP0XYRAMLENG_END 0x100EDC
-+#define SEMAPHOREREGDSP0 0x100EE0
-+#define DSP0INTCONTMASKREG 0x100EE4
-+#define DSP0INTCONTPENDREG 0x100EE8
-+#define DSP0INTCONTSERVINT 0x100EEC
-+#define DSPINTCONTEXTINTMODREG 0x100EEC
-+#define GPIODSP0 0x100EFC
-+#define DMADSPBASEADDRREG_STARTDSP0 0x100F00
-+#define DMADSPBASEADDRREG_ENDDSP0 0x100F1C
-+#define DMAHOSTBASEADDRREG_STARTDSP0 0x100F20
-+#define DMAHOSTBASEADDRREG_ENDDSP0 0x100F3C
-+#define DMADSPCURADDRREG_STARTDSP0 0x100F40
-+#define DMADSPCURADDRREG_ENDDSP0 0x100F5C
-+#define DMAHOSTCURADDRREG_STARTDSP0 0x100F60
-+#define DMAHOSTCURADDRREG_ENDDSP0 0x100F7C
-+#define DMATANXCOUNTREG_STARTDSP0 0x100F80
-+#define DMATANXCOUNTREG_ENDDSP0 0x100F9C
-+#define DMATIMEBUGREG_STARTDSP0 0x100FA0
-+#define DMATIMEBUGREG_ENDDSP0 0x100FAC
-+#define DMACNTLMODFREG_STARTDSP0 0x100FA0
-+#define DMACNTLMODFREG_ENDDSP0 0x100FAC
-+
-+#define DMAGLOBSTATSREGDSP0 0x100FEC
-+#define DSP0XGPRAM_START 0x101000
-+#define DSP0XGPRAM_END 0x1017FC
-+#define DSP0YGPRAM_START 0x101800
-+#define DSP0YGPRAM_END 0x101FFC
-+
-+
-+
-+
-+#define AUDIORINGIPDSP1_START 0x102000
-+#define AUDIORINGIPDSP1_END 0x1023FC
-+#define AUDIORINGOPDSP1_START 0x102400
-+#define AUDIORINGOPDSP1_END 0x1027FC
-+#define AUDPARARINGIODSP1_START 0x102800
-+#define AUDPARARINGIODSP1_END 0x102BFC
-+#define DSP1LOCALHWREG_START 0x102C00
-+#define DSP1LOCALHWREG_END 0x102C3C
-+#define DSP1XYRAMAGINDEX_START 0x102C40
-+#define DSP1XYRAMAGINDEX_END 0x102C5C
-+#define DSP1XYRAMAGMDFR_START 0x102C60
-+#define DSP1XYRAMAGMDFR_END 0x102C7C
-+#define DSP1INTCONTLVEC_START 0x102C80
-+#define DSP1INTCONTLVEC_END 0x102CD8
-+#define HOSTINTFPORTADDRCONTDSP1 0x102D40
-+#define HOSTINTFPORTDATADSP1 0x102D44
-+#define TIME0PERENBDSP1 0x102D60
-+#define TIME0COUNTERDSP1 0x102D64
-+#define TIME1PERENBDSP1 0x102D68
-+#define TIME1COUNTERDSP1 0x102D6C
-+#define TIME2PERENBDSP1 0x102D70
-+#define TIME2COUNTERDSP1 0x102D74
-+#define TIME3PERENBDSP1 0x102D78
-+#define TIME3COUNTERDSP1 0x102D7C
-+#define XRAMINDOPERREFNOUP_STARTDSP1 0x102D80
-+#define XRAMINDOPERREFNOUP_ENDDSP1 0x102D9C
-+#define XRAMINDOPERREFUP_STARTDSP1 0x102DA0
-+#define XRAMINDOPERREFUP_ENDDSP1 0x102DBC
-+#define YRAMINDOPERREFNOUP_STARTDSP1 0x102DC0
-+#define YRAMINDOPERREFNOUP_ENDDSP1 0x102DDC
-+#define YRAMINDOPERREFUP_STARTDSP1 0x102DE0
-+#define YRAMINDOPERREFUP_ENDDSP1 0x102DFC
-+
-+#define DSP1CONDCODE 0x102E00
-+#define DSP1STACKFLAG 0x102E04
-+#define DSP1PROGCOUNTSTACKPTREG 0x102E08
-+#define DSP1PROGCOUNTSTACKDATAREG 0x102E0C
-+#define DSP1CURLOOPADDRREG 0x102E10
-+#define DSP1CURLOOPCOUNT 0x102E14
-+#define DSP1TOPLOOPCOUNTSTACK 0x102E18
-+#define DSP1TOPLOOPADDRSTACK 0x102E1C
-+#define DSP1LOOPSTACKPTR 0x102E20
-+#define DSP1STASSTACKDATAREG 0x102E24
-+#define DSP1STASSTACKPTR 0x102E28
-+#define DSP1PROGCOUNT 0x102E2C
-+#define DSP1XYRAMBASE_START 0x102EA0
-+#define DSP1XYRAMBASE_END 0x102EBC
-+#define DSP1XYRAMLENG_START 0x102EC0
-+#define DSP1XYRAMLENG_END 0x102EDC
-+#define SEMAPHOREREGDSP1 0x102EE0
-+#define DSP1INTCONTMASKREG 0x102EE4
-+#define DSP1INTCONTPENDREG 0x102EE8
-+#define DSP1INTCONTSERVINT 0x102EEC
-+#define GPIODSP1 0x102EFC
-+#define DMADSPBASEADDRREG_STARTDSP1 0x102F00
-+#define DMADSPBASEADDRREG_ENDDSP1 0x102F1C
-+#define DMAHOSTBASEADDRREG_STARTDSP1 0x102F20
-+#define DMAHOSTBASEADDRREG_ENDDSP1 0x102F3C
-+#define DMADSPCURADDRREG_STARTDSP1 0x102F40
-+#define DMADSPCURADDRREG_ENDDSP1 0x102F5C
-+#define DMAHOSTCURADDRREG_STARTDSP1 0x102F60
-+#define DMAHOSTCURADDRREG_ENDDSP1 0x102F7C
-+#define DMATANXCOUNTREG_STARTDSP1 0x102F80
-+#define DMATANXCOUNTREG_ENDDSP1 0x102F9C
-+#define DMATIMEBUGREG_STARTDSP1 0x102FA0
-+#define DMATIMEBUGREG_ENDDSP1 0x102FAC
-+#define DMACNTLMODFREG_STARTDSP1 0x102FA0
-+#define DMACNTLMODFREG_ENDDSP1 0x102FAC
-+
-+#define DMAGLOBSTATSREGDSP1 0x102FEC
-+#define DSP1XGPRAM_START 0x103000
-+#define DSP1XGPRAM_END 0x1033FC
-+#define DSP1YGPRAM_START 0x103400
-+#define DSP1YGPRAM_END 0x1037FC
-+
-+
-+
-+#define AUDIORINGIPDSP2_START 0x104000
-+#define AUDIORINGIPDSP2_END 0x1043FC
-+#define AUDIORINGOPDSP2_START 0x104400
-+#define AUDIORINGOPDSP2_END 0x1047FC
-+#define AUDPARARINGIODSP2_START 0x104800
-+#define AUDPARARINGIODSP2_END 0x104BFC
-+#define DSP2LOCALHWREG_START 0x104C00
-+#define DSP2LOCALHWREG_END 0x104C3C
-+#define DSP2XYRAMAGINDEX_START 0x104C40
-+#define DSP2XYRAMAGINDEX_END 0x104C5C
-+#define DSP2XYRAMAGMDFR_START 0x104C60
-+#define DSP2XYRAMAGMDFR_END 0x104C7C
-+#define DSP2INTCONTLVEC_START 0x104C80
-+#define DSP2INTCONTLVEC_END 0x104CD8
-+#define HOSTINTFPORTADDRCONTDSP2 0x104D40
-+#define HOSTINTFPORTDATADSP2 0x104D44
-+#define TIME0PERENBDSP2 0x104D60
-+#define TIME0COUNTERDSP2 0x104D64
-+#define TIME1PERENBDSP2 0x104D68
-+#define TIME1COUNTERDSP2 0x104D6C
-+#define TIME2PERENBDSP2 0x104D70
-+#define TIME2COUNTERDSP2 0x104D74
-+#define TIME3PERENBDSP2 0x104D78
-+#define TIME3COUNTERDSP2 0x104D7C
-+#define XRAMINDOPERREFNOUP_STARTDSP2 0x104D80
-+#define XRAMINDOPERREFNOUP_ENDDSP2 0x104D9C
-+#define XRAMINDOPERREFUP_STARTDSP2 0x104DA0
-+#define XRAMINDOPERREFUP_ENDDSP2 0x104DBC
-+#define YRAMINDOPERREFNOUP_STARTDSP2 0x104DC0
-+#define YRAMINDOPERREFNOUP_ENDDSP2 0x104DDC
-+#define YRAMINDOPERREFUP_STARTDSP2 0x104DE0
-+#define YRAMINDOPERREFUP_ENDDSP2 0x104DFC
-+#define DSP2CONDCODE 0x104E00
-+#define DSP2STACKFLAG 0x104E04
-+#define DSP2PROGCOUNTSTACKPTREG 0x104E08
-+#define DSP2PROGCOUNTSTACKDATAREG 0x104E0C
-+#define DSP2CURLOOPADDRREG 0x104E10
-+#define DSP2CURLOOPCOUNT 0x104E14
-+#define DSP2TOPLOOPCOUNTSTACK 0x104E18
-+#define DSP2TOPLOOPADDRSTACK 0x104E1C
-+#define DSP2LOOPSTACKPTR 0x104E20
-+#define DSP2STASSTACKDATAREG 0x104E24
-+#define DSP2STASSTACKPTR 0x104E28
-+#define DSP2PROGCOUNT 0x104E2C
-+#define DSP2XYRAMBASE_START 0x104EA0
-+#define DSP2XYRAMBASE_END 0x104EBC
-+#define DSP2XYRAMLENG_START 0x104EC0
-+#define DSP2XYRAMLENG_END 0x104EDC
-+#define SEMAPHOREREGDSP2 0x104EE0
-+#define DSP2INTCONTMASKREG 0x104EE4
-+#define DSP2INTCONTPENDREG 0x104EE8
-+#define DSP2INTCONTSERVINT 0x104EEC
-+#define GPIODSP2 0x104EFC
-+#define DMADSPBASEADDRREG_STARTDSP2 0x104F00
-+#define DMADSPBASEADDRREG_ENDDSP2 0x104F1C
-+#define DMAHOSTBASEADDRREG_STARTDSP2 0x104F20
-+#define DMAHOSTBASEADDRREG_ENDDSP2 0x104F3C
-+#define DMADSPCURADDRREG_STARTDSP2 0x104F40
-+#define DMADSPCURADDRREG_ENDDSP2 0x104F5C
-+#define DMAHOSTCURADDRREG_STARTDSP2 0x104F60
-+#define DMAHOSTCURADDRREG_ENDDSP2 0x104F7C
-+#define DMATANXCOUNTREG_STARTDSP2 0x104F80
-+#define DMATANXCOUNTREG_ENDDSP2 0x104F9C
-+#define DMATIMEBUGREG_STARTDSP2 0x104FA0
-+#define DMATIMEBUGREG_ENDDSP2 0x104FAC
-+#define DMACNTLMODFREG_STARTDSP2 0x104FA0
-+#define DMACNTLMODFREG_ENDDSP2 0x104FAC
-+
-+#define DMAGLOBSTATSREGDSP2 0x104FEC
-+#define DSP2XGPRAM_START 0x105000
-+#define DSP2XGPRAM_END 0x1051FC
-+#define DSP2YGPRAM_START 0x105800
-+#define DSP2YGPRAM_END 0x1059FC
-+
-+
-+
-+#define AUDIORINGIPDSP3_START 0x106000
-+#define AUDIORINGIPDSP3_END 0x1063FC
-+#define AUDIORINGOPDSP3_START 0x106400
-+#define AUDIORINGOPDSP3_END 0x1067FC
-+#define AUDPARARINGIODSP3_START 0x106800
-+#define AUDPARARINGIODSP3_END 0x106BFC
-+#define DSP3LOCALHWREG_START 0x106C00
-+#define DSP3LOCALHWREG_END 0x106C3C
-+#define DSP3XYRAMAGINDEX_START 0x106C40
-+#define DSP3XYRAMAGINDEX_END 0x106C5C
-+#define DSP3XYRAMAGMDFR_START 0x106C60
-+#define DSP3XYRAMAGMDFR_END 0x106C7C
-+#define DSP3INTCONTLVEC_START 0x106C80
-+#define DSP3INTCONTLVEC_END 0x106CD8
-+#define HOSTINTFPORTADDRCONTDSP3 0x106D40
-+#define HOSTINTFPORTDATADSP3 0x106D44
-+#define TIME0PERENBDSP3 0x106D60
-+#define TIME0COUNTERDSP3 0x106D64
-+#define TIME1PERENBDSP3 0x106D68
-+#define TIME1COUNTERDSP3 0x106D6C
-+#define TIME2PERENBDSP3 0x106D70
-+#define TIME2COUNTERDSP3 0x106D74
-+#define TIME3PERENBDSP3 0x106D78
-+#define TIME3COUNTERDSP3 0x106D7C
-+#define XRAMINDOPERREFNOUP_STARTDSP3 0x106D80
-+#define XRAMINDOPERREFNOUP_ENDDSP3 0x106D9C
-+#define XRAMINDOPERREFUP_STARTDSP3 0x106DA0
-+#define XRAMINDOPERREFUP_ENDDSP3 0x106DBC
-+#define YRAMINDOPERREFNOUP_STARTDSP3 0x106DC0
-+#define YRAMINDOPERREFNOUP_ENDDSP3 0x106DDC
-+#define YRAMINDOPERREFUP_STARTDSP3 0x106DE0
-+#define YRAMINDOPERREFUP_ENDDSP3 0x100DFC
-+
-+#define DSP3CONDCODE 0x106E00
-+#define DSP3STACKFLAG 0x106E04
-+#define DSP3PROGCOUNTSTACKPTREG 0x106E08
-+#define DSP3PROGCOUNTSTACKDATAREG 0x106E0C
-+#define DSP3CURLOOPADDRREG 0x106E10
-+#define DSP3CURLOOPCOUNT 0x106E14
-+#define DSP3TOPLOOPCOUNTSTACK 0x106E18
-+#define DSP3TOPLOOPADDRSTACK 0x106E1C
-+#define DSP3LOOPSTACKPTR 0x106E20
-+#define DSP3STASSTACKDATAREG 0x106E24
-+#define DSP3STASSTACKPTR 0x106E28
-+#define DSP3PROGCOUNT 0x106E2C
-+#define DSP3XYRAMBASE_START 0x106EA0
-+#define DSP3XYRAMBASE_END 0x106EBC
-+#define DSP3XYRAMLENG_START 0x106EC0
-+#define DSP3XYRAMLENG_END 0x106EDC
-+#define SEMAPHOREREGDSP3 0x106EE0
-+#define DSP3INTCONTMASKREG 0x106EE4
-+#define DSP3INTCONTPENDREG 0x106EE8
-+#define DSP3INTCONTSERVINT 0x106EEC
-+#define GPIODSP3 0x106EFC
-+#define DMADSPBASEADDRREG_STARTDSP3 0x106F00
-+#define DMADSPBASEADDRREG_ENDDSP3 0x106F1C
-+#define DMAHOSTBASEADDRREG_STARTDSP3 0x106F20
-+#define DMAHOSTBASEADDRREG_ENDDSP3 0x106F3C
-+#define DMADSPCURADDRREG_STARTDSP3 0x106F40
-+#define DMADSPCURADDRREG_ENDDSP3 0x106F5C
-+#define DMAHOSTCURADDRREG_STARTDSP3 0x106F60
-+#define DMAHOSTCURADDRREG_ENDDSP3 0x106F7C
-+#define DMATANXCOUNTREG_STARTDSP3 0x106F80
-+#define DMATANXCOUNTREG_ENDDSP3 0x106F9C
-+#define DMATIMEBUGREG_STARTDSP3 0x106FA0
-+#define DMATIMEBUGREG_ENDDSP3 0x106FAC
-+#define DMACNTLMODFREG_STARTDSP3 0x106FA0
-+#define DMACNTLMODFREG_ENDDSP3 0x106FAC
-+
-+#define DMAGLOBSTATSREGDSP3 0x106FEC
-+#define DSP3XGPRAM_START 0x107000
-+#define DSP3XGPRAM_END 0x1071FC
-+#define DSP3YGPRAM_START 0x107800
-+#define DSP3YGPRAM_END 0x1079FC
-+
-+/* end of DSP reg definitions */
-+
-+#define DSPAIMAP_START 0x108000
-+#define DSPAIMAP_END 0x1083FC
-+#define DSPPIMAP_START 0x108400
-+#define DSPPIMAP_END 0x1087FC
-+#define DSPPOMAP_START 0x108800
-+#define DSPPOMAP_END 0x108BFC
-+#define DSPPOCTL 0x108C00
-+#define TKCTL_START 0x110000
-+#define TKCTL_END 0x110FFC
-+#define TKCC_START 0x111000
-+#define TKCC_END 0x111FFC
-+#define TKIMAP_START 0x112000
-+#define TKIMAP_END 0x112FFC
-+#define TKDCTR16 0x113000
-+#define TKPB16 0x113004
-+#define TKBS16 0x113008
-+#define TKDCTR32 0x11300C
-+#define TKPB32 0x113010
-+#define TKBS32 0x113014
-+#define ICDCTR16 0x113018
-+#define ITBS16 0x11301C
-+#define ICDCTR32 0x113020
-+#define ITBS32 0x113024
-+#define ITSTART 0x113028
-+#define TKSQ 0x11302C
-+
-+#define TKSCCTL_START 0x114000
-+#define TKSCCTL_END 0x11403C
-+#define TKSCADR_START 0x114100
-+#define TKSCADR_END 0x11413C
-+#define TKSCDATAX_START 0x114800
-+#define TKSCDATAX_END 0x1149FC
-+#define TKPCDATAX_START 0x120000
-+#define TKPCDATAX_END 0x12FFFC
-+
-+#define MALSA 0x130000
-+#define MAPPHA 0x130004
-+#define MAPPLA 0x130008
-+#define MALSB 0x130010
-+#define MAPPHB 0x130014
-+#define MAPPLB 0x130018
-+
-+#define TANSPORTMAPABREGS_START 0x130020
-+#define TANSPORTMAPABREGS_END 0x13A2FC
-+
-+#define PTPAHX 0x13B000
-+#define PTPALX 0x13B004
-+
-+#define TANSPPAGETABLEPHYADDR015_START 0x13B008
-+#define TANSPPAGETABLEPHYADDR015_END 0x13B07C
-+#define TRNQADRX_START 0x13B100
-+#define TRNQADRX_END 0x13B13C
-+#define TRNQTIMX_START 0x13B200
-+#define TRNQTIMX_END 0x13B23C
-+#define TRNQAPARMX_START 0x13B300
-+#define TRNQAPARMX_END 0x13B33C
-+
-+#define TRNQCNT 0x13B400
-+#define TRNCTL 0x13B404
-+#define TRNIS 0x13B408
-+#define TRNCURTS 0x13B40C
-+
-+#define AMOP_START 0x140000
-+#define AMOPLO 0x140000
-+#define AMOPHI 0x140004
-+#define AMOP_END 0x147FFC
-+#define PMOP_START 0x148000
-+#define PMOPLO 0x148000
-+#define PMOPHI 0x148004
-+#define PMOP_END 0x14FFFC
-+#define PCURR_START 0x150000
-+#define PCURR_END 0x153FFC
-+#define PTRAG_START 0x154000
-+#define PTRAG_END 0x157FFC
-+#define PSR_START 0x158000
-+#define PSR_END 0x15BFFC
-+
-+#define PFSTAT4SEG_START 0x160000
-+#define PFSTAT4SEG_END 0x160BFC
-+#define PFSTAT2SEG_START 0x160C00
-+#define PFSTAT2SEG_END 0x1617FC
-+#define PFTARG4SEG_START 0x164000
-+#define PFTARG4SEG_END 0x164BFC
-+#define PFTARG2SEG_START 0x164C00
-+#define PFTARG2SEG_END 0x1657FC
-+#define PFSR4SEG_START 0x168000
-+#define PFSR4SEG_END 0x168BFC
-+#define PFSR2SEG_START 0x168C00
-+#define PFSR2SEG_END 0x1697FC
-+#define PCURRMS4SEG_START 0x16C000
-+#define PCURRMS4SEG_END 0x16CCFC
-+#define PCURRMS2SEG_START 0x16CC00
-+#define PCURRMS2SEG_END 0x16D7FC
-+#define PTARGMS4SEG_START 0x170000
-+#define PTARGMS4SEG_END 0x172FFC
-+#define PTARGMS2SEG_START 0x173000
-+#define PTARGMS2SEG_END 0x1747FC
-+#define PSRMS4SEG_START 0x170000
-+#define PSRMS4SEG_END 0x172FFC
-+#define PSRMS2SEG_START 0x173000
-+#define PSRMS2SEG_END 0x1747FC
-+
-+#define PRING_LO_START 0x190000
-+#define PRING_LO_END 0x193FFC
-+#define PRING_HI_START 0x194000
-+#define PRING_HI_END 0x197FFC
-+#define PRING_LO_HI_START 0x198000
-+#define PRING_LO_HI 0x198000
-+#define PRING_LO_HI_END 0x19BFFC
-+
-+#define PINTFIFO 0x1A0000
-+#define SRCCTL 0x1B0000
-+#define SRCCCR 0x1B0004
-+#define SRCIMAP 0x1B0008
-+#define SRCODDC 0x1B000C
-+#define SRCCA 0x1B0010
-+#define SRCCF 0x1B0014
-+#define SRCSA 0x1B0018
-+#define SRCLA 0x1B001C
-+#define SRCCTLSWR 0x1B0020
-+
-+/* SRC HERE */
-+#define SRCALBA 0x1B002C
-+#define SRCMCTL 0x1B012C
-+#define SRCCERR 0x1B022C
-+#define SRCITB 0x1B032C
-+#define SRCIPM 0x1B082C
-+#define SRCIP 0x1B102C
-+#define SRCENBSTAT 0x1B202C
-+#define SRCENBLO 0x1B212C
-+#define SRCENBHI 0x1B222C
-+#define SRCENBS 0x1B232C
-+#define SRCENB 0x1B282C
-+#define SRCENB07 0x1B282C
-+#define SRCENBS07 0x1B302C
-+
-+#define SRCDN0Z 0x1B0030
-+#define SRCDN0Z0 0x1B0030
-+#define SRCDN0Z1 0x1B0034
-+#define SRCDN0Z2 0x1B0038
-+#define SRCDN0Z3 0x1B003C
-+#define SRCDN1Z 0x1B0040
-+#define SRCDN1Z0 0x1B0040
-+#define SRCDN1Z1 0x1B0044
-+#define SRCDN1Z2 0x1B0048
-+#define SRCDN1Z3 0x1B004C
-+#define SRCDN1Z4 0x1B0050
-+#define SRCDN1Z5 0x1B0054
-+#define SRCDN1Z6 0x1B0058
-+#define SRCDN1Z7 0x1B005C
-+#define SRCUPZ 0x1B0060
-+#define SRCUPZ0 0x1B0060
-+#define SRCUPZ1 0x1B0064
-+#define SRCUPZ2 0x1B0068
-+#define SRCUPZ3 0x1B006C
-+#define SRCUPZ4 0x1B0070
-+#define SRCUPZ5 0x1B0074
-+#define SRCUPZ6 0x1B0078
-+#define SRCUPZ7 0x1B007C
-+#define SRCCD0 0x1B0080
-+#define SRCCD1 0x1B0084
-+#define SRCCD2 0x1B0088
-+#define SRCCD3 0x1B008C
-+#define SRCCD4 0x1B0090
-+#define SRCCD5 0x1B0094
-+#define SRCCD6 0x1B0098
-+#define SRCCD7 0x1B009C
-+#define SRCCD8 0x1B00A0
-+#define SRCCD9 0x1B00A4
-+#define SRCCDA 0x1B00A8
-+#define SRCCDB 0x1B00AC
-+#define SRCCDC 0x1B00B0
-+#define SRCCDD 0x1B00B4
-+#define SRCCDE 0x1B00B8
-+#define SRCCDF 0x1B00BC
-+#define SRCCD10 0x1B00C0
-+#define SRCCD11 0x1B00C4
-+#define SRCCD12 0x1B00C8
-+#define SRCCD13 0x1B00CC
-+#define SRCCD14 0x1B00D0
-+#define SRCCD15 0x1B00D4
-+#define SRCCD16 0x1B00D8
-+#define SRCCD17 0x1B00DC
-+#define SRCCD18 0x1B00E0
-+#define SRCCD19 0x1B00E4
-+#define SRCCD1A 0x1B00E8
-+#define SRCCD1B 0x1B00EC
-+#define SRCCD1C 0x1B00F0
-+#define SRCCD1D 0x1B00F4
-+#define SRCCD1E 0x1B00F8
-+#define SRCCD1F 0x1B00FC
-+
-+#define SRCCONTRBLOCK_START 0x1B0100
-+#define SRCCONTRBLOCK_END 0x1BFFFC
-+#define FILTOP_START 0x1C0000
-+#define FILTOP_END 0x1C05FC
-+#define FILTIMAP_START 0x1C0800
-+#define FILTIMAP_END 0x1C0DFC
-+#define FILTZ1_START 0x1C1000
-+#define FILTZ1_END 0x1C15FC
-+#define FILTZ2_START 0x1C1800
-+#define FILTZ2_END 0x1C1DFC
-+#define DAOIMAP_START 0x1C5000
-+#define DAOIMAP 0x1C5000
-+#define DAOIMAP_END 0x1C5124
-+
-+#define AC97D 0x1C5400
-+#define AC97A 0x1C5404
-+#define AC97CTL 0x1C5408
-+#define I2SCTL 0x1C5420
-+
-+#define SPOS 0x1C5440
-+#define SPOSA 0x1C5440
-+#define SPOSB 0x1C5444
-+#define SPOSC 0x1C5448
-+#define SPOSD 0x1C544C
-+
-+#define SPISA 0x1C5450
-+#define SPISB 0x1C5454
-+#define SPISC 0x1C5458
-+#define SPISD 0x1C545C
-+
-+#define SPFSCTL 0x1C5460
-+
-+#define SPFS0 0x1C5468
-+#define SPFS1 0x1C546C
-+#define SPFS2 0x1C5470
-+#define SPFS3 0x1C5474
-+#define SPFS4 0x1C5478
-+#define SPFS5 0x1C547C
-+
-+#define SPOCTL 0x1C5480
-+#define SPICTL 0x1C5484
-+#define SPISTS 0x1C5488
-+#define SPINTP 0x1C548C
-+#define SPINTE 0x1C5490
-+#define SPUTCTLAB 0x1C5494
-+#define SPUTCTLCD 0x1C5498
-+
-+#define SRTSPA 0x1C54C0
-+#define SRTSPB 0x1C54C4
-+#define SRTSPC 0x1C54C8
-+#define SRTSPD 0x1C54CC
-+
-+#define SRTSCTL 0x1C54D0
-+#define SRTSCTLA 0x1C54D0
-+#define SRTSCTLB 0x1C54D4
-+#define SRTSCTLC 0x1C54D8
-+#define SRTSCTLD 0x1C54DC
-+
-+#define SRTI2S 0x1C54E0
-+#define SRTICTL 0x1C54F0
-+
-+#define WC 0x1C6000
-+#define TIMR 0x1C6004
-+# define TIMR_IE (1<<15)
-+# define TIMR_IP (1<<14)
-+
-+#define GIP 0x1C6010
-+#define GIE 0x1C6014
-+#define DIE 0x1C6018
-+#define DIC 0x1C601C
-+#define GPIO 0x1C6020
-+#define GPIOCTL 0x1C6024
-+#define GPIP 0x1C6028
-+#define GPIE 0x1C602C
-+#define DSPINT0 0x1C6030
-+#define DSPEIOC 0x1C6034
-+#define MUADAT 0x1C6040
-+#define MUACMD 0x1C6044
-+#define MUASTAT 0x1C6044
-+#define MUBDAT 0x1C6048
-+#define MUBCMD 0x1C604C
-+#define MUBSTAT 0x1C604C
-+#define UARTCMA 0x1C6050
-+#define UARTCMB 0x1C6054
-+#define UARTIP 0x1C6058
-+#define UARTIE 0x1C605C
-+#define PLLCTL 0x1C6060
-+#define PLLDCD 0x1C6064
-+#define GCTL 0x1C6070
-+#define ID0 0x1C6080
-+#define ID1 0x1C6084
-+#define ID2 0x1C6088
-+#define ID3 0x1C608C
-+#define SDRCTL 0x1C7000
-+
-+
-+#define I2SA_L 0x0L
-+#define I2SA_R 0x1L
-+#define I2SB_L 0x8L
-+#define I2SB_R 0x9L
-+#define I2SC_L 0x10L
-+#define I2SC_R 0x11L
-+#define I2SD_L 0x18L
-+#define I2SD_R 0x19L
-+
-+#endif /* CT20K1REG_H */
-+
-+
---- /dev/null
-+++ b/sound/pci/ctxfi/ct20k2reg.h
-@@ -0,0 +1,88 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ */
-+
-+#ifndef _20K2REGISTERS_H_
-+#define _20K2REGISTERS_H_
-+
-+
-+/* Timer Registers */
-+#define WC 0x1b7000
-+#define TIMR 0x1b7004
-+# define TIMR_IE (1<<15)
-+# define TIMR_IP (1<<14)
-+#define GIP 0x1b7010
-+#define GIE 0x1b7014
-+
-+/* I2C Registers */
-+#define I2C_IF_ADDRESS 0x1B9000
-+#define I2C_IF_WDATA 0x1B9004
-+#define I2C_IF_RDATA 0x1B9008
-+#define I2C_IF_STATUS 0x1B900C
-+#define I2C_IF_WLOCK 0x1B9010
-+
-+/* Global Control Registers */
-+#define GLOBAL_CNTL_GCTL 0x1B7090
-+
-+/* PLL Registers */
-+#define PLL_CTL 0x1B7080
-+#define PLL_STAT 0x1B7084
-+#define PLL_ENB 0x1B7088
-+
-+/* SRC Registers */
-+#define SRC_CTL 0x1A0000 /* 0x1A0000 + (256 * Chn) */
-+#define SRC_CCR 0x1A0004 /* 0x1A0004 + (256 * Chn) */
-+#define SRC_IMAP 0x1A0008 /* 0x1A0008 + (256 * Chn) */
-+#define SRC_CA 0x1A0010 /* 0x1A0010 + (256 * Chn) */
-+#define SRC_CF 0x1A0014 /* 0x1A0014 + (256 * Chn) */
-+#define SRC_SA 0x1A0018 /* 0x1A0018 + (256 * Chn) */
-+#define SRC_LA 0x1A001C /* 0x1A001C + (256 * Chn) */
-+#define SRC_CTLSWR 0x1A0020 /* 0x1A0020 + (256 * Chn) */
-+#define SRC_CD 0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */
-+#define SRC_MCTL 0x1A012C
-+#define SRC_IP 0x1A102C /* 0x1A102C + (256 * Regn) */
-+#define SRC_ENB 0x1A282C /* 0x1A282C + (256 * Regn) */
-+#define SRC_ENBSTAT 0x1A202C
-+#define SRC_ENBSA 0x1A232C
-+#define SRC_DN0Z 0x1A0030
-+#define SRC_DN1Z 0x1A0040
-+#define SRC_UPZ 0x1A0060
-+
-+/* GPIO Registers */
-+#define GPIO_DATA 0x1B7020
-+#define GPIO_CTRL 0x1B7024
-+
-+/* Virtual memory registers */
-+#define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */
-+#define VMEM_PTPAH 0x1C6304 /* 0x1C6304 + (16 * Chn) */
-+#define VMEM_CTL 0x1C7000
-+
-+/* Transport Registers */
-+#define TRANSPORT_ENB 0x1B6000
-+#define TRANSPORT_CTL 0x1B6004
-+#define TRANSPORT_INT 0x1B6008
-+
-+/* Audio IO */
-+#define AUDIO_IO_AIM 0x1B5000 /* 0x1B5000 + (0x04 * Chn) */
-+#define AUDIO_IO_TX_CTL 0x1B5400 /* 0x1B5400 + (0x40 * Chn) */
-+#define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */
-+#define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */
-+#define AUDIO_IO_RX_CTL 0x1B5410 /* 0x1B5410 + (0x40 * Chn) */
-+#define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */
-+#define AUDIO_IO_MCLK 0x1B5600
-+#define AUDIO_IO_TX_BLRCLK 0x1B5604
-+#define AUDIO_IO_RX_BLRCLK 0x1B5608
-+
-+/* Mixer */
-+#define MIXER_AMOPLO 0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */
-+#define MIXER_AMOPHI 0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */
-+#define MIXER_PRING_LO_HI 0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */
-+#define MIXER_PMOPLO 0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */
-+#define MIXER_PMOPHI 0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */
-+#define MIXER_AR_ENABLE 0x19000C
-+
-+#endif
---- /dev/null
-+++ b/sound/pci/ctxfi/ctamixer.c
-@@ -0,0 +1,486 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctamixer.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of the Audio Mixer
-+ * resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 21 2008
-+ *
-+ */
-+
-+#include "ctamixer.h"
-+#include "cthardware.h"
-+#include <linux/slab.h>
-+
-+#define AMIXER_RESOURCE_NUM 256
-+#define SUM_RESOURCE_NUM 256
-+
-+#define AMIXER_Y_IMMEDIATE 1
-+
-+#define BLANK_SLOT 4094
-+
-+static int amixer_master(struct rsc *rsc)
-+{
-+ rsc->conj = 0;
-+ return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
-+}
-+
-+static int amixer_next_conj(struct rsc *rsc)
-+{
-+ rsc->conj++;
-+ return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
-+}
-+
-+static int amixer_index(const struct rsc *rsc)
-+{
-+ return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
-+}
-+
-+static int amixer_output_slot(const struct rsc *rsc)
-+{
-+ return (amixer_index(rsc) << 4) + 0x4;
-+}
-+
-+static struct rsc_ops amixer_basic_rsc_ops = {
-+ .master = amixer_master,
-+ .next_conj = amixer_next_conj,
-+ .index = amixer_index,
-+ .output_slot = amixer_output_slot,
-+};
-+
-+static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
-+{
-+ struct hw *hw;
-+
-+ hw = amixer->rsc.hw;
-+ hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
-+ amixer->input = rsc;
-+ if (!rsc)
-+ hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
-+ else
-+ hw->amixer_set_x(amixer->rsc.ctrl_blk,
-+ rsc->ops->output_slot(rsc));
-+
-+ return 0;
-+}
-+
-+/* y is a 14-bit immediate constant */
-+static int amixer_set_y(struct amixer *amixer, unsigned int y)
-+{
-+ struct hw *hw;
-+
-+ hw = amixer->rsc.hw;
-+ hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
-+
-+ return 0;
-+}
-+
-+static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
-+{
-+ struct hw *hw;
-+
-+ hw = amixer->rsc.hw;
-+ hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
-+
-+ return 0;
-+}
-+
-+static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
-+{
-+ struct hw *hw;
-+
-+ hw = amixer->rsc.hw;
-+ amixer->sum = sum;
-+ if (!sum) {
-+ hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
-+ } else {
-+ hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
-+ hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
-+ sum->rsc.ops->index(&sum->rsc));
-+ }
-+
-+ return 0;
-+}
-+
-+static int amixer_commit_write(struct amixer *amixer)
-+{
-+ struct hw *hw;
-+ unsigned int index;
-+ int i;
-+ struct rsc *input;
-+ struct sum *sum;
-+
-+ hw = amixer->rsc.hw;
-+ input = amixer->input;
-+ sum = amixer->sum;
-+
-+ /* Program master and conjugate resources */
-+ amixer->rsc.ops->master(&amixer->rsc);
-+ if (input)
-+ input->ops->master(input);
-+
-+ if (sum)
-+ sum->rsc.ops->master(&sum->rsc);
-+
-+ for (i = 0; i < amixer->rsc.msr; i++) {
-+ hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
-+ if (input) {
-+ hw->amixer_set_x(amixer->rsc.ctrl_blk,
-+ input->ops->output_slot(input));
-+ input->ops->next_conj(input);
-+ }
-+ if (sum) {
-+ hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
-+ sum->rsc.ops->index(&sum->rsc));
-+ sum->rsc.ops->next_conj(&sum->rsc);
-+ }
-+ index = amixer->rsc.ops->output_slot(&amixer->rsc);
-+ hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
-+ amixer->rsc.ops->next_conj(&amixer->rsc);
-+ }
-+ amixer->rsc.ops->master(&amixer->rsc);
-+ if (input)
-+ input->ops->master(input);
-+
-+ if (sum)
-+ sum->rsc.ops->master(&sum->rsc);
-+
-+ return 0;
-+}
-+
-+static int amixer_commit_raw_write(struct amixer *amixer)
-+{
-+ struct hw *hw;
-+ unsigned int index;
-+
-+ hw = amixer->rsc.hw;
-+ index = amixer->rsc.ops->output_slot(&amixer->rsc);
-+ hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
-+
-+ return 0;
-+}
-+
-+static int amixer_get_y(struct amixer *amixer)
-+{
-+ struct hw *hw;
-+
-+ hw = amixer->rsc.hw;
-+ return hw->amixer_get_y(amixer->rsc.ctrl_blk);
-+}
-+
-+static int amixer_setup(struct amixer *amixer, struct rsc *input,
-+ unsigned int scale, struct sum *sum)
-+{
-+ amixer_set_input(amixer, input);
-+ amixer_set_y(amixer, scale);
-+ amixer_set_sum(amixer, sum);
-+ amixer_commit_write(amixer);
-+ return 0;
-+}
-+
-+static struct amixer_rsc_ops amixer_ops = {
-+ .set_input = amixer_set_input,
-+ .set_invalid_squash = amixer_set_invalid_squash,
-+ .set_scale = amixer_set_y,
-+ .set_sum = amixer_set_sum,
-+ .commit_write = amixer_commit_write,
-+ .commit_raw_write = amixer_commit_raw_write,
-+ .setup = amixer_setup,
-+ .get_scale = amixer_get_y,
-+};
-+
-+static int amixer_rsc_init(struct amixer *amixer,
-+ const struct amixer_desc *desc,
-+ struct amixer_mgr *mgr)
-+{
-+ int err;
-+
-+ err = rsc_init(&amixer->rsc, amixer->idx[0],
-+ AMIXER, desc->msr, mgr->mgr.hw);
-+ if (err)
-+ return err;
-+
-+ /* Set amixer specific operations */
-+ amixer->rsc.ops = &amixer_basic_rsc_ops;
-+ amixer->ops = &amixer_ops;
-+ amixer->input = NULL;
-+ amixer->sum = NULL;
-+
-+ amixer_setup(amixer, NULL, 0, NULL);
-+
-+ return 0;
-+}
-+
-+static int amixer_rsc_uninit(struct amixer *amixer)
-+{
-+ amixer_setup(amixer, NULL, 0, NULL);
-+ rsc_uninit(&amixer->rsc);
-+ amixer->ops = NULL;
-+ amixer->input = NULL;
-+ amixer->sum = NULL;
-+ return 0;
-+}
-+
-+static int get_amixer_rsc(struct amixer_mgr *mgr,
-+ const struct amixer_desc *desc,
-+ struct amixer **ramixer)
-+{
-+ int err, i;
-+ unsigned int idx;
-+ struct amixer *amixer;
-+ unsigned long flags;
-+
-+ *ramixer = NULL;
-+
-+ /* Allocate mem for amixer resource */
-+ amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
-+ if (!amixer)
-+ return -ENOMEM;
-+
-+ /* Check whether there are sufficient
-+ * amixer resources to meet request. */
-+ err = 0;
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i = 0; i < desc->msr; i++) {
-+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
-+ if (err)
-+ break;
-+
-+ amixer->idx[i] = idx;
-+ }
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
-+ goto error;
-+ }
-+
-+ err = amixer_rsc_init(amixer, desc, mgr);
-+ if (err)
-+ goto error;
-+
-+ *ramixer = amixer;
-+
-+ return 0;
-+
-+error:
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i--; i >= 0; i--)
-+ mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ kfree(amixer);
-+ return err;
-+}
-+
-+static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
-+{
-+ unsigned long flags;
-+ int i;
-+
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i = 0; i < amixer->rsc.msr; i++)
-+ mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ amixer_rsc_uninit(amixer);
-+ kfree(amixer);
-+
-+ return 0;
-+}
-+
-+int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
-+{
-+ int err;
-+ struct amixer_mgr *amixer_mgr;
-+
-+ *ramixer_mgr = NULL;
-+ amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
-+ if (!amixer_mgr)
-+ return -ENOMEM;
-+
-+ err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
-+ if (err)
-+ goto error;
-+
-+ spin_lock_init(&amixer_mgr->mgr_lock);
-+
-+ amixer_mgr->get_amixer = get_amixer_rsc;
-+ amixer_mgr->put_amixer = put_amixer_rsc;
-+
-+ *ramixer_mgr = amixer_mgr;
-+
-+ return 0;
-+
-+error:
-+ kfree(amixer_mgr);
-+ return err;
-+}
-+
-+int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
-+{
-+ rsc_mgr_uninit(&amixer_mgr->mgr);
-+ kfree(amixer_mgr);
-+ return 0;
-+}
-+
-+/* SUM resource management */
-+
-+static int sum_master(struct rsc *rsc)
-+{
-+ rsc->conj = 0;
-+ return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
-+}
-+
-+static int sum_next_conj(struct rsc *rsc)
-+{
-+ rsc->conj++;
-+ return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
-+}
-+
-+static int sum_index(const struct rsc *rsc)
-+{
-+ return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
-+}
-+
-+static int sum_output_slot(const struct rsc *rsc)
-+{
-+ return (sum_index(rsc) << 4) + 0xc;
-+}
-+
-+static struct rsc_ops sum_basic_rsc_ops = {
-+ .master = sum_master,
-+ .next_conj = sum_next_conj,
-+ .index = sum_index,
-+ .output_slot = sum_output_slot,
-+};
-+
-+static int sum_rsc_init(struct sum *sum,
-+ const struct sum_desc *desc,
-+ struct sum_mgr *mgr)
-+{
-+ int err;
-+
-+ err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
-+ if (err)
-+ return err;
-+
-+ sum->rsc.ops = &sum_basic_rsc_ops;
-+
-+ return 0;
-+}
-+
-+static int sum_rsc_uninit(struct sum *sum)
-+{
-+ rsc_uninit(&sum->rsc);
-+ return 0;
-+}
-+
-+static int get_sum_rsc(struct sum_mgr *mgr,
-+ const struct sum_desc *desc,
-+ struct sum **rsum)
-+{
-+ int err, i;
-+ unsigned int idx;
-+ struct sum *sum;
-+ unsigned long flags;
-+
-+ *rsum = NULL;
-+
-+ /* Allocate mem for sum resource */
-+ sum = kzalloc(sizeof(*sum), GFP_KERNEL);
-+ if (!sum)
-+ return -ENOMEM;
-+
-+ /* Check whether there are sufficient sum resources to meet request. */
-+ err = 0;
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i = 0; i < desc->msr; i++) {
-+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
-+ if (err)
-+ break;
-+
-+ sum->idx[i] = idx;
-+ }
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
-+ goto error;
-+ }
-+
-+ err = sum_rsc_init(sum, desc, mgr);
-+ if (err)
-+ goto error;
-+
-+ *rsum = sum;
-+
-+ return 0;
-+
-+error:
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i--; i >= 0; i--)
-+ mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ kfree(sum);
-+ return err;
-+}
-+
-+static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
-+{
-+ unsigned long flags;
-+ int i;
-+
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i = 0; i < sum->rsc.msr; i++)
-+ mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ sum_rsc_uninit(sum);
-+ kfree(sum);
-+
-+ return 0;
-+}
-+
-+int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
-+{
-+ int err;
-+ struct sum_mgr *sum_mgr;
-+
-+ *rsum_mgr = NULL;
-+ sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
-+ if (!sum_mgr)
-+ return -ENOMEM;
-+
-+ err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
-+ if (err)
-+ goto error;
-+
-+ spin_lock_init(&sum_mgr->mgr_lock);
-+
-+ sum_mgr->get_sum = get_sum_rsc;
-+ sum_mgr->put_sum = put_sum_rsc;
-+
-+ *rsum_mgr = sum_mgr;
-+
-+ return 0;
-+
-+error:
-+ kfree(sum_mgr);
-+ return err;
-+}
-+
-+int sum_mgr_destroy(struct sum_mgr *sum_mgr)
-+{
-+ rsc_mgr_uninit(&sum_mgr->mgr);
-+ kfree(sum_mgr);
-+ return 0;
-+}
-+
---- /dev/null
-+++ b/sound/pci/ctxfi/ctamixer.h
-@@ -0,0 +1,96 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctamixer.h
-+ *
-+ * @Brief
-+ * This file contains the definition of the Audio Mixer
-+ * resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 21 2008
-+ *
-+ */
-+
-+#ifndef CTAMIXER_H
-+#define CTAMIXER_H
-+
-+#include "ctresource.h"
-+#include <linux/spinlock.h>
-+
-+/* Define the descriptor of a summation node resource */
-+struct sum {
-+ struct rsc rsc; /* Basic resource info */
-+ unsigned char idx[8];
-+};
-+
-+/* Define sum resource request description info */
-+struct sum_desc {
-+ unsigned int msr;
-+};
-+
-+struct sum_mgr {
-+ struct rsc_mgr mgr; /* Basic resource manager info */
-+ spinlock_t mgr_lock;
-+
-+ /* request one sum resource */
-+ int (*get_sum)(struct sum_mgr *mgr,
-+ const struct sum_desc *desc, struct sum **rsum);
-+ /* return one sum resource */
-+ int (*put_sum)(struct sum_mgr *mgr, struct sum *sum);
-+};
-+
-+/* Constructor and destructor of daio resource manager */
-+int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr);
-+int sum_mgr_destroy(struct sum_mgr *sum_mgr);
-+
-+/* Define the descriptor of a amixer resource */
-+struct amixer_rsc_ops;
-+
-+struct amixer {
-+ struct rsc rsc; /* Basic resource info */
-+ unsigned char idx[8];
-+ struct rsc *input; /* pointer to a resource acting as source */
-+ struct sum *sum; /* Put amixer output to this summation node */
-+ struct amixer_rsc_ops *ops; /* AMixer specific operations */
-+};
-+
-+struct amixer_rsc_ops {
-+ int (*set_input)(struct amixer *amixer, struct rsc *rsc);
-+ int (*set_scale)(struct amixer *amixer, unsigned int scale);
-+ int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv);
-+ int (*set_sum)(struct amixer *amixer, struct sum *sum);
-+ int (*commit_write)(struct amixer *amixer);
-+ /* Only for interleaved recording */
-+ int (*commit_raw_write)(struct amixer *amixer);
-+ int (*setup)(struct amixer *amixer, struct rsc *input,
-+ unsigned int scale, struct sum *sum);
-+ int (*get_scale)(struct amixer *amixer);
-+};
-+
-+/* Define amixer resource request description info */
-+struct amixer_desc {
-+ unsigned int msr;
-+};
-+
-+struct amixer_mgr {
-+ struct rsc_mgr mgr; /* Basic resource manager info */
-+ spinlock_t mgr_lock;
-+
-+ /* request one amixer resource */
-+ int (*get_amixer)(struct amixer_mgr *mgr,
-+ const struct amixer_desc *desc,
-+ struct amixer **ramixer);
-+ /* return one amixer resource */
-+ int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer);
-+};
-+
-+/* Constructor and destructor of amixer resource manager */
-+int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr);
-+int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
-+
-+#endif /* CTAMIXER_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctatc.c
-@@ -0,0 +1,1712 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctatc.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of the device resource management
-+ * object.
-+ *
-+ * @Author Liu Chun
-+ * @Date Mar 28 2008
-+ */
-+
-+#include "ctatc.h"
-+#include "ctpcm.h"
-+#include "ctmixer.h"
-+#include "cthardware.h"
-+#include "ctsrc.h"
-+#include "ctamixer.h"
-+#include "ctdaio.h"
-+#include "cttimer.h"
-+#include <linux/delay.h>
-+#include <sound/pcm.h>
-+#include <sound/control.h>
-+#include <sound/asoundef.h>
-+
-+#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */
-+#define DAIONUM 7
-+#define MAX_MULTI_CHN 8
-+
-+#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
-+ | IEC958_AES0_CON_NOT_COPYRIGHT) \
-+ | ((IEC958_AES1_CON_MIXER \
-+ | IEC958_AES1_CON_ORIGINAL) << 8) \
-+ | (0x10 << 16) \
-+ | ((IEC958_AES3_CON_FS_48000) << 24))
-+
-+static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X),
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X),
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X),
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X),
-+ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000,
-+ "UAA", CTUAA),
-+ { } /* terminator */
-+};
-+
-+static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
-+ "SB0760", CTSB0760),
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
-+ "SB0880", CTSB0880),
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
-+ "SB0880", CTSB0880),
-+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803,
-+ "SB0880", CTSB0880),
-+ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
-+ PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
-+ CTHENDRIX),
-+ { } /* terminator */
-+};
-+
-+static const char *ct_subsys_name[NUM_CTCARDS] = {
-+ /* 20k1 models */
-+ [CTSB055X] = "SB055x",
-+ [CTSB073X] = "SB073x",
-+ [CTUAA] = "UAA",
-+ [CT20K1_UNKNOWN] = "Unknown",
-+ /* 20k2 models */
-+ [CTSB0760] = "SB076x",
-+ [CTHENDRIX] = "Hendrix",
-+ [CTSB0880] = "SB0880",
-+ [CT20K2_UNKNOWN] = "Unknown",
-+};
-+
-+static struct {
-+ int (*create)(struct ct_atc *atc,
-+ enum CTALSADEVS device, const char *device_name);
-+ int (*destroy)(void *alsa_dev);
-+ const char *public_name;
-+} alsa_dev_funcs[NUM_CTALSADEVS] = {
-+ [FRONT] = { .create = ct_alsa_pcm_create,
-+ .destroy = NULL,
-+ .public_name = "Front/WaveIn"},
-+ [SURROUND] = { .create = ct_alsa_pcm_create,
-+ .destroy = NULL,
-+ .public_name = "Surround"},
-+ [CLFE] = { .create = ct_alsa_pcm_create,
-+ .destroy = NULL,
-+ .public_name = "Center/LFE"},
-+ [SIDE] = { .create = ct_alsa_pcm_create,
-+ .destroy = NULL,
-+ .public_name = "Side"},
-+ [IEC958] = { .create = ct_alsa_pcm_create,
-+ .destroy = NULL,
-+ .public_name = "IEC958 Non-audio"},
-+
-+ [MIXER] = { .create = ct_alsa_mix_create,
-+ .destroy = NULL,
-+ .public_name = "Mixer"}
-+};
-+
-+typedef int (*create_t)(void *, void **);
-+typedef int (*destroy_t)(void *);
-+
-+static struct {
-+ int (*create)(void *hw, void **rmgr);
-+ int (*destroy)(void *mgr);
-+} rsc_mgr_funcs[NUM_RSCTYP] = {
-+ [SRC] = { .create = (create_t)src_mgr_create,
-+ .destroy = (destroy_t)src_mgr_destroy },
-+ [SRCIMP] = { .create = (create_t)srcimp_mgr_create,
-+ .destroy = (destroy_t)srcimp_mgr_destroy },
-+ [AMIXER] = { .create = (create_t)amixer_mgr_create,
-+ .destroy = (destroy_t)amixer_mgr_destroy },
-+ [SUM] = { .create = (create_t)sum_mgr_create,
-+ .destroy = (destroy_t)sum_mgr_destroy },
-+ [DAIO] = { .create = (create_t)daio_mgr_create,
-+ .destroy = (destroy_t)daio_mgr_destroy }
-+};
-+
-+static int
-+atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+
-+/* *
-+ * Only mono and interleaved modes are supported now.
-+ * Always allocates a contiguous channel block.
-+ * */
-+
-+static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct snd_pcm_runtime *runtime;
-+ struct ct_vm *vm;
-+
-+ if (!apcm->substream)
-+ return 0;
-+
-+ runtime = apcm->substream->runtime;
-+ vm = atc->vm;
-+
-+ apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
-+
-+ if (!apcm->vm_block)
-+ return -ENOENT;
-+
-+ return 0;
-+}
-+
-+static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct ct_vm *vm;
-+
-+ if (!apcm->vm_block)
-+ return;
-+
-+ vm = atc->vm;
-+
-+ vm->unmap(vm, apcm->vm_block);
-+
-+ apcm->vm_block = NULL;
-+}
-+
-+static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
-+{
-+ struct ct_vm *vm;
-+ void *kvirt_addr;
-+ unsigned long phys_addr;
-+
-+ vm = atc->vm;
-+ kvirt_addr = vm->get_ptp_virt(vm, index);
-+ if (kvirt_addr == NULL)
-+ phys_addr = (~0UL);
-+ else
-+ phys_addr = virt_to_phys(kvirt_addr);
-+
-+ return phys_addr;
-+}
-+
-+static unsigned int convert_format(snd_pcm_format_t snd_format)
-+{
-+ switch (snd_format) {
-+ case SNDRV_PCM_FORMAT_U8:
-+ return SRC_SF_U8;
-+ case SNDRV_PCM_FORMAT_S16_LE:
-+ return SRC_SF_S16;
-+ case SNDRV_PCM_FORMAT_S24_3LE:
-+ return SRC_SF_S24;
-+ case SNDRV_PCM_FORMAT_S32_LE:
-+ return SRC_SF_S32;
-+ case SNDRV_PCM_FORMAT_FLOAT_LE:
-+ return SRC_SF_F32;
-+ default:
-+ printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
-+ snd_format);
-+ return SRC_SF_S16;
-+ }
-+}
-+
-+static unsigned int
-+atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
-+{
-+ unsigned int pitch;
-+ int b;
-+
-+ /* get pitch and convert to fixed-point 8.24 format. */
-+ pitch = (input_rate / output_rate) << 24;
-+ input_rate %= output_rate;
-+ input_rate /= 100;
-+ output_rate /= 100;
-+ for (b = 31; ((b >= 0) && !(input_rate >> b)); )
-+ b--;
-+
-+ if (b >= 0) {
-+ input_rate <<= (31 - b);
-+ input_rate /= output_rate;
-+ b = 24 - (31 - b);
-+ if (b >= 0)
-+ input_rate <<= b;
-+ else
-+ input_rate >>= -b;
-+
-+ pitch |= input_rate;
-+ }
-+
-+ return pitch;
-+}
-+
-+static int select_rom(unsigned int pitch)
-+{
-+ if (pitch > 0x00428f5c && pitch < 0x01b851ec) {
-+ /* 0.26 <= pitch <= 1.72 */
-+ return 1;
-+ } else if (pitch == 0x01d66666 || pitch == 0x01d66667) {
-+ /* pitch == 1.8375 */
-+ return 2;
-+ } else if (pitch == 0x02000000) {
-+ /* pitch == 2 */
-+ return 3;
-+ } else if (pitch >= 0x0 && pitch <= 0x08000000) {
-+ /* 0 <= pitch <= 8 */
-+ return 0;
-+ } else {
-+ return -ENOENT;
-+ }
-+}
-+
-+static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
-+ struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
-+ struct src_desc desc = {0};
-+ struct amixer_desc mix_dsc = {0};
-+ struct src *src;
-+ struct amixer *amixer;
-+ int err;
-+ int n_amixer = apcm->substream->runtime->channels, i = 0;
-+ int device = apcm->substream->pcm->device;
-+ unsigned int pitch;
-+
-+ /* first release old resources */
-+ atc_pcm_release_resources(atc, apcm);
-+
-+ /* Get SRC resource */
-+ desc.multi = apcm->substream->runtime->channels;
-+ desc.msr = atc->msr;
-+ desc.mode = MEMRD;
-+ err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
-+ if (err)
-+ goto error1;
-+
-+ pitch = atc_get_pitch(apcm->substream->runtime->rate,
-+ (atc->rsr * atc->msr));
-+ src = apcm->src;
-+ src->ops->set_pitch(src, pitch);
-+ src->ops->set_rom(src, select_rom(pitch));
-+ src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
-+ src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
-+
-+ /* Get AMIXER resource */
-+ n_amixer = (n_amixer < 2) ? 2 : n_amixer;
-+ apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
-+ if (!apcm->amixers) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+ mix_dsc.msr = atc->msr;
-+ for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
-+ err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
-+ (struct amixer **)&apcm->amixers[i]);
-+ if (err)
-+ goto error1;
-+
-+ apcm->n_amixer++;
-+ }
-+
-+ /* Set up device virtual mem map */
-+ err = ct_map_audio_buffer(atc, apcm);
-+ if (err < 0)
-+ goto error1;
-+
-+ /* Connect resources */
-+ src = apcm->src;
-+ for (i = 0; i < n_amixer; i++) {
-+ amixer = apcm->amixers[i];
-+ mutex_lock(&atc->atc_mutex);
-+ amixer->ops->setup(amixer, &src->rsc,
-+ INIT_VOL, atc->pcm[i+device*2]);
-+ mutex_unlock(&atc->atc_mutex);
-+ src = src->ops->next_interleave(src);
-+ if (!src)
-+ src = apcm->src;
-+ }
-+
-+ ct_timer_prepare(apcm->timer);
-+
-+ return 0;
-+
-+error1:
-+ atc_pcm_release_resources(atc, apcm);
-+ return err;
-+}
-+
-+static int
-+atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
-+ struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-+ struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
-+ struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
-+ struct srcimp *srcimp;
-+ int i;
-+
-+ if (apcm->srcimps) {
-+ for (i = 0; i < apcm->n_srcimp; i++) {
-+ srcimp = apcm->srcimps[i];
-+ srcimp->ops->unmap(srcimp);
-+ srcimp_mgr->put_srcimp(srcimp_mgr, srcimp);
-+ apcm->srcimps[i] = NULL;
-+ }
-+ kfree(apcm->srcimps);
-+ apcm->srcimps = NULL;
-+ }
-+
-+ if (apcm->srccs) {
-+ for (i = 0; i < apcm->n_srcc; i++) {
-+ src_mgr->put_src(src_mgr, apcm->srccs[i]);
-+ apcm->srccs[i] = NULL;
-+ }
-+ kfree(apcm->srccs);
-+ apcm->srccs = NULL;
-+ }
-+
-+ if (apcm->amixers) {
-+ for (i = 0; i < apcm->n_amixer; i++) {
-+ amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
-+ apcm->amixers[i] = NULL;
-+ }
-+ kfree(apcm->amixers);
-+ apcm->amixers = NULL;
-+ }
-+
-+ if (apcm->mono) {
-+ sum_mgr->put_sum(sum_mgr, apcm->mono);
-+ apcm->mono = NULL;
-+ }
-+
-+ if (apcm->src) {
-+ src_mgr->put_src(src_mgr, apcm->src);
-+ apcm->src = NULL;
-+ }
-+
-+ if (apcm->vm_block) {
-+ /* Undo device virtual mem map */
-+ ct_unmap_audio_buffer(atc, apcm);
-+ apcm->vm_block = NULL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ unsigned int max_cisz;
-+ struct src *src = apcm->src;
-+
-+ if (apcm->started)
-+ return 0;
-+ apcm->started = 1;
-+
-+ max_cisz = src->multi * src->rsc.msr;
-+ max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8);
-+
-+ src->ops->set_sa(src, apcm->vm_block->addr);
-+ src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
-+ src->ops->set_ca(src, apcm->vm_block->addr + max_cisz);
-+ src->ops->set_cisz(src, max_cisz);
-+
-+ src->ops->set_bm(src, 1);
-+ src->ops->set_state(src, SRC_STATE_INIT);
-+ src->ops->commit_write(src);
-+
-+ ct_timer_start(apcm->timer);
-+ return 0;
-+}
-+
-+static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src *src;
-+ int i;
-+
-+ ct_timer_stop(apcm->timer);
-+
-+ src = apcm->src;
-+ src->ops->set_bm(src, 0);
-+ src->ops->set_state(src, SRC_STATE_OFF);
-+ src->ops->commit_write(src);
-+
-+ if (apcm->srccs) {
-+ for (i = 0; i < apcm->n_srcc; i++) {
-+ src = apcm->srccs[i];
-+ src->ops->set_bm(src, 0);
-+ src->ops->set_state(src, SRC_STATE_OFF);
-+ src->ops->commit_write(src);
-+ }
-+ }
-+
-+ apcm->started = 0;
-+
-+ return 0;
-+}
-+
-+static int
-+atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src *src = apcm->src;
-+ u32 size, max_cisz;
-+ int position;
-+
-+ if (!src)
-+ return 0;
-+ position = src->ops->get_ca(src);
-+
-+ size = apcm->vm_block->size;
-+ max_cisz = src->multi * src->rsc.msr;
-+ max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8);
-+
-+ return (position + size - max_cisz - apcm->vm_block->addr) % size;
-+}
-+
-+struct src_node_conf_t {
-+ unsigned int pitch;
-+ unsigned int msr:8;
-+ unsigned int mix_msr:8;
-+ unsigned int imp_msr:8;
-+ unsigned int vo:1;
-+};
-+
-+static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
-+ struct src_node_conf_t *conf, int *n_srcc)
-+{
-+ unsigned int pitch;
-+
-+ /* get pitch and convert to fixed-point 8.24 format. */
-+ pitch = atc_get_pitch((atc->rsr * atc->msr),
-+ apcm->substream->runtime->rate);
-+ *n_srcc = 0;
-+
-+ if (1 == atc->msr) {
-+ *n_srcc = apcm->substream->runtime->channels;
-+ conf[0].pitch = pitch;
-+ conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
-+ conf[0].vo = 1;
-+ } else if (2 == atc->msr) {
-+ if (0x8000000 < pitch) {
-+ /* Need two-stage SRCs, SRCIMPs and
-+ * AMIXERs for converting format */
-+ conf[0].pitch = (atc->msr << 24);
-+ conf[0].msr = conf[0].mix_msr = 1;
-+ conf[0].imp_msr = atc->msr;
-+ conf[0].vo = 0;
-+ conf[1].pitch = atc_get_pitch(atc->rsr,
-+ apcm->substream->runtime->rate);
-+ conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1;
-+ conf[1].vo = 1;
-+ *n_srcc = apcm->substream->runtime->channels * 2;
-+ } else if (0x1000000 < pitch) {
-+ /* Need one-stage SRCs, SRCIMPs and
-+ * AMIXERs for converting format */
-+ conf[0].pitch = pitch;
-+ conf[0].msr = conf[0].mix_msr
-+ = conf[0].imp_msr = atc->msr;
-+ conf[0].vo = 1;
-+ *n_srcc = apcm->substream->runtime->channels;
-+ }
-+ }
-+}
-+
-+static int
-+atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
-+ struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-+ struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
-+ struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
-+ struct src_desc src_dsc = {0};
-+ struct src *src;
-+ struct srcimp_desc srcimp_dsc = {0};
-+ struct srcimp *srcimp;
-+ struct amixer_desc mix_dsc = {0};
-+ struct sum_desc sum_dsc = {0};
-+ unsigned int pitch;
-+ int multi, err, i;
-+ int n_srcimp, n_amixer, n_srcc, n_sum;
-+ struct src_node_conf_t src_node_conf[2] = {{0} };
-+
-+ /* first release old resources */
-+ atc_pcm_release_resources(atc, apcm);
-+
-+ /* The numbers of converting SRCs and SRCIMPs should be determined
-+ * by pitch value. */
-+
-+ multi = apcm->substream->runtime->channels;
-+
-+ /* get pitch and convert to fixed-point 8.24 format. */
-+ pitch = atc_get_pitch((atc->rsr * atc->msr),
-+ apcm->substream->runtime->rate);
-+
-+ setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc);
-+ n_sum = (1 == multi) ? 1 : 0;
-+ n_amixer = n_sum * 2 + n_srcc;
-+ n_srcimp = n_srcc;
-+ if ((multi > 1) && (0x8000000 >= pitch)) {
-+ /* Need extra AMIXERs and SRCIMPs for special treatment
-+ * of interleaved recording of conjugate channels */
-+ n_amixer += multi * atc->msr;
-+ n_srcimp += multi * atc->msr;
-+ } else {
-+ n_srcimp += multi;
-+ }
-+
-+ if (n_srcc) {
-+ apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL);
-+ if (!apcm->srccs)
-+ return -ENOMEM;
-+ }
-+ if (n_amixer) {
-+ apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
-+ if (!apcm->amixers) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+ }
-+ apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL);
-+ if (!apcm->srcimps) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+
-+ /* Allocate SRCs for sample rate conversion if needed */
-+ src_dsc.multi = 1;
-+ src_dsc.mode = ARCRW;
-+ for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) {
-+ src_dsc.msr = src_node_conf[i/multi].msr;
-+ err = src_mgr->get_src(src_mgr, &src_dsc,
-+ (struct src **)&apcm->srccs[i]);
-+ if (err)
-+ goto error1;
-+
-+ src = apcm->srccs[i];
-+ pitch = src_node_conf[i/multi].pitch;
-+ src->ops->set_pitch(src, pitch);
-+ src->ops->set_rom(src, select_rom(pitch));
-+ src->ops->set_vo(src, src_node_conf[i/multi].vo);
-+
-+ apcm->n_srcc++;
-+ }
-+
-+ /* Allocate AMIXERs for routing SRCs of conversion if needed */
-+ for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
-+ if (i < (n_sum*2))
-+ mix_dsc.msr = atc->msr;
-+ else if (i < (n_sum*2+n_srcc))
-+ mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr;
-+ else
-+ mix_dsc.msr = 1;
-+
-+ err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
-+ (struct amixer **)&apcm->amixers[i]);
-+ if (err)
-+ goto error1;
-+
-+ apcm->n_amixer++;
-+ }
-+
-+ /* Allocate a SUM resource to mix all input channels together */
-+ sum_dsc.msr = atc->msr;
-+ err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono);
-+ if (err)
-+ goto error1;
-+
-+ pitch = atc_get_pitch((atc->rsr * atc->msr),
-+ apcm->substream->runtime->rate);
-+ /* Allocate SRCIMP resources */
-+ for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) {
-+ if (i < (n_srcc))
-+ srcimp_dsc.msr = src_node_conf[i/multi].imp_msr;
-+ else if (1 == multi)
-+ srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1;
-+ else
-+ srcimp_dsc.msr = 1;
-+
-+ err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp);
-+ if (err)
-+ goto error1;
-+
-+ apcm->srcimps[i] = srcimp;
-+ apcm->n_srcimp++;
-+ }
-+
-+ /* Allocate a SRC for writing data to host memory */
-+ src_dsc.multi = apcm->substream->runtime->channels;
-+ src_dsc.msr = 1;
-+ src_dsc.mode = MEMWR;
-+ err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src);
-+ if (err)
-+ goto error1;
-+
-+ src = apcm->src;
-+ src->ops->set_pitch(src, pitch);
-+
-+ /* Set up device virtual mem map */
-+ err = ct_map_audio_buffer(atc, apcm);
-+ if (err < 0)
-+ goto error1;
-+
-+ return 0;
-+
-+error1:
-+ atc_pcm_release_resources(atc, apcm);
-+ return err;
-+}
-+
-+static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src *src;
-+ struct amixer *amixer;
-+ struct srcimp *srcimp;
-+ struct ct_mixer *mixer = atc->mixer;
-+ struct sum *mono;
-+ struct rsc *out_ports[8] = {NULL};
-+ int err, i, j, n_sum, multi;
-+ unsigned int pitch;
-+ int mix_base = 0, imp_base = 0;
-+
-+ atc_pcm_release_resources(atc, apcm);
-+
-+ /* Get needed resources. */
-+ err = atc_pcm_capture_get_resources(atc, apcm);
-+ if (err)
-+ return err;
-+
-+ /* Connect resources */
-+ mixer->get_output_ports(mixer, MIX_PCMO_FRONT,
-+ &out_ports[0], &out_ports[1]);
-+
-+ multi = apcm->substream->runtime->channels;
-+ if (1 == multi) {
-+ mono = apcm->mono;
-+ for (i = 0; i < 2; i++) {
-+ amixer = apcm->amixers[i];
-+ amixer->ops->setup(amixer, out_ports[i],
-+ MONO_SUM_SCALE, mono);
-+ }
-+ out_ports[0] = &mono->rsc;
-+ n_sum = 1;
-+ mix_base = n_sum * 2;
-+ }
-+
-+ for (i = 0; i < apcm->n_srcc; i++) {
-+ src = apcm->srccs[i];
-+ srcimp = apcm->srcimps[imp_base+i];
-+ amixer = apcm->amixers[mix_base+i];
-+ srcimp->ops->map(srcimp, src, out_ports[i%multi]);
-+ amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
-+ out_ports[i%multi] = &amixer->rsc;
-+ }
-+
-+ pitch = atc_get_pitch((atc->rsr * atc->msr),
-+ apcm->substream->runtime->rate);
-+
-+ if ((multi > 1) && (pitch <= 0x8000000)) {
-+ /* Special connection for interleaved
-+ * recording with conjugate channels */
-+ for (i = 0; i < multi; i++) {
-+ out_ports[i]->ops->master(out_ports[i]);
-+ for (j = 0; j < atc->msr; j++) {
-+ amixer = apcm->amixers[apcm->n_srcc+j*multi+i];
-+ amixer->ops->set_input(amixer, out_ports[i]);
-+ amixer->ops->set_scale(amixer, INIT_VOL);
-+ amixer->ops->set_sum(amixer, NULL);
-+ amixer->ops->commit_raw_write(amixer);
-+ out_ports[i]->ops->next_conj(out_ports[i]);
-+
-+ srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i];
-+ srcimp->ops->map(srcimp, apcm->src,
-+ &amixer->rsc);
-+ }
-+ }
-+ } else {
-+ for (i = 0; i < multi; i++) {
-+ srcimp = apcm->srcimps[apcm->n_srcc+i];
-+ srcimp->ops->map(srcimp, apcm->src, out_ports[i]);
-+ }
-+ }
-+
-+ ct_timer_prepare(apcm->timer);
-+
-+ return 0;
-+}
-+
-+static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src *src;
-+ struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
-+ int i, multi;
-+
-+ if (apcm->started)
-+ return 0;
-+
-+ apcm->started = 1;
-+ multi = apcm->substream->runtime->channels;
-+ /* Set up converting SRCs */
-+ for (i = 0; i < apcm->n_srcc; i++) {
-+ src = apcm->srccs[i];
-+ src->ops->set_pm(src, ((i%multi) != (multi-1)));
-+ src_mgr->src_disable(src_mgr, src);
-+ }
-+
-+ /* Set up recording SRC */
-+ src = apcm->src;
-+ src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
-+ src->ops->set_sa(src, apcm->vm_block->addr);
-+ src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
-+ src->ops->set_ca(src, apcm->vm_block->addr);
-+ src_mgr->src_disable(src_mgr, src);
-+
-+ /* Disable relevant SRCs firstly */
-+ src_mgr->commit_write(src_mgr);
-+
-+ /* Enable SRCs respectively */
-+ for (i = 0; i < apcm->n_srcc; i++) {
-+ src = apcm->srccs[i];
-+ src->ops->set_state(src, SRC_STATE_RUN);
-+ src->ops->commit_write(src);
-+ src_mgr->src_enable_s(src_mgr, src);
-+ }
-+ src = apcm->src;
-+ src->ops->set_bm(src, 1);
-+ src->ops->set_state(src, SRC_STATE_RUN);
-+ src->ops->commit_write(src);
-+ src_mgr->src_enable_s(src_mgr, src);
-+
-+ /* Enable relevant SRCs synchronously */
-+ src_mgr->commit_write(src_mgr);
-+
-+ ct_timer_start(apcm->timer);
-+ return 0;
-+}
-+
-+static int
-+atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src *src = apcm->src;
-+
-+ if (!src)
-+ return 0;
-+ return src->ops->get_ca(src) - apcm->vm_block->addr;
-+}
-+
-+static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
-+ struct ct_atc_pcm *apcm)
-+{
-+ struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
-+ struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
-+ struct src_desc desc = {0};
-+ struct amixer_desc mix_dsc = {0};
-+ struct src *src;
-+ int err;
-+ int n_amixer = apcm->substream->runtime->channels, i;
-+ unsigned int pitch, rsr = atc->pll_rate;
-+
-+ /* first release old resources */
-+ atc_pcm_release_resources(atc, apcm);
-+
-+ /* Get SRC resource */
-+ desc.multi = apcm->substream->runtime->channels;
-+ desc.msr = 1;
-+ while (apcm->substream->runtime->rate > (rsr * desc.msr))
-+ desc.msr <<= 1;
-+
-+ desc.mode = MEMRD;
-+ err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
-+ if (err)
-+ goto error1;
-+
-+ pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr));
-+ src = apcm->src;
-+ src->ops->set_pitch(src, pitch);
-+ src->ops->set_rom(src, select_rom(pitch));
-+ src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
-+ src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
-+ src->ops->set_bp(src, 1);
-+
-+ /* Get AMIXER resource */
-+ n_amixer = (n_amixer < 2) ? 2 : n_amixer;
-+ apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
-+ if (!apcm->amixers) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+ mix_dsc.msr = desc.msr;
-+ for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
-+ err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
-+ (struct amixer **)&apcm->amixers[i]);
-+ if (err)
-+ goto error1;
-+
-+ apcm->n_amixer++;
-+ }
-+
-+ /* Set up device virtual mem map */
-+ err = ct_map_audio_buffer(atc, apcm);
-+ if (err < 0)
-+ goto error1;
-+
-+ return 0;
-+
-+error1:
-+ atc_pcm_release_resources(atc, apcm);
-+ return err;
-+}
-+
-+static int atc_pll_init(struct ct_atc *atc, int rate)
-+{
-+ struct hw *hw = atc->hw;
-+ int err;
-+ err = hw->pll_init(hw, rate);
-+ atc->pll_rate = err ? 0 : rate;
-+ return err;
-+}
-+
-+static int
-+spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
-+ unsigned int rate = apcm->substream->runtime->rate;
-+ unsigned int status;
-+ int err = 0;
-+ unsigned char iec958_con_fs;
-+
-+ switch (rate) {
-+ case 48000:
-+ iec958_con_fs = IEC958_AES3_CON_FS_48000;
-+ break;
-+ case 44100:
-+ iec958_con_fs = IEC958_AES3_CON_FS_44100;
-+ break;
-+ case 32000:
-+ iec958_con_fs = IEC958_AES3_CON_FS_32000;
-+ break;
-+ default:
-+ return -ENOENT;
-+ }
-+
-+ mutex_lock(&atc->atc_mutex);
-+ dao->ops->get_spos(dao, &status);
-+ if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
-+ status &= ((~IEC958_AES3_CON_FS) << 24);
-+ status |= (iec958_con_fs << 24);
-+ dao->ops->set_spos(dao, status);
-+ dao->ops->commit_write(dao);
-+ }
-+ if ((rate != atc->pll_rate) && (32000 != rate))
-+ err = atc_pll_init(atc, rate);
-+ mutex_unlock(&atc->atc_mutex);
-+
-+ return err;
-+}
-+
-+static int
-+spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
-+{
-+ struct src *src;
-+ struct amixer *amixer;
-+ struct dao *dao;
-+ int err;
-+ int i;
-+
-+ atc_pcm_release_resources(atc, apcm);
-+
-+ /* Configure SPDIFOO and PLL to passthrough mode;
-+ * determine pll_rate. */
-+ err = spdif_passthru_playback_setup(atc, apcm);
-+ if (err)
-+ return err;
-+
-+ /* Get needed resources. */
-+ err = spdif_passthru_playback_get_resources(atc, apcm);
-+ if (err)
-+ return err;
-+
-+ /* Connect resources */
-+ src = apcm->src;
-+ for (i = 0; i < apcm->n_amixer; i++) {
-+ amixer = apcm->amixers[i];
-+ amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
-+ src = src->ops->next_interleave(src);
-+ if (!src)
-+ src = apcm->src;
-+ }
-+ /* Connect to SPDIFOO */
-+ mutex_lock(&atc->atc_mutex);
-+ dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
-+ amixer = apcm->amixers[0];
-+ dao->ops->set_left_input(dao, &amixer->rsc);
-+ amixer = apcm->amixers[1];
-+ dao->ops->set_right_input(dao, &amixer->rsc);
-+ mutex_unlock(&atc->atc_mutex);
-+
-+ ct_timer_prepare(apcm->timer);
-+
-+ return 0;
-+}
-+
-+static int atc_select_line_in(struct ct_atc *atc)
-+{
-+ struct hw *hw = atc->hw;
-+ struct ct_mixer *mixer = atc->mixer;
-+ struct src *src;
-+
-+ if (hw->is_adc_source_selected(hw, ADC_LINEIN))
-+ return 0;
-+
-+ mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
-+ mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
-+
-+ hw->select_adc_source(hw, ADC_LINEIN);
-+
-+ src = atc->srcs[2];
-+ mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
-+ src = atc->srcs[3];
-+ mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
-+
-+ return 0;
-+}
-+
-+static int atc_select_mic_in(struct ct_atc *atc)
-+{
-+ struct hw *hw = atc->hw;
-+ struct ct_mixer *mixer = atc->mixer;
-+ struct src *src;
-+
-+ if (hw->is_adc_source_selected(hw, ADC_MICIN))
-+ return 0;
-+
-+ mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
-+ mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
-+
-+ hw->select_adc_source(hw, ADC_MICIN);
-+
-+ src = atc->srcs[2];
-+ mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
-+ src = atc->srcs[3];
-+ mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
-+
-+ return 0;
-+}
-+
-+static int atc_have_digit_io_switch(struct ct_atc *atc)
-+{
-+ struct hw *hw = atc->hw;
-+
-+ return hw->have_digit_io_switch(hw);
-+}
-+
-+static int atc_select_digit_io(struct ct_atc *atc)
-+{
-+ struct hw *hw = atc->hw;
-+
-+ if (hw->is_adc_source_selected(hw, ADC_NONE))
-+ return 0;
-+
-+ hw->select_adc_source(hw, ADC_NONE);
-+
-+ return 0;
-+}
-+
-+static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type)
-+{
-+ struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO];
-+
-+ if (state)
-+ daio_mgr->daio_enable(daio_mgr, atc->daios[type]);
-+ else
-+ daio_mgr->daio_disable(daio_mgr, atc->daios[type]);
-+
-+ daio_mgr->commit_write(daio_mgr);
-+
-+ return 0;
-+}
-+
-+static int
-+atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type)
-+{
-+ struct dao *dao = container_of(atc->daios[type], struct dao, daio);
-+ return dao->ops->get_spos(dao, status);
-+}
-+
-+static int
-+atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type)
-+{
-+ struct dao *dao = container_of(atc->daios[type], struct dao, daio);
-+
-+ dao->ops->set_spos(dao, status);
-+ dao->ops->commit_write(dao);
-+ return 0;
-+}
-+
-+static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, LINEO1);
-+}
-+
-+static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, LINEO4);
-+}
-+
-+static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, LINEO3);
-+}
-+
-+static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, LINEO2);
-+}
-+
-+static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, LINEIM);
-+}
-+
-+static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, SPDIFOO);
-+}
-+
-+static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state)
-+{
-+ return atc_daio_unmute(atc, state, SPDIFIO);
-+}
-+
-+static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status)
-+{
-+ return atc_dao_get_status(atc, status, SPDIFOO);
-+}
-+
-+static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
-+{
-+ return atc_dao_set_status(atc, status, SPDIFOO);
-+}
-+
-+static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
-+{
-+ struct dao_desc da_dsc = {0};
-+ struct dao *dao;
-+ int err;
-+ struct ct_mixer *mixer = atc->mixer;
-+ struct rsc *rscs[2] = {NULL};
-+ unsigned int spos = 0;
-+
-+ mutex_lock(&atc->atc_mutex);
-+ dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
-+ da_dsc.msr = state ? 1 : atc->msr;
-+ da_dsc.passthru = state ? 1 : 0;
-+ err = dao->ops->reinit(dao, &da_dsc);
-+ if (state) {
-+ spos = IEC958_DEFAULT_CON;
-+ } else {
-+ mixer->get_output_ports(mixer, MIX_SPDIF_OUT,
-+ &rscs[0], &rscs[1]);
-+ dao->ops->set_left_input(dao, rscs[0]);
-+ dao->ops->set_right_input(dao, rscs[1]);
-+ /* Restore PLL to atc->rsr if needed. */
-+ if (atc->pll_rate != atc->rsr)
-+ err = atc_pll_init(atc, atc->rsr);
-+ }
-+ dao->ops->set_spos(dao, spos);
-+ dao->ops->commit_write(dao);
-+ mutex_unlock(&atc->atc_mutex);
-+
-+ return err;
-+}
-+
-+static int atc_release_resources(struct ct_atc *atc)
-+{
-+ int i;
-+ struct daio_mgr *daio_mgr = NULL;
-+ struct dao *dao = NULL;
-+ struct dai *dai = NULL;
-+ struct daio *daio = NULL;
-+ struct sum_mgr *sum_mgr = NULL;
-+ struct src_mgr *src_mgr = NULL;
-+ struct srcimp_mgr *srcimp_mgr = NULL;
-+ struct srcimp *srcimp = NULL;
-+ struct ct_mixer *mixer = NULL;
-+
-+ /* disconnect internal mixer objects */
-+ if (atc->mixer) {
-+ mixer = atc->mixer;
-+ mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
-+ mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
-+ mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
-+ mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
-+ mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
-+ mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
-+ }
-+
-+ if (atc->daios) {
-+ daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
-+ for (i = 0; i < atc->n_daio; i++) {
-+ daio = atc->daios[i];
-+ if (daio->type < LINEIM) {
-+ dao = container_of(daio, struct dao, daio);
-+ dao->ops->clear_left_input(dao);
-+ dao->ops->clear_right_input(dao);
-+ } else {
-+ dai = container_of(daio, struct dai, daio);
-+ /* some thing to do for dai ... */
-+ }
-+ daio_mgr->put_daio(daio_mgr, daio);
-+ }
-+ kfree(atc->daios);
-+ atc->daios = NULL;
-+ }
-+
-+ if (atc->pcm) {
-+ sum_mgr = atc->rsc_mgrs[SUM];
-+ for (i = 0; i < atc->n_pcm; i++)
-+ sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
-+
-+ kfree(atc->pcm);
-+ atc->pcm = NULL;
-+ }
-+
-+ if (atc->srcs) {
-+ src_mgr = atc->rsc_mgrs[SRC];
-+ for (i = 0; i < atc->n_src; i++)
-+ src_mgr->put_src(src_mgr, atc->srcs[i]);
-+
-+ kfree(atc->srcs);
-+ atc->srcs = NULL;
-+ }
-+
-+ if (atc->srcimps) {
-+ srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-+ for (i = 0; i < atc->n_srcimp; i++) {
-+ srcimp = atc->srcimps[i];
-+ srcimp->ops->unmap(srcimp);
-+ srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
-+ }
-+ kfree(atc->srcimps);
-+ atc->srcimps = NULL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ct_atc_destroy(struct ct_atc *atc)
-+{
-+ int i = 0;
-+
-+ if (!atc)
-+ return 0;
-+
-+ if (atc->timer) {
-+ ct_timer_free(atc->timer);
-+ atc->timer = NULL;
-+ }
-+
-+ atc_release_resources(atc);
-+
-+ /* Destroy internal mixer objects */
-+ if (atc->mixer)
-+ ct_mixer_destroy(atc->mixer);
-+
-+ for (i = 0; i < NUM_RSCTYP; i++) {
-+ if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i])
-+ rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
-+
-+ }
-+
-+ if (atc->hw)
-+ destroy_hw_obj((struct hw *)atc->hw);
-+
-+ /* Destroy device virtual memory manager object */
-+ if (atc->vm) {
-+ ct_vm_destroy(atc->vm);
-+ atc->vm = NULL;
-+ }
-+
-+ kfree(atc);
-+
-+ return 0;
-+}
-+
-+static int atc_dev_free(struct snd_device *dev)
-+{
-+ struct ct_atc *atc = dev->device_data;
-+ return ct_atc_destroy(atc);
-+}
-+
-+static int __devinit atc_identify_card(struct ct_atc *atc)
-+{
-+ const struct snd_pci_quirk *p;
-+ const struct snd_pci_quirk *list;
-+
-+ switch (atc->chip_type) {
-+ case ATC20K1:
-+ atc->chip_name = "20K1";
-+ list = subsys_20k1_list;
-+ break;
-+ case ATC20K2:
-+ atc->chip_name = "20K2";
-+ list = subsys_20k2_list;
-+ break;
-+ default:
-+ return -ENOENT;
-+ }
-+ p = snd_pci_quirk_lookup(atc->pci, list);
-+ if (p) {
-+ if (p->value < 0) {
-+ printk(KERN_ERR "ctxfi: "
-+ "Device %04x:%04x is black-listed\n",
-+ atc->pci->subsystem_vendor,
-+ atc->pci->subsystem_device);
-+ return -ENOENT;
-+ }
-+ atc->model = p->value;
-+ } else {
-+ if (atc->chip_type == ATC20K1)
-+ atc->model = CT20K1_UNKNOWN;
-+ else
-+ atc->model = CT20K2_UNKNOWN;
-+ }
-+ atc->model_name = ct_subsys_name[atc->model];
-+ snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
-+ atc->chip_name, atc->model_name,
-+ atc->pci->subsystem_vendor,
-+ atc->pci->subsystem_device);
-+ return 0;
-+}
-+
-+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc)
-+{
-+ enum CTALSADEVS i;
-+ int err;
-+
-+ alsa_dev_funcs[MIXER].public_name = atc->chip_name;
-+
-+ for (i = 0; i < NUM_CTALSADEVS; i++) {
-+ if (!alsa_dev_funcs[i].create)
-+ continue;
-+
-+ err = alsa_dev_funcs[i].create(atc, i,
-+ alsa_dev_funcs[i].public_name);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: "
-+ "Creating alsa device %d failed!\n", i);
-+ return err;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int __devinit atc_create_hw_devs(struct ct_atc *atc)
-+{
-+ struct hw *hw;
-+ struct card_conf info = {0};
-+ int i, err;
-+
-+ err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
-+ if (err) {
-+ printk(KERN_ERR "Failed to create hw obj!!!\n");
-+ return err;
-+ }
-+ atc->hw = hw;
-+
-+ /* Initialize card hardware. */
-+ info.rsr = atc->rsr;
-+ info.msr = atc->msr;
-+ info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
-+ err = hw->card_init(hw, &info);
-+ if (err < 0)
-+ return err;
-+
-+ for (i = 0; i < NUM_RSCTYP; i++) {
-+ if (!rsc_mgr_funcs[i].create)
-+ continue;
-+
-+ err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: "
-+ "Failed to create rsc_mgr %d!!!\n", i);
-+ return err;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int atc_get_resources(struct ct_atc *atc)
-+{
-+ struct daio_desc da_desc = {0};
-+ struct daio_mgr *daio_mgr;
-+ struct src_desc src_dsc = {0};
-+ struct src_mgr *src_mgr;
-+ struct srcimp_desc srcimp_dsc = {0};
-+ struct srcimp_mgr *srcimp_mgr;
-+ struct sum_desc sum_dsc = {0};
-+ struct sum_mgr *sum_mgr;
-+ int err, i;
-+
-+ atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
-+ if (!atc->daios)
-+ return -ENOMEM;
-+
-+ atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
-+ if (!atc->srcs)
-+ return -ENOMEM;
-+
-+ atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
-+ if (!atc->srcimps)
-+ return -ENOMEM;
-+
-+ atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL);
-+ if (!atc->pcm)
-+ return -ENOMEM;
-+
-+ daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
-+ da_desc.msr = atc->msr;
-+ for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
-+ da_desc.type = i;
-+ err = daio_mgr->get_daio(daio_mgr, &da_desc,
-+ (struct daio **)&atc->daios[i]);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Failed to get DAIO "
-+ "resource %d!!!\n", i);
-+ return err;
-+ }
-+ atc->n_daio++;
-+ }
-+ if (atc->model == CTSB073X)
-+ da_desc.type = SPDIFI1;
-+ else
-+ da_desc.type = SPDIFIO;
-+ err = daio_mgr->get_daio(daio_mgr, &da_desc,
-+ (struct daio **)&atc->daios[i]);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
-+ return err;
-+ }
-+ atc->n_daio++;
-+
-+ src_mgr = atc->rsc_mgrs[SRC];
-+ src_dsc.multi = 1;
-+ src_dsc.msr = atc->msr;
-+ src_dsc.mode = ARCRW;
-+ for (i = 0, atc->n_src = 0; i < (2*2); i++) {
-+ err = src_mgr->get_src(src_mgr, &src_dsc,
-+ (struct src **)&atc->srcs[i]);
-+ if (err)
-+ return err;
-+
-+ atc->n_src++;
-+ }
-+
-+ srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-+ srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
-+ for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
-+ err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-+ (struct srcimp **)&atc->srcimps[i]);
-+ if (err)
-+ return err;
-+
-+ atc->n_srcimp++;
-+ }
-+ srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
-+ for (i = 0; i < (2*1); i++) {
-+ err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-+ (struct srcimp **)&atc->srcimps[2*1+i]);
-+ if (err)
-+ return err;
-+
-+ atc->n_srcimp++;
-+ }
-+
-+ sum_mgr = atc->rsc_mgrs[SUM];
-+ sum_dsc.msr = atc->msr;
-+ for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
-+ err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
-+ (struct sum **)&atc->pcm[i]);
-+ if (err)
-+ return err;
-+
-+ atc->n_pcm++;
-+ }
-+
-+ return 0;
-+}
-+
-+static void
-+atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
-+ struct src **srcs, struct srcimp **srcimps)
-+{
-+ struct rsc *rscs[2] = {NULL};
-+ struct src *src;
-+ struct srcimp *srcimp;
-+ int i = 0;
-+
-+ rscs[0] = &dai->daio.rscl;
-+ rscs[1] = &dai->daio.rscr;
-+ for (i = 0; i < 2; i++) {
-+ src = srcs[i];
-+ srcimp = srcimps[i];
-+ srcimp->ops->map(srcimp, src, rscs[i]);
-+ src_mgr->src_disable(src_mgr, src);
-+ }
-+
-+ src_mgr->commit_write(src_mgr); /* Actually disable SRCs */
-+
-+ src = srcs[0];
-+ src->ops->set_pm(src, 1);
-+ for (i = 0; i < 2; i++) {
-+ src = srcs[i];
-+ src->ops->set_state(src, SRC_STATE_RUN);
-+ src->ops->commit_write(src);
-+ src_mgr->src_enable_s(src_mgr, src);
-+ }
-+
-+ dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc));
-+ dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc));
-+
-+ dai->ops->set_enb_src(dai, 1);
-+ dai->ops->set_enb_srt(dai, 1);
-+ dai->ops->commit_write(dai);
-+
-+ src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
-+}
-+
-+static void atc_connect_resources(struct ct_atc *atc)
-+{
-+ struct dai *dai;
-+ struct dao *dao;
-+ struct src *src;
-+ struct sum *sum;
-+ struct ct_mixer *mixer;
-+ struct rsc *rscs[2] = {NULL};
-+ int i, j;
-+
-+ mixer = atc->mixer;
-+
-+ for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
-+ mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
-+ dao = container_of(atc->daios[j], struct dao, daio);
-+ dao->ops->set_left_input(dao, rscs[0]);
-+ dao->ops->set_right_input(dao, rscs[1]);
-+ }
-+
-+ dai = container_of(atc->daios[LINEIM], struct dai, daio);
-+ atc_connect_dai(atc->rsc_mgrs[SRC], dai,
-+ (struct src **)&atc->srcs[2],
-+ (struct srcimp **)&atc->srcimps[2]);
-+ src = atc->srcs[2];
-+ mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
-+ src = atc->srcs[3];
-+ mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
-+
-+ dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
-+ atc_connect_dai(atc->rsc_mgrs[SRC], dai,
-+ (struct src **)&atc->srcs[0],
-+ (struct srcimp **)&atc->srcimps[0]);
-+
-+ src = atc->srcs[0];
-+ mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc);
-+ src = atc->srcs[1];
-+ mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc);
-+
-+ for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) {
-+ sum = atc->pcm[j];
-+ mixer->set_input_left(mixer, i, &sum->rsc);
-+ sum = atc->pcm[j+1];
-+ mixer->set_input_right(mixer, i, &sum->rsc);
-+ }
-+}
-+
-+#ifdef CONFIG_PM
-+static int atc_suspend(struct ct_atc *atc, pm_message_t state)
-+{
-+ int i;
-+ struct hw *hw = atc->hw;
-+
-+ snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot);
-+
-+ for (i = FRONT; i < NUM_PCMS; i++) {
-+ if (!atc->pcms[i])
-+ continue;
-+
-+ snd_pcm_suspend_all(atc->pcms[i]);
-+ }
-+
-+ atc_release_resources(atc);
-+
-+ hw->suspend(hw, state);
-+
-+ return 0;
-+}
-+
-+static int atc_hw_resume(struct ct_atc *atc)
-+{
-+ struct hw *hw = atc->hw;
-+ struct card_conf info = {0};
-+
-+ /* Re-initialize card hardware. */
-+ info.rsr = atc->rsr;
-+ info.msr = atc->msr;
-+ info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
-+ return hw->resume(hw, &info);
-+}
-+
-+static int atc_resources_resume(struct ct_atc *atc)
-+{
-+ struct ct_mixer *mixer;
-+ int err = 0;
-+
-+ /* Get resources */
-+ err = atc_get_resources(atc);
-+ if (err < 0) {
-+ atc_release_resources(atc);
-+ return err;
-+ }
-+
-+ /* Build topology */
-+ atc_connect_resources(atc);
-+
-+ mixer = atc->mixer;
-+ mixer->resume(mixer);
-+
-+ return 0;
-+}
-+
-+static int atc_resume(struct ct_atc *atc)
-+{
-+ int err = 0;
-+
-+ /* Do hardware resume. */
-+ err = atc_hw_resume(atc);
-+ if (err < 0) {
-+ printk(KERN_ERR "ctxfi: pci_enable_device failed, "
-+ "disabling device\n");
-+ snd_card_disconnect(atc->card);
-+ return err;
-+ }
-+
-+ err = atc_resources_resume(atc);
-+ if (err < 0)
-+ return err;
-+
-+ snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0);
-+
-+ return 0;
-+}
-+#endif
-+
-+static struct ct_atc atc_preset __devinitdata = {
-+ .map_audio_buffer = ct_map_audio_buffer,
-+ .unmap_audio_buffer = ct_unmap_audio_buffer,
-+ .pcm_playback_prepare = atc_pcm_playback_prepare,
-+ .pcm_release_resources = atc_pcm_release_resources,
-+ .pcm_playback_start = atc_pcm_playback_start,
-+ .pcm_playback_stop = atc_pcm_stop,
-+ .pcm_playback_position = atc_pcm_playback_position,
-+ .pcm_capture_prepare = atc_pcm_capture_prepare,
-+ .pcm_capture_start = atc_pcm_capture_start,
-+ .pcm_capture_stop = atc_pcm_stop,
-+ .pcm_capture_position = atc_pcm_capture_position,
-+ .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare,
-+ .get_ptp_phys = atc_get_ptp_phys,
-+ .select_line_in = atc_select_line_in,
-+ .select_mic_in = atc_select_mic_in,
-+ .select_digit_io = atc_select_digit_io,
-+ .line_front_unmute = atc_line_front_unmute,
-+ .line_surround_unmute = atc_line_surround_unmute,
-+ .line_clfe_unmute = atc_line_clfe_unmute,
-+ .line_rear_unmute = atc_line_rear_unmute,
-+ .line_in_unmute = atc_line_in_unmute,
-+ .spdif_out_unmute = atc_spdif_out_unmute,
-+ .spdif_in_unmute = atc_spdif_in_unmute,
-+ .spdif_out_get_status = atc_spdif_out_get_status,
-+ .spdif_out_set_status = atc_spdif_out_set_status,
-+ .spdif_out_passthru = atc_spdif_out_passthru,
-+ .have_digit_io_switch = atc_have_digit_io_switch,
-+#ifdef CONFIG_PM
-+ .suspend = atc_suspend,
-+ .resume = atc_resume,
-+#endif
-+};
-+
-+/**
-+ * ct_atc_create - create and initialize a hardware manager
-+ * @card: corresponding alsa card object
-+ * @pci: corresponding kernel pci device object
-+ * @ratc: return created object address in it
-+ *
-+ * Creates and initializes a hardware manager.
-+ *
-+ * Creates kmallocated ct_atc structure. Initializes hardware.
-+ * Returns 0 if suceeds, or negative error code if fails.
-+ */
-+
-+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
-+ unsigned int rsr, unsigned int msr,
-+ int chip_type, struct ct_atc **ratc)
-+{
-+ struct ct_atc *atc;
-+ static struct snd_device_ops ops = {
-+ .dev_free = atc_dev_free,
-+ };
-+ int err;
-+
-+ *ratc = NULL;
-+
-+ atc = kzalloc(sizeof(*atc), GFP_KERNEL);
-+ if (!atc)
-+ return -ENOMEM;
-+
-+ /* Set operations */
-+ *atc = atc_preset;
-+
-+ atc->card = card;
-+ atc->pci = pci;
-+ atc->rsr = rsr;
-+ atc->msr = msr;
-+ atc->chip_type = chip_type;
-+
-+ mutex_init(&atc->atc_mutex);
-+
-+ /* Find card model */
-+ err = atc_identify_card(atc);
-+ if (err < 0) {
-+ printk(KERN_ERR "ctatc: Card not recognised\n");
-+ goto error1;
-+ }
-+
-+ /* Set up device virtual memory management object */
-+ err = ct_vm_create(&atc->vm);
-+ if (err < 0)
-+ goto error1;
-+
-+ /* Create all atc hw devices */
-+ err = atc_create_hw_devs(atc);
-+ if (err < 0)
-+ goto error1;
-+
-+ err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
-+ goto error1;
-+ }
-+
-+ /* Get resources */
-+ err = atc_get_resources(atc);
-+ if (err < 0)
-+ goto error1;
-+
-+ /* Build topology */
-+ atc_connect_resources(atc);
-+
-+ atc->timer = ct_timer_new(atc);
-+ if (!atc->timer)
-+ goto error1;
-+
-+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
-+ if (err < 0)
-+ goto error1;
-+
-+ snd_card_set_dev(card, &pci->dev);
-+
-+ *ratc = atc;
-+ return 0;
-+
-+error1:
-+ ct_atc_destroy(atc);
-+ printk(KERN_ERR "ctxfi: Something wrong!!!\n");
-+ return err;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/ctatc.h
-@@ -0,0 +1,154 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctatc.h
-+ *
-+ * @Brief
-+ * This file contains the definition of the device resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date Mar 28 2008
-+ *
-+ */
-+
-+#ifndef CTATC_H
-+#define CTATC_H
-+
-+#include <linux/types.h>
-+#include <linux/mutex.h>
-+#include <linux/pci.h>
-+#include <linux/timer.h>
-+#include <sound/core.h>
-+
-+#include "ctvmem.h"
-+#include "ctresource.h"
-+
-+enum CTALSADEVS { /* Types of alsa devices */
-+ FRONT,
-+ SURROUND,
-+ CLFE,
-+ SIDE,
-+ IEC958,
-+ MIXER,
-+ NUM_CTALSADEVS /* This should always be the last */
-+};
-+
-+struct ct_atc_chip_sub_details {
-+ u16 subsys;
-+ const char *nm_model;
-+};
-+
-+struct ct_atc_chip_details {
-+ u16 vendor;
-+ u16 device;
-+ const struct ct_atc_chip_sub_details *sub_details;
-+ const char *nm_card;
-+};
-+
-+struct ct_atc;
-+struct ct_timer;
-+struct ct_timer_instance;
-+
-+/* alsa pcm stream descriptor */
-+struct ct_atc_pcm {
-+ struct snd_pcm_substream *substream;
-+ void (*interrupt)(struct ct_atc_pcm *apcm);
-+ struct ct_timer_instance *timer;
-+ unsigned int started:1;
-+
-+ /* Only mono and interleaved modes are supported now. */
-+ struct ct_vm_block *vm_block;
-+ void *src; /* SRC for interacting with host memory */
-+ void **srccs; /* SRCs for sample rate conversion */
-+ void **srcimps; /* SRC Input Mappers */
-+ void **amixers; /* AMIXERs for routing converted data */
-+ void *mono; /* A SUM resource for mixing chs to one */
-+ unsigned char n_srcc; /* Number of converting SRCs */
-+ unsigned char n_srcimp; /* Number of SRC Input Mappers */
-+ unsigned char n_amixer; /* Number of AMIXERs */
-+};
-+
-+/* Chip resource management object */
-+struct ct_atc {
-+ struct pci_dev *pci;
-+ struct snd_card *card;
-+ unsigned int rsr; /* reference sample rate in Hz */
-+ unsigned int msr; /* master sample rate in rsr */
-+ unsigned int pll_rate; /* current rate of Phase Lock Loop */
-+
-+ int chip_type;
-+ int model;
-+ const char *chip_name;
-+ const char *model_name;
-+
-+ struct ct_vm *vm; /* device virtual memory manager for this card */
-+ int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
-+
-+ struct mutex atc_mutex;
-+
-+ int (*pcm_playback_prepare)(struct ct_atc *atc,
-+ struct ct_atc_pcm *apcm);
-+ int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ int (*pcm_playback_position)(struct ct_atc *atc,
-+ struct ct_atc_pcm *apcm);
-+ int (*spdif_passthru_playback_prepare)(struct ct_atc *atc,
-+ struct ct_atc_pcm *apcm);
-+ int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
-+ int (*pcm_capture_position)(struct ct_atc *atc,
-+ struct ct_atc_pcm *apcm);
-+ int (*pcm_release_resources)(struct ct_atc *atc,
-+ struct ct_atc_pcm *apcm);
-+ int (*select_line_in)(struct ct_atc *atc);
-+ int (*select_mic_in)(struct ct_atc *atc);
-+ int (*select_digit_io)(struct ct_atc *atc);
-+ int (*line_front_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
-+ int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
-+ int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
-+ int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
-+ int (*have_digit_io_switch)(struct ct_atc *atc);
-+
-+ /* Don't touch! Used for internal object. */
-+ void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
-+ void *mixer; /* internal mixer object */
-+ void *hw; /* chip specific hardware access object */
-+ void **daios; /* digital audio io resources */
-+ void **pcm; /* SUMs for collecting all pcm stream */
-+ void **srcs; /* Sample Rate Converters for input signal */
-+ void **srcimps; /* input mappers for SRCs */
-+ unsigned char n_daio;
-+ unsigned char n_src;
-+ unsigned char n_srcimp;
-+ unsigned char n_pcm;
-+
-+ struct ct_timer *timer;
-+
-+#ifdef CONFIG_PM
-+ int (*suspend)(struct ct_atc *atc, pm_message_t state);
-+ int (*resume)(struct ct_atc *atc);
-+#define NUM_PCMS (NUM_CTALSADEVS - 1)
-+ struct snd_pcm *pcms[NUM_PCMS];
-+#endif
-+};
-+
-+
-+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
-+ unsigned int rsr, unsigned int msr, int chip_type,
-+ struct ct_atc **ratc);
-+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
-+
-+#endif /* CTATC_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctdaio.c
-@@ -0,0 +1,769 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctdaio.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of Digital Audio Input Output
-+ * resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 23 2008
-+ *
-+ */
-+
-+#include "ctdaio.h"
-+#include "cthardware.h"
-+#include "ctimap.h"
-+#include <linux/slab.h>
-+#include <linux/kernel.h>
-+
-+#define DAIO_RESOURCE_NUM NUM_DAIOTYP
-+#define DAIO_OUT_MAX SPDIFOO
-+
-+union daio_usage {
-+ struct {
-+ unsigned short lineo1:1;
-+ unsigned short lineo2:1;
-+ unsigned short lineo3:1;
-+ unsigned short lineo4:1;
-+ unsigned short spdifoo:1;
-+ unsigned short lineim:1;
-+ unsigned short spdifio:1;
-+ unsigned short spdifi1:1;
-+ } bf;
-+ unsigned short data;
-+};
-+
-+struct daio_rsc_idx {
-+ unsigned short left;
-+ unsigned short right;
-+};
-+
-+struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
-+ [LINEO1] = {.left = 0x00, .right = 0x01},
-+ [LINEO2] = {.left = 0x18, .right = 0x19},
-+ [LINEO3] = {.left = 0x08, .right = 0x09},
-+ [LINEO4] = {.left = 0x10, .right = 0x11},
-+ [LINEIM] = {.left = 0x1b5, .right = 0x1bd},
-+ [SPDIFOO] = {.left = 0x20, .right = 0x21},
-+ [SPDIFIO] = {.left = 0x15, .right = 0x1d},
-+ [SPDIFI1] = {.left = 0x95, .right = 0x9d},
-+};
-+
-+struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
-+ [LINEO1] = {.left = 0x40, .right = 0x41},
-+ [LINEO2] = {.left = 0x60, .right = 0x61},
-+ [LINEO3] = {.left = 0x50, .right = 0x51},
-+ [LINEO4] = {.left = 0x70, .right = 0x71},
-+ [LINEIM] = {.left = 0x45, .right = 0xc5},
-+ [SPDIFOO] = {.left = 0x00, .right = 0x01},
-+ [SPDIFIO] = {.left = 0x05, .right = 0x85},
-+};
-+
-+static int daio_master(struct rsc *rsc)
-+{
-+ /* Actually, this is not the resource index of DAIO.
-+ * For DAO, it is the input mapper index. And, for DAI,
-+ * it is the output time-slot index. */
-+ return rsc->conj = rsc->idx;
-+}
-+
-+static int daio_index(const struct rsc *rsc)
-+{
-+ return rsc->conj;
-+}
-+
-+static int daio_out_next_conj(struct rsc *rsc)
-+{
-+ return rsc->conj += 2;
-+}
-+
-+static int daio_in_next_conj_20k1(struct rsc *rsc)
-+{
-+ return rsc->conj += 0x200;
-+}
-+
-+static int daio_in_next_conj_20k2(struct rsc *rsc)
-+{
-+ return rsc->conj += 0x100;
-+}
-+
-+static struct rsc_ops daio_out_rsc_ops = {
-+ .master = daio_master,
-+ .next_conj = daio_out_next_conj,
-+ .index = daio_index,
-+ .output_slot = NULL,
-+};
-+
-+static struct rsc_ops daio_in_rsc_ops_20k1 = {
-+ .master = daio_master,
-+ .next_conj = daio_in_next_conj_20k1,
-+ .index = NULL,
-+ .output_slot = daio_index,
-+};
-+
-+static struct rsc_ops daio_in_rsc_ops_20k2 = {
-+ .master = daio_master,
-+ .next_conj = daio_in_next_conj_20k2,
-+ .index = NULL,
-+ .output_slot = daio_index,
-+};
-+
-+static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
-+{
-+ switch (hw->chip_type) {
-+ case ATC20K1:
-+ switch (type) {
-+ case SPDIFOO: return 0;
-+ case SPDIFIO: return 0;
-+ case SPDIFI1: return 1;
-+ case LINEO1: return 4;
-+ case LINEO2: return 7;
-+ case LINEO3: return 5;
-+ case LINEO4: return 6;
-+ case LINEIM: return 7;
-+ default: return -EINVAL;
-+ }
-+ case ATC20K2:
-+ switch (type) {
-+ case SPDIFOO: return 0;
-+ case SPDIFIO: return 0;
-+ case LINEO1: return 4;
-+ case LINEO2: return 7;
-+ case LINEO3: return 5;
-+ case LINEO4: return 6;
-+ case LINEIM: return 4;
-+ default: return -EINVAL;
-+ }
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc);
-+
-+static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)
-+{
-+ ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos);
-+ return 0;
-+}
-+
-+static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
-+{
-+ ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos);
-+ return 0;
-+}
-+
-+static int dao_commit_write(struct dao *dao)
-+{
-+ ((struct hw *)dao->hw)->dao_commit_write(dao->hw,
-+ daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
-+ return 0;
-+}
-+
-+static int dao_set_left_input(struct dao *dao, struct rsc *input)
-+{
-+ struct imapper *entry;
-+ struct daio *daio = &dao->daio;
-+ int i;
-+
-+ entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
-+ if (!entry)
-+ return -ENOMEM;
-+
-+ /* Program master and conjugate resources */
-+ input->ops->master(input);
-+ daio->rscl.ops->master(&daio->rscl);
-+ for (i = 0; i < daio->rscl.msr; i++, entry++) {
-+ entry->slot = input->ops->output_slot(input);
-+ entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl);
-+ dao->mgr->imap_add(dao->mgr, entry);
-+ dao->imappers[i] = entry;
-+
-+ input->ops->next_conj(input);
-+ daio->rscl.ops->next_conj(&daio->rscl);
-+ }
-+ input->ops->master(input);
-+ daio->rscl.ops->master(&daio->rscl);
-+
-+ return 0;
-+}
-+
-+static int dao_set_right_input(struct dao *dao, struct rsc *input)
-+{
-+ struct imapper *entry;
-+ struct daio *daio = &dao->daio;
-+ int i;
-+
-+ entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
-+ if (!entry)
-+ return -ENOMEM;
-+
-+ /* Program master and conjugate resources */
-+ input->ops->master(input);
-+ daio->rscr.ops->master(&daio->rscr);
-+ for (i = 0; i < daio->rscr.msr; i++, entry++) {
-+ entry->slot = input->ops->output_slot(input);
-+ entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr);
-+ dao->mgr->imap_add(dao->mgr, entry);
-+ dao->imappers[daio->rscl.msr + i] = entry;
-+
-+ input->ops->next_conj(input);
-+ daio->rscr.ops->next_conj(&daio->rscr);
-+ }
-+ input->ops->master(input);
-+ daio->rscr.ops->master(&daio->rscr);
-+
-+ return 0;
-+}
-+
-+static int dao_clear_left_input(struct dao *dao)
-+{
-+ struct imapper *entry;
-+ struct daio *daio = &dao->daio;
-+ int i;
-+
-+ if (!dao->imappers[0])
-+ return 0;
-+
-+ entry = dao->imappers[0];
-+ dao->mgr->imap_delete(dao->mgr, entry);
-+ /* Program conjugate resources */
-+ for (i = 1; i < daio->rscl.msr; i++) {
-+ entry = dao->imappers[i];
-+ dao->mgr->imap_delete(dao->mgr, entry);
-+ dao->imappers[i] = NULL;
-+ }
-+
-+ kfree(dao->imappers[0]);
-+ dao->imappers[0] = NULL;
-+
-+ return 0;
-+}
-+
-+static int dao_clear_right_input(struct dao *dao)
-+{
-+ struct imapper *entry;
-+ struct daio *daio = &dao->daio;
-+ int i;
-+
-+ if (!dao->imappers[daio->rscl.msr])
-+ return 0;
-+
-+ entry = dao->imappers[daio->rscl.msr];
-+ dao->mgr->imap_delete(dao->mgr, entry);
-+ /* Program conjugate resources */
-+ for (i = 1; i < daio->rscr.msr; i++) {
-+ entry = dao->imappers[daio->rscl.msr + i];
-+ dao->mgr->imap_delete(dao->mgr, entry);
-+ dao->imappers[daio->rscl.msr + i] = NULL;
-+ }
-+
-+ kfree(dao->imappers[daio->rscl.msr]);
-+ dao->imappers[daio->rscl.msr] = NULL;
-+
-+ return 0;
-+}
-+
-+static struct dao_rsc_ops dao_ops = {
-+ .set_spos = dao_spdif_set_spos,
-+ .commit_write = dao_commit_write,
-+ .get_spos = dao_spdif_get_spos,
-+ .reinit = dao_rsc_reinit,
-+ .set_left_input = dao_set_left_input,
-+ .set_right_input = dao_set_right_input,
-+ .clear_left_input = dao_clear_left_input,
-+ .clear_right_input = dao_clear_right_input,
-+};
-+
-+static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)
-+{
-+ src->ops->master(src);
-+ ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk,
-+ src->ops->index(src));
-+ return 0;
-+}
-+
-+static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)
-+{
-+ src->ops->master(src);
-+ ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk,
-+ src->ops->index(src));
-+ return 0;
-+}
-+
-+static int dai_set_srt_msr(struct dai *dai, unsigned int msr)
-+{
-+ unsigned int rsr;
-+
-+ for (rsr = 0; msr > 1; msr >>= 1)
-+ rsr++;
-+
-+ ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr);
-+ return 0;
-+}
-+
-+static int dai_set_enb_src(struct dai *dai, unsigned int enb)
-+{
-+ ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb);
-+ return 0;
-+}
-+
-+static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
-+{
-+ ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb);
-+ return 0;
-+}
-+
-+static int dai_commit_write(struct dai *dai)
-+{
-+ ((struct hw *)dai->hw)->dai_commit_write(dai->hw,
-+ daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
-+ return 0;
-+}
-+
-+static struct dai_rsc_ops dai_ops = {
-+ .set_srt_srcl = dai_set_srt_srcl,
-+ .set_srt_srcr = dai_set_srt_srcr,
-+ .set_srt_msr = dai_set_srt_msr,
-+ .set_enb_src = dai_set_enb_src,
-+ .set_enb_srt = dai_set_enb_srt,
-+ .commit_write = dai_commit_write,
-+};
-+
-+static int daio_rsc_init(struct daio *daio,
-+ const struct daio_desc *desc,
-+ void *hw)
-+{
-+ int err;
-+ unsigned int idx_l, idx_r;
-+
-+ switch (((struct hw *)hw)->chip_type) {
-+ case ATC20K1:
-+ idx_l = idx_20k1[desc->type].left;
-+ idx_r = idx_20k1[desc->type].right;
-+ break;
-+ case ATC20K2:
-+ idx_l = idx_20k2[desc->type].left;
-+ idx_r = idx_20k2[desc->type].right;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw);
-+ if (err)
-+ return err;
-+
-+ err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw);
-+ if (err)
-+ goto error1;
-+
-+ /* Set daio->rscl/r->ops to daio specific ones */
-+ if (desc->type <= DAIO_OUT_MAX) {
-+ daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
-+ } else {
-+ switch (((struct hw *)hw)->chip_type) {
-+ case ATC20K1:
-+ daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
-+ break;
-+ case ATC20K2:
-+ daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2;
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+ daio->type = desc->type;
-+
-+ return 0;
-+
-+error1:
-+ rsc_uninit(&daio->rscl);
-+ return err;
-+}
-+
-+static int daio_rsc_uninit(struct daio *daio)
-+{
-+ rsc_uninit(&daio->rscl);
-+ rsc_uninit(&daio->rscr);
-+
-+ return 0;
-+}
-+
-+static int dao_rsc_init(struct dao *dao,
-+ const struct daio_desc *desc,
-+ struct daio_mgr *mgr)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+ unsigned int conf;
-+ int err;
-+
-+ err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw);
-+ if (err)
-+ return err;
-+
-+ dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL);
-+ if (!dao->imappers) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+ dao->ops = &dao_ops;
-+ dao->mgr = mgr;
-+ dao->hw = hw;
-+ err = hw->dao_get_ctrl_blk(&dao->ctrl_blk);
-+ if (err)
-+ goto error2;
-+
-+ hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
-+ daio_device_index(dao->daio.type, hw));
-+ hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
-+
-+ conf = (desc->msr & 0x7) | (desc->passthru << 3);
-+ hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
-+ daio_device_index(dao->daio.type, hw), conf);
-+ hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
-+ daio_device_index(dao->daio.type, hw));
-+ hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
-+
-+ return 0;
-+
-+error2:
-+ kfree(dao->imappers);
-+ dao->imappers = NULL;
-+error1:
-+ daio_rsc_uninit(&dao->daio);
-+ return err;
-+}
-+
-+static int dao_rsc_uninit(struct dao *dao)
-+{
-+ if (dao->imappers) {
-+ if (dao->imappers[0])
-+ dao_clear_left_input(dao);
-+
-+ if (dao->imappers[dao->daio.rscl.msr])
-+ dao_clear_right_input(dao);
-+
-+ kfree(dao->imappers);
-+ dao->imappers = NULL;
-+ }
-+ ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk);
-+ dao->hw = dao->ctrl_blk = NULL;
-+ daio_rsc_uninit(&dao->daio);
-+
-+ return 0;
-+}
-+
-+static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
-+{
-+ struct daio_mgr *mgr = dao->mgr;
-+ struct daio_desc dsc = {0};
-+
-+ dsc.type = dao->daio.type;
-+ dsc.msr = desc->msr;
-+ dsc.passthru = desc->passthru;
-+ dao_rsc_uninit(dao);
-+ return dao_rsc_init(dao, &dsc, mgr);
-+}
-+
-+static int dai_rsc_init(struct dai *dai,
-+ const struct daio_desc *desc,
-+ struct daio_mgr *mgr)
-+{
-+ int err;
-+ struct hw *hw = mgr->mgr.hw;
-+ unsigned int rsr, msr;
-+
-+ err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw);
-+ if (err)
-+ return err;
-+
-+ dai->ops = &dai_ops;
-+ dai->hw = mgr->mgr.hw;
-+ err = hw->dai_get_ctrl_blk(&dai->ctrl_blk);
-+ if (err)
-+ goto error1;
-+
-+ for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1)
-+ rsr++;
-+
-+ hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);
-+ hw->dai_srt_set_drat(dai->ctrl_blk, 0);
-+ /* default to disabling control of a SRC */
-+ hw->dai_srt_set_ec(dai->ctrl_blk, 0);
-+ hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */
-+ hw->dai_commit_write(hw,
-+ daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
-+
-+ return 0;
-+
-+error1:
-+ daio_rsc_uninit(&dai->daio);
-+ return err;
-+}
-+
-+static int dai_rsc_uninit(struct dai *dai)
-+{
-+ ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk);
-+ dai->hw = dai->ctrl_blk = NULL;
-+ daio_rsc_uninit(&dai->daio);
-+ return 0;
-+}
-+
-+static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
-+{
-+ if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
-+ return -ENOENT;
-+
-+ ((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
-+{
-+ ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
-+
-+ return 0;
-+}
-+
-+static int get_daio_rsc(struct daio_mgr *mgr,
-+ const struct daio_desc *desc,
-+ struct daio **rdaio)
-+{
-+ int err;
-+ struct dai *dai = NULL;
-+ struct dao *dao = NULL;
-+ unsigned long flags;
-+
-+ *rdaio = NULL;
-+
-+ /* Check whether there are sufficient daio resources to meet request. */
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ if (err) {
-+ printk(KERN_ERR "Can't meet DAIO resource request!\n");
-+ return err;
-+ }
-+
-+ /* Allocate mem for daio resource */
-+ if (desc->type <= DAIO_OUT_MAX) {
-+ dao = kzalloc(sizeof(*dao), GFP_KERNEL);
-+ if (!dao) {
-+ err = -ENOMEM;
-+ goto error;
-+ }
-+ err = dao_rsc_init(dao, desc, mgr);
-+ if (err)
-+ goto error;
-+
-+ *rdaio = &dao->daio;
-+ } else {
-+ dai = kzalloc(sizeof(*dai), GFP_KERNEL);
-+ if (!dai) {
-+ err = -ENOMEM;
-+ goto error;
-+ }
-+ err = dai_rsc_init(dai, desc, mgr);
-+ if (err)
-+ goto error;
-+
-+ *rdaio = &dai->daio;
-+ }
-+
-+ mgr->daio_enable(mgr, *rdaio);
-+ mgr->commit_write(mgr);
-+
-+ return 0;
-+
-+error:
-+ if (dao)
-+ kfree(dao);
-+ else if (dai)
-+ kfree(dai);
-+
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ daio_mgr_put_rsc(&mgr->mgr, desc->type);
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ return err;
-+}
-+
-+static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
-+{
-+ unsigned long flags;
-+
-+ mgr->daio_disable(mgr, daio);
-+ mgr->commit_write(mgr);
-+
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ daio_mgr_put_rsc(&mgr->mgr, daio->type);
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+
-+ if (daio->type <= DAIO_OUT_MAX) {
-+ dao_rsc_uninit(container_of(daio, struct dao, daio));
-+ kfree(container_of(daio, struct dao, daio));
-+ } else {
-+ dai_rsc_uninit(container_of(daio, struct dai, daio));
-+ kfree(container_of(daio, struct dai, daio));
-+ }
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+
-+ if (DAIO_OUT_MAX >= daio->type) {
-+ hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
-+ daio_device_index(daio->type, hw));
-+ } else {
-+ hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk,
-+ daio_device_index(daio->type, hw));
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+
-+ if (DAIO_OUT_MAX >= daio->type) {
-+ hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
-+ daio_device_index(daio->type, hw));
-+ } else {
-+ hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk,
-+ daio_device_index(daio->type, hw));
-+ }
-+ return 0;
-+}
-+
-+static int daio_map_op(void *data, struct imapper *entry)
-+{
-+ struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr;
-+ struct hw *hw = mgr->hw;
-+
-+ hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
-+ hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
-+ hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
-+ hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
-+
-+ return 0;
-+}
-+
-+static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)
-+{
-+ unsigned long flags;
-+ int err;
-+
-+ spin_lock_irqsave(&mgr->imap_lock, flags);
-+ if (!entry->addr && mgr->init_imap_added) {
-+ input_mapper_delete(&mgr->imappers, mgr->init_imap,
-+ daio_map_op, mgr);
-+ mgr->init_imap_added = 0;
-+ }
-+ err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);
-+ spin_unlock_irqrestore(&mgr->imap_lock, flags);
-+
-+ return err;
-+}
-+
-+static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry)
-+{
-+ unsigned long flags;
-+ int err;
-+
-+ spin_lock_irqsave(&mgr->imap_lock, flags);
-+ err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr);
-+ if (list_empty(&mgr->imappers)) {
-+ input_mapper_add(&mgr->imappers, mgr->init_imap,
-+ daio_map_op, mgr);
-+ mgr->init_imap_added = 1;
-+ }
-+ spin_unlock_irqrestore(&mgr->imap_lock, flags);
-+
-+ return err;
-+}
-+
-+static int daio_mgr_commit_write(struct daio_mgr *mgr)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+
-+ hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
-+ return 0;
-+}
-+
-+int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
-+{
-+ int err, i;
-+ struct daio_mgr *daio_mgr;
-+ struct imapper *entry;
-+
-+ *rdaio_mgr = NULL;
-+ daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);
-+ if (!daio_mgr)
-+ return -ENOMEM;
-+
-+ err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
-+ if (err)
-+ goto error1;
-+
-+ spin_lock_init(&daio_mgr->mgr_lock);
-+ spin_lock_init(&daio_mgr->imap_lock);
-+ INIT_LIST_HEAD(&daio_mgr->imappers);
-+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-+ if (!entry) {
-+ err = -ENOMEM;
-+ goto error2;
-+ }
-+ entry->slot = entry->addr = entry->next = entry->user = 0;
-+ list_add(&entry->list, &daio_mgr->imappers);
-+ daio_mgr->init_imap = entry;
-+ daio_mgr->init_imap_added = 1;
-+
-+ daio_mgr->get_daio = get_daio_rsc;
-+ daio_mgr->put_daio = put_daio_rsc;
-+ daio_mgr->daio_enable = daio_mgr_enb_daio;
-+ daio_mgr->daio_disable = daio_mgr_dsb_daio;
-+ daio_mgr->imap_add = daio_imap_add;
-+ daio_mgr->imap_delete = daio_imap_delete;
-+ daio_mgr->commit_write = daio_mgr_commit_write;
-+
-+ for (i = 0; i < 8; i++) {
-+ ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
-+ ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
-+ }
-+ ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
-+
-+ *rdaio_mgr = daio_mgr;
-+
-+ return 0;
-+
-+error2:
-+ rsc_mgr_uninit(&daio_mgr->mgr);
-+error1:
-+ kfree(daio_mgr);
-+ return err;
-+}
-+
-+int daio_mgr_destroy(struct daio_mgr *daio_mgr)
-+{
-+ unsigned long flags;
-+
-+ /* free daio input mapper list */
-+ spin_lock_irqsave(&daio_mgr->imap_lock, flags);
-+ free_input_mapper_list(&daio_mgr->imappers);
-+ spin_unlock_irqrestore(&daio_mgr->imap_lock, flags);
-+
-+ rsc_mgr_uninit(&daio_mgr->mgr);
-+ kfree(daio_mgr);
-+
-+ return 0;
-+}
-+
---- /dev/null
-+++ b/sound/pci/ctxfi/ctdaio.h
-@@ -0,0 +1,122 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctdaio.h
-+ *
-+ * @Brief
-+ * This file contains the definition of Digital Audio Input Output
-+ * resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 23 2008
-+ *
-+ */
-+
-+#ifndef CTDAIO_H
-+#define CTDAIO_H
-+
-+#include "ctresource.h"
-+#include "ctimap.h"
-+#include <linux/spinlock.h>
-+#include <linux/list.h>
-+
-+/* Define the descriptor of a daio resource */
-+enum DAIOTYP {
-+ LINEO1,
-+ LINEO2,
-+ LINEO3,
-+ LINEO4,
-+ SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */
-+ LINEIM,
-+ SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */
-+ SPDIFI1, /* S/PDIF In on internal Drive Bay */
-+ NUM_DAIOTYP
-+};
-+
-+struct dao_rsc_ops;
-+struct dai_rsc_ops;
-+struct daio_mgr;
-+
-+struct daio {
-+ struct rsc rscl; /* Basic resource info for left TX/RX */
-+ struct rsc rscr; /* Basic resource info for right TX/RX */
-+ enum DAIOTYP type;
-+};
-+
-+struct dao {
-+ struct daio daio;
-+ struct dao_rsc_ops *ops; /* DAO specific operations */
-+ struct imapper **imappers;
-+ struct daio_mgr *mgr;
-+ void *hw;
-+ void *ctrl_blk;
-+};
-+
-+struct dai {
-+ struct daio daio;
-+ struct dai_rsc_ops *ops; /* DAI specific operations */
-+ void *hw;
-+ void *ctrl_blk;
-+};
-+
-+struct dao_desc {
-+ unsigned int msr:4;
-+ unsigned int passthru:1;
-+};
-+
-+struct dao_rsc_ops {
-+ int (*set_spos)(struct dao *dao, unsigned int spos);
-+ int (*commit_write)(struct dao *dao);
-+ int (*get_spos)(struct dao *dao, unsigned int *spos);
-+ int (*reinit)(struct dao *dao, const struct dao_desc *desc);
-+ int (*set_left_input)(struct dao *dao, struct rsc *input);
-+ int (*set_right_input)(struct dao *dao, struct rsc *input);
-+ int (*clear_left_input)(struct dao *dao);
-+ int (*clear_right_input)(struct dao *dao);
-+};
-+
-+struct dai_rsc_ops {
-+ int (*set_srt_srcl)(struct dai *dai, struct rsc *src);
-+ int (*set_srt_srcr)(struct dai *dai, struct rsc *src);
-+ int (*set_srt_msr)(struct dai *dai, unsigned int msr);
-+ int (*set_enb_src)(struct dai *dai, unsigned int enb);
-+ int (*set_enb_srt)(struct dai *dai, unsigned int enb);
-+ int (*commit_write)(struct dai *dai);
-+};
-+
-+/* Define daio resource request description info */
-+struct daio_desc {
-+ unsigned int type:4;
-+ unsigned int msr:4;
-+ unsigned int passthru:1;
-+};
-+
-+struct daio_mgr {
-+ struct rsc_mgr mgr; /* Basic resource manager info */
-+ spinlock_t mgr_lock;
-+ spinlock_t imap_lock;
-+ struct list_head imappers;
-+ struct imapper *init_imap;
-+ unsigned int init_imap_added;
-+
-+ /* request one daio resource */
-+ int (*get_daio)(struct daio_mgr *mgr,
-+ const struct daio_desc *desc, struct daio **rdaio);
-+ /* return one daio resource */
-+ int (*put_daio)(struct daio_mgr *mgr, struct daio *daio);
-+ int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio);
-+ int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio);
-+ int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry);
-+ int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry);
-+ int (*commit_write)(struct daio_mgr *mgr);
-+};
-+
-+/* Constructor and destructor of daio resource manager */
-+int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr);
-+int daio_mgr_destroy(struct daio_mgr *daio_mgr);
-+
-+#endif /* CTDAIO_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/cthardware.c
-@@ -0,0 +1,91 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File cthardware.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of hardware access methord.
-+ *
-+ * @Author Liu Chun
-+ * @Date Jun 26 2008
-+ *
-+ */
-+
-+#include "cthardware.h"
-+#include "cthw20k1.h"
-+#include "cthw20k2.h"
-+#include <linux/bug.h>
-+
-+int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
-+ enum CTCARDS model, struct hw **rhw)
-+{
-+ int err;
-+
-+ switch (chip_type) {
-+ case ATC20K1:
-+ err = create_20k1_hw_obj(rhw);
-+ break;
-+ case ATC20K2:
-+ err = create_20k2_hw_obj(rhw);
-+ break;
-+ default:
-+ err = -ENODEV;
-+ break;
-+ }
-+ if (err)
-+ return err;
-+
-+ (*rhw)->pci = pci;
-+ (*rhw)->chip_type = chip_type;
-+ (*rhw)->model = model;
-+
-+ return 0;
-+}
-+
-+int destroy_hw_obj(struct hw *hw)
-+{
-+ int err;
-+
-+ switch (hw->pci->device) {
-+ case 0x0005: /* 20k1 device */
-+ err = destroy_20k1_hw_obj(hw);
-+ break;
-+ case 0x000B: /* 20k2 device */
-+ err = destroy_20k2_hw_obj(hw);
-+ break;
-+ default:
-+ err = -ENODEV;
-+ break;
-+ }
-+
-+ return err;
-+}
-+
-+unsigned int get_field(unsigned int data, unsigned int field)
-+{
-+ int i;
-+
-+ BUG_ON(!field);
-+ /* @field should always be greater than 0 */
-+ for (i = 0; !(field & (1 << i)); )
-+ i++;
-+
-+ return (data & field) >> i;
-+}
-+
-+void set_field(unsigned int *data, unsigned int field, unsigned int value)
-+{
-+ int i;
-+
-+ BUG_ON(!field);
-+ /* @field should always be greater than 0 */
-+ for (i = 0; !(field & (1 << i)); )
-+ i++;
-+
-+ *data = (*data & (~field)) | ((value << i) & field);
-+}
-+
---- /dev/null
-+++ b/sound/pci/ctxfi/cthardware.h
-@@ -0,0 +1,203 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File cthardware.h
-+ *
-+ * @Brief
-+ * This file contains the definition of hardware access methord.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 13 2008
-+ *
-+ */
-+
-+#ifndef CTHARDWARE_H
-+#define CTHARDWARE_H
-+
-+#include <linux/types.h>
-+#include <linux/pci.h>
-+
-+enum CHIPTYP {
-+ ATC20K1,
-+ ATC20K2,
-+ ATCNONE
-+};
-+
-+enum CTCARDS {
-+ /* 20k1 models */
-+ CTSB055X,
-+ CT20K1_MODEL_FIRST = CTSB055X,
-+ CTSB073X,
-+ CTUAA,
-+ CT20K1_UNKNOWN,
-+ /* 20k2 models */
-+ CTSB0760,
-+ CT20K2_MODEL_FIRST = CTSB0760,
-+ CTHENDRIX,
-+ CTSB0880,
-+ CT20K2_UNKNOWN,
-+ NUM_CTCARDS /* This should always be the last */
-+};
-+
-+/* Type of input source for ADC */
-+enum ADCSRC{
-+ ADC_MICIN,
-+ ADC_LINEIN,
-+ ADC_VIDEO,
-+ ADC_AUX,
-+ ADC_NONE /* Switch to digital input */
-+};
-+
-+struct card_conf {
-+ /* device virtual mem page table page physical addr
-+ * (supporting one page table page now) */
-+ unsigned long vm_pgt_phys;
-+ unsigned int rsr; /* reference sample rate in Hzs*/
-+ unsigned int msr; /* master sample rate in rsrs */
-+};
-+
-+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
-+ int (*suspend)(struct hw *hw, pm_message_t state);
-+ int (*resume)(struct hw *hw, struct card_conf *info);
-+#endif
-+ int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
-+ int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
-+ int (*have_digit_io_switch)(struct hw *hw);
-+
-+ /* SRC operations */
-+ int (*src_rsc_get_ctrl_blk)(void **rblk);
-+ int (*src_rsc_put_ctrl_blk)(void *blk);
-+ int (*src_set_state)(void *blk, unsigned int state);
-+ int (*src_set_bm)(void *blk, unsigned int bm);
-+ int (*src_set_rsr)(void *blk, unsigned int rsr);
-+ int (*src_set_sf)(void *blk, unsigned int sf);
-+ int (*src_set_wr)(void *blk, unsigned int wr);
-+ int (*src_set_pm)(void *blk, unsigned int pm);
-+ int (*src_set_rom)(void *blk, unsigned int rom);
-+ int (*src_set_vo)(void *blk, unsigned int vo);
-+ int (*src_set_st)(void *blk, unsigned int st);
-+ int (*src_set_ie)(void *blk, unsigned int ie);
-+ int (*src_set_ilsz)(void *blk, unsigned int ilsz);
-+ int (*src_set_bp)(void *blk, unsigned int bp);
-+ int (*src_set_cisz)(void *blk, unsigned int cisz);
-+ int (*src_set_ca)(void *blk, unsigned int ca);
-+ int (*src_set_sa)(void *blk, unsigned int sa);
-+ int (*src_set_la)(void *blk, unsigned int la);
-+ int (*src_set_pitch)(void *blk, unsigned int pitch);
-+ int (*src_set_clear_zbufs)(void *blk, unsigned int clear);
-+ int (*src_set_dirty)(void *blk, unsigned int flags);
-+ int (*src_set_dirty_all)(void *blk);
-+ int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk);
-+ int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk);
-+ unsigned int (*src_get_dirty)(void *blk);
-+ unsigned int (*src_dirty_conj_mask)(void);
-+ int (*src_mgr_get_ctrl_blk)(void **rblk);
-+ int (*src_mgr_put_ctrl_blk)(void *blk);
-+ /* syncly enable src @idx */
-+ int (*src_mgr_enbs_src)(void *blk, unsigned int idx);
-+ /* enable src @idx */
-+ int (*src_mgr_enb_src)(void *blk, unsigned int idx);
-+ /* disable src @idx */
-+ int (*src_mgr_dsb_src)(void *blk, unsigned int idx);
-+ int (*src_mgr_commit_write)(struct hw *hw, void *blk);
-+
-+ /* SRC Input Mapper operations */
-+ int (*srcimp_mgr_get_ctrl_blk)(void **rblk);
-+ int (*srcimp_mgr_put_ctrl_blk)(void *blk);
-+ int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot);
-+ int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user);
-+ int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next);
-+ int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr);
-+ int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk);
-+
-+ /* AMIXER operations */
-+ int (*amixer_rsc_get_ctrl_blk)(void **rblk);
-+ int (*amixer_rsc_put_ctrl_blk)(void *blk);
-+ int (*amixer_mgr_get_ctrl_blk)(void **rblk);
-+ int (*amixer_mgr_put_ctrl_blk)(void *blk);
-+ int (*amixer_set_mode)(void *blk, unsigned int mode);
-+ int (*amixer_set_iv)(void *blk, unsigned int iv);
-+ int (*amixer_set_x)(void *blk, unsigned int x);
-+ int (*amixer_set_y)(void *blk, unsigned int y);
-+ int (*amixer_set_sadr)(void *blk, unsigned int sadr);
-+ int (*amixer_set_se)(void *blk, unsigned int se);
-+ int (*amixer_set_dirty)(void *blk, unsigned int flags);
-+ int (*amixer_set_dirty_all)(void *blk);
-+ int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk);
-+ int (*amixer_get_y)(void *blk);
-+ unsigned int (*amixer_get_dirty)(void *blk);
-+
-+ /* DAIO operations */
-+ int (*dai_get_ctrl_blk)(void **rblk);
-+ int (*dai_put_ctrl_blk)(void *blk);
-+ int (*dai_srt_set_srco)(void *blk, unsigned int src);
-+ int (*dai_srt_set_srcm)(void *blk, unsigned int src);
-+ int (*dai_srt_set_rsr)(void *blk, unsigned int rsr);
-+ int (*dai_srt_set_drat)(void *blk, unsigned int drat);
-+ int (*dai_srt_set_ec)(void *blk, unsigned int ec);
-+ int (*dai_srt_set_et)(void *blk, unsigned int et);
-+ int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk);
-+ int (*dao_get_ctrl_blk)(void **rblk);
-+ int (*dao_put_ctrl_blk)(void *blk);
-+ int (*dao_set_spos)(void *blk, unsigned int spos);
-+ int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk);
-+ int (*dao_get_spos)(void *blk, unsigned int *spos);
-+
-+ int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk);
-+ int (*daio_mgr_put_ctrl_blk)(void *blk);
-+ int (*daio_mgr_enb_dai)(void *blk, unsigned int idx);
-+ int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
-+ int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
-+ int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
-+ int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
-+ unsigned int conf);
-+ int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
-+ int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
-+ int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
-+ int (*daio_mgr_commit_write)(struct hw *hw, void *blk);
-+
-+ int (*set_timer_irq)(struct hw *hw, int enable);
-+ int (*set_timer_tick)(struct hw *hw, unsigned int tick);
-+ unsigned int (*get_wc)(struct hw *hw);
-+
-+ void (*irq_callback)(void *data, unsigned int bit);
-+ void *irq_callback_data;
-+
-+ struct pci_dev *pci; /* the pci kernel structure of this card */
-+ int irq;
-+ unsigned long io_base;
-+ unsigned long mem_base;
-+
-+ enum CHIPTYP chip_type;
-+ enum CTCARDS model;
-+};
-+
-+int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
-+ enum CTCARDS model, struct hw **rhw);
-+int destroy_hw_obj(struct hw *hw);
-+
-+unsigned int get_field(unsigned int data, unsigned int field);
-+void set_field(unsigned int *data, unsigned int field, unsigned int value);
-+
-+/* IRQ bits */
-+#define PLL_INT (1 << 10) /* PLL input-clock out-of-range */
-+#define FI_INT (1 << 9) /* forced interrupt */
-+#define IT_INT (1 << 8) /* timer interrupt */
-+#define PCI_INT (1 << 7) /* PCI bus error pending */
-+#define URT_INT (1 << 6) /* UART Tx/Rx */
-+#define GPI_INT (1 << 5) /* GPI pin */
-+#define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */
-+#define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */
-+#define TP_INT (1 << 2) /* transport priority queue */
-+#define DSP_INT (1 << 1) /* DSP */
-+#define SRC_INT (1 << 0) /* SRC channels */
-+
-+#endif /* CTHARDWARE_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/cthw20k1.c
-@@ -0,0 +1,2297 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File cthw20k1.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of hardware access methord for 20k1.
-+ *
-+ * @Author Liu Chun
-+ * @Date Jun 24 2008
-+ *
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/io.h>
-+#include <linux/string.h>
-+#include <linux/spinlock.h>
-+#include <linux/kernel.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include "cthw20k1.h"
-+#include "ct20k1reg.h"
-+
-+#if BITS_PER_LONG == 32
-+#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-+#else
-+#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-+#endif
-+
-+struct hw20k1 {
-+ struct hw hw;
-+ spinlock_t reg_20k1_lock;
-+ spinlock_t reg_pci_lock;
-+};
-+
-+static u32 hw_read_20kx(struct hw *hw, u32 reg);
-+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
-+static u32 hw_read_pci(struct hw *hw, u32 reg);
-+static void hw_write_pci(struct hw *hw, u32 reg, u32 data);
-+
-+/*
-+ * Type definition block.
-+ * The layout of control structures can be directly applied on 20k2 chip.
-+ */
-+
-+/*
-+ * SRC control block definitions.
-+ */
-+
-+/* SRC resource control block */
-+#define SRCCTL_STATE 0x00000007
-+#define SRCCTL_BM 0x00000008
-+#define SRCCTL_RSR 0x00000030
-+#define SRCCTL_SF 0x000001C0
-+#define SRCCTL_WR 0x00000200
-+#define SRCCTL_PM 0x00000400
-+#define SRCCTL_ROM 0x00001800
-+#define SRCCTL_VO 0x00002000
-+#define SRCCTL_ST 0x00004000
-+#define SRCCTL_IE 0x00008000
-+#define SRCCTL_ILSZ 0x000F0000
-+#define SRCCTL_BP 0x00100000
-+
-+#define SRCCCR_CISZ 0x000007FF
-+#define SRCCCR_CWA 0x001FF800
-+#define SRCCCR_D 0x00200000
-+#define SRCCCR_RS 0x01C00000
-+#define SRCCCR_NAL 0x3E000000
-+#define SRCCCR_RA 0xC0000000
-+
-+#define SRCCA_CA 0x03FFFFFF
-+#define SRCCA_RS 0x1C000000
-+#define SRCCA_NAL 0xE0000000
-+
-+#define SRCSA_SA 0x03FFFFFF
-+
-+#define SRCLA_LA 0x03FFFFFF
-+
-+/* Mixer Parameter Ring ram Low and Hight register.
-+ * Fixed-point value in 8.24 format for parameter channel */
-+#define MPRLH_PITCH 0xFFFFFFFF
-+
-+/* SRC resource register dirty flags */
-+union src_dirty {
-+ struct {
-+ u16 ctl:1;
-+ u16 ccr:1;
-+ u16 sa:1;
-+ u16 la:1;
-+ u16 ca:1;
-+ u16 mpr:1;
-+ u16 czbfs:1; /* Clear Z-Buffers */
-+ u16 rsv:9;
-+ } bf;
-+ u16 data;
-+};
-+
-+struct src_rsc_ctrl_blk {
-+ unsigned int ctl;
-+ unsigned int ccr;
-+ unsigned int ca;
-+ unsigned int sa;
-+ unsigned int la;
-+ unsigned int mpr;
-+ union src_dirty dirty;
-+};
-+
-+/* SRC manager control block */
-+union src_mgr_dirty {
-+ struct {
-+ u16 enb0:1;
-+ u16 enb1:1;
-+ u16 enb2:1;
-+ u16 enb3:1;
-+ u16 enb4:1;
-+ u16 enb5:1;
-+ u16 enb6:1;
-+ u16 enb7:1;
-+ u16 enbsa:1;
-+ u16 rsv:7;
-+ } bf;
-+ u16 data;
-+};
-+
-+struct src_mgr_ctrl_blk {
-+ unsigned int enbsa;
-+ unsigned int enb[8];
-+ union src_mgr_dirty dirty;
-+};
-+
-+/* SRCIMP manager control block */
-+#define SRCAIM_ARC 0x00000FFF
-+#define SRCAIM_NXT 0x00FF0000
-+#define SRCAIM_SRC 0xFF000000
-+
-+struct srcimap {
-+ unsigned int srcaim;
-+ unsigned int idx;
-+};
-+
-+/* SRCIMP manager register dirty flags */
-+union srcimp_mgr_dirty {
-+ struct {
-+ u16 srcimap:1;
-+ u16 rsv:15;
-+ } bf;
-+ u16 data;
-+};
-+
-+struct srcimp_mgr_ctrl_blk {
-+ struct srcimap srcimap;
-+ union srcimp_mgr_dirty dirty;
-+};
-+
-+/*
-+ * Function implementation block.
-+ */
-+
-+static int src_get_rsc_ctrl_blk(void **rblk)
-+{
-+ struct src_rsc_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int src_put_rsc_ctrl_blk(void *blk)
-+{
-+ kfree((struct src_rsc_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+static int src_set_state(void *blk, unsigned int state)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_STATE, state);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_bm(void *blk, unsigned int bm)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_BM, bm);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_rsr(void *blk, unsigned int rsr)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_RSR, rsr);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_sf(void *blk, unsigned int sf)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_SF, sf);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_wr(void *blk, unsigned int wr)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_WR, wr);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_pm(void *blk, unsigned int pm)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_PM, pm);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_rom(void *blk, unsigned int rom)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_ROM, rom);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_vo(void *blk, unsigned int vo)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_VO, vo);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_st(void *blk, unsigned int st)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_ST, st);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_ie(void *blk, unsigned int ie)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_IE, ie);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_ilsz(void *blk, unsigned int ilsz)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_bp(void *blk, unsigned int bp)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_BP, bp);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_cisz(void *blk, unsigned int cisz)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
-+ ctl->dirty.bf.ccr = 1;
-+ return 0;
-+}
-+
-+static int src_set_ca(void *blk, unsigned int ca)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ca, SRCCA_CA, ca);
-+ ctl->dirty.bf.ca = 1;
-+ return 0;
-+}
-+
-+static int src_set_sa(void *blk, unsigned int sa)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->sa, SRCSA_SA, sa);
-+ ctl->dirty.bf.sa = 1;
-+ return 0;
-+}
-+
-+static int src_set_la(void *blk, unsigned int la)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->la, SRCLA_LA, la);
-+ ctl->dirty.bf.la = 1;
-+ return 0;
-+}
-+
-+static int src_set_pitch(void *blk, unsigned int pitch)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->mpr, MPRLH_PITCH, pitch);
-+ ctl->dirty.bf.mpr = 1;
-+ return 0;
-+}
-+
-+static int src_set_clear_zbufs(void *blk, unsigned int clear)
-+{
-+ ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
-+ return 0;
-+}
-+
-+static int src_set_dirty(void *blk, unsigned int flags)
-+{
-+ ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
-+ return 0;
-+}
-+
-+static int src_set_dirty_all(void *blk)
-+{
-+ ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
-+ return 0;
-+}
-+
-+#define AR_SLOT_SIZE 4096
-+#define AR_SLOT_BLOCK_SIZE 16
-+#define AR_PTS_PITCH 6
-+#define AR_PARAM_SRC_OFFSET 0x60
-+
-+static unsigned int src_param_pitch_mixer(unsigned int src_idx)
-+{
-+ return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
-+ - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
-+
-+}
-+
-+static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+ int i;
-+
-+ if (ctl->dirty.bf.czbfs) {
-+ /* Clear Z-Buffer registers */
-+ for (i = 0; i < 8; i++)
-+ hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0);
-+
-+ for (i = 0; i < 4; i++)
-+ hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0);
-+
-+ for (i = 0; i < 8; i++)
-+ hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0);
-+
-+ ctl->dirty.bf.czbfs = 0;
-+ }
-+ if (ctl->dirty.bf.mpr) {
-+ /* Take the parameter mixer resource in the same group as that
-+ * the idx src is in for simplicity. Unlike src, all conjugate
-+ * parameter mixer resources must be programmed for
-+ * corresponding conjugate src resources. */
-+ unsigned int pm_idx = src_param_pitch_mixer(idx);
-+ hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr);
-+ hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3);
-+ hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0);
-+ ctl->dirty.bf.mpr = 0;
-+ }
-+ if (ctl->dirty.bf.sa) {
-+ hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa);
-+ ctl->dirty.bf.sa = 0;
-+ }
-+ if (ctl->dirty.bf.la) {
-+ hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la);
-+ ctl->dirty.bf.la = 0;
-+ }
-+ if (ctl->dirty.bf.ca) {
-+ hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca);
-+ ctl->dirty.bf.ca = 0;
-+ }
-+
-+ /* Write srccf register */
-+ hw_write_20kx(hw, SRCCF+idx*0x100, 0x0);
-+
-+ if (ctl->dirty.bf.ccr) {
-+ hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr);
-+ ctl->dirty.bf.ccr = 0;
-+ }
-+ if (ctl->dirty.bf.ctl) {
-+ hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl);
-+ ctl->dirty.bf.ctl = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100);
-+ ctl->dirty.bf.ca = 0;
-+
-+ return get_field(ctl->ca, SRCCA_CA);
-+}
-+
-+static unsigned int src_get_dirty(void *blk)
-+{
-+ return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
-+}
-+
-+static unsigned int src_dirty_conj_mask(void)
-+{
-+ return 0x20;
-+}
-+
-+static int src_mgr_enbs_src(void *blk, unsigned int idx)
-+{
-+ ((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0);
-+ ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
-+ ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
-+ return 0;
-+}
-+
-+static int src_mgr_enb_src(void *blk, unsigned int idx)
-+{
-+ ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
-+ ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
-+ return 0;
-+}
-+
-+static int src_mgr_dsb_src(void *blk, unsigned int idx)
-+{
-+ ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
-+ ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
-+ return 0;
-+}
-+
-+static int src_mgr_commit_write(struct hw *hw, void *blk)
-+{
-+ struct src_mgr_ctrl_blk *ctl = blk;
-+ int i;
-+ unsigned int ret;
-+
-+ if (ctl->dirty.bf.enbsa) {
-+ do {
-+ ret = hw_read_20kx(hw, SRCENBSTAT);
-+ } while (ret & 0x1);
-+ hw_write_20kx(hw, SRCENBS, ctl->enbsa);
-+ ctl->dirty.bf.enbsa = 0;
-+ }
-+ for (i = 0; i < 8; i++) {
-+ if ((ctl->dirty.data & (0x1 << i))) {
-+ hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]);
-+ ctl->dirty.data &= ~(0x1 << i);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int src_mgr_get_ctrl_blk(void **rblk)
-+{
-+ struct src_mgr_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int src_mgr_put_ctrl_blk(void *blk)
-+{
-+ kfree((struct src_mgr_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+static int srcimp_mgr_get_ctrl_blk(void **rblk)
-+{
-+ struct srcimp_mgr_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int srcimp_mgr_put_ctrl_blk(void *blk)
-+{
-+ kfree((struct srcimp_mgr_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ ctl->srcimap.idx = addr;
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.srcimap) {
-+ hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100,
-+ ctl->srcimap.srcaim);
-+ ctl->dirty.bf.srcimap = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * AMIXER control block definitions.
-+ */
-+
-+#define AMOPLO_M 0x00000003
-+#define AMOPLO_X 0x0003FFF0
-+#define AMOPLO_Y 0xFFFC0000
-+
-+#define AMOPHI_SADR 0x000000FF
-+#define AMOPHI_SE 0x80000000
-+
-+/* AMIXER resource register dirty flags */
-+union amixer_dirty {
-+ struct {
-+ u16 amoplo:1;
-+ u16 amophi:1;
-+ u16 rsv:14;
-+ } bf;
-+ u16 data;
-+};
-+
-+/* AMIXER resource control block */
-+struct amixer_rsc_ctrl_blk {
-+ unsigned int amoplo;
-+ unsigned int amophi;
-+ union amixer_dirty dirty;
-+};
-+
-+static int amixer_set_mode(void *blk, unsigned int mode)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_M, mode);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_iv(void *blk, unsigned int iv)
-+{
-+ /* 20k1 amixer does not have this field */
-+ return 0;
-+}
-+
-+static int amixer_set_x(void *blk, unsigned int x)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_X, x);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_y(void *blk, unsigned int y)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_Y, y);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_sadr(void *blk, unsigned int sadr)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amophi, AMOPHI_SADR, sadr);
-+ ctl->dirty.bf.amophi = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_se(void *blk, unsigned int se)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amophi, AMOPHI_SE, se);
-+ ctl->dirty.bf.amophi = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_dirty(void *blk, unsigned int flags)
-+{
-+ ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
-+ return 0;
-+}
-+
-+static int amixer_set_dirty_all(void *blk)
-+{
-+ ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
-+ return 0;
-+}
-+
-+static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
-+ hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo);
-+ ctl->dirty.bf.amoplo = 0;
-+ hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi);
-+ ctl->dirty.bf.amophi = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int amixer_get_y(void *blk)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ return get_field(ctl->amoplo, AMOPLO_Y);
-+}
-+
-+static unsigned int amixer_get_dirty(void *blk)
-+{
-+ return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
-+}
-+
-+static int amixer_rsc_get_ctrl_blk(void **rblk)
-+{
-+ struct amixer_rsc_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int amixer_rsc_put_ctrl_blk(void *blk)
-+{
-+ kfree((struct amixer_rsc_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+static int amixer_mgr_get_ctrl_blk(void **rblk)
-+{
-+ /*amixer_mgr_ctrl_blk_t *blk;*/
-+
-+ *rblk = NULL;
-+ /*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;*/
-+
-+ return 0;
-+}
-+
-+static int amixer_mgr_put_ctrl_blk(void *blk)
-+{
-+ /*kfree((amixer_mgr_ctrl_blk_t *)blk);*/
-+
-+ return 0;
-+}
-+
-+/*
-+ * DAIO control block definitions.
-+ */
-+
-+/* Receiver Sample Rate Tracker Control register */
-+#define SRTCTL_SRCR 0x000000FF
-+#define SRTCTL_SRCL 0x0000FF00
-+#define SRTCTL_RSR 0x00030000
-+#define SRTCTL_DRAT 0x000C0000
-+#define SRTCTL_RLE 0x10000000
-+#define SRTCTL_RLP 0x20000000
-+#define SRTCTL_EC 0x40000000
-+#define SRTCTL_ET 0x80000000
-+
-+/* DAIO Receiver register dirty flags */
-+union dai_dirty {
-+ struct {
-+ u16 srtctl:1;
-+ u16 rsv:15;
-+ } bf;
-+ u16 data;
-+};
-+
-+/* DAIO Receiver control block */
-+struct dai_ctrl_blk {
-+ unsigned int srtctl;
-+ union dai_dirty dirty;
-+};
-+
-+/* S/PDIF Transmitter register dirty flags */
-+union dao_dirty {
-+ struct {
-+ u16 spos:1;
-+ u16 rsv:15;
-+ } bf;
-+ u16 data;
-+};
-+
-+/* S/PDIF Transmitter control block */
-+struct dao_ctrl_blk {
-+ unsigned int spos; /* S/PDIF Output Channel Status Register */
-+ union dao_dirty dirty;
-+};
-+
-+/* Audio Input Mapper RAM */
-+#define AIM_ARC 0x00000FFF
-+#define AIM_NXT 0x007F0000
-+
-+struct daoimap {
-+ unsigned int aim;
-+ unsigned int idx;
-+};
-+
-+/* I2S Transmitter/Receiver Control register */
-+#define I2SCTL_EA 0x00000004
-+#define I2SCTL_EI 0x00000010
-+
-+/* S/PDIF Transmitter Control register */
-+#define SPOCTL_OE 0x00000001
-+#define SPOCTL_OS 0x0000000E
-+#define SPOCTL_RIV 0x00000010
-+#define SPOCTL_LIV 0x00000020
-+#define SPOCTL_SR 0x000000C0
-+
-+/* S/PDIF Receiver Control register */
-+#define SPICTL_EN 0x00000001
-+#define SPICTL_I24 0x00000002
-+#define SPICTL_IB 0x00000004
-+#define SPICTL_SM 0x00000008
-+#define SPICTL_VM 0x00000010
-+
-+/* DAIO manager register dirty flags */
-+union daio_mgr_dirty {
-+ struct {
-+ u32 i2soctl:4;
-+ u32 i2sictl:4;
-+ u32 spoctl:4;
-+ u32 spictl:4;
-+ u32 daoimap:1;
-+ u32 rsv:15;
-+ } bf;
-+ u32 data;
-+};
-+
-+/* DAIO manager control block */
-+struct daio_mgr_ctrl_blk {
-+ unsigned int i2sctl;
-+ unsigned int spoctl;
-+ unsigned int spictl;
-+ struct daoimap daoimap;
-+ union daio_mgr_dirty dirty;
-+};
-+
-+static int dai_srt_set_srcr(void *blk, unsigned int src)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srtctl, SRTCTL_SRCR, src);
-+ ctl->dirty.bf.srtctl = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_srcl(void *blk, unsigned int src)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srtctl, SRTCTL_SRCL, src);
-+ ctl->dirty.bf.srtctl = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_rsr(void *blk, unsigned int rsr)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srtctl, SRTCTL_RSR, rsr);
-+ ctl->dirty.bf.srtctl = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_drat(void *blk, unsigned int drat)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srtctl, SRTCTL_DRAT, drat);
-+ ctl->dirty.bf.srtctl = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_ec(void *blk, unsigned int ec)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0);
-+ ctl->dirty.bf.srtctl = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_et(void *blk, unsigned int et)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0);
-+ ctl->dirty.bf.srtctl = 1;
-+ return 0;
-+}
-+
-+static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.srtctl) {
-+ if (idx < 4) {
-+ /* S/PDIF SRTs */
-+ hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl);
-+ } else {
-+ /* I2S SRT */
-+ hw_write_20kx(hw, SRTICTL, ctl->srtctl);
-+ }
-+ ctl->dirty.bf.srtctl = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int dai_get_ctrl_blk(void **rblk)
-+{
-+ struct dai_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int dai_put_ctrl_blk(void *blk)
-+{
-+ kfree((struct dai_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+static int dao_set_spos(void *blk, unsigned int spos)
-+{
-+ ((struct dao_ctrl_blk *)blk)->spos = spos;
-+ ((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1;
-+ return 0;
-+}
-+
-+static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct dao_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.spos) {
-+ if (idx < 4) {
-+ /* S/PDIF SPOSx */
-+ hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos);
-+ }
-+ ctl->dirty.bf.spos = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int dao_get_spos(void *blk, unsigned int *spos)
-+{
-+ *spos = ((struct dao_ctrl_blk *)blk)->spos;
-+ return 0;
-+}
-+
-+static int dao_get_ctrl_blk(void **rblk)
-+{
-+ struct dao_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int dao_put_ctrl_blk(void *blk)
-+{
-+ kfree((struct dao_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_enb_dai(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ if (idx < 4) {
-+ /* S/PDIF input */
-+ set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1);
-+ ctl->dirty.bf.spictl |= (0x1 << idx);
-+ } else {
-+ /* I2S input */
-+ idx %= 4;
-+ set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1);
-+ ctl->dirty.bf.i2sictl |= (0x1 << idx);
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ if (idx < 4) {
-+ /* S/PDIF input */
-+ set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0);
-+ ctl->dirty.bf.spictl |= (0x1 << idx);
-+ } else {
-+ /* I2S input */
-+ idx %= 4;
-+ set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0);
-+ ctl->dirty.bf.i2sictl |= (0x1 << idx);
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_enb_dao(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ if (idx < 4) {
-+ /* S/PDIF output */
-+ set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1);
-+ ctl->dirty.bf.spoctl |= (0x1 << idx);
-+ } else {
-+ /* I2S output */
-+ idx %= 4;
-+ set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1);
-+ ctl->dirty.bf.i2soctl |= (0x1 << idx);
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ if (idx < 4) {
-+ /* S/PDIF output */
-+ set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0);
-+ ctl->dirty.bf.spoctl |= (0x1 << idx);
-+ } else {
-+ /* I2S output */
-+ idx %= 4;
-+ set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0);
-+ ctl->dirty.bf.i2soctl |= (0x1 << idx);
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ if (idx < 4) {
-+ /* S/PDIF output */
-+ switch ((conf & 0x7)) {
-+ case 0:
-+ set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3);
-+ break; /* CDIF */
-+ case 1:
-+ set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0);
-+ break;
-+ case 2:
-+ set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1);
-+ break;
-+ case 4:
-+ set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2);
-+ break;
-+ default:
-+ break;
-+ }
-+ set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8),
-+ (conf >> 4) & 0x1); /* Non-audio */
-+ set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8),
-+ (conf >> 4) & 0x1); /* Non-audio */
-+ set_field(&ctl->spoctl, SPOCTL_OS << (idx*8),
-+ ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */
-+
-+ ctl->dirty.bf.spoctl |= (0x1 << idx);
-+ } else {
-+ /* I2S output */
-+ /*idx %= 4; */
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->daoimap.aim, AIM_ARC, slot);
-+ ctl->dirty.bf.daoimap = 1;
-+ return 0;
-+}
-+
-+static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->daoimap.aim, AIM_NXT, next);
-+ ctl->dirty.bf.daoimap = 1;
-+ return 0;
-+}
-+
-+static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ ctl->daoimap.idx = addr;
-+ ctl->dirty.bf.daoimap = 1;
-+ return 0;
-+}
-+
-+static int daio_mgr_commit_write(struct hw *hw, void *blk)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+ int i;
-+
-+ if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) {
-+ for (i = 0; i < 4; i++) {
-+ if ((ctl->dirty.bf.i2sictl & (0x1 << i)))
-+ ctl->dirty.bf.i2sictl &= ~(0x1 << i);
-+
-+ if ((ctl->dirty.bf.i2soctl & (0x1 << i)))
-+ ctl->dirty.bf.i2soctl &= ~(0x1 << i);
-+ }
-+ hw_write_20kx(hw, I2SCTL, ctl->i2sctl);
-+ mdelay(1);
-+ }
-+ if (ctl->dirty.bf.spoctl) {
-+ for (i = 0; i < 4; i++) {
-+ if ((ctl->dirty.bf.spoctl & (0x1 << i)))
-+ ctl->dirty.bf.spoctl &= ~(0x1 << i);
-+ }
-+ hw_write_20kx(hw, SPOCTL, ctl->spoctl);
-+ mdelay(1);
-+ }
-+ if (ctl->dirty.bf.spictl) {
-+ for (i = 0; i < 4; i++) {
-+ if ((ctl->dirty.bf.spictl & (0x1 << i)))
-+ ctl->dirty.bf.spictl &= ~(0x1 << i);
-+ }
-+ hw_write_20kx(hw, SPICTL, ctl->spictl);
-+ mdelay(1);
-+ }
-+ if (ctl->dirty.bf.daoimap) {
-+ hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4,
-+ ctl->daoimap.aim);
-+ ctl->dirty.bf.daoimap = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
-+{
-+ struct daio_mgr_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ blk->i2sctl = hw_read_20kx(hw, I2SCTL);
-+ blk->spoctl = hw_read_20kx(hw, SPOCTL);
-+ blk->spictl = hw_read_20kx(hw, SPICTL);
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_put_ctrl_blk(void *blk)
-+{
-+ kfree((struct daio_mgr_ctrl_blk *)blk);
-+
-+ return 0;
-+}
-+
-+/* Timer interrupt */
-+static int set_timer_irq(struct hw *hw, int enable)
-+{
-+ hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
-+ return 0;
-+}
-+
-+static int set_timer_tick(struct hw *hw, unsigned int ticks)
-+{
-+ if (ticks)
-+ ticks |= TIMR_IE | TIMR_IP;
-+ hw_write_20kx(hw, TIMR, ticks);
-+ return 0;
-+}
-+
-+static unsigned int get_wc(struct hw *hw)
-+{
-+ return hw_read_20kx(hw, WC);
-+}
-+
-+/* Card hardware initialization block */
-+struct dac_conf {
-+ unsigned int msr; /* master sample rate in rsrs */
-+};
-+
-+struct adc_conf {
-+ unsigned int msr; /* master sample rate in rsrs */
-+ unsigned char input; /* the input source of ADC */
-+ unsigned char mic20db; /* boost mic by 20db if input is microphone */
-+};
-+
-+struct daio_conf {
-+ unsigned int msr; /* master sample rate in rsrs */
-+};
-+
-+struct trn_conf {
-+ unsigned long vm_pgt_phys;
-+};
-+
-+static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
-+{
-+ u32 i2sorg;
-+ u32 spdorg;
-+
-+ /* Read I2S CTL. Keep original value. */
-+ /*i2sorg = hw_read_20kx(hw, I2SCTL);*/
-+ i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
-+ /* Program I2S with proper master sample rate and enable
-+ * the correct I2S channel. */
-+ i2sorg &= 0xfffffffc;
-+
-+ /* Enable S/PDIF-out-A in fixed 24-bit data
-+ * format and default to 48kHz. */
-+ /* Disable all before doing any changes. */
-+ hw_write_20kx(hw, SPOCTL, 0x0);
-+ spdorg = 0x05;
-+
-+ switch (info->msr) {
-+ case 1:
-+ i2sorg |= 1;
-+ spdorg |= (0x0 << 6);
-+ break;
-+ case 2:
-+ i2sorg |= 2;
-+ spdorg |= (0x1 << 6);
-+ break;
-+ case 4:
-+ i2sorg |= 3;
-+ spdorg |= (0x2 << 6);
-+ break;
-+ default:
-+ i2sorg |= 1;
-+ break;
-+ }
-+
-+ hw_write_20kx(hw, I2SCTL, i2sorg);
-+ hw_write_20kx(hw, SPOCTL, spdorg);
-+
-+ /* Enable S/PDIF-in-A in fixed 24-bit data format. */
-+ /* Disable all before doing any changes. */
-+ hw_write_20kx(hw, SPICTL, 0x0);
-+ mdelay(1);
-+ spdorg = 0x0a0a0a0a;
-+ hw_write_20kx(hw, SPICTL, spdorg);
-+ mdelay(1);
-+
-+ return 0;
-+}
-+
-+/* TRANSPORT operations */
-+static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
-+{
-+ u32 trnctl;
-+ u32 ptp_phys_low, ptp_phys_high;
-+
-+ /* Set up device page table */
-+ if ((~0UL) == info->vm_pgt_phys) {
-+ printk(KERN_ERR "Wrong device page table page address!\n");
-+ return -1;
-+ }
-+
-+ trnctl = 0x13; /* 32-bit, 4k-size page */
-+ ptp_phys_low = (u32)info->vm_pgt_phys;
-+ ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
-+ if (sizeof(void *) == 8) /* 64bit address */
-+ trnctl |= (1 << 2);
-+#if 0 /* Only 4k h/w pages for simplicitiy */
-+#if PAGE_SIZE == 8192
-+ trnctl |= (1<<5);
-+#endif
-+#endif
-+ hw_write_20kx(hw, PTPALX, ptp_phys_low);
-+ hw_write_20kx(hw, PTPAHX, ptp_phys_high);
-+ hw_write_20kx(hw, TRNCTL, trnctl);
-+ hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */
-+
-+ return 0;
-+}
-+
-+/* Card initialization */
-+#define GCTL_EAC 0x00000001
-+#define GCTL_EAI 0x00000002
-+#define GCTL_BEP 0x00000004
-+#define GCTL_BES 0x00000008
-+#define GCTL_DSP 0x00000010
-+#define GCTL_DBP 0x00000020
-+#define GCTL_ABP 0x00000040
-+#define GCTL_TBP 0x00000080
-+#define GCTL_SBP 0x00000100
-+#define GCTL_FBP 0x00000200
-+#define GCTL_XA 0x00000400
-+#define GCTL_ET 0x00000800
-+#define GCTL_PR 0x00001000
-+#define GCTL_MRL 0x00002000
-+#define GCTL_SDE 0x00004000
-+#define GCTL_SDI 0x00008000
-+#define GCTL_SM 0x00010000
-+#define GCTL_SR 0x00020000
-+#define GCTL_SD 0x00040000
-+#define GCTL_SE 0x00080000
-+#define GCTL_AID 0x00100000
-+
-+static int hw_pll_init(struct hw *hw, unsigned int rsr)
-+{
-+ unsigned int pllctl;
-+ int i;
-+
-+ pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
-+ for (i = 0; i < 3; i++) {
-+ if (hw_read_20kx(hw, PLLCTL) == pllctl)
-+ break;
-+
-+ hw_write_20kx(hw, PLLCTL, pllctl);
-+ mdelay(40);
-+ }
-+ if (i >= 3) {
-+ printk(KERN_ALERT "PLL initialization failed!!!\n");
-+ return -EBUSY;
-+ }
-+
-+ return 0;
-+}
-+
-+static int hw_auto_init(struct hw *hw)
-+{
-+ unsigned int gctl;
-+ int i;
-+
-+ gctl = hw_read_20kx(hw, GCTL);
-+ set_field(&gctl, GCTL_EAI, 0);
-+ hw_write_20kx(hw, GCTL, gctl);
-+ set_field(&gctl, GCTL_EAI, 1);
-+ hw_write_20kx(hw, GCTL, gctl);
-+ mdelay(10);
-+ for (i = 0; i < 400000; i++) {
-+ gctl = hw_read_20kx(hw, GCTL);
-+ if (get_field(gctl, GCTL_AID))
-+ break;
-+ }
-+ if (!get_field(gctl, GCTL_AID)) {
-+ printk(KERN_ALERT "Card Auto-init failed!!!\n");
-+ return -EBUSY;
-+ }
-+
-+ return 0;
-+}
-+
-+static int i2c_unlock(struct hw *hw)
-+{
-+ if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
-+ return 0;
-+
-+ hw_write_pci(hw, 0xcc, 0x8c);
-+ hw_write_pci(hw, 0xcc, 0x0e);
-+ if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
-+ return 0;
-+
-+ hw_write_pci(hw, 0xcc, 0xee);
-+ hw_write_pci(hw, 0xcc, 0xaa);
-+ if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
-+ return 0;
-+
-+ return -1;
-+}
-+
-+static void i2c_lock(struct hw *hw)
-+{
-+ if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
-+ hw_write_pci(hw, 0xcc, 0x00);
-+}
-+
-+static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
-+{
-+ unsigned int ret;
-+
-+ do {
-+ ret = hw_read_pci(hw, 0xEC);
-+ } while (!(ret & 0x800000));
-+ hw_write_pci(hw, 0xE0, device);
-+ hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
-+}
-+
-+/* DAC operations */
-+
-+static int hw_reset_dac(struct hw *hw)
-+{
-+ u32 i;
-+ u16 gpioorg;
-+ unsigned int ret;
-+
-+ if (i2c_unlock(hw))
-+ return -1;
-+
-+ do {
-+ ret = hw_read_pci(hw, 0xEC);
-+ } while (!(ret & 0x800000));
-+ hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */
-+
-+ /* To be effective, need to reset the DAC twice. */
-+ for (i = 0; i < 2; i++) {
-+ /* set gpio */
-+ mdelay(100);
-+ gpioorg = (u16)hw_read_20kx(hw, GPIO);
-+ gpioorg &= 0xfffd;
-+ hw_write_20kx(hw, GPIO, gpioorg);
-+ mdelay(1);
-+ hw_write_20kx(hw, GPIO, gpioorg | 0x2);
-+ }
-+
-+ i2c_write(hw, 0x00180080, 0x01, 0x80);
-+ i2c_write(hw, 0x00180080, 0x02, 0x10);
-+
-+ i2c_lock(hw);
-+
-+ return 0;
-+}
-+
-+static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
-+{
-+ u32 data;
-+ u16 gpioorg;
-+ unsigned int ret;
-+
-+ if (hw->model == CTSB055X) {
-+ /* SB055x, unmute outputs */
-+ gpioorg = (u16)hw_read_20kx(hw, GPIO);
-+ gpioorg &= 0xffbf; /* set GPIO6 to low */
-+ gpioorg |= 2; /* set GPIO1 to high */
-+ hw_write_20kx(hw, GPIO, gpioorg);
-+ return 0;
-+ }
-+
-+ /* mute outputs */
-+ gpioorg = (u16)hw_read_20kx(hw, GPIO);
-+ gpioorg &= 0xffbf;
-+ hw_write_20kx(hw, GPIO, gpioorg);
-+
-+ hw_reset_dac(hw);
-+
-+ if (i2c_unlock(hw))
-+ return -1;
-+
-+ hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */
-+ do {
-+ ret = hw_read_pci(hw, 0xEC);
-+ } while (!(ret & 0x800000));
-+
-+ switch (info->msr) {
-+ case 1:
-+ data = 0x24;
-+ break;
-+ case 2:
-+ data = 0x25;
-+ break;
-+ case 4:
-+ data = 0x26;
-+ break;
-+ default:
-+ data = 0x24;
-+ break;
-+ }
-+
-+ i2c_write(hw, 0x00180080, 0x06, data);
-+ i2c_write(hw, 0x00180080, 0x09, data);
-+ i2c_write(hw, 0x00180080, 0x0c, data);
-+ i2c_write(hw, 0x00180080, 0x0f, data);
-+
-+ i2c_lock(hw);
-+
-+ /* unmute outputs */
-+ gpioorg = (u16)hw_read_20kx(hw, GPIO);
-+ gpioorg = gpioorg | 0x40;
-+ hw_write_20kx(hw, GPIO, gpioorg);
-+
-+ return 0;
-+}
-+
-+/* ADC operations */
-+
-+static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
-+{
-+ return 0;
-+}
-+
-+static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
-+{
-+ u32 data;
-+
-+ data = hw_read_20kx(hw, GPIO);
-+ switch (type) {
-+ case ADC_MICIN:
-+ data = ((data & (0x1<<7)) && (data & (0x1<<8)));
-+ break;
-+ case ADC_LINEIN:
-+ data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
-+ break;
-+ case ADC_NONE: /* Digital I/O */
-+ data = (!(data & (0x1<<8)));
-+ break;
-+ default:
-+ data = 0;
-+ }
-+ return data;
-+}
-+
-+static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
-+{
-+ u32 data;
-+
-+ data = hw_read_20kx(hw, GPIO);
-+ switch (type) {
-+ case ADC_MICIN:
-+ data = (data & (0x1 << 7)) ? 1 : 0;
-+ break;
-+ case ADC_LINEIN:
-+ data = (data & (0x1 << 7)) ? 0 : 1;
-+ break;
-+ default:
-+ data = 0;
-+ }
-+ return data;
-+}
-+
-+static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
-+{
-+ switch (hw->model) {
-+ case CTSB055X:
-+ return is_adc_input_selected_SB055x(hw, type);
-+ case CTSB073X:
-+ return is_adc_input_selected_hendrix(hw, type);
-+ case CTUAA:
-+ return is_adc_input_selected_hendrix(hw, type);
-+ default:
-+ return is_adc_input_selected_SBx(hw, type);
-+ }
-+}
-+
-+static int
-+adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
-+{
-+ u32 data;
-+
-+ /*
-+ * check and set the following GPIO bits accordingly
-+ * ADC_Gain = GPIO2
-+ * DRM_off = GPIO3
-+ * Mic_Pwr_on = GPIO7
-+ * Digital_IO_Sel = GPIO8
-+ * Mic_Sw = GPIO9
-+ * Aux/MicLine_Sw = GPIO12
-+ */
-+ data = hw_read_20kx(hw, GPIO);
-+ data &= 0xec73;
-+ switch (type) {
-+ case ADC_MICIN:
-+ data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
-+ data |= boost ? (0x1<<2) : 0;
-+ break;
-+ case ADC_LINEIN:
-+ data |= (0x1<<8);
-+ break;
-+ case ADC_AUX:
-+ data |= (0x1<<8) | (0x1<<12);
-+ break;
-+ case ADC_NONE:
-+ data |= (0x1<<12); /* set to digital */
-+ break;
-+ default:
-+ return -1;
-+ }
-+
-+ hw_write_20kx(hw, GPIO, data);
-+
-+ return 0;
-+}
-+
-+
-+static int
-+adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
-+{
-+ u32 data;
-+ u32 i2c_data;
-+ unsigned int ret;
-+
-+ if (i2c_unlock(hw))
-+ return -1;
-+
-+ do {
-+ ret = hw_read_pci(hw, 0xEC);
-+ } while (!(ret & 0x800000)); /* i2c ready poll */
-+ /* set i2c access mode as Direct Control */
-+ hw_write_pci(hw, 0xEC, 0x05);
-+
-+ data = hw_read_20kx(hw, GPIO);
-+ switch (type) {
-+ case ADC_MICIN:
-+ data |= ((0x1 << 7) | (0x1 << 8));
-+ i2c_data = 0x1; /* Mic-in */
-+ break;
-+ case ADC_LINEIN:
-+ data &= ~(0x1 << 7);
-+ data |= (0x1 << 8);
-+ i2c_data = 0x2; /* Line-in */
-+ break;
-+ case ADC_NONE:
-+ data &= ~(0x1 << 8);
-+ i2c_data = 0x0; /* set to Digital */
-+ break;
-+ default:
-+ i2c_lock(hw);
-+ return -1;
-+ }
-+ hw_write_20kx(hw, GPIO, data);
-+ i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
-+ if (boost) {
-+ i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
-+ i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
-+ } else {
-+ i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
-+ i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
-+ }
-+
-+ i2c_lock(hw);
-+
-+ return 0;
-+}
-+
-+static int
-+adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
-+{
-+ u32 data;
-+ u32 i2c_data;
-+ unsigned int ret;
-+
-+ if (i2c_unlock(hw))
-+ return -1;
-+
-+ do {
-+ ret = hw_read_pci(hw, 0xEC);
-+ } while (!(ret & 0x800000)); /* i2c ready poll */
-+ /* set i2c access mode as Direct Control */
-+ hw_write_pci(hw, 0xEC, 0x05);
-+
-+ data = hw_read_20kx(hw, GPIO);
-+ switch (type) {
-+ case ADC_MICIN:
-+ data |= (0x1 << 7);
-+ i2c_data = 0x1; /* Mic-in */
-+ break;
-+ case ADC_LINEIN:
-+ data &= ~(0x1 << 7);
-+ i2c_data = 0x2; /* Line-in */
-+ break;
-+ default:
-+ i2c_lock(hw);
-+ return -1;
-+ }
-+ hw_write_20kx(hw, GPIO, data);
-+ i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
-+ if (boost) {
-+ i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
-+ i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
-+ } else {
-+ i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
-+ i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
-+ }
-+
-+ i2c_lock(hw);
-+
-+ return 0;
-+}
-+
-+static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
-+{
-+ int state = type == ADC_MICIN;
-+
-+ switch (hw->model) {
-+ case CTSB055X:
-+ return adc_input_select_SB055x(hw, type, state);
-+ case CTSB073X:
-+ return adc_input_select_hendrix(hw, type, state);
-+ case CTUAA:
-+ return adc_input_select_hendrix(hw, type, state);
-+ default:
-+ return adc_input_select_SBx(hw, type, state);
-+ }
-+}
-+
-+static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
-+{
-+ return adc_input_select_SB055x(hw, input, mic20db);
-+}
-+
-+static int adc_init_SBx(struct hw *hw, int input, int mic20db)
-+{
-+ u16 gpioorg;
-+ u16 input_source;
-+ u32 adcdata;
-+ unsigned int ret;
-+
-+ input_source = 0x100; /* default to analog */
-+ switch (input) {
-+ case ADC_MICIN:
-+ adcdata = 0x1;
-+ input_source = 0x180; /* set GPIO7 to select Mic */
-+ break;
-+ case ADC_LINEIN:
-+ adcdata = 0x2;
-+ break;
-+ case ADC_VIDEO:
-+ adcdata = 0x4;
-+ break;
-+ case ADC_AUX:
-+ adcdata = 0x8;
-+ break;
-+ case ADC_NONE:
-+ adcdata = 0x0;
-+ input_source = 0x0; /* set to Digital */
-+ break;
-+ default:
-+ adcdata = 0x0;
-+ break;
-+ }
-+
-+ if (i2c_unlock(hw))
-+ return -1;
-+
-+ do {
-+ ret = hw_read_pci(hw, 0xEC);
-+ } while (!(ret & 0x800000)); /* i2c ready poll */
-+ hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */
-+
-+ i2c_write(hw, 0x001a0080, 0x0e, 0x08);
-+ i2c_write(hw, 0x001a0080, 0x18, 0x0a);
-+ i2c_write(hw, 0x001a0080, 0x28, 0x86);
-+ i2c_write(hw, 0x001a0080, 0x2a, adcdata);
-+
-+ if (mic20db) {
-+ i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
-+ i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
-+ } else {
-+ i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
-+ i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
-+ }
-+
-+ if (!(hw_read_20kx(hw, ID0) & 0x100))
-+ i2c_write(hw, 0x001a0080, 0x16, 0x26);
-+
-+ i2c_lock(hw);
-+
-+ gpioorg = (u16)hw_read_20kx(hw, GPIO);
-+ gpioorg &= 0xfe7f;
-+ gpioorg |= input_source;
-+ hw_write_20kx(hw, GPIO, gpioorg);
-+
-+ return 0;
-+}
-+
-+static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
-+{
-+ if (hw->model == CTSB055X)
-+ return adc_init_SB055x(hw, info->input, info->mic20db);
-+ else
-+ return adc_init_SBx(hw, info->input, info->mic20db);
-+}
-+
-+static int hw_have_digit_io_switch(struct hw *hw)
-+{
-+ /* SB073x and Vista compatible cards have no digit IO switch */
-+ return !(hw->model == CTSB073X || hw->model == CTUAA);
-+}
-+
-+#define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
-+
-+#define UAA_CFG_PWRSTATUS 0x44
-+#define UAA_CFG_SPACE_FLAG 0xA0
-+#define UAA_CORE_CHANGE 0x3FFC
-+static int uaa_to_xfi(struct pci_dev *pci)
-+{
-+ unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
-+ unsigned int cmd, irq, cl_size, l_timer, pwr;
-+ unsigned int is_uaa;
-+ unsigned int data[4] = {0};
-+ unsigned int io_base;
-+ void *mem_base;
-+ int i;
-+ const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
-+ const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
-+ const u32 CTLF = CTLBITS('C', 'T', 'L', 'F');
-+ const u32 CTLi = CTLBITS('C', 'T', 'L', 'i');
-+ const u32 CTLA = CTLBITS('C', 'T', 'L', 'A');
-+ const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z');
-+ const u32 CTLL = CTLBITS('C', 'T', 'L', 'L');
-+
-+ /* By default, Hendrix card UAA Bar0 should be using memory... */
-+ io_base = pci_resource_start(pci, 0);
-+ mem_base = ioremap(io_base, pci_resource_len(pci, 0));
-+ if (!mem_base)
-+ return -ENOENT;
-+
-+ /* Read current mode from Mode Change Register */
-+ for (i = 0; i < 4; i++)
-+ data[i] = readl(mem_base + UAA_CORE_CHANGE);
-+
-+ /* Determine current mode... */
-+ if (data[0] == CTLA) {
-+ is_uaa = ((data[1] == CTLZ && data[2] == CTLL
-+ && data[3] == CTLA) || (data[1] == CTLA
-+ && data[2] == CTLZ && data[3] == CTLL));
-+ } else if (data[0] == CTLZ) {
-+ is_uaa = (data[1] == CTLL
-+ && data[2] == CTLA && data[3] == CTLA);
-+ } else if (data[0] == CTLL) {
-+ is_uaa = (data[1] == CTLA
-+ && data[2] == CTLA && data[3] == CTLZ);
-+ } else {
-+ is_uaa = 0;
-+ }
-+
-+ if (!is_uaa) {
-+ /* Not in UAA mode currently. Return directly. */
-+ iounmap(mem_base);
-+ return 0;
-+ }
-+
-+ pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
-+ pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
-+ pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
-+ pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
-+ pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
-+ pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
-+ pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
-+ pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
-+ pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
-+ pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
-+ pci_read_config_dword(pci, PCI_COMMAND, &cmd);
-+
-+ /* Set up X-Fi core PCI configuration space. */
-+ /* Switch to X-Fi config space with BAR0 exposed. */
-+ pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
-+ /* Copy UAA's BAR5 into X-Fi BAR0 */
-+ pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
-+ /* Switch to X-Fi config space without BAR0 exposed. */
-+ pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
-+ pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
-+ pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
-+ pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
-+ pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
-+ pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
-+ pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
-+ pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
-+ pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
-+ pci_write_config_dword(pci, PCI_COMMAND, cmd);
-+
-+ /* Switch to X-Fi mode */
-+ writel(CTLX, (mem_base + UAA_CORE_CHANGE));
-+ writel(CTL_, (mem_base + UAA_CORE_CHANGE));
-+ writel(CTLF, (mem_base + UAA_CORE_CHANGE));
-+ writel(CTLi, (mem_base + UAA_CORE_CHANGE));
-+
-+ iounmap(mem_base);
-+
-+ return 0;
-+}
-+
-+static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
-+{
-+ struct hw *hw = dev_id;
-+ unsigned int status;
-+
-+ status = hw_read_20kx(hw, GIP);
-+ if (!status)
-+ return IRQ_NONE;
-+
-+ if (hw->irq_callback)
-+ hw->irq_callback(hw->irq_callback_data, status);
-+
-+ hw_write_20kx(hw, GIP, status);
-+ return IRQ_HANDLED;
-+}
-+
-+static int hw_card_start(struct hw *hw)
-+{
-+ int err;
-+ struct pci_dev *pci = hw->pci;
-+
-+ err = pci_enable_device(pci);
-+ if (err < 0)
-+ return err;
-+
-+ /* Set DMA transfer mask */
-+ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
-+ pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
-+ printk(KERN_ERR "architecture does not support PCI "
-+ "busmaster DMA with mask 0x%llx\n",
-+ CT_XFI_DMA_MASK);
-+ err = -ENXIO;
-+ goto error1;
-+ }
-+
-+ if (!hw->io_base) {
-+ err = pci_request_regions(pci, "XFi");
-+ if (err < 0)
-+ goto error1;
-+
-+ if (hw->model == CTUAA)
-+ hw->io_base = pci_resource_start(pci, 5);
-+ else
-+ hw->io_base = pci_resource_start(pci, 0);
-+
-+ }
-+
-+ /* Switch to X-Fi mode from UAA mode if neeeded */
-+ if (hw->model == CTUAA) {
-+ err = uaa_to_xfi(pci);
-+ if (err)
-+ goto error2;
-+
-+ }
-+
-+ if (hw->irq < 0) {
-+ err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
-+ "ctxfi", hw);
-+ if (err < 0) {
-+ printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
-+ goto error2;
-+ }
-+ hw->irq = pci->irq;
-+ }
-+
-+ pci_set_master(pci);
-+
-+ return 0;
-+
-+error2:
-+ pci_release_regions(pci);
-+ hw->io_base = 0;
-+error1:
-+ pci_disable_device(pci);
-+ return err;
-+}
-+
-+static int hw_card_stop(struct hw *hw)
-+{
-+ unsigned int data;
-+
-+ /* disable transport bus master and queueing of request */
-+ hw_write_20kx(hw, TRNCTL, 0x00);
-+
-+ /* disable pll */
-+ data = hw_read_20kx(hw, PLLCTL);
-+ hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12))));
-+
-+ /* TODO: Disable interrupt and so on... */
-+ if (hw->irq >= 0)
-+ synchronize_irq(hw->irq);
-+ return 0;
-+}
-+
-+static int hw_card_shutdown(struct hw *hw)
-+{
-+ if (hw->irq >= 0)
-+ free_irq(hw->irq, hw);
-+
-+ hw->irq = -1;
-+
-+ if (hw->mem_base)
-+ iounmap((void *)hw->mem_base);
-+
-+ hw->mem_base = (unsigned long)NULL;
-+
-+ if (hw->io_base)
-+ pci_release_regions(hw->pci);
-+
-+ hw->io_base = 0;
-+
-+ pci_disable_device(hw->pci);
-+
-+ return 0;
-+}
-+
-+static int hw_card_init(struct hw *hw, struct card_conf *info)
-+{
-+ int err;
-+ unsigned int gctl;
-+ u32 data;
-+ struct dac_conf dac_info = {0};
-+ struct adc_conf adc_info = {0};
-+ struct daio_conf daio_info = {0};
-+ struct trn_conf trn_info = {0};
-+
-+ /* Get PCI io port base address and do Hendrix switch if needed. */
-+ err = hw_card_start(hw);
-+ if (err)
-+ return err;
-+
-+ /* PLL init */
-+ err = hw_pll_init(hw, info->rsr);
-+ if (err < 0)
-+ return err;
-+
-+ /* kick off auto-init */
-+ err = hw_auto_init(hw);
-+ if (err < 0)
-+ return err;
-+
-+ /* Enable audio ring */
-+ gctl = hw_read_20kx(hw, GCTL);
-+ set_field(&gctl, GCTL_EAC, 1);
-+ set_field(&gctl, GCTL_DBP, 1);
-+ set_field(&gctl, GCTL_TBP, 1);
-+ set_field(&gctl, GCTL_FBP, 1);
-+ set_field(&gctl, GCTL_ET, 1);
-+ hw_write_20kx(hw, GCTL, gctl);
-+ mdelay(10);
-+
-+ /* Reset all global pending interrupts */
-+ hw_write_20kx(hw, GIE, 0);
-+ /* Reset all SRC pending interrupts */
-+ hw_write_20kx(hw, SRCIP, 0);
-+ mdelay(30);
-+
-+ /* Detect the card ID and configure GPIO accordingly. */
-+ switch (hw->model) {
-+ case CTSB055X:
-+ hw_write_20kx(hw, GPIOCTL, 0x13fe);
-+ break;
-+ case CTSB073X:
-+ hw_write_20kx(hw, GPIOCTL, 0x00e6);
-+ break;
-+ case CTUAA:
-+ hw_write_20kx(hw, GPIOCTL, 0x00c2);
-+ break;
-+ default:
-+ hw_write_20kx(hw, GPIOCTL, 0x01e6);
-+ break;
-+ }
-+
-+ trn_info.vm_pgt_phys = info->vm_pgt_phys;
-+ err = hw_trn_init(hw, &trn_info);
-+ if (err < 0)
-+ return err;
-+
-+ daio_info.msr = info->msr;
-+ err = hw_daio_init(hw, &daio_info);
-+ if (err < 0)
-+ return err;
-+
-+ dac_info.msr = info->msr;
-+ err = hw_dac_init(hw, &dac_info);
-+ if (err < 0)
-+ return err;
-+
-+ adc_info.msr = info->msr;
-+ adc_info.input = ADC_LINEIN;
-+ adc_info.mic20db = 0;
-+ err = hw_adc_init(hw, &adc_info);
-+ if (err < 0)
-+ return err;
-+
-+ data = hw_read_20kx(hw, SRCMCTL);
-+ data |= 0x1; /* Enables input from the audio ring */
-+ hw_write_20kx(hw, SRCMCTL, data);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int hw_suspend(struct hw *hw, pm_message_t state)
-+{
-+ struct pci_dev *pci = hw->pci;
-+
-+ hw_card_stop(hw);
-+
-+ if (hw->model == CTUAA) {
-+ /* Switch to UAA config space. */
-+ pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
-+ }
-+
-+ pci_disable_device(pci);
-+ pci_save_state(pci);
-+ pci_set_power_state(pci, pci_choose_state(pci, state));
-+
-+ return 0;
-+}
-+
-+static int hw_resume(struct hw *hw, struct card_conf *info)
-+{
-+ struct pci_dev *pci = hw->pci;
-+
-+ pci_set_power_state(pci, PCI_D0);
-+ pci_restore_state(pci);
-+
-+ /* Re-initialize card hardware. */
-+ return hw_card_init(hw, info);
-+}
-+#endif
-+
-+static u32 hw_read_20kx(struct hw *hw, u32 reg)
-+{
-+ u32 value;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(
-+ &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
-+ outl(reg, hw->io_base + 0x0);
-+ value = inl(hw->io_base + 0x4);
-+ spin_unlock_irqrestore(
-+ &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
-+
-+ return value;
-+}
-+
-+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(
-+ &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
-+ outl(reg, hw->io_base + 0x0);
-+ outl(data, hw->io_base + 0x4);
-+ spin_unlock_irqrestore(
-+ &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
-+
-+}
-+
-+static u32 hw_read_pci(struct hw *hw, u32 reg)
-+{
-+ u32 value;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(
-+ &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
-+ outl(reg, hw->io_base + 0x10);
-+ value = inl(hw->io_base + 0x14);
-+ spin_unlock_irqrestore(
-+ &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
-+
-+ return value;
-+}
-+
-+static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(
-+ &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
-+ outl(reg, hw->io_base + 0x10);
-+ outl(data, hw->io_base + 0x14);
-+ spin_unlock_irqrestore(
-+ &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
-+}
-+
-+static struct hw ct20k1_preset __devinitdata = {
-+ .irq = -1,
-+
-+ .card_init = hw_card_init,
-+ .card_stop = hw_card_stop,
-+ .pll_init = hw_pll_init,
-+ .is_adc_source_selected = hw_is_adc_input_selected,
-+ .select_adc_source = hw_adc_input_select,
-+ .have_digit_io_switch = hw_have_digit_io_switch,
-+#ifdef CONFIG_PM
-+ .suspend = hw_suspend,
-+ .resume = hw_resume,
-+#endif
-+
-+ .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
-+ .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
-+ .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
-+ .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
-+ .src_set_state = src_set_state,
-+ .src_set_bm = src_set_bm,
-+ .src_set_rsr = src_set_rsr,
-+ .src_set_sf = src_set_sf,
-+ .src_set_wr = src_set_wr,
-+ .src_set_pm = src_set_pm,
-+ .src_set_rom = src_set_rom,
-+ .src_set_vo = src_set_vo,
-+ .src_set_st = src_set_st,
-+ .src_set_ie = src_set_ie,
-+ .src_set_ilsz = src_set_ilsz,
-+ .src_set_bp = src_set_bp,
-+ .src_set_cisz = src_set_cisz,
-+ .src_set_ca = src_set_ca,
-+ .src_set_sa = src_set_sa,
-+ .src_set_la = src_set_la,
-+ .src_set_pitch = src_set_pitch,
-+ .src_set_dirty = src_set_dirty,
-+ .src_set_clear_zbufs = src_set_clear_zbufs,
-+ .src_set_dirty_all = src_set_dirty_all,
-+ .src_commit_write = src_commit_write,
-+ .src_get_ca = src_get_ca,
-+ .src_get_dirty = src_get_dirty,
-+ .src_dirty_conj_mask = src_dirty_conj_mask,
-+ .src_mgr_enbs_src = src_mgr_enbs_src,
-+ .src_mgr_enb_src = src_mgr_enb_src,
-+ .src_mgr_dsb_src = src_mgr_dsb_src,
-+ .src_mgr_commit_write = src_mgr_commit_write,
-+
-+ .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
-+ .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
-+ .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
-+ .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
-+ .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
-+ .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
-+ .srcimp_mgr_commit_write = srcimp_mgr_commit_write,
-+
-+ .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
-+ .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
-+ .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
-+ .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
-+ .amixer_set_mode = amixer_set_mode,
-+ .amixer_set_iv = amixer_set_iv,
-+ .amixer_set_x = amixer_set_x,
-+ .amixer_set_y = amixer_set_y,
-+ .amixer_set_sadr = amixer_set_sadr,
-+ .amixer_set_se = amixer_set_se,
-+ .amixer_set_dirty = amixer_set_dirty,
-+ .amixer_set_dirty_all = amixer_set_dirty_all,
-+ .amixer_commit_write = amixer_commit_write,
-+ .amixer_get_y = amixer_get_y,
-+ .amixer_get_dirty = amixer_get_dirty,
-+
-+ .dai_get_ctrl_blk = dai_get_ctrl_blk,
-+ .dai_put_ctrl_blk = dai_put_ctrl_blk,
-+ .dai_srt_set_srco = dai_srt_set_srcr,
-+ .dai_srt_set_srcm = dai_srt_set_srcl,
-+ .dai_srt_set_rsr = dai_srt_set_rsr,
-+ .dai_srt_set_drat = dai_srt_set_drat,
-+ .dai_srt_set_ec = dai_srt_set_ec,
-+ .dai_srt_set_et = dai_srt_set_et,
-+ .dai_commit_write = dai_commit_write,
-+
-+ .dao_get_ctrl_blk = dao_get_ctrl_blk,
-+ .dao_put_ctrl_blk = dao_put_ctrl_blk,
-+ .dao_set_spos = dao_set_spos,
-+ .dao_commit_write = dao_commit_write,
-+ .dao_get_spos = dao_get_spos,
-+
-+ .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
-+ .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
-+ .daio_mgr_enb_dai = daio_mgr_enb_dai,
-+ .daio_mgr_dsb_dai = daio_mgr_dsb_dai,
-+ .daio_mgr_enb_dao = daio_mgr_enb_dao,
-+ .daio_mgr_dsb_dao = daio_mgr_dsb_dao,
-+ .daio_mgr_dao_init = daio_mgr_dao_init,
-+ .daio_mgr_set_imaparc = daio_mgr_set_imaparc,
-+ .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
-+ .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
-+ .daio_mgr_commit_write = daio_mgr_commit_write,
-+
-+ .set_timer_irq = set_timer_irq,
-+ .set_timer_tick = set_timer_tick,
-+ .get_wc = get_wc,
-+};
-+
-+int __devinit create_20k1_hw_obj(struct hw **rhw)
-+{
-+ struct hw20k1 *hw20k1;
-+
-+ *rhw = NULL;
-+ hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
-+ if (!hw20k1)
-+ return -ENOMEM;
-+
-+ spin_lock_init(&hw20k1->reg_20k1_lock);
-+ spin_lock_init(&hw20k1->reg_pci_lock);
-+
-+ hw20k1->hw = ct20k1_preset;
-+
-+ *rhw = &hw20k1->hw;
-+
-+ return 0;
-+}
-+
-+int destroy_20k1_hw_obj(struct hw *hw)
-+{
-+ if (hw->io_base)
-+ hw_card_shutdown(hw);
-+
-+ kfree(container_of(hw, struct hw20k1, hw));
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/cthw20k1.h
-@@ -0,0 +1,26 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File cthw20k1.h
-+ *
-+ * @Brief
-+ * This file contains the definition of hardware access methord.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 13 2008
-+ *
-+ */
-+
-+#ifndef CTHW20K1_H
-+#define CTHW20K1_H
-+
-+#include "cthardware.h"
-+
-+int create_20k1_hw_obj(struct hw **rhw);
-+int destroy_20k1_hw_obj(struct hw *hw);
-+
-+#endif /* CTHW20K1_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/cthw20k2.c
-@@ -0,0 +1,2219 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File cthw20k2.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of hardware access methord for 20k2.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 14 2008
-+ *
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/io.h>
-+#include <linux/string.h>
-+#include <linux/kernel.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include "cthw20k2.h"
-+#include "ct20k2reg.h"
-+
-+#if BITS_PER_LONG == 32
-+#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-+#else
-+#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-+#endif
-+
-+struct hw20k2 {
-+ struct hw hw;
-+ /* for i2c */
-+ unsigned char dev_id;
-+ unsigned char addr_size;
-+ unsigned char data_size;
-+};
-+
-+static u32 hw_read_20kx(struct hw *hw, u32 reg);
-+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
-+
-+/*
-+ * Type definition block.
-+ * The layout of control structures can be directly applied on 20k2 chip.
-+ */
-+
-+/*
-+ * SRC control block definitions.
-+ */
-+
-+/* SRC resource control block */
-+#define SRCCTL_STATE 0x00000007
-+#define SRCCTL_BM 0x00000008
-+#define SRCCTL_RSR 0x00000030
-+#define SRCCTL_SF 0x000001C0
-+#define SRCCTL_WR 0x00000200
-+#define SRCCTL_PM 0x00000400
-+#define SRCCTL_ROM 0x00001800
-+#define SRCCTL_VO 0x00002000
-+#define SRCCTL_ST 0x00004000
-+#define SRCCTL_IE 0x00008000
-+#define SRCCTL_ILSZ 0x000F0000
-+#define SRCCTL_BP 0x00100000
-+
-+#define SRCCCR_CISZ 0x000007FF
-+#define SRCCCR_CWA 0x001FF800
-+#define SRCCCR_D 0x00200000
-+#define SRCCCR_RS 0x01C00000
-+#define SRCCCR_NAL 0x3E000000
-+#define SRCCCR_RA 0xC0000000
-+
-+#define SRCCA_CA 0x0FFFFFFF
-+#define SRCCA_RS 0xE0000000
-+
-+#define SRCSA_SA 0x0FFFFFFF
-+
-+#define SRCLA_LA 0x0FFFFFFF
-+
-+/* Mixer Parameter Ring ram Low and Hight register.
-+ * Fixed-point value in 8.24 format for parameter channel */
-+#define MPRLH_PITCH 0xFFFFFFFF
-+
-+/* SRC resource register dirty flags */
-+union src_dirty {
-+ struct {
-+ u16 ctl:1;
-+ u16 ccr:1;
-+ u16 sa:1;
-+ u16 la:1;
-+ u16 ca:1;
-+ u16 mpr:1;
-+ u16 czbfs:1; /* Clear Z-Buffers */
-+ u16 rsv:9;
-+ } bf;
-+ u16 data;
-+};
-+
-+struct src_rsc_ctrl_blk {
-+ unsigned int ctl;
-+ unsigned int ccr;
-+ unsigned int ca;
-+ unsigned int sa;
-+ unsigned int la;
-+ unsigned int mpr;
-+ union src_dirty dirty;
-+};
-+
-+/* SRC manager control block */
-+union src_mgr_dirty {
-+ struct {
-+ u16 enb0:1;
-+ u16 enb1:1;
-+ u16 enb2:1;
-+ u16 enb3:1;
-+ u16 enb4:1;
-+ u16 enb5:1;
-+ u16 enb6:1;
-+ u16 enb7:1;
-+ u16 enbsa:1;
-+ u16 rsv:7;
-+ } bf;
-+ u16 data;
-+};
-+
-+struct src_mgr_ctrl_blk {
-+ unsigned int enbsa;
-+ unsigned int enb[8];
-+ union src_mgr_dirty dirty;
-+};
-+
-+/* SRCIMP manager control block */
-+#define SRCAIM_ARC 0x00000FFF
-+#define SRCAIM_NXT 0x00FF0000
-+#define SRCAIM_SRC 0xFF000000
-+
-+struct srcimap {
-+ unsigned int srcaim;
-+ unsigned int idx;
-+};
-+
-+/* SRCIMP manager register dirty flags */
-+union srcimp_mgr_dirty {
-+ struct {
-+ u16 srcimap:1;
-+ u16 rsv:15;
-+ } bf;
-+ u16 data;
-+};
-+
-+struct srcimp_mgr_ctrl_blk {
-+ struct srcimap srcimap;
-+ union srcimp_mgr_dirty dirty;
-+};
-+
-+/*
-+ * Function implementation block.
-+ */
-+
-+static int src_get_rsc_ctrl_blk(void **rblk)
-+{
-+ struct src_rsc_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int src_put_rsc_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+static int src_set_state(void *blk, unsigned int state)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_STATE, state);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_bm(void *blk, unsigned int bm)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_BM, bm);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_rsr(void *blk, unsigned int rsr)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_RSR, rsr);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_sf(void *blk, unsigned int sf)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_SF, sf);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_wr(void *blk, unsigned int wr)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_WR, wr);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_pm(void *blk, unsigned int pm)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_PM, pm);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_rom(void *blk, unsigned int rom)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_ROM, rom);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_vo(void *blk, unsigned int vo)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_VO, vo);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_st(void *blk, unsigned int st)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_ST, st);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_ie(void *blk, unsigned int ie)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_IE, ie);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_ilsz(void *blk, unsigned int ilsz)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_bp(void *blk, unsigned int bp)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ctl, SRCCTL_BP, bp);
-+ ctl->dirty.bf.ctl = 1;
-+ return 0;
-+}
-+
-+static int src_set_cisz(void *blk, unsigned int cisz)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
-+ ctl->dirty.bf.ccr = 1;
-+ return 0;
-+}
-+
-+static int src_set_ca(void *blk, unsigned int ca)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->ca, SRCCA_CA, ca);
-+ ctl->dirty.bf.ca = 1;
-+ return 0;
-+}
-+
-+static int src_set_sa(void *blk, unsigned int sa)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->sa, SRCSA_SA, sa);
-+ ctl->dirty.bf.sa = 1;
-+ return 0;
-+}
-+
-+static int src_set_la(void *blk, unsigned int la)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->la, SRCLA_LA, la);
-+ ctl->dirty.bf.la = 1;
-+ return 0;
-+}
-+
-+static int src_set_pitch(void *blk, unsigned int pitch)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->mpr, MPRLH_PITCH, pitch);
-+ ctl->dirty.bf.mpr = 1;
-+ return 0;
-+}
-+
-+static int src_set_clear_zbufs(void *blk, unsigned int clear)
-+{
-+ ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
-+ return 0;
-+}
-+
-+static int src_set_dirty(void *blk, unsigned int flags)
-+{
-+ ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
-+ return 0;
-+}
-+
-+static int src_set_dirty_all(void *blk)
-+{
-+ ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
-+ return 0;
-+}
-+
-+#define AR_SLOT_SIZE 4096
-+#define AR_SLOT_BLOCK_SIZE 16
-+#define AR_PTS_PITCH 6
-+#define AR_PARAM_SRC_OFFSET 0x60
-+
-+static unsigned int src_param_pitch_mixer(unsigned int src_idx)
-+{
-+ return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
-+ - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
-+
-+}
-+
-+static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+ int i;
-+
-+ if (ctl->dirty.bf.czbfs) {
-+ /* Clear Z-Buffer registers */
-+ for (i = 0; i < 8; i++)
-+ hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0);
-+
-+ for (i = 0; i < 4; i++)
-+ hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0);
-+
-+ for (i = 0; i < 8; i++)
-+ hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0);
-+
-+ ctl->dirty.bf.czbfs = 0;
-+ }
-+ if (ctl->dirty.bf.mpr) {
-+ /* Take the parameter mixer resource in the same group as that
-+ * the idx src is in for simplicity. Unlike src, all conjugate
-+ * parameter mixer resources must be programmed for
-+ * corresponding conjugate src resources. */
-+ unsigned int pm_idx = src_param_pitch_mixer(idx);
-+ hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr);
-+ hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3);
-+ hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0);
-+ ctl->dirty.bf.mpr = 0;
-+ }
-+ if (ctl->dirty.bf.sa) {
-+ hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa);
-+ ctl->dirty.bf.sa = 0;
-+ }
-+ if (ctl->dirty.bf.la) {
-+ hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la);
-+ ctl->dirty.bf.la = 0;
-+ }
-+ if (ctl->dirty.bf.ca) {
-+ hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca);
-+ ctl->dirty.bf.ca = 0;
-+ }
-+
-+ /* Write srccf register */
-+ hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0);
-+
-+ if (ctl->dirty.bf.ccr) {
-+ hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr);
-+ ctl->dirty.bf.ccr = 0;
-+ }
-+ if (ctl->dirty.bf.ctl) {
-+ hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl);
-+ ctl->dirty.bf.ctl = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct src_rsc_ctrl_blk *ctl = blk;
-+
-+ ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100);
-+ ctl->dirty.bf.ca = 0;
-+
-+ return get_field(ctl->ca, SRCCA_CA);
-+}
-+
-+static unsigned int src_get_dirty(void *blk)
-+{
-+ return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
-+}
-+
-+static unsigned int src_dirty_conj_mask(void)
-+{
-+ return 0x20;
-+}
-+
-+static int src_mgr_enbs_src(void *blk, unsigned int idx)
-+{
-+ ((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4));
-+ ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
-+ ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
-+ return 0;
-+}
-+
-+static int src_mgr_enb_src(void *blk, unsigned int idx)
-+{
-+ ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
-+ ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
-+ return 0;
-+}
-+
-+static int src_mgr_dsb_src(void *blk, unsigned int idx)
-+{
-+ ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
-+ ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
-+ return 0;
-+}
-+
-+static int src_mgr_commit_write(struct hw *hw, void *blk)
-+{
-+ struct src_mgr_ctrl_blk *ctl = blk;
-+ int i;
-+ unsigned int ret;
-+
-+ if (ctl->dirty.bf.enbsa) {
-+ do {
-+ ret = hw_read_20kx(hw, SRC_ENBSTAT);
-+ } while (ret & 0x1);
-+ hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa);
-+ ctl->dirty.bf.enbsa = 0;
-+ }
-+ for (i = 0; i < 8; i++) {
-+ if ((ctl->dirty.data & (0x1 << i))) {
-+ hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]);
-+ ctl->dirty.data &= ~(0x1 << i);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int src_mgr_get_ctrl_blk(void **rblk)
-+{
-+ struct src_mgr_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int src_mgr_put_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+static int srcimp_mgr_get_ctrl_blk(void **rblk)
-+{
-+ struct srcimp_mgr_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int srcimp_mgr_put_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
-+ ctl->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
-+{
-+ ((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr;
-+ ((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1;
-+ return 0;
-+}
-+
-+static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
-+{
-+ struct srcimp_mgr_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.srcimap) {
-+ hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100,
-+ ctl->srcimap.srcaim);
-+ ctl->dirty.bf.srcimap = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * AMIXER control block definitions.
-+ */
-+
-+#define AMOPLO_M 0x00000003
-+#define AMOPLO_IV 0x00000004
-+#define AMOPLO_X 0x0003FFF0
-+#define AMOPLO_Y 0xFFFC0000
-+
-+#define AMOPHI_SADR 0x000000FF
-+#define AMOPHI_SE 0x80000000
-+
-+/* AMIXER resource register dirty flags */
-+union amixer_dirty {
-+ struct {
-+ u16 amoplo:1;
-+ u16 amophi:1;
-+ u16 rsv:14;
-+ } bf;
-+ u16 data;
-+};
-+
-+/* AMIXER resource control block */
-+struct amixer_rsc_ctrl_blk {
-+ unsigned int amoplo;
-+ unsigned int amophi;
-+ union amixer_dirty dirty;
-+};
-+
-+static int amixer_set_mode(void *blk, unsigned int mode)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_M, mode);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_iv(void *blk, unsigned int iv)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_IV, iv);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_x(void *blk, unsigned int x)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_X, x);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_y(void *blk, unsigned int y)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amoplo, AMOPLO_Y, y);
-+ ctl->dirty.bf.amoplo = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_sadr(void *blk, unsigned int sadr)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amophi, AMOPHI_SADR, sadr);
-+ ctl->dirty.bf.amophi = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_se(void *blk, unsigned int se)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->amophi, AMOPHI_SE, se);
-+ ctl->dirty.bf.amophi = 1;
-+ return 0;
-+}
-+
-+static int amixer_set_dirty(void *blk, unsigned int flags)
-+{
-+ ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
-+ return 0;
-+}
-+
-+static int amixer_set_dirty_all(void *blk)
-+{
-+ ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
-+ return 0;
-+}
-+
-+static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
-+ hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo);
-+ ctl->dirty.bf.amoplo = 0;
-+ hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi);
-+ ctl->dirty.bf.amophi = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int amixer_get_y(void *blk)
-+{
-+ struct amixer_rsc_ctrl_blk *ctl = blk;
-+
-+ return get_field(ctl->amoplo, AMOPLO_Y);
-+}
-+
-+static unsigned int amixer_get_dirty(void *blk)
-+{
-+ return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
-+}
-+
-+static int amixer_rsc_get_ctrl_blk(void **rblk)
-+{
-+ struct amixer_rsc_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int amixer_rsc_put_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+static int amixer_mgr_get_ctrl_blk(void **rblk)
-+{
-+ *rblk = NULL;
-+
-+ return 0;
-+}
-+
-+static int amixer_mgr_put_ctrl_blk(void *blk)
-+{
-+ return 0;
-+}
-+
-+/*
-+ * DAIO control block definitions.
-+ */
-+
-+/* Receiver Sample Rate Tracker Control register */
-+#define SRTCTL_SRCO 0x000000FF
-+#define SRTCTL_SRCM 0x0000FF00
-+#define SRTCTL_RSR 0x00030000
-+#define SRTCTL_DRAT 0x00300000
-+#define SRTCTL_EC 0x01000000
-+#define SRTCTL_ET 0x10000000
-+
-+/* DAIO Receiver register dirty flags */
-+union dai_dirty {
-+ struct {
-+ u16 srt:1;
-+ u16 rsv:15;
-+ } bf;
-+ u16 data;
-+};
-+
-+/* DAIO Receiver control block */
-+struct dai_ctrl_blk {
-+ unsigned int srt;
-+ union dai_dirty dirty;
-+};
-+
-+/* Audio Input Mapper RAM */
-+#define AIM_ARC 0x00000FFF
-+#define AIM_NXT 0x007F0000
-+
-+struct daoimap {
-+ unsigned int aim;
-+ unsigned int idx;
-+};
-+
-+/* Audio Transmitter Control and Status register */
-+#define ATXCTL_EN 0x00000001
-+#define ATXCTL_MODE 0x00000010
-+#define ATXCTL_CD 0x00000020
-+#define ATXCTL_RAW 0x00000100
-+#define ATXCTL_MT 0x00000200
-+#define ATXCTL_NUC 0x00003000
-+#define ATXCTL_BEN 0x00010000
-+#define ATXCTL_BMUX 0x00700000
-+#define ATXCTL_B24 0x01000000
-+#define ATXCTL_CPF 0x02000000
-+#define ATXCTL_RIV 0x10000000
-+#define ATXCTL_LIV 0x20000000
-+#define ATXCTL_RSAT 0x40000000
-+#define ATXCTL_LSAT 0x80000000
-+
-+/* XDIF Transmitter register dirty flags */
-+union dao_dirty {
-+ struct {
-+ u16 atxcsl:1;
-+ u16 rsv:15;
-+ } bf;
-+ u16 data;
-+};
-+
-+/* XDIF Transmitter control block */
-+struct dao_ctrl_blk {
-+ /* XDIF Transmitter Channel Status Low Register */
-+ unsigned int atxcsl;
-+ union dao_dirty dirty;
-+};
-+
-+/* Audio Receiver Control register */
-+#define ARXCTL_EN 0x00000001
-+
-+/* DAIO manager register dirty flags */
-+union daio_mgr_dirty {
-+ struct {
-+ u32 atxctl:8;
-+ u32 arxctl:8;
-+ u32 daoimap:1;
-+ u32 rsv:15;
-+ } bf;
-+ u32 data;
-+};
-+
-+/* DAIO manager control block */
-+struct daio_mgr_ctrl_blk {
-+ struct daoimap daoimap;
-+ unsigned int txctl[8];
-+ unsigned int rxctl[8];
-+ union daio_mgr_dirty dirty;
-+};
-+
-+static int dai_srt_set_srco(void *blk, unsigned int src)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srt, SRTCTL_SRCO, src);
-+ ctl->dirty.bf.srt = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_srcm(void *blk, unsigned int src)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srt, SRTCTL_SRCM, src);
-+ ctl->dirty.bf.srt = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_rsr(void *blk, unsigned int rsr)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srt, SRTCTL_RSR, rsr);
-+ ctl->dirty.bf.srt = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_drat(void *blk, unsigned int drat)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srt, SRTCTL_DRAT, drat);
-+ ctl->dirty.bf.srt = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_ec(void *blk, unsigned int ec)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0);
-+ ctl->dirty.bf.srt = 1;
-+ return 0;
-+}
-+
-+static int dai_srt_set_et(void *blk, unsigned int et)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0);
-+ ctl->dirty.bf.srt = 1;
-+ return 0;
-+}
-+
-+static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct dai_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.srt) {
-+ hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt);
-+ ctl->dirty.bf.srt = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int dai_get_ctrl_blk(void **rblk)
-+{
-+ struct dai_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int dai_put_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+static int dao_set_spos(void *blk, unsigned int spos)
-+{
-+ ((struct dao_ctrl_blk *)blk)->atxcsl = spos;
-+ ((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1;
-+ return 0;
-+}
-+
-+static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
-+{
-+ struct dao_ctrl_blk *ctl = blk;
-+
-+ if (ctl->dirty.bf.atxcsl) {
-+ if (idx < 4) {
-+ /* S/PDIF SPOSx */
-+ hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
-+ ctl->atxcsl);
-+ }
-+ ctl->dirty.bf.atxcsl = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int dao_get_spos(void *blk, unsigned int *spos)
-+{
-+ *spos = ((struct dao_ctrl_blk *)blk)->atxcsl;
-+ return 0;
-+}
-+
-+static int dao_get_ctrl_blk(void **rblk)
-+{
-+ struct dao_ctrl_blk *blk;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int dao_put_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_enb_dai(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->rxctl[idx], ARXCTL_EN, 1);
-+ ctl->dirty.bf.arxctl |= (0x1 << idx);
-+ return 0;
-+}
-+
-+static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->rxctl[idx], ARXCTL_EN, 0);
-+
-+ ctl->dirty.bf.arxctl |= (0x1 << idx);
-+ return 0;
-+}
-+
-+static int daio_mgr_enb_dao(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->txctl[idx], ATXCTL_EN, 1);
-+ ctl->dirty.bf.atxctl |= (0x1 << idx);
-+ return 0;
-+}
-+
-+static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->txctl[idx], ATXCTL_EN, 0);
-+ ctl->dirty.bf.atxctl |= (0x1 << idx);
-+ return 0;
-+}
-+
-+static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ if (idx < 4) {
-+ /* S/PDIF output */
-+ switch ((conf & 0x7)) {
-+ case 1:
-+ set_field(&ctl->txctl[idx], ATXCTL_NUC, 0);
-+ break;
-+ case 2:
-+ set_field(&ctl->txctl[idx], ATXCTL_NUC, 1);
-+ break;
-+ case 4:
-+ set_field(&ctl->txctl[idx], ATXCTL_NUC, 2);
-+ break;
-+ case 8:
-+ set_field(&ctl->txctl[idx], ATXCTL_NUC, 3);
-+ break;
-+ default:
-+ break;
-+ }
-+ /* CDIF */
-+ set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7)));
-+ /* Non-audio */
-+ set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1);
-+ /* Non-audio */
-+ set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1);
-+ set_field(&ctl->txctl[idx], ATXCTL_RAW,
-+ ((conf >> 3) & 0x1) ? 0 : 0);
-+ ctl->dirty.bf.atxctl |= (0x1 << idx);
-+ } else {
-+ /* I2S output */
-+ /*idx %= 4; */
-+ }
-+ return 0;
-+}
-+
-+static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->daoimap.aim, AIM_ARC, slot);
-+ ctl->dirty.bf.daoimap = 1;
-+ return 0;
-+}
-+
-+static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+
-+ set_field(&ctl->daoimap.aim, AIM_NXT, next);
-+ ctl->dirty.bf.daoimap = 1;
-+ return 0;
-+}
-+
-+static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
-+{
-+ ((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr;
-+ ((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1;
-+ return 0;
-+}
-+
-+static int daio_mgr_commit_write(struct hw *hw, void *blk)
-+{
-+ struct daio_mgr_ctrl_blk *ctl = blk;
-+ unsigned int data;
-+ int i;
-+
-+ for (i = 0; i < 8; i++) {
-+ if ((ctl->dirty.bf.atxctl & (0x1 << i))) {
-+ data = ctl->txctl[i];
-+ hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
-+ ctl->dirty.bf.atxctl &= ~(0x1 << i);
-+ mdelay(1);
-+ }
-+ if ((ctl->dirty.bf.arxctl & (0x1 << i))) {
-+ data = ctl->rxctl[i];
-+ hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
-+ ctl->dirty.bf.arxctl &= ~(0x1 << i);
-+ mdelay(1);
-+ }
-+ }
-+ if (ctl->dirty.bf.daoimap) {
-+ hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4,
-+ ctl->daoimap.aim);
-+ ctl->dirty.bf.daoimap = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
-+{
-+ struct daio_mgr_ctrl_blk *blk;
-+ int i;
-+
-+ *rblk = NULL;
-+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return -ENOMEM;
-+
-+ for (i = 0; i < 8; i++) {
-+ blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i));
-+ blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i));
-+ }
-+
-+ *rblk = blk;
-+
-+ return 0;
-+}
-+
-+static int daio_mgr_put_ctrl_blk(void *blk)
-+{
-+ kfree(blk);
-+
-+ return 0;
-+}
-+
-+/* Timer interrupt */
-+static int set_timer_irq(struct hw *hw, int enable)
-+{
-+ hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
-+ return 0;
-+}
-+
-+static int set_timer_tick(struct hw *hw, unsigned int ticks)
-+{
-+ if (ticks)
-+ ticks |= TIMR_IE | TIMR_IP;
-+ hw_write_20kx(hw, TIMR, ticks);
-+ return 0;
-+}
-+
-+static unsigned int get_wc(struct hw *hw)
-+{
-+ return hw_read_20kx(hw, WC);
-+}
-+
-+/* Card hardware initialization block */
-+struct dac_conf {
-+ unsigned int msr; /* master sample rate in rsrs */
-+};
-+
-+struct adc_conf {
-+ unsigned int msr; /* master sample rate in rsrs */
-+ unsigned char input; /* the input source of ADC */
-+ unsigned char mic20db; /* boost mic by 20db if input is microphone */
-+};
-+
-+struct daio_conf {
-+ unsigned int msr; /* master sample rate in rsrs */
-+};
-+
-+struct trn_conf {
-+ unsigned long vm_pgt_phys;
-+};
-+
-+static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
-+{
-+ u32 data;
-+ int i;
-+
-+ /* Program I2S with proper sample rate and enable the correct I2S
-+ * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */
-+ if (1 == info->msr) {
-+ hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101);
-+ hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
-+ hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
-+ } else if (2 == info->msr) {
-+ hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
-+ /* Specify all playing 96khz
-+ * EA [0] - Enabled
-+ * RTA [4:5] - 96kHz
-+ * EB [8] - Enabled
-+ * RTB [12:13] - 96kHz
-+ * EC [16] - Enabled
-+ * RTC [20:21] - 96kHz
-+ * ED [24] - Enabled
-+ * RTD [28:29] - 96kHz */
-+ hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
-+ hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
-+ } else {
-+ printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < 8; i++) {
-+ if (i <= 3) {
-+ /* 1st 3 channels are SPDIFs (SB0960) */
-+ if (i == 3)
-+ data = 0x1001001;
-+ else
-+ data = 0x1000001;
-+
-+ hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
-+ hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
-+
-+ /* Initialize the SPDIF Out Channel status registers.
-+ * The value specified here is based on the typical
-+ * values provided in the specification, namely: Clock
-+ * Accuracy of 1000ppm, Sample Rate of 48KHz,
-+ * unspecified source number, Generation status = 1,
-+ * Category code = 0x12 (Digital Signal Mixer),
-+ * Mode = 0, Emph = 0, Copy Permitted, AN = 0
-+ * (indicating that we're transmitting digital audio,
-+ * and the Professional Use bit is 0. */
-+
-+ hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i),
-+ 0x02109204); /* Default to 48kHz */
-+
-+ hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
-+ } else {
-+ /* Next 5 channels are I2S (SB0960) */
-+ data = 0x11;
-+ hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
-+ if (2 == info->msr) {
-+ /* Four channels per sample period */
-+ data |= 0x1000;
-+ }
-+ hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* TRANSPORT operations */
-+static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
-+{
-+ u32 vmctl, data;
-+ u32 ptp_phys_low, ptp_phys_high;
-+ int i;
-+
-+ /* Set up device page table */
-+ if ((~0UL) == info->vm_pgt_phys) {
-+ printk(KERN_ALERT "ctxfi: "
-+ "Wrong device page table page address!!!\n");
-+ return -1;
-+ }
-+
-+ vmctl = 0x80000C0F; /* 32-bit, 4k-size page */
-+ ptp_phys_low = (u32)info->vm_pgt_phys;
-+ ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
-+ if (sizeof(void *) == 8) /* 64bit address */
-+ vmctl |= (3 << 8);
-+ /* Write page table physical address to all PTPAL registers */
-+ for (i = 0; i < 64; i++) {
-+ hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low);
-+ hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high);
-+ }
-+ /* Enable virtual memory transfer */
-+ hw_write_20kx(hw, VMEM_CTL, vmctl);
-+ /* Enable transport bus master and queueing of request */
-+ hw_write_20kx(hw, TRANSPORT_CTL, 0x03);
-+ hw_write_20kx(hw, TRANSPORT_INT, 0x200c01);
-+ /* Enable transport ring */
-+ data = hw_read_20kx(hw, TRANSPORT_ENB);
-+ hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03));
-+
-+ return 0;
-+}
-+
-+/* Card initialization */
-+#define GCTL_AIE 0x00000001
-+#define GCTL_UAA 0x00000002
-+#define GCTL_DPC 0x00000004
-+#define GCTL_DBP 0x00000008
-+#define GCTL_ABP 0x00000010
-+#define GCTL_TBP 0x00000020
-+#define GCTL_SBP 0x00000040
-+#define GCTL_FBP 0x00000080
-+#define GCTL_ME 0x00000100
-+#define GCTL_AID 0x00001000
-+
-+#define PLLCTL_SRC 0x00000007
-+#define PLLCTL_SPE 0x00000008
-+#define PLLCTL_RD 0x000000F0
-+#define PLLCTL_FD 0x0001FF00
-+#define PLLCTL_OD 0x00060000
-+#define PLLCTL_B 0x00080000
-+#define PLLCTL_AS 0x00100000
-+#define PLLCTL_LF 0x03E00000
-+#define PLLCTL_SPS 0x1C000000
-+#define PLLCTL_AD 0x60000000
-+
-+#define PLLSTAT_CCS 0x00000007
-+#define PLLSTAT_SPL 0x00000008
-+#define PLLSTAT_CRD 0x000000F0
-+#define PLLSTAT_CFD 0x0001FF00
-+#define PLLSTAT_SL 0x00020000
-+#define PLLSTAT_FAS 0x00040000
-+#define PLLSTAT_B 0x00080000
-+#define PLLSTAT_PD 0x00100000
-+#define PLLSTAT_OCA 0x00200000
-+#define PLLSTAT_NCA 0x00400000
-+
-+static int hw_pll_init(struct hw *hw, unsigned int rsr)
-+{
-+ unsigned int pllenb;
-+ unsigned int pllctl;
-+ unsigned int pllstat;
-+ int i;
-+
-+ pllenb = 0xB;
-+ hw_write_20kx(hw, PLL_ENB, pllenb);
-+ pllctl = 0x20D00000;
-+ set_field(&pllctl, PLLCTL_FD, 16 - 4);
-+ hw_write_20kx(hw, PLL_CTL, pllctl);
-+ mdelay(40);
-+ pllctl = hw_read_20kx(hw, PLL_CTL);
-+ set_field(&pllctl, PLLCTL_B, 0);
-+ if (48000 == rsr) {
-+ set_field(&pllctl, PLLCTL_FD, 16 - 2);
-+ set_field(&pllctl, PLLCTL_RD, 1 - 1);
-+ } else { /* 44100 */
-+ set_field(&pllctl, PLLCTL_FD, 147 - 2);
-+ set_field(&pllctl, PLLCTL_RD, 10 - 1);
-+ }
-+ hw_write_20kx(hw, PLL_CTL, pllctl);
-+ mdelay(40);
-+ for (i = 0; i < 1000; i++) {
-+ pllstat = hw_read_20kx(hw, PLL_STAT);
-+ if (get_field(pllstat, PLLSTAT_PD))
-+ continue;
-+
-+ if (get_field(pllstat, PLLSTAT_B) !=
-+ get_field(pllctl, PLLCTL_B))
-+ continue;
-+
-+ if (get_field(pllstat, PLLSTAT_CCS) !=
-+ get_field(pllctl, PLLCTL_SRC))
-+ continue;
-+
-+ if (get_field(pllstat, PLLSTAT_CRD) !=
-+ get_field(pllctl, PLLCTL_RD))
-+ continue;
-+
-+ if (get_field(pllstat, PLLSTAT_CFD) !=
-+ get_field(pllctl, PLLCTL_FD))
-+ continue;
-+
-+ break;
-+ }
-+ if (i >= 1000) {
-+ printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
-+ return -EBUSY;
-+ }
-+
-+ return 0;
-+}
-+
-+static int hw_auto_init(struct hw *hw)
-+{
-+ unsigned int gctl;
-+ int i;
-+
-+ gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
-+ set_field(&gctl, GCTL_AIE, 0);
-+ hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
-+ set_field(&gctl, GCTL_AIE, 1);
-+ hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
-+ mdelay(10);
-+ for (i = 0; i < 400000; i++) {
-+ gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
-+ if (get_field(gctl, GCTL_AID))
-+ break;
-+ }
-+ if (!get_field(gctl, GCTL_AID)) {
-+ printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n");
-+ return -EBUSY;
-+ }
-+
-+ return 0;
-+}
-+
-+/* DAC operations */
-+
-+#define CS4382_MC1 0x1
-+#define CS4382_MC2 0x2
-+#define CS4382_MC3 0x3
-+#define CS4382_FC 0x4
-+#define CS4382_IC 0x5
-+#define CS4382_XC1 0x6
-+#define CS4382_VCA1 0x7
-+#define CS4382_VCB1 0x8
-+#define CS4382_XC2 0x9
-+#define CS4382_VCA2 0xA
-+#define CS4382_VCB2 0xB
-+#define CS4382_XC3 0xC
-+#define CS4382_VCA3 0xD
-+#define CS4382_VCB3 0xE
-+#define CS4382_XC4 0xF
-+#define CS4382_VCA4 0x10
-+#define CS4382_VCB4 0x11
-+#define CS4382_CREV 0x12
-+
-+/* I2C status */
-+#define STATE_LOCKED 0x00
-+#define STATE_UNLOCKED 0xAA
-+#define DATA_READY 0x800000 /* Used with I2C_IF_STATUS */
-+#define DATA_ABORT 0x10000 /* Used with I2C_IF_STATUS */
-+
-+#define I2C_STATUS_DCM 0x00000001
-+#define I2C_STATUS_BC 0x00000006
-+#define I2C_STATUS_APD 0x00000008
-+#define I2C_STATUS_AB 0x00010000
-+#define I2C_STATUS_DR 0x00800000
-+
-+#define I2C_ADDRESS_PTAD 0x0000FFFF
-+#define I2C_ADDRESS_SLAD 0x007F0000
-+
-+struct regs_cs4382 {
-+ u32 mode_control_1;
-+ u32 mode_control_2;
-+ u32 mode_control_3;
-+
-+ u32 filter_control;
-+ u32 invert_control;
-+
-+ u32 mix_control_P1;
-+ u32 vol_control_A1;
-+ u32 vol_control_B1;
-+
-+ u32 mix_control_P2;
-+ u32 vol_control_A2;
-+ u32 vol_control_B2;
-+
-+ u32 mix_control_P3;
-+ u32 vol_control_A3;
-+ u32 vol_control_B3;
-+
-+ u32 mix_control_P4;
-+ u32 vol_control_A4;
-+ u32 vol_control_B4;
-+};
-+
-+static int hw20k2_i2c_unlock_full_access(struct hw *hw)
-+{
-+ u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] = {0xB3, 0xD4};
-+
-+ /* Send keys for forced BIOS mode */
-+ hw_write_20kx(hw, I2C_IF_WLOCK,
-+ UnlockKeySequence_FLASH_FULLACCESS_MODE[0]);
-+ hw_write_20kx(hw, I2C_IF_WLOCK,
-+ UnlockKeySequence_FLASH_FULLACCESS_MODE[1]);
-+ /* Check whether the chip is unlocked */
-+ if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED)
-+ return 0;
-+
-+ return -1;
-+}
-+
-+static int hw20k2_i2c_lock_chip(struct hw *hw)
-+{
-+ /* Write twice */
-+ hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
-+ hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
-+ if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED)
-+ return 0;
-+
-+ return -1;
-+}
-+
-+static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size)
-+{
-+ struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
-+ int err;
-+ unsigned int i2c_status;
-+ unsigned int i2c_addr;
-+
-+ err = hw20k2_i2c_unlock_full_access(hw);
-+ if (err < 0)
-+ return err;
-+
-+ hw20k2->addr_size = addr_size;
-+ hw20k2->data_size = data_size;
-+ hw20k2->dev_id = dev_id;
-+
-+ i2c_addr = 0;
-+ set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id);
-+
-+ hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
-+
-+ i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
-+
-+ set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */
-+
-+ hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
-+
-+ return 0;
-+}
-+
-+static int hw20k2_i2c_uninit(struct hw *hw)
-+{
-+ unsigned int i2c_status;
-+ unsigned int i2c_addr;
-+
-+ i2c_addr = 0;
-+ set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */
-+
-+ hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
-+
-+ i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
-+
-+ set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */
-+
-+ hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
-+
-+ return hw20k2_i2c_lock_chip(hw);
-+}
-+
-+static int hw20k2_i2c_wait_data_ready(struct hw *hw)
-+{
-+ int i = 0x400000;
-+ unsigned int ret;
-+
-+ do {
-+ ret = hw_read_20kx(hw, I2C_IF_STATUS);
-+ } while ((!(ret & DATA_READY)) && --i);
-+
-+ return i;
-+}
-+
-+static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap)
-+{
-+ struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
-+ unsigned int i2c_status;
-+
-+ i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
-+ set_field(&i2c_status, I2C_STATUS_BC,
-+ (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size);
-+ hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
-+ if (!hw20k2_i2c_wait_data_ready(hw))
-+ return -1;
-+
-+ hw_write_20kx(hw, I2C_IF_WDATA, addr);
-+ if (!hw20k2_i2c_wait_data_ready(hw))
-+ return -1;
-+
-+ /* Force a read operation */
-+ hw_write_20kx(hw, I2C_IF_RDATA, 0);
-+ if (!hw20k2_i2c_wait_data_ready(hw))
-+ return -1;
-+
-+ *datap = hw_read_20kx(hw, I2C_IF_RDATA);
-+
-+ return 0;
-+}
-+
-+static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
-+{
-+ struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
-+ unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr;
-+ unsigned int i2c_status;
-+
-+ i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
-+
-+ set_field(&i2c_status, I2C_STATUS_BC,
-+ (4 == (hw20k2->addr_size + hw20k2->data_size)) ?
-+ 0 : (hw20k2->addr_size + hw20k2->data_size));
-+
-+ hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
-+ hw20k2_i2c_wait_data_ready(hw);
-+ /* Dummy write to trigger the write oprtation */
-+ hw_write_20kx(hw, I2C_IF_WDATA, 0);
-+ hw20k2_i2c_wait_data_ready(hw);
-+
-+ /* This is the real data */
-+ hw_write_20kx(hw, I2C_IF_WDATA, i2c_data);
-+ hw20k2_i2c_wait_data_ready(hw);
-+
-+ return 0;
-+}
-+
-+static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
-+{
-+ int err;
-+ u32 data;
-+ int i;
-+ struct regs_cs4382 cs_read = {0};
-+ struct regs_cs4382 cs_def = {
-+ 0x00000001, /* Mode Control 1 */
-+ 0x00000000, /* Mode Control 2 */
-+ 0x00000084, /* Mode Control 3 */
-+ 0x00000000, /* Filter Control */
-+ 0x00000000, /* Invert Control */
-+ 0x00000024, /* Mixing Control Pair 1 */
-+ 0x00000000, /* Vol Control A1 */
-+ 0x00000000, /* Vol Control B1 */
-+ 0x00000024, /* Mixing Control Pair 2 */
-+ 0x00000000, /* Vol Control A2 */
-+ 0x00000000, /* Vol Control B2 */
-+ 0x00000024, /* Mixing Control Pair 3 */
-+ 0x00000000, /* Vol Control A3 */
-+ 0x00000000, /* Vol Control B3 */
-+ 0x00000024, /* Mixing Control Pair 4 */
-+ 0x00000000, /* Vol Control A4 */
-+ 0x00000000 /* Vol Control B4 */
-+ };
-+
-+ /* Set DAC reset bit as output */
-+ data = hw_read_20kx(hw, GPIO_CTRL);
-+ data |= 0x02;
-+ hw_write_20kx(hw, GPIO_CTRL, data);
-+
-+ err = hw20k2_i2c_init(hw, 0x18, 1, 1);
-+ if (err < 0)
-+ goto End;
-+
-+ for (i = 0; i < 2; i++) {
-+ /* Reset DAC twice just in-case the chip
-+ * didn't initialized properly */
-+ data = hw_read_20kx(hw, GPIO_DATA);
-+ /* GPIO data bit 1 */
-+ data &= 0xFFFFFFFD;
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ mdelay(10);
-+ data |= 0x2;
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ mdelay(50);
-+
-+ /* Reset the 2nd time */
-+ data &= 0xFFFFFFFD;
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ mdelay(10);
-+ data |= 0x2;
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ mdelay(50);
-+
-+ if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_MC2, &cs_read.mode_control_2))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_MC3, &cs_read.mode_control_3))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_FC, &cs_read.filter_control))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_IC, &cs_read.invert_control))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_XC1, &cs_read.mix_control_P1))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_XC2, &cs_read.mix_control_P2))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_XC3, &cs_read.mix_control_P3))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_XC4, &cs_read.mix_control_P4))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4))
-+ continue;
-+
-+ if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4))
-+ continue;
-+
-+ if (memcmp(&cs_read, &cs_def, sizeof(cs_read)))
-+ continue;
-+ else
-+ break;
-+ }
-+
-+ if (i >= 2)
-+ goto End;
-+
-+ /* Note: Every I2C write must have some delay.
-+ * This is not a requirement but the delay works here... */
-+ hw20k2_i2c_write(hw, CS4382_MC1, 0x80);
-+ hw20k2_i2c_write(hw, CS4382_MC2, 0x10);
-+ if (1 == info->msr) {
-+ hw20k2_i2c_write(hw, CS4382_XC1, 0x24);
-+ hw20k2_i2c_write(hw, CS4382_XC2, 0x24);
-+ hw20k2_i2c_write(hw, CS4382_XC3, 0x24);
-+ hw20k2_i2c_write(hw, CS4382_XC4, 0x24);
-+ } else if (2 == info->msr) {
-+ hw20k2_i2c_write(hw, CS4382_XC1, 0x25);
-+ hw20k2_i2c_write(hw, CS4382_XC2, 0x25);
-+ hw20k2_i2c_write(hw, CS4382_XC3, 0x25);
-+ hw20k2_i2c_write(hw, CS4382_XC4, 0x25);
-+ } else {
-+ hw20k2_i2c_write(hw, CS4382_XC1, 0x26);
-+ hw20k2_i2c_write(hw, CS4382_XC2, 0x26);
-+ hw20k2_i2c_write(hw, CS4382_XC3, 0x26);
-+ hw20k2_i2c_write(hw, CS4382_XC4, 0x26);
-+ }
-+
-+ return 0;
-+End:
-+
-+ hw20k2_i2c_uninit(hw);
-+ return -1;
-+}
-+
-+/* ADC operations */
-+#define MAKE_WM8775_ADDR(addr, data) (u32)(((addr<<1)&0xFE)|((data>>8)&0x1))
-+#define MAKE_WM8775_DATA(data) (u32)(data&0xFF)
-+
-+#define WM8775_IC 0x0B
-+#define WM8775_MMC 0x0C
-+#define WM8775_AADCL 0x0E
-+#define WM8775_AADCR 0x0F
-+#define WM8775_ADCMC 0x15
-+#define WM8775_RESET 0x17
-+
-+static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
-+{
-+ u32 data;
-+
-+ data = hw_read_20kx(hw, GPIO_DATA);
-+ switch (type) {
-+ case ADC_MICIN:
-+ data = (data & (0x1 << 14)) ? 1 : 0;
-+ break;
-+ case ADC_LINEIN:
-+ data = (data & (0x1 << 14)) ? 0 : 1;
-+ break;
-+ default:
-+ data = 0;
-+ }
-+ return data;
-+}
-+
-+static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
-+{
-+ u32 data;
-+
-+ data = hw_read_20kx(hw, GPIO_DATA);
-+ switch (type) {
-+ case ADC_MICIN:
-+ data |= (0x1 << 14);
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-+ MAKE_WM8775_DATA(0x101)); /* Mic-in */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-+ MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-+ MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-+ break;
-+ case ADC_LINEIN:
-+ data &= ~(0x1 << 14);
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-+ MAKE_WM8775_DATA(0x102)); /* Line-in */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-+ MAKE_WM8775_DATA(0xCF)); /* No boost */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-+ MAKE_WM8775_DATA(0xCF)); /* No boost */
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
-+{
-+ int err;
-+ u32 mux = 2, data, ctl;
-+
-+ /* Set ADC reset bit as output */
-+ data = hw_read_20kx(hw, GPIO_CTRL);
-+ data |= (0x1 << 15);
-+ hw_write_20kx(hw, GPIO_CTRL, data);
-+
-+ /* Initialize I2C */
-+ err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
-+ if (err < 0) {
-+ printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n");
-+ goto error;
-+ }
-+
-+ /* Make ADC in normal operation */
-+ data = hw_read_20kx(hw, GPIO_DATA);
-+ data &= ~(0x1 << 15);
-+ mdelay(10);
-+ data |= (0x1 << 15);
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+ mdelay(50);
-+
-+ /* Set the master mode (256fs) */
-+ if (1 == info->msr) {
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
-+ MAKE_WM8775_DATA(0x02));
-+ } else if (2 == info->msr) {
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
-+ MAKE_WM8775_DATA(0x0A));
-+ } else {
-+ printk(KERN_ALERT "ctxfi: Invalid master sampling "
-+ "rate (msr %d)!!!\n", info->msr);
-+ err = -EINVAL;
-+ goto error;
-+ }
-+
-+ /* Configure GPIO bit 14 change to line-in/mic-in */
-+ ctl = hw_read_20kx(hw, GPIO_CTRL);
-+ ctl |= 0x1 << 14;
-+ hw_write_20kx(hw, GPIO_CTRL, ctl);
-+
-+ /* Check using Mic-in or Line-in */
-+ data = hw_read_20kx(hw, GPIO_DATA);
-+
-+ if (mux == 1) {
-+ /* Configures GPIO data to select Mic-in */
-+ data |= 0x1 << 14;
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-+ MAKE_WM8775_DATA(0x101)); /* Mic-in */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-+ MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-+ MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-+ } else if (mux == 2) {
-+ /* Configures GPIO data to select Line-in */
-+ data &= ~(0x1 << 14);
-+ hw_write_20kx(hw, GPIO_DATA, data);
-+
-+ /* Setup ADC */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-+ MAKE_WM8775_DATA(0x102)); /* Line-in */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-+ MAKE_WM8775_DATA(0xCF)); /* No boost */
-+ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-+ MAKE_WM8775_DATA(0xCF)); /* No boost */
-+ } else {
-+ printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
-+ err = -EINVAL;
-+ goto error;
-+ }
-+
-+ return 0;
-+
-+error:
-+ hw20k2_i2c_uninit(hw);
-+ return err;
-+}
-+
-+static int hw_have_digit_io_switch(struct hw *hw)
-+{
-+ return 0;
-+}
-+
-+static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
-+{
-+ struct hw *hw = dev_id;
-+ unsigned int status;
-+
-+ status = hw_read_20kx(hw, GIP);
-+ if (!status)
-+ return IRQ_NONE;
-+
-+ if (hw->irq_callback)
-+ hw->irq_callback(hw->irq_callback_data, status);
-+
-+ hw_write_20kx(hw, GIP, status);
-+ return IRQ_HANDLED;
-+}
-+
-+static int hw_card_start(struct hw *hw)
-+{
-+ int err = 0;
-+ struct pci_dev *pci = hw->pci;
-+ unsigned int gctl;
-+
-+ err = pci_enable_device(pci);
-+ if (err < 0)
-+ return err;
-+
-+ /* Set DMA transfer mask */
-+ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
-+ pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
-+ printk(KERN_ERR "ctxfi: architecture does not support PCI "
-+ "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
-+ err = -ENXIO;
-+ goto error1;
-+ }
-+
-+ if (!hw->io_base) {
-+ err = pci_request_regions(pci, "XFi");
-+ if (err < 0)
-+ goto error1;
-+
-+ hw->io_base = pci_resource_start(hw->pci, 2);
-+ hw->mem_base = (unsigned long)ioremap(hw->io_base,
-+ pci_resource_len(hw->pci, 2));
-+ if (!hw->mem_base) {
-+ err = -ENOENT;
-+ goto error2;
-+ }
-+ }
-+
-+ /* Switch to 20k2 mode from UAA mode. */
-+ gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
-+ set_field(&gctl, GCTL_UAA, 0);
-+ hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
-+
-+ if (hw->irq < 0) {
-+ err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
-+ "ctxfi", hw);
-+ if (err < 0) {
-+ printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
-+ goto error2;
-+ }
-+ hw->irq = pci->irq;
-+ }
-+
-+ pci_set_master(pci);
-+
-+ return 0;
-+
-+/*error3:
-+ iounmap((void *)hw->mem_base);
-+ hw->mem_base = (unsigned long)NULL;*/
-+error2:
-+ pci_release_regions(pci);
-+ hw->io_base = 0;
-+error1:
-+ pci_disable_device(pci);
-+ return err;
-+}
-+
-+static int hw_card_stop(struct hw *hw)
-+{
-+ unsigned int data;
-+
-+ /* disable transport bus master and queueing of request */
-+ hw_write_20kx(hw, TRANSPORT_CTL, 0x00);
-+
-+ /* disable pll */
-+ data = hw_read_20kx(hw, PLL_ENB);
-+ hw_write_20kx(hw, PLL_ENB, (data & (~0x07)));
-+
-+ /* TODO: Disable interrupt and so on... */
-+ return 0;
-+}
-+
-+static int hw_card_shutdown(struct hw *hw)
-+{
-+ if (hw->irq >= 0)
-+ free_irq(hw->irq, hw);
-+
-+ hw->irq = -1;
-+
-+ if (hw->mem_base)
-+ iounmap((void *)hw->mem_base);
-+
-+ hw->mem_base = (unsigned long)NULL;
-+
-+ if (hw->io_base)
-+ pci_release_regions(hw->pci);
-+
-+ hw->io_base = 0;
-+
-+ pci_disable_device(hw->pci);
-+
-+ return 0;
-+}
-+
-+static int hw_card_init(struct hw *hw, struct card_conf *info)
-+{
-+ int err;
-+ unsigned int gctl;
-+ u32 data = 0;
-+ struct dac_conf dac_info = {0};
-+ struct adc_conf adc_info = {0};
-+ struct daio_conf daio_info = {0};
-+ struct trn_conf trn_info = {0};
-+
-+ /* Get PCI io port/memory base address and
-+ * do 20kx core switch if needed. */
-+ err = hw_card_start(hw);
-+ if (err)
-+ return err;
-+
-+ /* PLL init */
-+ err = hw_pll_init(hw, info->rsr);
-+ if (err < 0)
-+ return err;
-+
-+ /* kick off auto-init */
-+ err = hw_auto_init(hw);
-+ if (err < 0)
-+ return err;
-+
-+ gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
-+ set_field(&gctl, GCTL_DBP, 1);
-+ set_field(&gctl, GCTL_TBP, 1);
-+ set_field(&gctl, GCTL_FBP, 1);
-+ set_field(&gctl, GCTL_DPC, 0);
-+ hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
-+
-+ /* Reset all global pending interrupts */
-+ hw_write_20kx(hw, GIE, 0);
-+ /* Reset all SRC pending interrupts */
-+ hw_write_20kx(hw, SRC_IP, 0);
-+
-+ /* TODO: detect the card ID and configure GPIO accordingly. */
-+ /* Configures GPIO (0xD802 0x98028) */
-+ /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
-+ /* Configures GPIO (SB0880) */
-+ /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
-+ hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-+
-+ /* Enable audio ring */
-+ hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
-+
-+ trn_info.vm_pgt_phys = info->vm_pgt_phys;
-+ err = hw_trn_init(hw, &trn_info);
-+ if (err < 0)
-+ return err;
-+
-+ daio_info.msr = info->msr;
-+ err = hw_daio_init(hw, &daio_info);
-+ if (err < 0)
-+ return err;
-+
-+ dac_info.msr = info->msr;
-+ err = hw_dac_init(hw, &dac_info);
-+ if (err < 0)
-+ return err;
-+
-+ adc_info.msr = info->msr;
-+ adc_info.input = ADC_LINEIN;
-+ adc_info.mic20db = 0;
-+ err = hw_adc_init(hw, &adc_info);
-+ if (err < 0)
-+ return err;
-+
-+ data = hw_read_20kx(hw, SRC_MCTL);
-+ data |= 0x1; /* Enables input from the audio ring */
-+ hw_write_20kx(hw, SRC_MCTL, data);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int hw_suspend(struct hw *hw, pm_message_t state)
-+{
-+ struct pci_dev *pci = hw->pci;
-+
-+ hw_card_stop(hw);
-+
-+ pci_disable_device(pci);
-+ pci_save_state(pci);
-+ pci_set_power_state(pci, pci_choose_state(pci, state));
-+
-+ return 0;
-+}
-+
-+static int hw_resume(struct hw *hw, struct card_conf *info)
-+{
-+ struct pci_dev *pci = hw->pci;
-+
-+ pci_set_power_state(pci, PCI_D0);
-+ pci_restore_state(pci);
-+
-+ /* Re-initialize card hardware. */
-+ return hw_card_init(hw, info);
-+}
-+#endif
-+
-+static u32 hw_read_20kx(struct hw *hw, u32 reg)
-+{
-+ return readl((void *)(hw->mem_base + reg));
-+}
-+
-+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
-+{
-+ writel(data, (void *)(hw->mem_base + reg));
-+}
-+
-+static struct hw ct20k2_preset __devinitdata = {
-+ .irq = -1,
-+
-+ .card_init = hw_card_init,
-+ .card_stop = hw_card_stop,
-+ .pll_init = hw_pll_init,
-+ .is_adc_source_selected = hw_is_adc_input_selected,
-+ .select_adc_source = hw_adc_input_select,
-+ .have_digit_io_switch = hw_have_digit_io_switch,
-+#ifdef CONFIG_PM
-+ .suspend = hw_suspend,
-+ .resume = hw_resume,
-+#endif
-+
-+ .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
-+ .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
-+ .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
-+ .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
-+ .src_set_state = src_set_state,
-+ .src_set_bm = src_set_bm,
-+ .src_set_rsr = src_set_rsr,
-+ .src_set_sf = src_set_sf,
-+ .src_set_wr = src_set_wr,
-+ .src_set_pm = src_set_pm,
-+ .src_set_rom = src_set_rom,
-+ .src_set_vo = src_set_vo,
-+ .src_set_st = src_set_st,
-+ .src_set_ie = src_set_ie,
-+ .src_set_ilsz = src_set_ilsz,
-+ .src_set_bp = src_set_bp,
-+ .src_set_cisz = src_set_cisz,
-+ .src_set_ca = src_set_ca,
-+ .src_set_sa = src_set_sa,
-+ .src_set_la = src_set_la,
-+ .src_set_pitch = src_set_pitch,
-+ .src_set_dirty = src_set_dirty,
-+ .src_set_clear_zbufs = src_set_clear_zbufs,
-+ .src_set_dirty_all = src_set_dirty_all,
-+ .src_commit_write = src_commit_write,
-+ .src_get_ca = src_get_ca,
-+ .src_get_dirty = src_get_dirty,
-+ .src_dirty_conj_mask = src_dirty_conj_mask,
-+ .src_mgr_enbs_src = src_mgr_enbs_src,
-+ .src_mgr_enb_src = src_mgr_enb_src,
-+ .src_mgr_dsb_src = src_mgr_dsb_src,
-+ .src_mgr_commit_write = src_mgr_commit_write,
-+
-+ .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
-+ .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
-+ .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
-+ .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
-+ .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
-+ .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
-+ .srcimp_mgr_commit_write = srcimp_mgr_commit_write,
-+
-+ .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
-+ .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
-+ .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
-+ .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
-+ .amixer_set_mode = amixer_set_mode,
-+ .amixer_set_iv = amixer_set_iv,
-+ .amixer_set_x = amixer_set_x,
-+ .amixer_set_y = amixer_set_y,
-+ .amixer_set_sadr = amixer_set_sadr,
-+ .amixer_set_se = amixer_set_se,
-+ .amixer_set_dirty = amixer_set_dirty,
-+ .amixer_set_dirty_all = amixer_set_dirty_all,
-+ .amixer_commit_write = amixer_commit_write,
-+ .amixer_get_y = amixer_get_y,
-+ .amixer_get_dirty = amixer_get_dirty,
-+
-+ .dai_get_ctrl_blk = dai_get_ctrl_blk,
-+ .dai_put_ctrl_blk = dai_put_ctrl_blk,
-+ .dai_srt_set_srco = dai_srt_set_srco,
-+ .dai_srt_set_srcm = dai_srt_set_srcm,
-+ .dai_srt_set_rsr = dai_srt_set_rsr,
-+ .dai_srt_set_drat = dai_srt_set_drat,
-+ .dai_srt_set_ec = dai_srt_set_ec,
-+ .dai_srt_set_et = dai_srt_set_et,
-+ .dai_commit_write = dai_commit_write,
-+
-+ .dao_get_ctrl_blk = dao_get_ctrl_blk,
-+ .dao_put_ctrl_blk = dao_put_ctrl_blk,
-+ .dao_set_spos = dao_set_spos,
-+ .dao_commit_write = dao_commit_write,
-+ .dao_get_spos = dao_get_spos,
-+
-+ .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
-+ .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
-+ .daio_mgr_enb_dai = daio_mgr_enb_dai,
-+ .daio_mgr_dsb_dai = daio_mgr_dsb_dai,
-+ .daio_mgr_enb_dao = daio_mgr_enb_dao,
-+ .daio_mgr_dsb_dao = daio_mgr_dsb_dao,
-+ .daio_mgr_dao_init = daio_mgr_dao_init,
-+ .daio_mgr_set_imaparc = daio_mgr_set_imaparc,
-+ .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
-+ .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
-+ .daio_mgr_commit_write = daio_mgr_commit_write,
-+
-+ .set_timer_irq = set_timer_irq,
-+ .set_timer_tick = set_timer_tick,
-+ .get_wc = get_wc,
-+};
-+
-+int __devinit create_20k2_hw_obj(struct hw **rhw)
-+{
-+ struct hw20k2 *hw20k2;
-+
-+ *rhw = NULL;
-+ hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL);
-+ if (!hw20k2)
-+ return -ENOMEM;
-+
-+ hw20k2->hw = ct20k2_preset;
-+ *rhw = &hw20k2->hw;
-+
-+ return 0;
-+}
-+
-+int destroy_20k2_hw_obj(struct hw *hw)
-+{
-+ if (hw->io_base)
-+ hw_card_shutdown(hw);
-+
-+ kfree(hw);
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/cthw20k2.h
-@@ -0,0 +1,26 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File cthw20k2.h
-+ *
-+ * @Brief
-+ * This file contains the definition of hardware access methord.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 13 2008
-+ *
-+ */
-+
-+#ifndef CTHW20K2_H
-+#define CTHW20K2_H
-+
-+#include "cthardware.h"
-+
-+int create_20k2_hw_obj(struct hw **rhw);
-+int destroy_20k2_hw_obj(struct hw *hw);
-+
-+#endif /* CTHW20K2_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctimap.c
-@@ -0,0 +1,112 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctimap.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of generic input mapper operations
-+ * for input mapper management.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 23 2008
-+ *
-+ */
-+
-+#include "ctimap.h"
-+#include <linux/slab.h>
-+
-+int input_mapper_add(struct list_head *mappers, struct imapper *entry,
-+ int (*map_op)(void *, struct imapper *), void *data)
-+{
-+ struct list_head *pos, *pre, *head;
-+ struct imapper *pre_ent, *pos_ent;
-+
-+ head = mappers;
-+
-+ if (list_empty(head)) {
-+ entry->next = entry->addr;
-+ map_op(data, entry);
-+ list_add(&entry->list, head);
-+ return 0;
-+ }
-+
-+ list_for_each(pos, head) {
-+ pos_ent = list_entry(pos, struct imapper, list);
-+ if (pos_ent->slot > entry->slot) {
-+ /* found a position in list */
-+ break;
-+ }
-+ }
-+
-+ if (pos != head) {
-+ pre = pos->prev;
-+ if (pre == head)
-+ pre = head->prev;
-+
-+ __list_add(&entry->list, pos->prev, pos);
-+ } else {
-+ pre = head->prev;
-+ pos = head->next;
-+ list_add_tail(&entry->list, head);
-+ }
-+
-+ pre_ent = list_entry(pre, struct imapper, list);
-+ pos_ent = list_entry(pos, struct imapper, list);
-+
-+ entry->next = pos_ent->addr;
-+ map_op(data, entry);
-+ pre_ent->next = entry->addr;
-+ map_op(data, pre_ent);
-+
-+ return 0;
-+}
-+
-+int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
-+ int (*map_op)(void *, struct imapper *), void *data)
-+{
-+ struct list_head *next, *pre, *head;
-+ struct imapper *pre_ent, *next_ent;
-+
-+ head = mappers;
-+
-+ if (list_empty(head))
-+ return 0;
-+
-+ pre = (entry->list.prev == head) ? head->prev : entry->list.prev;
-+ next = (entry->list.next == head) ? head->next : entry->list.next;
-+
-+ if (pre == &entry->list) {
-+ /* entry is the only one node in mappers list */
-+ entry->next = entry->addr = entry->user = entry->slot = 0;
-+ map_op(data, entry);
-+ list_del(&entry->list);
-+ return 0;
-+ }
-+
-+ pre_ent = list_entry(pre, struct imapper, list);
-+ next_ent = list_entry(next, struct imapper, list);
-+
-+ pre_ent->next = next_ent->addr;
-+ map_op(data, pre_ent);
-+ list_del(&entry->list);
-+
-+ return 0;
-+}
-+
-+void free_input_mapper_list(struct list_head *head)
-+{
-+ struct imapper *entry;
-+ struct list_head *pos;
-+
-+ while (!list_empty(head)) {
-+ pos = head->next;
-+ list_del(pos);
-+ entry = list_entry(pos, struct imapper, list);
-+ kfree(entry);
-+ }
-+}
-+
---- /dev/null
-+++ b/sound/pci/ctxfi/ctimap.h
-@@ -0,0 +1,40 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctimap.h
-+ *
-+ * @Brief
-+ * This file contains the definition of generic input mapper operations
-+ * for input mapper management.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 23 2008
-+ *
-+ */
-+
-+#ifndef CTIMAP_H
-+#define CTIMAP_H
-+
-+#include <linux/list.h>
-+
-+struct imapper {
-+ unsigned short slot; /* the id of the slot containing input data */
-+ unsigned short user; /* the id of the user resource consuming data */
-+ unsigned short addr; /* the input mapper ram id */
-+ unsigned short next; /* the next input mapper ram id */
-+ struct list_head list;
-+};
-+
-+int input_mapper_add(struct list_head *mappers, struct imapper *entry,
-+ int (*map_op)(void *, struct imapper *), void *data);
-+
-+int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
-+ int (*map_op)(void *, struct imapper *), void *data);
-+
-+void free_input_mapper_list(struct list_head *mappers);
-+
-+#endif /* CTIMAP_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctmixer.c
-@@ -0,0 +1,1157 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctmixer.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of alsa mixer device functions.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 28 2008
-+ *
-+ */
-+
-+
-+#include "ctmixer.h"
-+#include "ctamixer.h"
-+#include <linux/slab.h>
-+#include <sound/core.h>
-+#include <sound/control.h>
-+#include <sound/asoundef.h>
-+#include <sound/pcm.h>
-+#include <sound/tlv.h>
-+
-+enum CT_SUM_CTL {
-+ SUM_IN_F,
-+ SUM_IN_R,
-+ SUM_IN_C,
-+ SUM_IN_S,
-+ SUM_IN_F_C,
-+
-+ NUM_CT_SUMS
-+};
-+
-+enum CT_AMIXER_CTL {
-+ /* volume control mixers */
-+ AMIXER_MASTER_F,
-+ AMIXER_MASTER_R,
-+ AMIXER_MASTER_C,
-+ AMIXER_MASTER_S,
-+ AMIXER_PCM_F,
-+ AMIXER_PCM_R,
-+ AMIXER_PCM_C,
-+ AMIXER_PCM_S,
-+ AMIXER_SPDIFI,
-+ AMIXER_LINEIN,
-+ AMIXER_MIC,
-+ AMIXER_SPDIFO,
-+ AMIXER_WAVE_F,
-+ AMIXER_WAVE_R,
-+ AMIXER_WAVE_C,
-+ AMIXER_WAVE_S,
-+ AMIXER_MASTER_F_C,
-+ AMIXER_PCM_F_C,
-+ AMIXER_SPDIFI_C,
-+ AMIXER_LINEIN_C,
-+ AMIXER_MIC_C,
-+
-+ /* this should always be the last one */
-+ NUM_CT_AMIXERS
-+};
-+
-+enum CTALSA_MIXER_CTL {
-+ /* volume control mixers */
-+ MIXER_MASTER_P,
-+ MIXER_PCM_P,
-+ MIXER_LINEIN_P,
-+ MIXER_MIC_P,
-+ MIXER_SPDIFI_P,
-+ MIXER_SPDIFO_P,
-+ MIXER_WAVEF_P,
-+ MIXER_WAVER_P,
-+ MIXER_WAVEC_P,
-+ MIXER_WAVES_P,
-+ MIXER_MASTER_C,
-+ MIXER_PCM_C,
-+ MIXER_LINEIN_C,
-+ MIXER_MIC_C,
-+ MIXER_SPDIFI_C,
-+
-+ /* switch control mixers */
-+ MIXER_PCM_C_S,
-+ MIXER_LINEIN_C_S,
-+ MIXER_MIC_C_S,
-+ MIXER_SPDIFI_C_S,
-+ MIXER_LINEIN_P_S,
-+ MIXER_SPDIFO_P_S,
-+ MIXER_SPDIFI_P_S,
-+ MIXER_WAVEF_P_S,
-+ MIXER_WAVER_P_S,
-+ MIXER_WAVEC_P_S,
-+ MIXER_WAVES_P_S,
-+ MIXER_DIGITAL_IO_S,
-+ MIXER_IEC958_MASK,
-+ MIXER_IEC958_DEFAULT,
-+ MIXER_IEC958_STREAM,
-+
-+ /* this should always be the last one */
-+ NUM_CTALSA_MIXERS
-+};
-+
-+#define VOL_MIXER_START MIXER_MASTER_P
-+#define VOL_MIXER_END MIXER_SPDIFI_C
-+#define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1)
-+#define SWH_MIXER_START MIXER_PCM_C_S
-+#define SWH_MIXER_END MIXER_DIGITAL_IO_S
-+#define SWH_CAPTURE_START MIXER_PCM_C_S
-+#define SWH_CAPTURE_END MIXER_SPDIFI_C_S
-+
-+#define CHN_NUM 2
-+
-+struct ct_kcontrol_init {
-+ unsigned char ctl;
-+ char *name;
-+};
-+
-+static struct ct_kcontrol_init
-+ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
-+ [MIXER_MASTER_P] = {
-+ .ctl = 1,
-+ .name = "Master Playback Volume",
-+ },
-+ [MIXER_MASTER_C] = {
-+ .ctl = 1,
-+ .name = "Master Capture Volume",
-+ },
-+ [MIXER_PCM_P] = {
-+ .ctl = 1,
-+ .name = "PCM Playback Volume",
-+ },
-+ [MIXER_PCM_C] = {
-+ .ctl = 1,
-+ .name = "PCM Capture Volume",
-+ },
-+ [MIXER_LINEIN_P] = {
-+ .ctl = 1,
-+ .name = "Line-in Playback Volume",
-+ },
-+ [MIXER_LINEIN_C] = {
-+ .ctl = 1,
-+ .name = "Line-in Capture Volume",
-+ },
-+ [MIXER_MIC_P] = {
-+ .ctl = 1,
-+ .name = "Mic Playback Volume",
-+ },
-+ [MIXER_MIC_C] = {
-+ .ctl = 1,
-+ .name = "Mic Capture Volume",
-+ },
-+ [MIXER_SPDIFI_P] = {
-+ .ctl = 1,
-+ .name = "S/PDIF-in Playback Volume",
-+ },
-+ [MIXER_SPDIFI_C] = {
-+ .ctl = 1,
-+ .name = "S/PDIF-in Capture Volume",
-+ },
-+ [MIXER_SPDIFO_P] = {
-+ .ctl = 1,
-+ .name = "S/PDIF-out Playback Volume",
-+ },
-+ [MIXER_WAVEF_P] = {
-+ .ctl = 1,
-+ .name = "Front Playback Volume",
-+ },
-+ [MIXER_WAVES_P] = {
-+ .ctl = 1,
-+ .name = "Side Playback Volume",
-+ },
-+ [MIXER_WAVEC_P] = {
-+ .ctl = 1,
-+ .name = "Center/LFE Playback Volume",
-+ },
-+ [MIXER_WAVER_P] = {
-+ .ctl = 1,
-+ .name = "Surround Playback Volume",
-+ },
-+
-+ [MIXER_PCM_C_S] = {
-+ .ctl = 1,
-+ .name = "PCM Capture Switch",
-+ },
-+ [MIXER_LINEIN_C_S] = {
-+ .ctl = 1,
-+ .name = "Line-in Capture Switch",
-+ },
-+ [MIXER_MIC_C_S] = {
-+ .ctl = 1,
-+ .name = "Mic Capture Switch",
-+ },
-+ [MIXER_SPDIFI_C_S] = {
-+ .ctl = 1,
-+ .name = "S/PDIF-in Capture Switch",
-+ },
-+ [MIXER_LINEIN_P_S] = {
-+ .ctl = 1,
-+ .name = "Line-in Playback Switch",
-+ },
-+ [MIXER_SPDIFO_P_S] = {
-+ .ctl = 1,
-+ .name = "S/PDIF-out Playback Switch",
-+ },
-+ [MIXER_SPDIFI_P_S] = {
-+ .ctl = 1,
-+ .name = "S/PDIF-in Playback Switch",
-+ },
-+ [MIXER_WAVEF_P_S] = {
-+ .ctl = 1,
-+ .name = "Front Playback Switch",
-+ },
-+ [MIXER_WAVES_P_S] = {
-+ .ctl = 1,
-+ .name = "Side Playback Switch",
-+ },
-+ [MIXER_WAVEC_P_S] = {
-+ .ctl = 1,
-+ .name = "Center/LFE Playback Switch",
-+ },
-+ [MIXER_WAVER_P_S] = {
-+ .ctl = 1,
-+ .name = "Surround Playback Switch",
-+ },
-+ [MIXER_DIGITAL_IO_S] = {
-+ .ctl = 0,
-+ .name = "Digit-IO Playback Switch",
-+ },
-+};
-+
-+static void
-+ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
-+
-+static void
-+ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
-+
-+static struct snd_kcontrol *kctls[2] = {NULL};
-+
-+static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
-+{
-+ switch (alsa_index) {
-+ case MIXER_MASTER_P: return AMIXER_MASTER_F;
-+ case MIXER_MASTER_C: return AMIXER_MASTER_F_C;
-+ case MIXER_PCM_P: return AMIXER_PCM_F;
-+ case MIXER_PCM_C:
-+ case MIXER_PCM_C_S: return AMIXER_PCM_F_C;
-+ case MIXER_LINEIN_P: return AMIXER_LINEIN;
-+ case MIXER_LINEIN_C:
-+ case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C;
-+ case MIXER_MIC_P: return AMIXER_MIC;
-+ case MIXER_MIC_C:
-+ case MIXER_MIC_C_S: return AMIXER_MIC_C;
-+ case MIXER_SPDIFI_P: return AMIXER_SPDIFI;
-+ case MIXER_SPDIFI_C:
-+ case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C;
-+ case MIXER_SPDIFO_P: return AMIXER_SPDIFO;
-+ case MIXER_WAVEF_P: return AMIXER_WAVE_F;
-+ case MIXER_WAVES_P: return AMIXER_WAVE_S;
-+ case MIXER_WAVEC_P: return AMIXER_WAVE_C;
-+ case MIXER_WAVER_P: return AMIXER_WAVE_R;
-+ default: return NUM_CT_AMIXERS;
-+ }
-+}
-+
-+static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
-+{
-+ switch (index) {
-+ case AMIXER_MASTER_F: return AMIXER_MASTER_F_C;
-+ case AMIXER_PCM_F: return AMIXER_PCM_F_C;
-+ case AMIXER_SPDIFI: return AMIXER_SPDIFI_C;
-+ case AMIXER_LINEIN: return AMIXER_LINEIN_C;
-+ case AMIXER_MIC: return AMIXER_MIC_C;
-+ default: return NUM_CT_AMIXERS;
-+ }
-+}
-+
-+static unsigned char
-+get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
-+{
-+ return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
-+ ? 1 : 0;
-+}
-+
-+static void
-+set_switch_state(struct ct_mixer *mixer,
-+ enum CTALSA_MIXER_CTL type, unsigned char state)
-+{
-+ if (state)
-+ mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
-+ else
-+ mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
-+}
-+
-+#if 0 /* not used */
-+/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
-+ * from 2^-6 to (1+1023/1024) */
-+static unsigned int uint16_to_float14(unsigned int x)
-+{
-+ unsigned int i;
-+
-+ if (x < 17)
-+ return 0;
-+
-+ x *= 2031;
-+ x /= 65535;
-+ x += 16;
-+
-+ /* i <= 6 */
-+ for (i = 0; !(x & 0x400); i++)
-+ x <<= 1;
-+
-+ x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
-+
-+ return x;
-+}
-+
-+static unsigned int float14_to_uint16(unsigned int x)
-+{
-+ unsigned int e;
-+
-+ if (!x)
-+ return x;
-+
-+ e = (x >> 10) & 0x7;
-+ x &= 0x3ff;
-+ x += 1024;
-+ x >>= (7 - e);
-+ x -= 16;
-+ x *= 65535;
-+ x /= 2031;
-+
-+ return x;
-+}
-+#endif /* not used */
-+
-+#define VOL_SCALE 0x1c
-+#define VOL_MAX 0x100
-+
-+static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);
-+
-+static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count = 2;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = VOL_MAX;
-+
-+ return 0;
-+}
-+
-+static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
-+ enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
-+ struct amixer *amixer;
-+ int i, val;
-+
-+ for (i = 0; i < 2; i++) {
-+ amixer = ((struct ct_mixer *)atc->mixer)->
-+ amixers[type*CHN_NUM+i];
-+ val = amixer->ops->get_scale(amixer) / VOL_SCALE;
-+ if (val < 0)
-+ val = 0;
-+ else if (val > VOL_MAX)
-+ val = VOL_MAX;
-+ ucontrol->value.integer.value[i] = val;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
-+ struct ct_mixer *mixer = atc->mixer;
-+ enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
-+ struct amixer *amixer;
-+ int i, j, val, oval, change = 0;
-+
-+ for (i = 0; i < 2; i++) {
-+ val = ucontrol->value.integer.value[i];
-+ if (val < 0)
-+ val = 0;
-+ else if (val > VOL_MAX)
-+ val = VOL_MAX;
-+ val *= VOL_SCALE;
-+ amixer = mixer->amixers[type*CHN_NUM+i];
-+ oval = amixer->ops->get_scale(amixer);
-+ if (val != oval) {
-+ amixer->ops->set_scale(amixer, val);
-+ amixer->ops->commit_write(amixer);
-+ change = 1;
-+ /* Synchronize Master/PCM playback AMIXERs. */
-+ if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
-+ for (j = 1; j < 4; j++) {
-+ amixer = mixer->
-+ amixers[(type+j)*CHN_NUM+i];
-+ amixer->ops->set_scale(amixer, val);
-+ amixer->ops->commit_write(amixer);
-+ }
-+ }
-+ }
-+ }
-+
-+ return change;
-+}
-+
-+static struct snd_kcontrol_new vol_ctl = {
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .info = ct_alsa_mix_volume_info,
-+ .get = ct_alsa_mix_volume_get,
-+ .put = ct_alsa_mix_volume_put,
-+ .tlv = { .p = ct_vol_db_scale },
-+};
-+
-+static void
-+do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
-+{
-+
-+ if (MIXER_LINEIN_C_S == type) {
-+ atc->select_line_in(atc);
-+ set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
-+ snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
-+ &kctls[1]->id);
-+ } else if (MIXER_MIC_C_S == type) {
-+ atc->select_mic_in(atc);
-+ set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
-+ snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
-+ &kctls[0]->id);
-+ }
-+}
-+
-+static void
-+do_digit_io_switch(struct ct_atc *atc, int state)
-+{
-+ struct ct_mixer *mixer = atc->mixer;
-+
-+ if (state) {
-+ atc->select_digit_io(atc);
-+ atc->spdif_out_unmute(atc,
-+ get_switch_state(mixer, MIXER_SPDIFO_P_S));
-+ atc->spdif_in_unmute(atc, 1);
-+ atc->line_in_unmute(atc, 0);
-+ return;
-+ }
-+
-+ if (get_switch_state(mixer, MIXER_LINEIN_C_S))
-+ atc->select_line_in(atc);
-+ else if (get_switch_state(mixer, MIXER_MIC_C_S))
-+ atc->select_mic_in(atc);
-+
-+ atc->spdif_out_unmute(atc, 0);
-+ atc->spdif_in_unmute(atc, 0);
-+ atc->line_in_unmute(atc, 1);
-+ return;
-+}
-+
-+static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
-+{
-+ struct ct_mixer *mixer = atc->mixer;
-+
-+ /* Do changes in mixer. */
-+ if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
-+ if (state) {
-+ ct_mixer_recording_select(mixer,
-+ get_amixer_index(type));
-+ } else {
-+ ct_mixer_recording_unselect(mixer,
-+ get_amixer_index(type));
-+ }
-+ }
-+ /* Do changes out of mixer. */
-+ if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-+ do_line_mic_switch(atc, type);
-+ else if (MIXER_WAVEF_P_S == type)
-+ atc->line_front_unmute(atc, state);
-+ else if (MIXER_WAVES_P_S == type)
-+ atc->line_surround_unmute(atc, state);
-+ else if (MIXER_WAVEC_P_S == type)
-+ atc->line_clfe_unmute(atc, state);
-+ else if (MIXER_WAVER_P_S == type)
-+ atc->line_rear_unmute(atc, state);
-+ else if (MIXER_LINEIN_P_S == type)
-+ atc->line_in_unmute(atc, state);
-+ else if (MIXER_SPDIFO_P_S == type)
-+ atc->spdif_out_unmute(atc, state);
-+ else if (MIXER_SPDIFI_P_S == type)
-+ atc->spdif_in_unmute(atc, state);
-+ else if (MIXER_DIGITAL_IO_S == type)
-+ do_digit_io_switch(atc, state);
-+
-+ return;
-+}
-+
-+static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = 1;
-+ uinfo->value.integer.step = 1;
-+
-+ return 0;
-+}
-+
-+static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct ct_mixer *mixer =
-+ ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
-+ enum CTALSA_MIXER_CTL type = kcontrol->private_value;
-+
-+ ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
-+ return 0;
-+}
-+
-+static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
-+ struct ct_mixer *mixer = atc->mixer;
-+ enum CTALSA_MIXER_CTL type = kcontrol->private_value;
-+ int state;
-+
-+ state = ucontrol->value.integer.value[0];
-+ if (get_switch_state(mixer, type) == state)
-+ return 0;
-+
-+ set_switch_state(mixer, type, state);
-+ do_switch(atc, type, state);
-+
-+ return 1;
-+}
-+
-+static struct snd_kcontrol_new swh_ctl = {
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .info = ct_alsa_mix_switch_info,
-+ .get = ct_alsa_mix_switch_get,
-+ .put = ct_alsa_mix_switch_put
-+};
-+
-+static int ct_spdif_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-+ uinfo->count = 1;
-+ return 0;
-+}
-+
-+static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ ucontrol->value.iec958.status[0] = 0xff;
-+ ucontrol->value.iec958.status[1] = 0xff;
-+ ucontrol->value.iec958.status[2] = 0xff;
-+ ucontrol->value.iec958.status[3] = 0xff;
-+ return 0;
-+}
-+
-+static int ct_spdif_default_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF;
-+
-+ ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
-+ ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
-+ ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
-+ ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
-+
-+ return 0;
-+}
-+
-+static int ct_spdif_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
-+ unsigned int status;
-+
-+ atc->spdif_out_get_status(atc, &status);
-+ ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
-+ ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
-+ ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
-+ ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
-+
-+ return 0;
-+}
-+
-+static int ct_spdif_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
-+ int change;
-+ unsigned int status, old_status;
-+
-+ status = (ucontrol->value.iec958.status[0] << 0) |
-+ (ucontrol->value.iec958.status[1] << 8) |
-+ (ucontrol->value.iec958.status[2] << 16) |
-+ (ucontrol->value.iec958.status[3] << 24);
-+
-+ atc->spdif_out_get_status(atc, &old_status);
-+ change = (old_status != status);
-+ if (change)
-+ atc->spdif_out_set_status(atc, status);
-+
-+ return change;
-+}
-+
-+static struct snd_kcontrol_new iec958_mask_ctl = {
-+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
-+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
-+ .count = 1,
-+ .info = ct_spdif_info,
-+ .get = ct_spdif_get_mask,
-+ .private_value = MIXER_IEC958_MASK
-+};
-+
-+static struct snd_kcontrol_new iec958_default_ctl = {
-+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
-+ .count = 1,
-+ .info = ct_spdif_info,
-+ .get = ct_spdif_default_get,
-+ .put = ct_spdif_put,
-+ .private_value = MIXER_IEC958_DEFAULT
-+};
-+
-+static struct snd_kcontrol_new iec958_ctl = {
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
-+ .count = 1,
-+ .info = ct_spdif_info,
-+ .get = ct_spdif_get,
-+ .put = ct_spdif_put,
-+ .private_value = MIXER_IEC958_STREAM
-+};
-+
-+#define NUM_IEC958_CTL 3
-+
-+static int
-+ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
-+{
-+ struct snd_kcontrol *kctl;
-+ int err;
-+
-+ kctl = snd_ctl_new1(new, mixer->atc);
-+ if (!kctl)
-+ return -ENOMEM;
-+
-+ if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
-+ kctl->id.device = IEC958;
-+
-+ err = snd_ctl_add(mixer->atc->card, kctl);
-+ if (err)
-+ return err;
-+
-+ switch (new->private_value) {
-+ case MIXER_LINEIN_C_S:
-+ kctls[0] = kctl; break;
-+ case MIXER_MIC_C_S:
-+ kctls[1] = kctl; break;
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
-+{
-+ enum CTALSA_MIXER_CTL type;
-+ struct ct_atc *atc = mixer->atc;
-+ int err;
-+
-+ /* Create snd kcontrol instances on demand */
-+ for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
-+ if (ct_kcontrol_init_table[type].ctl) {
-+ vol_ctl.name = ct_kcontrol_init_table[type].name;
-+ vol_ctl.private_value = (unsigned long)type;
-+ err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
-+ if (err)
-+ return err;
-+ }
-+ }
-+
-+ ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
-+ atc->have_digit_io_switch(atc);
-+ for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
-+ if (ct_kcontrol_init_table[type].ctl) {
-+ swh_ctl.name = ct_kcontrol_init_table[type].name;
-+ swh_ctl.private_value = (unsigned long)type;
-+ err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
-+ if (err)
-+ return err;
-+ }
-+ }
-+
-+ err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
-+ if (err)
-+ return err;
-+
-+ err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
-+ if (err)
-+ return err;
-+
-+ err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
-+ if (err)
-+ return err;
-+
-+ atc->line_front_unmute(atc, 1);
-+ set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
-+ atc->line_surround_unmute(atc, 0);
-+ set_switch_state(mixer, MIXER_WAVES_P_S, 0);
-+ atc->line_clfe_unmute(atc, 0);
-+ set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
-+ atc->line_rear_unmute(atc, 0);
-+ set_switch_state(mixer, MIXER_WAVER_P_S, 0);
-+ atc->spdif_out_unmute(atc, 0);
-+ set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
-+ atc->line_in_unmute(atc, 0);
-+ set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
-+ atc->spdif_in_unmute(atc, 0);
-+ set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
-+
-+ set_switch_state(mixer, MIXER_PCM_C_S, 1);
-+ set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
-+ set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
-+
-+ return 0;
-+}
-+
-+static void
-+ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
-+{
-+ struct amixer *amix_d;
-+ struct sum *sum_c;
-+ int i;
-+
-+ for (i = 0; i < 2; i++) {
-+ amix_d = mixer->amixers[type*CHN_NUM+i];
-+ sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
-+ amix_d->ops->set_sum(amix_d, sum_c);
-+ amix_d->ops->commit_write(amix_d);
-+ }
-+}
-+
-+static void
-+ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
-+{
-+ struct amixer *amix_d;
-+ int i;
-+
-+ for (i = 0; i < 2; i++) {
-+ amix_d = mixer->amixers[type*CHN_NUM+i];
-+ amix_d->ops->set_sum(amix_d, NULL);
-+ amix_d->ops->commit_write(amix_d);
-+ }
-+}
-+
-+static int ct_mixer_get_resources(struct ct_mixer *mixer)
-+{
-+ struct sum_mgr *sum_mgr;
-+ struct sum *sum;
-+ struct sum_desc sum_desc = {0};
-+ struct amixer_mgr *amixer_mgr;
-+ struct amixer *amixer;
-+ struct amixer_desc am_desc = {0};
-+ int err;
-+ int i;
-+
-+ /* Allocate sum resources for mixer obj */
-+ sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
-+ sum_desc.msr = mixer->atc->msr;
-+ for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
-+ err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi:Failed to get sum resources for "
-+ "front output!\n");
-+ break;
-+ }
-+ mixer->sums[i] = sum;
-+ }
-+ if (err)
-+ goto error1;
-+
-+ /* Allocate amixer resources for mixer obj */
-+ amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
-+ am_desc.msr = mixer->atc->msr;
-+ for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
-+ err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi:Failed to get amixer resources "
-+ "for mixer obj!\n");
-+ break;
-+ }
-+ mixer->amixers[i] = amixer;
-+ }
-+ if (err)
-+ goto error2;
-+
-+ return 0;
-+
-+error2:
-+ for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
-+ if (NULL != mixer->amixers[i]) {
-+ amixer = mixer->amixers[i];
-+ amixer_mgr->put_amixer(amixer_mgr, amixer);
-+ mixer->amixers[i] = NULL;
-+ }
-+ }
-+error1:
-+ for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
-+ if (NULL != mixer->sums[i]) {
-+ sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
-+ mixer->sums[i] = NULL;
-+ }
-+ }
-+
-+ return err;
-+}
-+
-+static int ct_mixer_get_mem(struct ct_mixer **rmixer)
-+{
-+ struct ct_mixer *mixer;
-+ int err;
-+
-+ *rmixer = NULL;
-+ /* Allocate mem for mixer obj */
-+ mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
-+ if (!mixer)
-+ return -ENOMEM;
-+
-+ mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM),
-+ GFP_KERNEL);
-+ if (!mixer->amixers) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+ mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL);
-+ if (!mixer->sums) {
-+ err = -ENOMEM;
-+ goto error2;
-+ }
-+
-+ *rmixer = mixer;
-+ return 0;
-+
-+error2:
-+ kfree(mixer->amixers);
-+error1:
-+ kfree(mixer);
-+ return err;
-+}
-+
-+static int ct_mixer_topology_build(struct ct_mixer *mixer)
-+{
-+ struct sum *sum;
-+ struct amixer *amix_d, *amix_s;
-+ enum CT_AMIXER_CTL i, j;
-+
-+ /* Build topology from destination to source */
-+
-+ /* Set up Master mixer */
-+ for (i = AMIXER_MASTER_F, j = SUM_IN_F;
-+ i <= AMIXER_MASTER_S; i++, j++) {
-+ amix_d = mixer->amixers[i*CHN_NUM];
-+ sum = mixer->sums[j*CHN_NUM];
-+ amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
-+ amix_d = mixer->amixers[i*CHN_NUM+1];
-+ sum = mixer->sums[j*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
-+ }
-+
-+ /* Set up Wave-out mixer */
-+ for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
-+ i <= AMIXER_WAVE_S; i++, j++) {
-+ amix_d = mixer->amixers[i*CHN_NUM];
-+ amix_s = mixer->amixers[j*CHN_NUM];
-+ amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
-+ amix_d = mixer->amixers[i*CHN_NUM+1];
-+ amix_s = mixer->amixers[j*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
-+ }
-+
-+ /* Set up S/PDIF-out mixer */
-+ amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
-+ amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
-+ amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
-+ amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
-+ amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
-+
-+ /* Set up PCM-in mixer */
-+ for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) {
-+ amix_d = mixer->amixers[i*CHN_NUM];
-+ sum = mixer->sums[j*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[i*CHN_NUM+1];
-+ sum = mixer->sums[j*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ }
-+
-+ /* Set up Line-in mixer */
-+ amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ /* Set up Mic-in mixer */
-+ amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ /* Set up S/PDIF-in mixer */
-+ amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ /* Set up Master recording mixer */
-+ amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
-+ amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
-+ amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
-+
-+ /* Set up PCM-in recording mixer */
-+ amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ /* Set up Line-in recording mixer */
-+ amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ /* Set up Mic-in recording mixer */
-+ amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ /* Set up S/PDIF-in recording mixer */
-+ amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+ amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
-+ sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
-+ amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
-+
-+ return 0;
-+}
-+
-+static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
-+{
-+ amixer->ops->set_input(amixer, rsc);
-+ amixer->ops->commit_write(amixer);
-+
-+ return 0;
-+}
-+
-+static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
-+{
-+ switch (type) {
-+ case MIX_WAVE_FRONT: return AMIXER_WAVE_F;
-+ case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;
-+ case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C;
-+ case MIX_WAVE_REAR: return AMIXER_WAVE_R;
-+ case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C;
-+ case MIX_SPDIF_OUT: return AMIXER_SPDIFO;
-+ case MIX_LINE_IN: return AMIXER_LINEIN;
-+ case MIX_MIC_IN: return AMIXER_MIC;
-+ case MIX_SPDIF_IN: return AMIXER_SPDIFI;
-+ case MIX_PCMI_FRONT: return AMIXER_PCM_F;
-+ case MIX_PCMI_SURROUND: return AMIXER_PCM_S;
-+ case MIX_PCMI_CENTLFE: return AMIXER_PCM_C;
-+ case MIX_PCMI_REAR: return AMIXER_PCM_R;
-+ default: return 0;
-+ }
-+}
-+
-+static int mixer_get_output_ports(struct ct_mixer *mixer,
-+ enum MIXER_PORT_T type,
-+ struct rsc **rleft, struct rsc **rright)
-+{
-+ enum CT_AMIXER_CTL amix = port_to_amixer(type);
-+
-+ if (NULL != rleft)
-+ *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
-+
-+ if (NULL != rright)
-+ *rright =
-+ &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
-+
-+ return 0;
-+}
-+
-+static int mixer_set_input_left(struct ct_mixer *mixer,
-+ enum MIXER_PORT_T type, struct rsc *rsc)
-+{
-+ enum CT_AMIXER_CTL amix = port_to_amixer(type);
-+
-+ mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
-+ amix = get_recording_amixer(amix);
-+ if (amix < NUM_CT_AMIXERS)
-+ mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
-+
-+ return 0;
-+}
-+
-+static int
-+mixer_set_input_right(struct ct_mixer *mixer,
-+ enum MIXER_PORT_T type, struct rsc *rsc)
-+{
-+ enum CT_AMIXER_CTL amix = port_to_amixer(type);
-+
-+ mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
-+ amix = get_recording_amixer(amix);
-+ if (amix < NUM_CT_AMIXERS)
-+ mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int mixer_resume(struct ct_mixer *mixer)
-+{
-+ int i, state;
-+ struct amixer *amixer;
-+
-+ /* resume topology and volume gain. */
-+ for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {
-+ amixer = mixer->amixers[i];
-+ amixer->ops->commit_write(amixer);
-+ }
-+
-+ /* resume switch state. */
-+ for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {
-+ state = get_switch_state(mixer, i);
-+ do_switch(mixer->atc, i, state);
-+ }
-+
-+ return 0;
-+}
-+#endif
-+
-+int ct_mixer_destroy(struct ct_mixer *mixer)
-+{
-+ struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
-+ struct amixer_mgr *amixer_mgr =
-+ (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
-+ struct amixer *amixer;
-+ int i = 0;
-+
-+ /* Release amixer resources */
-+ for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
-+ if (NULL != mixer->amixers[i]) {
-+ amixer = mixer->amixers[i];
-+ amixer_mgr->put_amixer(amixer_mgr, amixer);
-+ }
-+ }
-+
-+ /* Release sum resources */
-+ for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
-+ if (NULL != mixer->sums[i])
-+ sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
-+ }
-+
-+ /* Release mem assigned to mixer object */
-+ kfree(mixer->sums);
-+ kfree(mixer->amixers);
-+ kfree(mixer);
-+
-+ return 0;
-+}
-+
-+int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
-+{
-+ struct ct_mixer *mixer;
-+ int err;
-+
-+ *rmixer = NULL;
-+
-+ /* Allocate mem for mixer obj */
-+ err = ct_mixer_get_mem(&mixer);
-+ if (err)
-+ return err;
-+
-+ mixer->switch_state = 0;
-+ mixer->atc = atc;
-+ /* Set operations */
-+ 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
-+ mixer->resume = mixer_resume;
-+#endif
-+
-+ /* Allocate chip resources for mixer obj */
-+ err = ct_mixer_get_resources(mixer);
-+ if (err)
-+ goto error;
-+
-+ /* Build internal mixer topology */
-+ ct_mixer_topology_build(mixer);
-+
-+ *rmixer = mixer;
-+
-+ return 0;
-+
-+error:
-+ ct_mixer_destroy(mixer);
-+ return err;
-+}
-+
-+int ct_alsa_mix_create(struct ct_atc *atc,
-+ enum CTALSADEVS device,
-+ const char *device_name)
-+{
-+ int err;
-+
-+ /* Create snd kcontrol instances on demand */
-+ /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
-+ err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
-+ if (err)
-+ return err;
-+
-+ strcpy(atc->card->mixername, device_name);
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/ctmixer.h
-@@ -0,0 +1,70 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctmixer.h
-+ *
-+ * @Brief
-+ * This file contains the definition of the mixer device functions.
-+ *
-+ * @Author Liu Chun
-+ * @Date Mar 28 2008
-+ *
-+ */
-+
-+#ifndef CTMIXER_H
-+#define CTMIXER_H
-+
-+#include "ctatc.h"
-+#include "ctresource.h"
-+
-+#define INIT_VOL 0x1c00
-+
-+enum MIXER_PORT_T {
-+ MIX_WAVE_FRONT,
-+ MIX_WAVE_REAR,
-+ MIX_WAVE_CENTLFE,
-+ MIX_WAVE_SURROUND,
-+ MIX_SPDIF_OUT,
-+ MIX_PCMO_FRONT,
-+ MIX_MIC_IN,
-+ MIX_LINE_IN,
-+ MIX_SPDIF_IN,
-+ MIX_PCMI_FRONT,
-+ MIX_PCMI_REAR,
-+ MIX_PCMI_CENTLFE,
-+ MIX_PCMI_SURROUND,
-+
-+ NUM_MIX_PORTS
-+};
-+
-+/* alsa mixer descriptor */
-+struct ct_mixer {
-+ struct ct_atc *atc;
-+
-+ void **amixers; /* amixer resources for volume control */
-+ void **sums; /* sum resources for signal collection */
-+ unsigned int switch_state; /* A bit-map to indicate state of switches */
-+
-+ int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type,
-+ struct rsc **rleft, struct rsc **rright);
-+
-+ int (*set_input_left)(struct ct_mixer *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
-+ int (*resume)(struct ct_mixer *mixer);
-+#endif
-+};
-+
-+int ct_alsa_mix_create(struct ct_atc *atc,
-+ enum CTALSADEVS device,
-+ const char *device_name);
-+int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer);
-+int ct_mixer_destroy(struct ct_mixer *mixer);
-+
-+#endif /* CTMIXER_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctpcm.c
-@@ -0,0 +1,430 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctpcm.c
-+ *
-+ * @Brief
-+ * This file contains the definition of the pcm device functions.
-+ *
-+ * @Author Liu Chun
-+ * @Date Apr 2 2008
-+ *
-+ */
-+
-+#include "ctpcm.h"
-+#include "cttimer.h"
-+#include <sound/pcm.h>
-+
-+/* Hardware descriptions for playback */
-+static struct snd_pcm_hardware ct_pcm_playback_hw = {
-+ .info = (SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_INTERLEAVED |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_PAUSE),
-+ .formats = (SNDRV_PCM_FMTBIT_U8 |
-+ SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_3LE |
-+ SNDRV_PCM_FMTBIT_S32_LE |
-+ SNDRV_PCM_FMTBIT_FLOAT_LE),
-+ .rates = (SNDRV_PCM_RATE_CONTINUOUS |
-+ SNDRV_PCM_RATE_8000_192000),
-+ .rate_min = 8000,
-+ .rate_max = 192000,
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .buffer_bytes_max = (128*1024),
-+ .period_bytes_min = (64),
-+ .period_bytes_max = (128*1024),
-+ .periods_min = 2,
-+ .periods_max = 1024,
-+ .fifo_size = 0,
-+};
-+
-+static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
-+ .info = (SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_INTERLEAVED |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_PAUSE),
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
-+ .rates = (SNDRV_PCM_RATE_48000 |
-+ SNDRV_PCM_RATE_44100 |
-+ SNDRV_PCM_RATE_32000),
-+ .rate_min = 32000,
-+ .rate_max = 48000,
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .buffer_bytes_max = (128*1024),
-+ .period_bytes_min = (64),
-+ .period_bytes_max = (128*1024),
-+ .periods_min = 2,
-+ .periods_max = 1024,
-+ .fifo_size = 0,
-+};
-+
-+/* Hardware descriptions for capture */
-+static struct snd_pcm_hardware ct_pcm_capture_hw = {
-+ .info = (SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_INTERLEAVED |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_PAUSE |
-+ SNDRV_PCM_INFO_MMAP_VALID),
-+ .formats = (SNDRV_PCM_FMTBIT_U8 |
-+ SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_3LE |
-+ SNDRV_PCM_FMTBIT_S32_LE |
-+ SNDRV_PCM_FMTBIT_FLOAT_LE),
-+ .rates = (SNDRV_PCM_RATE_CONTINUOUS |
-+ SNDRV_PCM_RATE_8000_96000),
-+ .rate_min = 8000,
-+ .rate_max = 96000,
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .buffer_bytes_max = (128*1024),
-+ .period_bytes_min = (384),
-+ .period_bytes_max = (64*1024),
-+ .periods_min = 2,
-+ .periods_max = 1024,
-+ .fifo_size = 0,
-+};
-+
-+static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
-+{
-+ struct ct_atc_pcm *apcm = atc_pcm;
-+
-+ if (!apcm->substream)
-+ return;
-+
-+ snd_pcm_period_elapsed(apcm->substream);
-+}
-+
-+static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
-+{
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+ struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
-+
-+ atc->pcm_release_resources(atc, apcm);
-+ ct_timer_instance_free(apcm->timer);
-+ kfree(apcm);
-+ runtime->private_data = NULL;
-+}
-+
-+/* pcm playback operations */
-+static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm;
-+ int err;
-+
-+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
-+ if (!apcm)
-+ return -ENOMEM;
-+
-+ apcm->substream = substream;
-+ apcm->interrupt = ct_atc_pcm_interrupt;
-+ runtime->private_data = apcm;
-+ runtime->private_free = ct_atc_pcm_free_substream;
-+ if (IEC958 == substream->pcm->device) {
-+ runtime->hw = ct_spdif_passthru_playback_hw;
-+ atc->spdif_out_passthru(atc, 1);
-+ } else {
-+ runtime->hw = ct_pcm_playback_hw;
-+ if (FRONT == substream->pcm->device)
-+ runtime->hw.channels_max = 8;
-+ }
-+
-+ err = snd_pcm_hw_constraint_integer(runtime,
-+ SNDRV_PCM_HW_PARAM_PERIODS);
-+ if (err < 0) {
-+ kfree(apcm);
-+ return err;
-+ }
-+ err = snd_pcm_hw_constraint_minmax(runtime,
-+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-+ 1024, UINT_MAX);
-+ if (err < 0) {
-+ kfree(apcm);
-+ return err;
-+ }
-+
-+ apcm->timer = ct_timer_instance_new(atc->timer, apcm);
-+ if (!apcm->timer)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+
-+ /* TODO: Notify mixer inactive. */
-+ if (IEC958 == substream->pcm->device)
-+ atc->spdif_out_passthru(atc, 0);
-+
-+ /* The ct_atc_pcm object will be freed by runtime->private_free */
-+
-+ return 0;
-+}
-+
-+static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *hw_params)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct ct_atc_pcm *apcm = substream->runtime->private_data;
-+ int err;
-+
-+ err = snd_pcm_lib_malloc_pages(substream,
-+ params_buffer_bytes(hw_params));
-+ if (err < 0)
-+ return err;
-+ /* clear previous resources */
-+ atc->pcm_release_resources(atc, apcm);
-+ return err;
-+}
-+
-+static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct ct_atc_pcm *apcm = substream->runtime->private_data;
-+
-+ /* clear previous resources */
-+ atc->pcm_release_resources(atc, apcm);
-+ /* Free snd-allocated pages */
-+ return snd_pcm_lib_free_pages(substream);
-+}
-+
-+
-+static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
-+{
-+ int err;
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+
-+ if (IEC958 == substream->pcm->device)
-+ err = atc->spdif_passthru_playback_prepare(atc, apcm);
-+ else
-+ err = atc->pcm_playback_prepare(atc, apcm);
-+
-+ if (err < 0) {
-+ printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ atc->pcm_playback_start(atc, apcm);
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ atc->pcm_playback_stop(atc, apcm);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static snd_pcm_uframes_t
-+ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
-+{
-+ unsigned long position;
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+
-+ /* Read out playback position */
-+ position = atc->pcm_playback_position(atc, apcm);
-+ position = bytes_to_frames(runtime, position);
-+ if (position >= runtime->buffer_size)
-+ position = 0;
-+ return position;
-+}
-+
-+/* pcm capture operations */
-+static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm;
-+ int err;
-+
-+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
-+ if (!apcm)
-+ return -ENOMEM;
-+
-+ apcm->started = 0;
-+ apcm->substream = substream;
-+ apcm->interrupt = ct_atc_pcm_interrupt;
-+ runtime->private_data = apcm;
-+ runtime->private_free = ct_atc_pcm_free_substream;
-+ runtime->hw = ct_pcm_capture_hw;
-+ runtime->hw.rate_max = atc->rsr * atc->msr;
-+
-+ err = snd_pcm_hw_constraint_integer(runtime,
-+ SNDRV_PCM_HW_PARAM_PERIODS);
-+ if (err < 0) {
-+ kfree(apcm);
-+ return err;
-+ }
-+ err = snd_pcm_hw_constraint_minmax(runtime,
-+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-+ 1024, UINT_MAX);
-+ if (err < 0) {
-+ kfree(apcm);
-+ return err;
-+ }
-+
-+ apcm->timer = ct_timer_instance_new(atc->timer, apcm);
-+ if (!apcm->timer)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
-+{
-+ /* The ct_atc_pcm object will be freed by runtime->private_free */
-+ /* TODO: Notify mixer inactive. */
-+ return 0;
-+}
-+
-+static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
-+{
-+ int err;
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+
-+ err = atc->pcm_capture_prepare(atc, apcm);
-+ if (err < 0) {
-+ printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ atc->pcm_capture_start(atc, apcm);
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ atc->pcm_capture_stop(atc, apcm);
-+ break;
-+ default:
-+ atc->pcm_capture_stop(atc, apcm);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static snd_pcm_uframes_t
-+ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
-+{
-+ unsigned long position;
-+ struct ct_atc *atc = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = runtime->private_data;
-+
-+ /* Read out playback position */
-+ position = atc->pcm_capture_position(atc, apcm);
-+ position = bytes_to_frames(runtime, position);
-+ if (position >= runtime->buffer_size)
-+ position = 0;
-+ return position;
-+}
-+
-+/* PCM operators for playback */
-+static struct snd_pcm_ops ct_pcm_playback_ops = {
-+ .open = ct_pcm_playback_open,
-+ .close = ct_pcm_playback_close,
-+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = ct_pcm_hw_params,
-+ .hw_free = ct_pcm_hw_free,
-+ .prepare = ct_pcm_playback_prepare,
-+ .trigger = ct_pcm_playback_trigger,
-+ .pointer = ct_pcm_playback_pointer,
-+ .page = snd_pcm_sgbuf_ops_page,
-+};
-+
-+/* PCM operators for capture */
-+static struct snd_pcm_ops ct_pcm_capture_ops = {
-+ .open = ct_pcm_capture_open,
-+ .close = ct_pcm_capture_close,
-+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = ct_pcm_hw_params,
-+ .hw_free = ct_pcm_hw_free,
-+ .prepare = ct_pcm_capture_prepare,
-+ .trigger = ct_pcm_capture_trigger,
-+ .pointer = ct_pcm_capture_pointer,
-+ .page = snd_pcm_sgbuf_ops_page,
-+};
-+
-+/* Create ALSA pcm device */
-+int ct_alsa_pcm_create(struct ct_atc *atc,
-+ enum CTALSADEVS device,
-+ const char *device_name)
-+{
-+ struct snd_pcm *pcm;
-+ int err;
-+ int playback_count, capture_count;
-+
-+ playback_count = (IEC958 == device) ? 1 : 8;
-+ capture_count = (FRONT == device) ? 1 : 0;
-+ err = snd_pcm_new(atc->card, "ctxfi", device,
-+ playback_count, capture_count, &pcm);
-+ if (err < 0) {
-+ printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
-+ return err;
-+ }
-+
-+ pcm->private_data = atc;
-+ pcm->info_flags = 0;
-+ pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
-+ strlcpy(pcm->name, device_name, sizeof(pcm->name));
-+
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
-+
-+ if (FRONT == device)
-+ snd_pcm_set_ops(pcm,
-+ SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
-+
-+ 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
-+ atc->pcms[device] = pcm;
-+#endif
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/ctpcm.h
-@@ -0,0 +1,27 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctpcm.h
-+ *
-+ * @Brief
-+ * This file contains the definition of the pcm device functions.
-+ *
-+ * @Author Liu Chun
-+ * @Date Mar 28 2008
-+ *
-+ */
-+
-+#ifndef CTPCM_H
-+#define CTPCM_H
-+
-+#include "ctatc.h"
-+
-+int ct_alsa_pcm_create(struct ct_atc *atc,
-+ enum CTALSADEVS device,
-+ const char *device_name);
-+
-+#endif /* CTPCM_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctresource.c
-@@ -0,0 +1,301 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctresource.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of some generic helper functions.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 15 2008
-+ *
-+ */
-+
-+#include "ctresource.h"
-+#include "cthardware.h"
-+#include <linux/err.h>
-+#include <linux/slab.h>
-+
-+#define AUDIO_SLOT_BLOCK_NUM 256
-+
-+/* Resource allocation based on bit-map management mechanism */
-+static int
-+get_resource(u8 *rscs, unsigned int amount,
-+ unsigned int multi, unsigned int *ridx)
-+{
-+ int i, j, k, n;
-+
-+ /* Check whether there are sufficient resources to meet request. */
-+ for (i = 0, n = multi; i < amount; i++) {
-+ j = i / 8;
-+ k = i % 8;
-+ if (rscs[j] & ((u8)1 << k)) {
-+ n = multi;
-+ continue;
-+ }
-+ if (!(--n))
-+ break; /* found sufficient contiguous resources */
-+ }
-+
-+ if (i >= amount) {
-+ /* Can not find sufficient contiguous resources */
-+ return -ENOENT;
-+ }
-+
-+ /* Mark the contiguous bits in resource bit-map as used */
-+ for (n = multi; n > 0; n--) {
-+ j = i / 8;
-+ k = i % 8;
-+ rscs[j] |= ((u8)1 << k);
-+ i--;
-+ }
-+
-+ *ridx = i + 1;
-+
-+ return 0;
-+}
-+
-+static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
-+{
-+ unsigned int i, j, k, n;
-+
-+ /* Mark the contiguous bits in resource bit-map as used */
-+ for (n = multi, i = idx; n > 0; n--) {
-+ j = i / 8;
-+ k = i % 8;
-+ rscs[j] &= ~((u8)1 << k);
-+ i++;
-+ }
-+
-+ return 0;
-+}
-+
-+int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
-+{
-+ int err;
-+
-+ if (n > mgr->avail)
-+ return -ENOENT;
-+
-+ err = get_resource(mgr->rscs, mgr->amount, n, ridx);
-+ if (!err)
-+ mgr->avail -= n;
-+
-+ return err;
-+}
-+
-+int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
-+{
-+ put_resource(mgr->rscs, n, idx);
-+ mgr->avail += n;
-+
-+ return 0;
-+}
-+
-+static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
-+ /* SRC channel is at Audio Ring slot 1 every 16 slots. */
-+ [SRC] = 0x1,
-+ [AMIXER] = 0x4,
-+ [SUM] = 0xc,
-+};
-+
-+static int rsc_index(const struct rsc *rsc)
-+{
-+ return rsc->conj;
-+}
-+
-+static int audio_ring_slot(const struct rsc *rsc)
-+{
-+ return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
-+}
-+
-+static int rsc_next_conj(struct rsc *rsc)
-+{
-+ unsigned int i;
-+ for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
-+ i++;
-+ rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
-+ return rsc->conj;
-+}
-+
-+static int rsc_master(struct rsc *rsc)
-+{
-+ return rsc->conj = rsc->idx;
-+}
-+
-+static struct rsc_ops rsc_generic_ops = {
-+ .index = rsc_index,
-+ .output_slot = audio_ring_slot,
-+ .master = rsc_master,
-+ .next_conj = rsc_next_conj,
-+};
-+
-+int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
-+{
-+ int err = 0;
-+
-+ rsc->idx = idx;
-+ rsc->conj = idx;
-+ rsc->type = type;
-+ rsc->msr = msr;
-+ rsc->hw = hw;
-+ rsc->ops = &rsc_generic_ops;
-+ if (!hw) {
-+ rsc->ctrl_blk = NULL;
-+ return 0;
-+ }
-+
-+ switch (type) {
-+ case SRC:
-+ err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
-+ break;
-+ case AMIXER:
-+ err = ((struct hw *)hw)->
-+ amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
-+ break;
-+ case SRCIMP:
-+ case SUM:
-+ case DAIO:
-+ break;
-+ default:
-+ printk(KERN_ERR
-+ "ctxfi: Invalid resource type value %d!\n", type);
-+ return -EINVAL;
-+ }
-+
-+ if (err) {
-+ printk(KERN_ERR
-+ "ctxfi: Failed to get resource control block!\n");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+int rsc_uninit(struct rsc *rsc)
-+{
-+ if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
-+ switch (rsc->type) {
-+ case SRC:
-+ ((struct hw *)rsc->hw)->
-+ src_rsc_put_ctrl_blk(rsc->ctrl_blk);
-+ break;
-+ case AMIXER:
-+ ((struct hw *)rsc->hw)->
-+ amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
-+ break;
-+ case SUM:
-+ case DAIO:
-+ break;
-+ default:
-+ printk(KERN_ERR "ctxfi: "
-+ "Invalid resource type value %d!\n", rsc->type);
-+ break;
-+ }
-+
-+ rsc->hw = rsc->ctrl_blk = NULL;
-+ }
-+
-+ rsc->idx = rsc->conj = 0;
-+ rsc->type = NUM_RSCTYP;
-+ rsc->msr = 0;
-+
-+ return 0;
-+}
-+
-+int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
-+ unsigned int amount, void *hw_obj)
-+{
-+ int err = 0;
-+ struct hw *hw = hw_obj;
-+
-+ mgr->type = NUM_RSCTYP;
-+
-+ mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
-+ if (!mgr->rscs)
-+ return -ENOMEM;
-+
-+ switch (type) {
-+ case SRC:
-+ err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
-+ break;
-+ case SRCIMP:
-+ err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
-+ break;
-+ case AMIXER:
-+ err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
-+ break;
-+ case DAIO:
-+ err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
-+ break;
-+ case SUM:
-+ break;
-+ default:
-+ printk(KERN_ERR
-+ "ctxfi: Invalid resource type value %d!\n", type);
-+ err = -EINVAL;
-+ goto error;
-+ }
-+
-+ if (err) {
-+ printk(KERN_ERR
-+ "ctxfi: Failed to get manager control block!\n");
-+ goto error;
-+ }
-+
-+ mgr->type = type;
-+ mgr->avail = mgr->amount = amount;
-+ mgr->hw = hw;
-+
-+ return 0;
-+
-+error:
-+ kfree(mgr->rscs);
-+ return err;
-+}
-+
-+int rsc_mgr_uninit(struct rsc_mgr *mgr)
-+{
-+ if (NULL != mgr->rscs) {
-+ kfree(mgr->rscs);
-+ mgr->rscs = NULL;
-+ }
-+
-+ if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
-+ switch (mgr->type) {
-+ case SRC:
-+ ((struct hw *)mgr->hw)->
-+ src_mgr_put_ctrl_blk(mgr->ctrl_blk);
-+ break;
-+ case SRCIMP:
-+ ((struct hw *)mgr->hw)->
-+ srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
-+ break;
-+ case AMIXER:
-+ ((struct hw *)mgr->hw)->
-+ amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
-+ break;
-+ case DAIO:
-+ ((struct hw *)mgr->hw)->
-+ daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
-+ break;
-+ case SUM:
-+ break;
-+ default:
-+ printk(KERN_ERR "ctxfi: "
-+ "Invalid resource type value %d!\n", mgr->type);
-+ break;
-+ }
-+
-+ mgr->hw = mgr->ctrl_blk = NULL;
-+ }
-+
-+ mgr->type = NUM_RSCTYP;
-+ mgr->avail = mgr->amount = 0;
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/ctresource.h
-@@ -0,0 +1,72 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctresource.h
-+ *
-+ * @Brief
-+ * This file contains the definition of generic hardware resources for
-+ * resource management.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 13 2008
-+ *
-+ */
-+
-+#ifndef CTRESOURCE_H
-+#define CTRESOURCE_H
-+
-+#include <linux/types.h>
-+
-+enum RSCTYP {
-+ SRC,
-+ SRCIMP,
-+ AMIXER,
-+ SUM,
-+ DAIO,
-+ NUM_RSCTYP /* This must be the last one and less than 16 */
-+};
-+
-+struct rsc_ops;
-+
-+struct rsc {
-+ u32 idx:12; /* The index of a resource */
-+ u32 type:4; /* The type (RSCTYP) of a resource */
-+ u32 conj:12; /* Current conjugate index */
-+ u32 msr:4; /* The Master Sample Rate a resource working on */
-+ void *ctrl_blk; /* Chip specific control info block for a resource */
-+ void *hw; /* Chip specific object for hardware access means */
-+ struct rsc_ops *ops; /* Generic resource operations */
-+};
-+
-+struct rsc_ops {
-+ int (*master)(struct rsc *rsc); /* Move to master resource */
-+ int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
-+ int (*index)(const struct rsc *rsc); /* Return the index of resource */
-+ /* Return the output slot number */
-+ int (*output_slot)(const struct rsc *rsc);
-+};
-+
-+int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw);
-+int rsc_uninit(struct rsc *rsc);
-+
-+struct rsc_mgr {
-+ enum RSCTYP type; /* The type (RSCTYP) of resource to manage */
-+ unsigned int amount; /* The total amount of a kind of resource */
-+ unsigned int avail; /* The amount of currently available resources */
-+ unsigned char *rscs; /* The bit-map for resource allocation */
-+ void *ctrl_blk; /* Chip specific control info block */
-+ void *hw; /* Chip specific object for hardware access */
-+};
-+
-+/* Resource management is based on bit-map mechanism */
-+int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
-+ unsigned int amount, void *hw);
-+int rsc_mgr_uninit(struct rsc_mgr *mgr);
-+int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx);
-+int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx);
-+
-+#endif /* CTRESOURCE_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctsrc.c
-@@ -0,0 +1,885 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctsrc.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of the Sample Rate Convertor
-+ * resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 13 2008
-+ *
-+ */
-+
-+#include "ctsrc.h"
-+#include "cthardware.h"
-+#include <linux/slab.h>
-+
-+#define SRC_RESOURCE_NUM 64
-+#define SRCIMP_RESOURCE_NUM 256
-+
-+static unsigned int conj_mask;
-+
-+static int src_default_config_memrd(struct src *src);
-+static int src_default_config_memwr(struct src *src);
-+static int src_default_config_arcrw(struct src *src);
-+
-+static int (*src_default_config[3])(struct src *) = {
-+ [MEMRD] = src_default_config_memrd,
-+ [MEMWR] = src_default_config_memwr,
-+ [ARCRW] = src_default_config_arcrw
-+};
-+
-+static int src_set_state(struct src *src, unsigned int state)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_state(src->rsc.ctrl_blk, state);
-+
-+ return 0;
-+}
-+
-+static int src_set_bm(struct src *src, unsigned int bm)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_bm(src->rsc.ctrl_blk, bm);
-+
-+ return 0;
-+}
-+
-+static int src_set_sf(struct src *src, unsigned int sf)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_sf(src->rsc.ctrl_blk, sf);
-+
-+ return 0;
-+}
-+
-+static int src_set_pm(struct src *src, unsigned int pm)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_pm(src->rsc.ctrl_blk, pm);
-+
-+ return 0;
-+}
-+
-+static int src_set_rom(struct src *src, unsigned int rom)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_rom(src->rsc.ctrl_blk, rom);
-+
-+ return 0;
-+}
-+
-+static int src_set_vo(struct src *src, unsigned int vo)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_vo(src->rsc.ctrl_blk, vo);
-+
-+ return 0;
-+}
-+
-+static int src_set_st(struct src *src, unsigned int st)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_st(src->rsc.ctrl_blk, st);
-+
-+ return 0;
-+}
-+
-+static int src_set_bp(struct src *src, unsigned int bp)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_bp(src->rsc.ctrl_blk, bp);
-+
-+ return 0;
-+}
-+
-+static int src_set_cisz(struct src *src, unsigned int cisz)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_cisz(src->rsc.ctrl_blk, cisz);
-+
-+ return 0;
-+}
-+
-+static int src_set_ca(struct src *src, unsigned int ca)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_ca(src->rsc.ctrl_blk, ca);
-+
-+ return 0;
-+}
-+
-+static int src_set_sa(struct src *src, unsigned int sa)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_sa(src->rsc.ctrl_blk, sa);
-+
-+ return 0;
-+}
-+
-+static int src_set_la(struct src *src, unsigned int la)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_la(src->rsc.ctrl_blk, la);
-+
-+ return 0;
-+}
-+
-+static int src_set_pitch(struct src *src, unsigned int pitch)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_pitch(src->rsc.ctrl_blk, pitch);
-+
-+ return 0;
-+}
-+
-+static int src_set_clear_zbufs(struct src *src)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
-+
-+ return 0;
-+}
-+
-+static int src_commit_write(struct src *src)
-+{
-+ struct hw *hw;
-+ int i;
-+ unsigned int dirty = 0;
-+
-+ hw = src->rsc.hw;
-+ src->rsc.ops->master(&src->rsc);
-+ if (src->rsc.msr > 1) {
-+ /* Save dirty flags for conjugate resource programming */
-+ dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask;
-+ }
-+ hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+
-+ /* Program conjugate parameter mixer resources */
-+ if (MEMWR == src->mode)
-+ return 0;
-+
-+ for (i = 1; i < src->rsc.msr; i++) {
-+ src->rsc.ops->next_conj(&src->rsc);
-+ hw->src_set_dirty(src->rsc.ctrl_blk, dirty);
-+ hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+ }
-+ src->rsc.ops->master(&src->rsc);
-+
-+ return 0;
-+}
-+
-+static int src_get_ca(struct src *src)
-+{
-+ struct hw *hw;
-+
-+ hw = src->rsc.hw;
-+ return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+}
-+
-+static int src_init(struct src *src)
-+{
-+ src_default_config[src->mode](src);
-+
-+ return 0;
-+}
-+
-+static struct src *src_next_interleave(struct src *src)
-+{
-+ return src->intlv;
-+}
-+
-+static int src_default_config_memrd(struct src *src)
-+{
-+ struct hw *hw = src->rsc.hw;
-+ unsigned int rsr, msr;
-+
-+ hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
-+ hw->src_set_bm(src->rsc.ctrl_blk, 1);
-+ for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1)
-+ rsr++;
-+
-+ hw->src_set_rsr(src->rsc.ctrl_blk, rsr);
-+ hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16);
-+ hw->src_set_wr(src->rsc.ctrl_blk, 0);
-+ hw->src_set_pm(src->rsc.ctrl_blk, 0);
-+ hw->src_set_rom(src->rsc.ctrl_blk, 0);
-+ hw->src_set_vo(src->rsc.ctrl_blk, 0);
-+ hw->src_set_st(src->rsc.ctrl_blk, 0);
-+ hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1);
-+ hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
-+ hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
-+ hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
-+ hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
-+ hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
-+ hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
-+
-+ src->rsc.ops->master(&src->rsc);
-+ hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+
-+ for (msr = 1; msr < src->rsc.msr; msr++) {
-+ src->rsc.ops->next_conj(&src->rsc);
-+ hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
-+ hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+ }
-+ src->rsc.ops->master(&src->rsc);
-+
-+ return 0;
-+}
-+
-+static int src_default_config_memwr(struct src *src)
-+{
-+ struct hw *hw = src->rsc.hw;
-+
-+ hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
-+ hw->src_set_bm(src->rsc.ctrl_blk, 1);
-+ hw->src_set_rsr(src->rsc.ctrl_blk, 0);
-+ hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16);
-+ hw->src_set_wr(src->rsc.ctrl_blk, 1);
-+ hw->src_set_pm(src->rsc.ctrl_blk, 0);
-+ hw->src_set_rom(src->rsc.ctrl_blk, 0);
-+ hw->src_set_vo(src->rsc.ctrl_blk, 0);
-+ hw->src_set_st(src->rsc.ctrl_blk, 0);
-+ hw->src_set_ilsz(src->rsc.ctrl_blk, 0);
-+ hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
-+ hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
-+ hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
-+ hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
-+ hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
-+ hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
-+
-+ src->rsc.ops->master(&src->rsc);
-+ hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+
-+ return 0;
-+}
-+
-+static int src_default_config_arcrw(struct src *src)
-+{
-+ struct hw *hw = src->rsc.hw;
-+ unsigned int rsr, msr;
-+ unsigned int dirty;
-+
-+ hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
-+ hw->src_set_bm(src->rsc.ctrl_blk, 0);
-+ for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1)
-+ rsr++;
-+
-+ hw->src_set_rsr(src->rsc.ctrl_blk, rsr);
-+ hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32);
-+ hw->src_set_wr(src->rsc.ctrl_blk, 0);
-+ hw->src_set_pm(src->rsc.ctrl_blk, 0);
-+ hw->src_set_rom(src->rsc.ctrl_blk, 0);
-+ hw->src_set_vo(src->rsc.ctrl_blk, 0);
-+ hw->src_set_st(src->rsc.ctrl_blk, 0);
-+ hw->src_set_ilsz(src->rsc.ctrl_blk, 0);
-+ hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
-+ hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
-+ /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/
-+ hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
-+ /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/
-+ hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
-+ hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
-+ hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
-+
-+ dirty = hw->src_get_dirty(src->rsc.ctrl_blk);
-+ src->rsc.ops->master(&src->rsc);
-+ for (msr = 0; msr < src->rsc.msr; msr++) {
-+ hw->src_set_dirty(src->rsc.ctrl_blk, dirty);
-+ hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
-+ src->rsc.ctrl_blk);
-+ src->rsc.ops->next_conj(&src->rsc);
-+ }
-+ src->rsc.ops->master(&src->rsc);
-+
-+ return 0;
-+}
-+
-+static struct src_rsc_ops src_rsc_ops = {
-+ .set_state = src_set_state,
-+ .set_bm = src_set_bm,
-+ .set_sf = src_set_sf,
-+ .set_pm = src_set_pm,
-+ .set_rom = src_set_rom,
-+ .set_vo = src_set_vo,
-+ .set_st = src_set_st,
-+ .set_bp = src_set_bp,
-+ .set_cisz = src_set_cisz,
-+ .set_ca = src_set_ca,
-+ .set_sa = src_set_sa,
-+ .set_la = src_set_la,
-+ .set_pitch = src_set_pitch,
-+ .set_clr_zbufs = src_set_clear_zbufs,
-+ .commit_write = src_commit_write,
-+ .get_ca = src_get_ca,
-+ .init = src_init,
-+ .next_interleave = src_next_interleave,
-+};
-+
-+static int
-+src_rsc_init(struct src *src, u32 idx,
-+ const struct src_desc *desc, struct src_mgr *mgr)
-+{
-+ int err;
-+ int i, n;
-+ struct src *p;
-+
-+ n = (MEMRD == desc->mode) ? desc->multi : 1;
-+ for (i = 0, p = src; i < n; i++, p++) {
-+ err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw);
-+ if (err)
-+ goto error1;
-+
-+ /* Initialize src specific rsc operations */
-+ p->ops = &src_rsc_ops;
-+ p->multi = (0 == i) ? desc->multi : 1;
-+ p->mode = desc->mode;
-+ src_default_config[desc->mode](p);
-+ mgr->src_enable(mgr, p);
-+ p->intlv = p + 1;
-+ }
-+ (--p)->intlv = NULL; /* Set @intlv of the last SRC to NULL */
-+
-+ mgr->commit_write(mgr);
-+
-+ return 0;
-+
-+error1:
-+ for (i--, p--; i >= 0; i--, p--) {
-+ mgr->src_disable(mgr, p);
-+ rsc_uninit(&p->rsc);
-+ }
-+ mgr->commit_write(mgr);
-+ return err;
-+}
-+
-+static int src_rsc_uninit(struct src *src, struct src_mgr *mgr)
-+{
-+ int i, n;
-+ struct src *p;
-+
-+ n = (MEMRD == src->mode) ? src->multi : 1;
-+ for (i = 0, p = src; i < n; i++, p++) {
-+ mgr->src_disable(mgr, p);
-+ rsc_uninit(&p->rsc);
-+ p->multi = 0;
-+ p->ops = NULL;
-+ p->mode = NUM_SRCMODES;
-+ p->intlv = NULL;
-+ }
-+ mgr->commit_write(mgr);
-+
-+ return 0;
-+}
-+
-+static int
-+get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
-+{
-+ unsigned int idx = SRC_RESOURCE_NUM;
-+ int err;
-+ struct src *src;
-+ unsigned long flags;
-+
-+ *rsrc = NULL;
-+
-+ /* Check whether there are sufficient src resources to meet request. */
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ if (MEMRD == desc->mode)
-+ err = mgr_get_resource(&mgr->mgr, desc->multi, &idx);
-+ else
-+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n");
-+ return err;
-+ }
-+
-+ /* Allocate mem for master src resource */
-+ if (MEMRD == desc->mode)
-+ src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL);
-+ else
-+ src = kzalloc(sizeof(*src), GFP_KERNEL);
-+
-+ if (!src) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+
-+ err = src_rsc_init(src, idx, desc, mgr);
-+ if (err)
-+ goto error2;
-+
-+ *rsrc = src;
-+
-+ return 0;
-+
-+error2:
-+ kfree(src);
-+error1:
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ if (MEMRD == desc->mode)
-+ mgr_put_resource(&mgr->mgr, desc->multi, idx);
-+ else
-+ mgr_put_resource(&mgr->mgr, 1, idx);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ return err;
-+}
-+
-+static int put_src_rsc(struct src_mgr *mgr, struct src *src)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ src->rsc.ops->master(&src->rsc);
-+ if (MEMRD == src->mode)
-+ mgr_put_resource(&mgr->mgr, src->multi,
-+ src->rsc.ops->index(&src->rsc));
-+ else
-+ mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc));
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ src_rsc_uninit(src, mgr);
-+ kfree(src);
-+
-+ return 0;
-+}
-+
-+static int src_enable_s(struct src_mgr *mgr, struct src *src)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+ int i;
-+
-+ src->rsc.ops->master(&src->rsc);
-+ for (i = 0; i < src->rsc.msr; i++) {
-+ hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk,
-+ src->rsc.ops->index(&src->rsc));
-+ src->rsc.ops->next_conj(&src->rsc);
-+ }
-+ src->rsc.ops->master(&src->rsc);
-+
-+ return 0;
-+}
-+
-+static int src_enable(struct src_mgr *mgr, struct src *src)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+ int i;
-+
-+ src->rsc.ops->master(&src->rsc);
-+ for (i = 0; i < src->rsc.msr; i++) {
-+ hw->src_mgr_enb_src(mgr->mgr.ctrl_blk,
-+ src->rsc.ops->index(&src->rsc));
-+ src->rsc.ops->next_conj(&src->rsc);
-+ }
-+ src->rsc.ops->master(&src->rsc);
-+
-+ return 0;
-+}
-+
-+static int src_disable(struct src_mgr *mgr, struct src *src)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+ int i;
-+
-+ src->rsc.ops->master(&src->rsc);
-+ for (i = 0; i < src->rsc.msr; i++) {
-+ hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk,
-+ src->rsc.ops->index(&src->rsc));
-+ src->rsc.ops->next_conj(&src->rsc);
-+ }
-+ src->rsc.ops->master(&src->rsc);
-+
-+ return 0;
-+}
-+
-+static int src_mgr_commit_write(struct src_mgr *mgr)
-+{
-+ struct hw *hw = mgr->mgr.hw;
-+
-+ hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
-+
-+ return 0;
-+}
-+
-+int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
-+{
-+ int err, i;
-+ struct src_mgr *src_mgr;
-+
-+ *rsrc_mgr = NULL;
-+ src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL);
-+ if (!src_mgr)
-+ return -ENOMEM;
-+
-+ err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw);
-+ if (err)
-+ goto error1;
-+
-+ spin_lock_init(&src_mgr->mgr_lock);
-+ conj_mask = ((struct hw *)hw)->src_dirty_conj_mask();
-+
-+ src_mgr->get_src = get_src_rsc;
-+ src_mgr->put_src = put_src_rsc;
-+ src_mgr->src_enable_s = src_enable_s;
-+ src_mgr->src_enable = src_enable;
-+ src_mgr->src_disable = src_disable;
-+ src_mgr->commit_write = src_mgr_commit_write;
-+
-+ /* Disable all SRC resources. */
-+ for (i = 0; i < 256; i++)
-+ ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
-+
-+ ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
-+
-+ *rsrc_mgr = src_mgr;
-+
-+ return 0;
-+
-+error1:
-+ kfree(src_mgr);
-+ return err;
-+}
-+
-+int src_mgr_destroy(struct src_mgr *src_mgr)
-+{
-+ rsc_mgr_uninit(&src_mgr->mgr);
-+ kfree(src_mgr);
-+
-+ return 0;
-+}
-+
-+/* SRCIMP resource manager operations */
-+
-+static int srcimp_master(struct rsc *rsc)
-+{
-+ rsc->conj = 0;
-+ return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
-+}
-+
-+static int srcimp_next_conj(struct rsc *rsc)
-+{
-+ rsc->conj++;
-+ return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
-+}
-+
-+static int srcimp_index(const struct rsc *rsc)
-+{
-+ return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
-+}
-+
-+static struct rsc_ops srcimp_basic_rsc_ops = {
-+ .master = srcimp_master,
-+ .next_conj = srcimp_next_conj,
-+ .index = srcimp_index,
-+ .output_slot = NULL,
-+};
-+
-+static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input)
-+{
-+ struct imapper *entry;
-+ int i;
-+
-+ srcimp->rsc.ops->master(&srcimp->rsc);
-+ src->rsc.ops->master(&src->rsc);
-+ input->ops->master(input);
-+
-+ /* Program master and conjugate resources */
-+ for (i = 0; i < srcimp->rsc.msr; i++) {
-+ entry = &srcimp->imappers[i];
-+ entry->slot = input->ops->output_slot(input);
-+ entry->user = src->rsc.ops->index(&src->rsc);
-+ entry->addr = srcimp->rsc.ops->index(&srcimp->rsc);
-+ srcimp->mgr->imap_add(srcimp->mgr, entry);
-+ srcimp->mapped |= (0x1 << i);
-+
-+ srcimp->rsc.ops->next_conj(&srcimp->rsc);
-+ input->ops->next_conj(input);
-+ }
-+
-+ srcimp->rsc.ops->master(&srcimp->rsc);
-+ input->ops->master(input);
-+
-+ return 0;
-+}
-+
-+static int srcimp_unmap(struct srcimp *srcimp)
-+{
-+ int i;
-+
-+ /* Program master and conjugate resources */
-+ for (i = 0; i < srcimp->rsc.msr; i++) {
-+ if (srcimp->mapped & (0x1 << i)) {
-+ srcimp->mgr->imap_delete(srcimp->mgr,
-+ &srcimp->imappers[i]);
-+ srcimp->mapped &= ~(0x1 << i);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static struct srcimp_rsc_ops srcimp_ops = {
-+ .map = srcimp_map,
-+ .unmap = srcimp_unmap
-+};
-+
-+static int srcimp_rsc_init(struct srcimp *srcimp,
-+ const struct srcimp_desc *desc,
-+ struct srcimp_mgr *mgr)
-+{
-+ int err;
-+
-+ err = rsc_init(&srcimp->rsc, srcimp->idx[0],
-+ SRCIMP, desc->msr, mgr->mgr.hw);
-+ if (err)
-+ return err;
-+
-+ /* Reserve memory for imapper nodes */
-+ srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr,
-+ GFP_KERNEL);
-+ if (!srcimp->imappers) {
-+ err = -ENOMEM;
-+ goto error1;
-+ }
-+
-+ /* Set srcimp specific operations */
-+ srcimp->rsc.ops = &srcimp_basic_rsc_ops;
-+ srcimp->ops = &srcimp_ops;
-+ srcimp->mgr = mgr;
-+
-+ srcimp->rsc.ops->master(&srcimp->rsc);
-+
-+ return 0;
-+
-+error1:
-+ rsc_uninit(&srcimp->rsc);
-+ return err;
-+}
-+
-+static int srcimp_rsc_uninit(struct srcimp *srcimp)
-+{
-+ if (NULL != srcimp->imappers) {
-+ kfree(srcimp->imappers);
-+ srcimp->imappers = NULL;
-+ }
-+ srcimp->ops = NULL;
-+ srcimp->mgr = NULL;
-+ rsc_uninit(&srcimp->rsc);
-+
-+ return 0;
-+}
-+
-+static int get_srcimp_rsc(struct srcimp_mgr *mgr,
-+ const struct srcimp_desc *desc,
-+ struct srcimp **rsrcimp)
-+{
-+ int err, i;
-+ unsigned int idx;
-+ struct srcimp *srcimp;
-+ unsigned long flags;
-+
-+ *rsrcimp = NULL;
-+
-+ /* Allocate mem for SRCIMP resource */
-+ srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
-+ if (!srcimp)
-+ return -ENOMEM;
-+
-+ /* Check whether there are sufficient SRCIMP resources. */
-+ err = 0;
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i = 0; i < desc->msr; i++) {
-+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
-+ if (err)
-+ break;
-+
-+ srcimp->idx[i] = idx;
-+ }
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ if (err) {
-+ printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n");
-+ goto error1;
-+ }
-+
-+ err = srcimp_rsc_init(srcimp, desc, mgr);
-+ if (err)
-+ goto error1;
-+
-+ *rsrcimp = srcimp;
-+
-+ return 0;
-+
-+error1:
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i--; i >= 0; i--)
-+ mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ kfree(srcimp);
-+ return err;
-+}
-+
-+static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp)
-+{
-+ unsigned long flags;
-+ int i;
-+
-+ spin_lock_irqsave(&mgr->mgr_lock, flags);
-+ for (i = 0; i < srcimp->rsc.msr; i++)
-+ mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
-+
-+ spin_unlock_irqrestore(&mgr->mgr_lock, flags);
-+ srcimp_rsc_uninit(srcimp);
-+ kfree(srcimp);
-+
-+ return 0;
-+}
-+
-+static int srcimp_map_op(void *data, struct imapper *entry)
-+{
-+ struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr;
-+ struct hw *hw = mgr->hw;
-+
-+ hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
-+ hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user);
-+ hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
-+ hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
-+ hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
-+
-+ return 0;
-+}
-+
-+static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry)
-+{
-+ unsigned long flags;
-+ int err;
-+
-+ spin_lock_irqsave(&mgr->imap_lock, flags);
-+ if ((0 == entry->addr) && (mgr->init_imap_added)) {
-+ input_mapper_delete(&mgr->imappers,
-+ mgr->init_imap, srcimp_map_op, mgr);
-+ mgr->init_imap_added = 0;
-+ }
-+ err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr);
-+ spin_unlock_irqrestore(&mgr->imap_lock, flags);
-+
-+ return err;
-+}
-+
-+static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry)
-+{
-+ unsigned long flags;
-+ int err;
-+
-+ spin_lock_irqsave(&mgr->imap_lock, flags);
-+ err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr);
-+ if (list_empty(&mgr->imappers)) {
-+ input_mapper_add(&mgr->imappers, mgr->init_imap,
-+ srcimp_map_op, mgr);
-+ mgr->init_imap_added = 1;
-+ }
-+ spin_unlock_irqrestore(&mgr->imap_lock, flags);
-+
-+ return err;
-+}
-+
-+int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
-+{
-+ int err;
-+ struct srcimp_mgr *srcimp_mgr;
-+ struct imapper *entry;
-+
-+ *rsrcimp_mgr = NULL;
-+ srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL);
-+ if (!srcimp_mgr)
-+ return -ENOMEM;
-+
-+ err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw);
-+ if (err)
-+ goto error1;
-+
-+ spin_lock_init(&srcimp_mgr->mgr_lock);
-+ spin_lock_init(&srcimp_mgr->imap_lock);
-+ INIT_LIST_HEAD(&srcimp_mgr->imappers);
-+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-+ if (!entry) {
-+ err = -ENOMEM;
-+ goto error2;
-+ }
-+ entry->slot = entry->addr = entry->next = entry->user = 0;
-+ list_add(&entry->list, &srcimp_mgr->imappers);
-+ srcimp_mgr->init_imap = entry;
-+ srcimp_mgr->init_imap_added = 1;
-+
-+ srcimp_mgr->get_srcimp = get_srcimp_rsc;
-+ srcimp_mgr->put_srcimp = put_srcimp_rsc;
-+ srcimp_mgr->imap_add = srcimp_imap_add;
-+ srcimp_mgr->imap_delete = srcimp_imap_delete;
-+
-+ *rsrcimp_mgr = srcimp_mgr;
-+
-+ return 0;
-+
-+error2:
-+ rsc_mgr_uninit(&srcimp_mgr->mgr);
-+error1:
-+ kfree(srcimp_mgr);
-+ return err;
-+}
-+
-+int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr)
-+{
-+ unsigned long flags;
-+
-+ /* free src input mapper list */
-+ spin_lock_irqsave(&srcimp_mgr->imap_lock, flags);
-+ free_input_mapper_list(&srcimp_mgr->imappers);
-+ spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags);
-+
-+ rsc_mgr_uninit(&srcimp_mgr->mgr);
-+ kfree(srcimp_mgr);
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/ctsrc.h
-@@ -0,0 +1,149 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctsrc.h
-+ *
-+ * @Brief
-+ * This file contains the definition of the Sample Rate Convertor
-+ * resource management object.
-+ *
-+ * @Author Liu Chun
-+ * @Date May 13 2008
-+ *
-+ */
-+
-+#ifndef CTSRC_H
-+#define CTSRC_H
-+
-+#include "ctresource.h"
-+#include "ctimap.h"
-+#include <linux/spinlock.h>
-+#include <linux/list.h>
-+
-+#define SRC_STATE_OFF 0x0
-+#define SRC_STATE_INIT 0x4
-+#define SRC_STATE_RUN 0x5
-+
-+#define SRC_SF_U8 0x0
-+#define SRC_SF_S16 0x1
-+#define SRC_SF_S24 0x2
-+#define SRC_SF_S32 0x3
-+#define SRC_SF_F32 0x4
-+
-+/* Define the descriptor of a src resource */
-+enum SRCMODE {
-+ MEMRD, /* Read data from host memory */
-+ MEMWR, /* Write data to host memory */
-+ ARCRW, /* Read from and write to audio ring channel */
-+ NUM_SRCMODES
-+};
-+
-+struct src_rsc_ops;
-+
-+struct src {
-+ struct rsc rsc; /* Basic resource info */
-+ struct src *intlv; /* Pointer to next interleaved SRC in a series */
-+ struct src_rsc_ops *ops; /* SRC specific operations */
-+ /* Number of contiguous srcs for interleaved usage */
-+ unsigned char multi;
-+ unsigned char mode; /* Working mode of this SRC resource */
-+};
-+
-+struct src_rsc_ops {
-+ int (*set_state)(struct src *src, unsigned int state);
-+ int (*set_bm)(struct src *src, unsigned int bm);
-+ int (*set_sf)(struct src *src, unsigned int sf);
-+ int (*set_pm)(struct src *src, unsigned int pm);
-+ int (*set_rom)(struct src *src, unsigned int rom);
-+ int (*set_vo)(struct src *src, unsigned int vo);
-+ int (*set_st)(struct src *src, unsigned int st);
-+ int (*set_bp)(struct src *src, unsigned int bp);
-+ int (*set_cisz)(struct src *src, unsigned int cisz);
-+ int (*set_ca)(struct src *src, unsigned int ca);
-+ int (*set_sa)(struct src *src, unsigned int sa);
-+ int (*set_la)(struct src *src, unsigned int la);
-+ int (*set_pitch)(struct src *src, unsigned int pitch);
-+ int (*set_clr_zbufs)(struct src *src);
-+ int (*commit_write)(struct src *src);
-+ int (*get_ca)(struct src *src);
-+ int (*init)(struct src *src);
-+ struct src* (*next_interleave)(struct src *src);
-+};
-+
-+/* Define src resource request description info */
-+struct src_desc {
-+ /* Number of contiguous master srcs for interleaved usage */
-+ unsigned char multi;
-+ unsigned char msr;
-+ unsigned char mode; /* Working mode of the requested srcs */
-+};
-+
-+/* Define src manager object */
-+struct src_mgr {
-+ struct rsc_mgr mgr; /* Basic resource manager info */
-+ spinlock_t mgr_lock;
-+
-+ /* request src resource */
-+ int (*get_src)(struct src_mgr *mgr,
-+ const struct src_desc *desc, struct src **rsrc);
-+ /* return src resource */
-+ int (*put_src)(struct src_mgr *mgr, struct src *src);
-+ int (*src_enable_s)(struct src_mgr *mgr, struct src *src);
-+ int (*src_enable)(struct src_mgr *mgr, struct src *src);
-+ int (*src_disable)(struct src_mgr *mgr, struct src *src);
-+ int (*commit_write)(struct src_mgr *mgr);
-+};
-+
-+/* Define the descriptor of a SRC Input Mapper resource */
-+struct srcimp_mgr;
-+struct srcimp_rsc_ops;
-+
-+struct srcimp {
-+ struct rsc rsc;
-+ unsigned char idx[8];
-+ struct imapper *imappers;
-+ unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */
-+ struct srcimp_mgr *mgr;
-+ struct srcimp_rsc_ops *ops;
-+};
-+
-+struct srcimp_rsc_ops {
-+ int (*map)(struct srcimp *srcimp, struct src *user, struct rsc *input);
-+ int (*unmap)(struct srcimp *srcimp);
-+};
-+
-+/* Define SRCIMP resource request description info */
-+struct srcimp_desc {
-+ unsigned int msr;
-+};
-+
-+struct srcimp_mgr {
-+ struct rsc_mgr mgr; /* Basic resource manager info */
-+ spinlock_t mgr_lock;
-+ spinlock_t imap_lock;
-+ struct list_head imappers;
-+ struct imapper *init_imap;
-+ unsigned int init_imap_added;
-+
-+ /* request srcimp resource */
-+ int (*get_srcimp)(struct srcimp_mgr *mgr,
-+ const struct srcimp_desc *desc,
-+ struct srcimp **rsrcimp);
-+ /* return srcimp resource */
-+ int (*put_srcimp)(struct srcimp_mgr *mgr, struct srcimp *srcimp);
-+ int (*imap_add)(struct srcimp_mgr *mgr, struct imapper *entry);
-+ int (*imap_delete)(struct srcimp_mgr *mgr, struct imapper *entry);
-+};
-+
-+/* Constructor and destructor of SRC resource manager */
-+int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr);
-+int src_mgr_destroy(struct src_mgr *src_mgr);
-+/* Constructor and destructor of SRCIMP resource manager */
-+int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr);
-+int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
-+
-+#endif /* CTSRC_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/cttimer.c
-@@ -0,0 +1,443 @@
-+/*
-+ * PCM timer handling on ctxfi
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/math64.h>
-+#include <linux/moduleparam.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include "ctatc.h"
-+#include "cthardware.h"
-+#include "cttimer.h"
-+
-+static int use_system_timer;
-+MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer");
-+module_param(use_system_timer, bool, S_IRUGO);
-+
-+struct ct_timer_ops {
-+ void (*init)(struct ct_timer_instance *);
-+ void (*prepare)(struct ct_timer_instance *);
-+ void (*start)(struct ct_timer_instance *);
-+ void (*stop)(struct ct_timer_instance *);
-+ void (*free_instance)(struct ct_timer_instance *);
-+ void (*interrupt)(struct ct_timer *);
-+ void (*free_global)(struct ct_timer *);
-+};
-+
-+/* timer instance -- assigned to each PCM stream */
-+struct ct_timer_instance {
-+ spinlock_t lock;
-+ struct ct_timer *timer_base;
-+ struct ct_atc_pcm *apcm;
-+ struct snd_pcm_substream *substream;
-+ struct timer_list timer;
-+ struct list_head instance_list;
-+ struct list_head running_list;
-+ unsigned int position;
-+ unsigned int frag_count;
-+ unsigned int running:1;
-+ unsigned int need_update:1;
-+};
-+
-+/* timer instance manager */
-+struct ct_timer {
-+ spinlock_t lock; /* global timer lock (for xfitimer) */
-+ spinlock_t list_lock; /* lock for instance list */
-+ struct ct_atc *atc;
-+ struct ct_timer_ops *ops;
-+ struct list_head instance_head;
-+ struct list_head running_head;
-+ unsigned int wc; /* current wallclock */
-+ unsigned int irq_handling:1; /* in IRQ handling */
-+ unsigned int reprogram:1; /* need to reprogram the internval */
-+ unsigned int running:1; /* global timer running */
-+};
-+
-+
-+/*
-+ * system-timer-based updates
-+ */
-+
-+static void ct_systimer_callback(unsigned long data)
-+{
-+ struct ct_timer_instance *ti = (struct ct_timer_instance *)data;
-+ struct snd_pcm_substream *substream = ti->substream;
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct ct_atc_pcm *apcm = ti->apcm;
-+ unsigned int period_size = runtime->period_size;
-+ unsigned int buffer_size = runtime->buffer_size;
-+ unsigned long flags;
-+ unsigned int position, dist, interval;
-+
-+ position = substream->ops->pointer(substream);
-+ dist = (position + buffer_size - ti->position) % buffer_size;
-+ if (dist >= period_size ||
-+ position / period_size != ti->position / period_size) {
-+ apcm->interrupt(apcm);
-+ ti->position = position;
-+ }
-+ /* Add extra HZ*5/1000 to avoid overrun issue when recording
-+ * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
-+ interval = ((period_size - (position % period_size))
-+ * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
-+ spin_lock_irqsave(&ti->lock, flags);
-+ if (ti->running)
-+ mod_timer(&ti->timer, jiffies + interval);
-+ spin_unlock_irqrestore(&ti->lock, flags);
-+}
-+
-+static void ct_systimer_init(struct ct_timer_instance *ti)
-+{
-+ setup_timer(&ti->timer, ct_systimer_callback,
-+ (unsigned long)ti);
-+}
-+
-+static void ct_systimer_start(struct ct_timer_instance *ti)
-+{
-+ struct snd_pcm_runtime *runtime = ti->substream->runtime;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ti->lock, flags);
-+ ti->running = 1;
-+ mod_timer(&ti->timer,
-+ jiffies + (runtime->period_size * HZ +
-+ (runtime->rate - 1)) / runtime->rate);
-+ spin_unlock_irqrestore(&ti->lock, flags);
-+}
-+
-+static void ct_systimer_stop(struct ct_timer_instance *ti)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ti->lock, flags);
-+ ti->running = 0;
-+ del_timer(&ti->timer);
-+ spin_unlock_irqrestore(&ti->lock, flags);
-+}
-+
-+static void ct_systimer_prepare(struct ct_timer_instance *ti)
-+{
-+ ct_systimer_stop(ti);
-+ try_to_del_timer_sync(&ti->timer);
-+}
-+
-+#define ct_systimer_free ct_systimer_prepare
-+
-+static struct ct_timer_ops ct_systimer_ops = {
-+ .init = ct_systimer_init,
-+ .free_instance = ct_systimer_free,
-+ .prepare = ct_systimer_prepare,
-+ .start = ct_systimer_start,
-+ .stop = ct_systimer_stop,
-+};
-+
-+
-+/*
-+ * Handling multiple streams using a global emu20k1 timer irq
-+ */
-+
-+#define CT_TIMER_FREQ 48000
-+#define MIN_TICKS 1
-+#define MAX_TICKS ((1 << 13) - 1)
-+
-+static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
-+{
-+ struct hw *hw = atimer->atc->hw;
-+ if (ticks > MAX_TICKS)
-+ ticks = MAX_TICKS;
-+ hw->set_timer_tick(hw, ticks);
-+ if (!atimer->running)
-+ hw->set_timer_irq(hw, 1);
-+ atimer->running = 1;
-+}
-+
-+static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
-+{
-+ if (atimer->running) {
-+ struct hw *hw = atimer->atc->hw;
-+ hw->set_timer_irq(hw, 0);
-+ hw->set_timer_tick(hw, 0);
-+ atimer->running = 0;
-+ }
-+}
-+
-+static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
-+{
-+ struct hw *hw = atimer->atc->hw;
-+ return hw->get_wc(hw);
-+}
-+
-+/*
-+ * reprogram the timer interval;
-+ * checks the running instance list and determines the next timer interval.
-+ * also updates the each stream position, returns the number of streams
-+ * to call snd_pcm_period_elapsed() appropriately
-+ *
-+ * call this inside the lock and irq disabled
-+ */
-+static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
-+{
-+ struct ct_timer_instance *ti;
-+ unsigned int min_intr = (unsigned int)-1;
-+ int updates = 0;
-+ unsigned int wc, diff;
-+
-+ if (list_empty(&atimer->running_head)) {
-+ ct_xfitimer_irq_stop(atimer);
-+ atimer->reprogram = 0; /* clear flag */
-+ return 0;
-+ }
-+
-+ wc = ct_xfitimer_get_wc(atimer);
-+ diff = wc - atimer->wc;
-+ atimer->wc = wc;
-+ list_for_each_entry(ti, &atimer->running_head, running_list) {
-+ if (ti->frag_count > diff)
-+ ti->frag_count -= diff;
-+ else {
-+ unsigned int pos;
-+ unsigned int period_size, rate;
-+
-+ period_size = ti->substream->runtime->period_size;
-+ rate = ti->substream->runtime->rate;
-+ pos = ti->substream->ops->pointer(ti->substream);
-+ if (pos / period_size != ti->position / period_size) {
-+ ti->need_update = 1;
-+ ti->position = pos;
-+ updates++;
-+ }
-+ pos %= period_size;
-+ pos = period_size - pos;
-+ ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
-+ rate - 1, rate);
-+ }
-+ if (ti->need_update && !can_update)
-+ min_intr = 0; /* pending to the next irq */
-+ if (ti->frag_count < min_intr)
-+ min_intr = ti->frag_count;
-+ }
-+
-+ if (min_intr < MIN_TICKS)
-+ min_intr = MIN_TICKS;
-+ ct_xfitimer_irq_rearm(atimer, min_intr);
-+ atimer->reprogram = 0; /* clear flag */
-+ return updates;
-+}
-+
-+/* look through the instance list and call period_elapsed if needed */
-+static void ct_xfitimer_check_period(struct ct_timer *atimer)
-+{
-+ struct ct_timer_instance *ti;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&atimer->list_lock, flags);
-+ list_for_each_entry(ti, &atimer->instance_head, instance_list) {
-+ if (ti->running && ti->need_update) {
-+ ti->need_update = 0;
-+ ti->apcm->interrupt(ti->apcm);
-+ }
-+ }
-+ spin_unlock_irqrestore(&atimer->list_lock, flags);
-+}
-+
-+/* Handle timer-interrupt */
-+static void ct_xfitimer_callback(struct ct_timer *atimer)
-+{
-+ int update;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&atimer->lock, flags);
-+ atimer->irq_handling = 1;
-+ do {
-+ update = ct_xfitimer_reprogram(atimer, 1);
-+ spin_unlock(&atimer->lock);
-+ if (update)
-+ ct_xfitimer_check_period(atimer);
-+ spin_lock(&atimer->lock);
-+ } while (atimer->reprogram);
-+ atimer->irq_handling = 0;
-+ spin_unlock_irqrestore(&atimer->lock, flags);
-+}
-+
-+static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
-+{
-+ ti->frag_count = ti->substream->runtime->period_size;
-+ ti->running = 0;
-+ ti->need_update = 0;
-+}
-+
-+
-+/* start/stop the timer */
-+static void ct_xfitimer_update(struct ct_timer *atimer)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&atimer->lock, flags);
-+ if (atimer->irq_handling) {
-+ /* reached from IRQ handler; let it handle later */
-+ atimer->reprogram = 1;
-+ spin_unlock_irqrestore(&atimer->lock, flags);
-+ return;
-+ }
-+
-+ ct_xfitimer_irq_stop(atimer);
-+ ct_xfitimer_reprogram(atimer, 0);
-+ spin_unlock_irqrestore(&atimer->lock, flags);
-+}
-+
-+static void ct_xfitimer_start(struct ct_timer_instance *ti)
-+{
-+ struct ct_timer *atimer = ti->timer_base;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&atimer->lock, flags);
-+ if (list_empty(&ti->running_list))
-+ atimer->wc = ct_xfitimer_get_wc(atimer);
-+ ti->running = 1;
-+ ti->need_update = 0;
-+ list_add(&ti->running_list, &atimer->running_head);
-+ spin_unlock_irqrestore(&atimer->lock, flags);
-+ ct_xfitimer_update(atimer);
-+}
-+
-+static void ct_xfitimer_stop(struct ct_timer_instance *ti)
-+{
-+ struct ct_timer *atimer = ti->timer_base;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&atimer->lock, flags);
-+ list_del_init(&ti->running_list);
-+ ti->running = 0;
-+ spin_unlock_irqrestore(&atimer->lock, flags);
-+ ct_xfitimer_update(atimer);
-+}
-+
-+static void ct_xfitimer_free_global(struct ct_timer *atimer)
-+{
-+ ct_xfitimer_irq_stop(atimer);
-+}
-+
-+static struct ct_timer_ops ct_xfitimer_ops = {
-+ .prepare = ct_xfitimer_prepare,
-+ .start = ct_xfitimer_start,
-+ .stop = ct_xfitimer_stop,
-+ .interrupt = ct_xfitimer_callback,
-+ .free_global = ct_xfitimer_free_global,
-+};
-+
-+/*
-+ * timer instance
-+ */
-+
-+struct ct_timer_instance *
-+ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
-+{
-+ struct ct_timer_instance *ti;
-+
-+ ti = kzalloc(sizeof(*ti), GFP_KERNEL);
-+ if (!ti)
-+ return NULL;
-+ spin_lock_init(&ti->lock);
-+ INIT_LIST_HEAD(&ti->instance_list);
-+ INIT_LIST_HEAD(&ti->running_list);
-+ ti->timer_base = atimer;
-+ ti->apcm = apcm;
-+ ti->substream = apcm->substream;
-+ if (atimer->ops->init)
-+ atimer->ops->init(ti);
-+
-+ spin_lock_irq(&atimer->list_lock);
-+ list_add(&ti->instance_list, &atimer->instance_head);
-+ spin_unlock_irq(&atimer->list_lock);
-+
-+ return ti;
-+}
-+
-+void ct_timer_prepare(struct ct_timer_instance *ti)
-+{
-+ if (ti->timer_base->ops->prepare)
-+ ti->timer_base->ops->prepare(ti);
-+ ti->position = 0;
-+ ti->running = 0;
-+}
-+
-+void ct_timer_start(struct ct_timer_instance *ti)
-+{
-+ struct ct_timer *atimer = ti->timer_base;
-+ atimer->ops->start(ti);
-+}
-+
-+void ct_timer_stop(struct ct_timer_instance *ti)
-+{
-+ struct ct_timer *atimer = ti->timer_base;
-+ atimer->ops->stop(ti);
-+}
-+
-+void ct_timer_instance_free(struct ct_timer_instance *ti)
-+{
-+ struct ct_timer *atimer = ti->timer_base;
-+
-+ atimer->ops->stop(ti); /* to be sure */
-+ if (atimer->ops->free_instance)
-+ atimer->ops->free_instance(ti);
-+
-+ spin_lock_irq(&atimer->list_lock);
-+ list_del(&ti->instance_list);
-+ spin_unlock_irq(&atimer->list_lock);
-+
-+ kfree(ti);
-+}
-+
-+/*
-+ * timer manager
-+ */
-+
-+static void ct_timer_interrupt(void *data, unsigned int status)
-+{
-+ struct ct_timer *timer = data;
-+
-+ /* Interval timer interrupt */
-+ if ((status & IT_INT) && timer->ops->interrupt)
-+ timer->ops->interrupt(timer);
-+}
-+
-+struct ct_timer *ct_timer_new(struct ct_atc *atc)
-+{
-+ struct ct_timer *atimer;
-+ struct hw *hw;
-+
-+ atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
-+ if (!atimer)
-+ return NULL;
-+ spin_lock_init(&atimer->lock);
-+ spin_lock_init(&atimer->list_lock);
-+ INIT_LIST_HEAD(&atimer->instance_head);
-+ INIT_LIST_HEAD(&atimer->running_head);
-+ atimer->atc = atc;
-+ hw = atc->hw;
-+ if (!use_system_timer && hw->set_timer_irq) {
-+ snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
-+ atimer->ops = &ct_xfitimer_ops;
-+ hw->irq_callback_data = atimer;
-+ hw->irq_callback = ct_timer_interrupt;
-+ } else {
-+ snd_printd(KERN_INFO "ctxfi: Use system timer\n");
-+ atimer->ops = &ct_systimer_ops;
-+ }
-+ return atimer;
-+}
-+
-+void ct_timer_free(struct ct_timer *atimer)
-+{
-+ struct hw *hw = atimer->atc->hw;
-+ hw->irq_callback = NULL;
-+ if (atimer->ops->free_global)
-+ atimer->ops->free_global(atimer);
-+ kfree(atimer);
-+}
-+
---- /dev/null
-+++ b/sound/pci/ctxfi/cttimer.h
-@@ -0,0 +1,29 @@
-+/*
-+ * Timer handling
-+ */
-+
-+#ifndef __CTTIMER_H
-+#define __CTTIMER_H
-+
-+#include <linux/spinlock.h>
-+#include <linux/timer.h>
-+#include <linux/list.h>
-+
-+struct snd_pcm_substream;
-+struct ct_atc;
-+struct ct_atc_pcm;
-+
-+struct ct_timer;
-+struct ct_timer_instance;
-+
-+struct ct_timer *ct_timer_new(struct ct_atc *atc);
-+void ct_timer_free(struct ct_timer *atimer);
-+
-+struct ct_timer_instance *
-+ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm);
-+void ct_timer_instance_free(struct ct_timer_instance *ti);
-+void ct_timer_start(struct ct_timer_instance *ti);
-+void ct_timer_stop(struct ct_timer_instance *ti);
-+void ct_timer_prepare(struct ct_timer_instance *ti);
-+
-+#endif /* __CTTIMER_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/ctvmem.c
-@@ -0,0 +1,250 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctvmem.c
-+ *
-+ * @Brief
-+ * This file contains the implementation of virtual memory management object
-+ * for card device.
-+ *
-+ * @Author Liu Chun
-+ * @Date Apr 1 2008
-+ */
-+
-+#include "ctvmem.h"
-+#include <linux/slab.h>
-+#include <linux/mm.h>
-+#include <linux/io.h>
-+#include <sound/pcm.h>
-+
-+#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *))
-+#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE)
-+
-+/* *
-+ * Find or create vm block based on requested @size.
-+ * @size must be page aligned.
-+ * */
-+static struct ct_vm_block *
-+get_vm_block(struct ct_vm *vm, unsigned int size)
-+{
-+ struct ct_vm_block *block = NULL, *entry;
-+ struct list_head *pos;
-+
-+ size = CT_PAGE_ALIGN(size);
-+ if (size > vm->size) {
-+ printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
-+ "memory space available!\n");
-+ return NULL;
-+ }
-+
-+ mutex_lock(&vm->lock);
-+ list_for_each(pos, &vm->unused) {
-+ entry = list_entry(pos, struct ct_vm_block, list);
-+ if (entry->size >= size)
-+ break; /* found a block that is big enough */
-+ }
-+ if (pos == &vm->unused)
-+ goto out;
-+
-+ if (entry->size == size) {
-+ /* Move the vm node from unused list to used list directly */
-+ list_del(&entry->list);
-+ list_add(&entry->list, &vm->used);
-+ vm->size -= size;
-+ block = entry;
-+ goto out;
-+ }
-+
-+ block = kzalloc(sizeof(*block), GFP_KERNEL);
-+ if (!block)
-+ goto out;
-+
-+ block->addr = entry->addr;
-+ block->size = size;
-+ list_add(&block->list, &vm->used);
-+ entry->addr += size;
-+ entry->size -= size;
-+ vm->size -= size;
-+
-+ out:
-+ mutex_unlock(&vm->lock);
-+ return block;
-+}
-+
-+static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
-+{
-+ struct ct_vm_block *entry, *pre_ent;
-+ struct list_head *pos, *pre;
-+
-+ block->size = CT_PAGE_ALIGN(block->size);
-+
-+ mutex_lock(&vm->lock);
-+ list_del(&block->list);
-+ vm->size += block->size;
-+
-+ list_for_each(pos, &vm->unused) {
-+ entry = list_entry(pos, struct ct_vm_block, list);
-+ if (entry->addr >= (block->addr + block->size))
-+ break; /* found a position */
-+ }
-+ if (pos == &vm->unused) {
-+ list_add_tail(&block->list, &vm->unused);
-+ entry = block;
-+ } else {
-+ if ((block->addr + block->size) == entry->addr) {
-+ entry->addr = block->addr;
-+ entry->size += block->size;
-+ kfree(block);
-+ } else {
-+ __list_add(&block->list, pos->prev, pos);
-+ entry = block;
-+ }
-+ }
-+
-+ pos = &entry->list;
-+ pre = pos->prev;
-+ while (pre != &vm->unused) {
-+ entry = list_entry(pos, struct ct_vm_block, list);
-+ pre_ent = list_entry(pre, struct ct_vm_block, list);
-+ if ((pre_ent->addr + pre_ent->size) > entry->addr)
-+ break;
-+
-+ pre_ent->size += entry->size;
-+ list_del(pos);
-+ kfree(entry);
-+ pos = pre;
-+ pre = pos->prev;
-+ }
-+ mutex_unlock(&vm->lock);
-+}
-+
-+/* Map host addr (kmalloced/vmalloced) to device logical addr. */
-+static struct ct_vm_block *
-+ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size)
-+{
-+ struct ct_vm_block *block;
-+ unsigned int pte_start;
-+ unsigned i, pages;
-+ unsigned long *ptp;
-+
-+ block = get_vm_block(vm, size);
-+ if (block == NULL) {
-+ printk(KERN_ERR "ctxfi: No virtual memory block that is big "
-+ "enough to allocate!\n");
-+ return NULL;
-+ }
-+
-+ ptp = vm->ptp[0];
-+ pte_start = (block->addr >> CT_PAGE_SHIFT);
-+ pages = block->size >> CT_PAGE_SHIFT;
-+ for (i = 0; i < pages; i++) {
-+ unsigned long addr;
-+ addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT);
-+ ptp[pte_start + i] = addr;
-+ }
-+
-+ block->size = size;
-+ return block;
-+}
-+
-+static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block)
-+{
-+ /* do unmapping */
-+ put_vm_block(vm, block);
-+}
-+
-+/* *
-+ * return the host (kmalloced) addr of the @index-th device
-+ * page talbe page on success, or NULL on failure.
-+ * The first returned NULL indicates the termination.
-+ * */
-+static void *
-+ct_get_ptp_virt(struct ct_vm *vm, int index)
-+{
-+ void *addr;
-+
-+ addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index];
-+
-+ return addr;
-+}
-+
-+int ct_vm_create(struct ct_vm **rvm)
-+{
-+ struct ct_vm *vm;
-+ struct ct_vm_block *block;
-+ int i;
-+
-+ *rvm = NULL;
-+
-+ vm = kzalloc(sizeof(*vm), GFP_KERNEL);
-+ if (!vm)
-+ return -ENOMEM;
-+
-+ mutex_init(&vm->lock);
-+
-+ /* Allocate page table pages */
-+ for (i = 0; i < CT_PTP_NUM; i++) {
-+ vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
-+ if (!vm->ptp[i])
-+ break;
-+ }
-+ if (!i) {
-+ /* no page table pages are allocated */
-+ kfree(vm);
-+ return -ENOMEM;
-+ }
-+ vm->size = CT_ADDRS_PER_PAGE * i;
-+ /* Initialise remaining ptps */
-+ for (; i < CT_PTP_NUM; i++)
-+ vm->ptp[i] = NULL;
-+
-+ vm->map = ct_vm_map;
-+ vm->unmap = ct_vm_unmap;
-+ vm->get_ptp_virt = ct_get_ptp_virt;
-+ INIT_LIST_HEAD(&vm->unused);
-+ INIT_LIST_HEAD(&vm->used);
-+ block = kzalloc(sizeof(*block), GFP_KERNEL);
-+ if (NULL != block) {
-+ block->addr = 0;
-+ block->size = vm->size;
-+ list_add(&block->list, &vm->unused);
-+ }
-+
-+ *rvm = vm;
-+ return 0;
-+}
-+
-+/* The caller must ensure no mapping pages are being used
-+ * by hardware before calling this function */
-+void ct_vm_destroy(struct ct_vm *vm)
-+{
-+ int i;
-+ struct list_head *pos;
-+ struct ct_vm_block *entry;
-+
-+ /* free used and unused list nodes */
-+ while (!list_empty(&vm->used)) {
-+ pos = vm->used.next;
-+ list_del(pos);
-+ entry = list_entry(pos, struct ct_vm_block, list);
-+ kfree(entry);
-+ }
-+ while (!list_empty(&vm->unused)) {
-+ pos = vm->unused.next;
-+ list_del(pos);
-+ entry = list_entry(pos, struct ct_vm_block, list);
-+ kfree(entry);
-+ }
-+
-+ /* free allocated page table pages */
-+ for (i = 0; i < CT_PTP_NUM; i++)
-+ kfree(vm->ptp[i]);
-+
-+ vm->size = 0;
-+
-+ kfree(vm);
-+}
---- /dev/null
-+++ b/sound/pci/ctxfi/ctvmem.h
-@@ -0,0 +1,61 @@
-+/**
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ *
-+ * @File ctvmem.h
-+ *
-+ * @Brief
-+ * This file contains the definition of virtual memory management object
-+ * for card device.
-+ *
-+ * @Author Liu Chun
-+ * @Date Mar 28 2008
-+ */
-+
-+#ifndef CTVMEM_H
-+#define CTVMEM_H
-+
-+#define CT_PTP_NUM 1 /* num of device page table pages */
-+
-+#include <linux/mutex.h>
-+#include <linux/list.h>
-+
-+/* The chip can handle the page table of 4k pages
-+ * (emu20k1 can handle even 8k pages, but we don't use it right now)
-+ */
-+#define CT_PAGE_SIZE 4096
-+#define CT_PAGE_SHIFT 12
-+#define CT_PAGE_MASK (~(PAGE_SIZE - 1))
-+#define CT_PAGE_ALIGN(addr) ALIGN(addr, CT_PAGE_SIZE)
-+
-+struct ct_vm_block {
-+ unsigned int addr; /* starting logical addr of this block */
-+ unsigned int size; /* size of this device virtual mem block */
-+ struct list_head list;
-+};
-+
-+struct snd_pcm_substream;
-+
-+/* Virtual memory management object for card device */
-+struct ct_vm {
-+ void *ptp[CT_PTP_NUM]; /* Device page table pages */
-+ unsigned int size; /* Available addr space in bytes */
-+ struct list_head unused; /* List of unused blocks */
-+ struct list_head used; /* List of used blocks */
-+ struct mutex lock;
-+
-+ /* Map host addr (kmalloced/vmalloced) to device logical addr. */
-+ struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *,
-+ int size);
-+ /* Unmap device logical addr area. */
-+ void (*unmap)(struct ct_vm *, struct ct_vm_block *block);
-+ void *(*get_ptp_virt)(struct ct_vm *vm, int index);
-+};
-+
-+int ct_vm_create(struct ct_vm **rvm);
-+void ct_vm_destroy(struct ct_vm *vm);
-+
-+#endif /* CTVMEM_H */
---- /dev/null
-+++ b/sound/pci/ctxfi/xfi.c
-@@ -0,0 +1,164 @@
-+/*
-+ * xfi linux driver.
-+ *
-+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
-+ *
-+ * This source file is released under GPL v2 license (no other versions).
-+ * See the COPYING file included in the main directory of this source
-+ * distribution for the license terms and conditions.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+#include <linux/moduleparam.h>
-+#include <linux/pci_ids.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include "ctatc.h"
-+#include "cthardware.h"
-+
-+MODULE_AUTHOR("Creative Technology Ltd");
-+MODULE_DESCRIPTION("X-Fi driver version 1.03");
-+MODULE_LICENSE("GPL v2");
-+MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}");
-+
-+static unsigned int reference_rate = 48000;
-+static unsigned int multiple = 2;
-+MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)");
-+module_param(reference_rate, uint, S_IRUGO);
-+MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)");
-+module_param(multiple, uint, S_IRUGO);
-+
-+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-+
-+module_param_array(index, int, NULL, 0444);
-+MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver");
-+module_param_array(id, charp, NULL, 0444);
-+MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver");
-+module_param_array(enable, bool, NULL, 0444);
-+MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver");
-+
-+static struct pci_device_id ct_pci_dev_ids[] = {
-+ /* only X-Fi is supported, so... */
-+ { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1),
-+ .driver_data = ATC20K1,
-+ },
-+ { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2),
-+ .driver_data = ATC20K2,
-+ },
-+ { 0, }
-+};
-+MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids);
-+
-+static int __devinit
-+ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
-+{
-+ static int dev;
-+ struct snd_card *card;
-+ struct ct_atc *atc;
-+ int err;
-+
-+ if (dev >= SNDRV_CARDS)
-+ return -ENODEV;
-+
-+ if (!enable[dev]) {
-+ dev++;
-+ return -ENOENT;
-+ }
-+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
-+ if (err)
-+ return err;
-+ if ((reference_rate != 48000) && (reference_rate != 44100)) {
-+ printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n",
-+ reference_rate);
-+ printk(KERN_ERR "ctxfi: The valid values for reference_rate "
-+ "are 48000 and 44100, Value 48000 is assumed.\n");
-+ reference_rate = 48000;
-+ }
-+ if ((multiple != 1) && (multiple != 2)) {
-+ printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
-+ multiple);
-+ printk(KERN_ERR "ctxfi: The valid values for multiple are "
-+ "1 and 2, Value 2 is assumed.\n");
-+ multiple = 2;
-+ }
-+ err = ct_atc_create(card, pci, reference_rate, multiple,
-+ pci_id->driver_data, &atc);
-+ if (err < 0)
-+ goto error;
-+
-+ card->private_data = atc;
-+
-+ /* Create alsa devices supported by this card */
-+ err = ct_atc_create_alsa_devs(atc);
-+ if (err < 0)
-+ goto error;
-+
-+ strcpy(card->driver, "SB-XFi");
-+ strcpy(card->shortname, "Creative X-Fi");
-+ snprintf(card->longname, sizeof(card->longname), "%s %s %s",
-+ card->shortname, atc->chip_name, atc->model_name);
-+
-+ err = snd_card_register(card);
-+ if (err < 0)
-+ goto error;
-+
-+ pci_set_drvdata(pci, card);
-+ dev++;
-+
-+ return 0;
-+
-+error:
-+ snd_card_free(card);
-+ return err;
-+}
-+
-+static void __devexit ct_card_remove(struct pci_dev *pci)
-+{
-+ snd_card_free(pci_get_drvdata(pci));
-+ pci_set_drvdata(pci, NULL);
-+}
-+
-+#ifdef CONFIG_PM
-+static int ct_card_suspend(struct pci_dev *pci, pm_message_t state)
-+{
-+ struct snd_card *card = pci_get_drvdata(pci);
-+ struct ct_atc *atc = card->private_data;
-+
-+ return atc->suspend(atc, state);
-+}
-+
-+static int ct_card_resume(struct pci_dev *pci)
-+{
-+ struct snd_card *card = pci_get_drvdata(pci);
-+ struct ct_atc *atc = card->private_data;
-+
-+ return atc->resume(atc);
-+}
-+#endif
-+
-+static struct pci_driver ct_driver = {
-+ .name = "SB-XFi",
-+ .id_table = ct_pci_dev_ids,
-+ .probe = ct_card_probe,
-+ .remove = __devexit_p(ct_card_remove),
-+#ifdef CONFIG_PM
-+ .suspend = ct_card_suspend,
-+ .resume = ct_card_resume,
-+#endif
-+};
-+
-+static int __init ct_card_init(void)
-+{
-+ return pci_register_driver(&ct_driver);
-+}
-+
-+static void __exit ct_card_exit(void)
-+{
-+ pci_unregister_driver(&ct_driver);
-+}
-+
-+module_init(ct_card_init)
-+module_exit(ct_card_exit)
diff --git a/patches.drivers/alsa-ctxfi-01-Native-timer-support-for-emu20k2 b/patches.drivers/alsa-ctxfi-01-Native-timer-support-for-emu20k2
new file mode 100644
index 0000000000..fa62819497
--- /dev/null
+++ b/patches.drivers/alsa-ctxfi-01-Native-timer-support-for-emu20k2
@@ -0,0 +1,128 @@
+From bc5304b6fb6c572452b538512761a126f0e0b0d8 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 20 Jul 2009 13:41:35 +0200
+Subject: ALSA: ctxfi - Native timer support for emu20k2
+Patch-mainline:
+References: FATE#306935
+
+Added the native timer support for emu20k2, which gives much more
+accurate update timing than the system timer.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/ctxfi/ct20k2reg.h | 9 ++++---
+ sound/pci/ctxfi/cthw20k2.c | 55 +++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 55 insertions(+), 9 deletions(-)
+
+--- a/sound/pci/ctxfi/ct20k2reg.h
++++ b/sound/pci/ctxfi/ct20k2reg.h
+@@ -11,9 +11,12 @@
+
+
+ /* Timer Registers */
+-#define TIMER_TIMR 0x1B7004
+-#define INTERRUPT_GIP 0x1B7010
+-#define INTERRUPT_GIE 0x1B7014
++#define WC 0x1b7000
++#define TIMR 0x1b7004
++# define TIMR_IE (1<<15)
++# define TIMR_IP (1<<14)
++#define GIP 0x1b7010
++#define GIE 0x1b7014
+
+ /* I2C Registers */
+ #define I2C_IF_ADDRESS 0x1B9000
+--- a/sound/pci/ctxfi/cthw20k2.c
++++ b/sound/pci/ctxfi/cthw20k2.c
+@@ -1112,6 +1112,26 @@
+ return 0;
+ }
+
++/* Timer interrupt */
++static int set_timer_irq(struct hw *hw, int enable)
++{
++ hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
++ return 0;
++}
++
++static int set_timer_tick(struct hw *hw, unsigned int ticks)
++{
++ if (ticks)
++ ticks |= TIMR_IE | TIMR_IP;
++ hw_write_20kx(hw, TIMR, ticks);
++ return 0;
++}
++
++static unsigned int get_wc(struct hw *hw)
++{
++ return hw_read_20kx(hw, WC);
++}
++
+ /* Card hardware initialization block */
+ struct dac_conf {
+ unsigned int msr; /* master sample rate in rsrs */
+@@ -1841,6 +1861,22 @@
+ return 0;
+ }
+
++static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
++{
++ struct hw *hw = dev_id;
++ unsigned int status;
++
++ status = hw_read_20kx(hw, GIP);
++ if (!status)
++ return IRQ_NONE;
++
++ if (hw->irq_callback)
++ hw->irq_callback(hw->irq_callback_data, status);
++
++ hw_write_20kx(hw, GIP, status);
++ return IRQ_HANDLED;
++}
++
+ static int hw_card_start(struct hw *hw)
+ {
+ int err = 0;
+@@ -1879,12 +1915,15 @@
+ set_field(&gctl, GCTL_UAA, 0);
+ hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+
+- /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED,
+- atc->chip_details->nm_card, hw))) {
+- goto error3;
++ if (hw->irq < 0) {
++ err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
++ "ctxfi", hw);
++ if (err < 0) {
++ printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
++ goto error2;
++ }
++ hw->irq = pci->irq;
+ }
+- hw->irq = pci->irq;
+- */
+
+ pci_set_master(pci);
+
+@@ -1972,7 +2011,7 @@
+ hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+
+ /* Reset all global pending interrupts */
+- hw_write_20kx(hw, INTERRUPT_GIE, 0);
++ hw_write_20kx(hw, GIE, 0);
+ /* Reset all SRC pending interrupts */
+ hw_write_20kx(hw, SRC_IP, 0);
+
+@@ -2149,6 +2188,10 @@
+ .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
+ .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
+ .daio_mgr_commit_write = daio_mgr_commit_write,
++
++ .set_timer_irq = set_timer_irq,
++ .set_timer_tick = set_timer_tick,
++ .get_wc = get_wc,
+ };
+
+ int __devinit create_20k2_hw_obj(struct hw **rhw)
diff --git a/patches.drivers/alsa-ctxfi-02-Fix-uninitialized-error-checks b/patches.drivers/alsa-ctxfi-02-Fix-uninitialized-error-checks
new file mode 100644
index 0000000000..32bfe22379
--- /dev/null
+++ b/patches.drivers/alsa-ctxfi-02-Fix-uninitialized-error-checks
@@ -0,0 +1,76 @@
+From 68110661e86868cd107955ec7c077e1f34519f78 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 22 Jul 2009 17:05:15 +0200
+Subject: [PATCH 2/3] ALSA: ctxfi - Fix uninitialized error checks
+Patch-mainline: 2.6.31-rc5
+References: FATE#306935
+
+Fix a few uninitialized error checks that were introduced recently
+mistakenlly during the clean-up:
+ sound/pci/ctxfi/ctamixer.c: In function 'get_amixer_rsc':
+ sound/pci/ctxfi/ctamixer.c:261: warning: 'err' may be used uninitialized in this function
+ sound/pci/ctxfi/ctamixer.c: In function 'get_sum_rsc':
+ sound/pci/ctxfi/ctamixer.c:415: warning: 'err' may be used uninitialized in this function
+ sound/pci/ctxfi/ctsrc.c: In function 'get_srcimp_rsc':
+ sound/pci/ctxfi/ctsrc.c:742: warning: 'err' may be used uninitialized in this function
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/ctxfi/ctamixer.c | 14 ++++++--------
+ sound/pci/ctxfi/ctsrc.c | 7 +++----
+ 2 files changed, 9 insertions(+), 12 deletions(-)
+
+--- a/sound/pci/ctxfi/ctamixer.c
++++ b/sound/pci/ctxfi/ctamixer.c
+@@ -242,13 +242,12 @@
+
+ /* Allocate mem for amixer resource */
+ amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
+- if (NULL == amixer) {
+- err = -ENOMEM;
+- return err;
+- }
++ if (!amixer)
++ return -ENOMEM;
+
+ /* Check whether there are sufficient
+ * amixer resources to meet request. */
++ err = 0;
+ spin_lock_irqsave(&mgr->mgr_lock, flags);
+ for (i = 0; i < desc->msr; i++) {
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
+@@ -397,12 +396,11 @@
+
+ /* Allocate mem for sum resource */
+ sum = kzalloc(sizeof(*sum), GFP_KERNEL);
+- if (NULL == sum) {
+- err = -ENOMEM;
+- return err;
+- }
++ if (!sum)
++ return -ENOMEM;
+
+ /* Check whether there are sufficient sum resources to meet request. */
++ err = 0;
+ spin_lock_irqsave(&mgr->mgr_lock, flags);
+ for (i = 0; i < desc->msr; i++) {
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
+--- a/sound/pci/ctxfi/ctsrc.c
++++ b/sound/pci/ctxfi/ctsrc.c
+@@ -724,12 +724,11 @@
+
+ /* Allocate mem for SRCIMP resource */
+ srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
+- if (NULL == srcimp) {
+- err = -ENOMEM;
+- return err;
+- }
++ if (!srcimp)
++ return -ENOMEM;
+
+ /* Check whether there are sufficient SRCIMP resources. */
++ err = 0;
+ spin_lock_irqsave(&mgr->mgr_lock, flags);
+ for (i = 0; i < desc->msr; i++) {
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
diff --git a/patches.drivers/alsa-ctxfi-03-Simple-code-clean-up b/patches.drivers/alsa-ctxfi-03-Simple-code-clean-up
new file mode 100644
index 0000000000..1b688f8e8c
--- /dev/null
+++ b/patches.drivers/alsa-ctxfi-03-Simple-code-clean-up
@@ -0,0 +1,858 @@
+From 35ebf6e7210dc0f7c612856513a8489a1da9de7e Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 22 Jul 2009 17:12:34 +0200
+Subject: ALSA: ctxfi - Simple code clean up
+Patch-mainline:
+References: FATE#306935
+
+- replace NULL == xxx with !xxx
+- replace NULL != xxx with xxx
+- similar trivial cleanups
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/ctxfi/ctamixer.c | 20 +++++------
+ sound/pci/ctxfi/ctatc.c | 77 +++++++++++++++++++++----------------------
+ sound/pci/ctxfi/ctdaio.c | 30 ++++++++--------
+ sound/pci/ctxfi/cthw20k1.c | 22 ++++++------
+ sound/pci/ctxfi/cthw20k2.c | 18 +++++-----
+ sound/pci/ctxfi/ctmixer.c | 8 ++--
+ sound/pci/ctxfi/ctpcm.c | 6 +--
+ sound/pci/ctxfi/ctresource.c | 4 +-
+ sound/pci/ctxfi/ctsrc.c | 10 ++---
+ sound/pci/ctxfi/ctvmem.c | 6 +--
+ 10 files changed, 100 insertions(+), 101 deletions(-)
+
+--- a/sound/pci/ctxfi/ctamixer.c
++++ b/sound/pci/ctxfi/ctamixer.c
+@@ -63,7 +63,7 @@
+ hw = amixer->rsc.hw;
+ hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
+ amixer->input = rsc;
+- if (NULL == rsc)
++ if (!rsc)
+ hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
+ else
+ hw->amixer_set_x(amixer->rsc.ctrl_blk,
+@@ -99,7 +99,7 @@
+
+ hw = amixer->rsc.hw;
+ amixer->sum = sum;
+- if (NULL == sum) {
++ if (!sum) {
+ hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
+ } else {
+ hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
+@@ -124,20 +124,20 @@
+
+ /* Program master and conjugate resources */
+ amixer->rsc.ops->master(&amixer->rsc);
+- if (NULL != input)
++ if (input)
+ input->ops->master(input);
+
+- if (NULL != sum)
++ if (sum)
+ sum->rsc.ops->master(&sum->rsc);
+
+ for (i = 0; i < amixer->rsc.msr; i++) {
+ hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
+- if (NULL != input) {
++ if (input) {
+ hw->amixer_set_x(amixer->rsc.ctrl_blk,
+ input->ops->output_slot(input));
+ input->ops->next_conj(input);
+ }
+- if (NULL != sum) {
++ if (sum) {
+ hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
+ sum->rsc.ops->index(&sum->rsc));
+ sum->rsc.ops->next_conj(&sum->rsc);
+@@ -147,10 +147,10 @@
+ amixer->rsc.ops->next_conj(&amixer->rsc);
+ }
+ amixer->rsc.ops->master(&amixer->rsc);
+- if (NULL != input)
++ if (input)
+ input->ops->master(input);
+
+- if (NULL != sum)
++ if (sum)
+ sum->rsc.ops->master(&sum->rsc);
+
+ return 0;
+@@ -303,7 +303,7 @@
+
+ *ramixer_mgr = NULL;
+ amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
+- if (NULL == amixer_mgr)
++ if (!amixer_mgr)
+ return -ENOMEM;
+
+ err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
+@@ -456,7 +456,7 @@
+
+ *rsum_mgr = NULL;
+ sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
+- if (NULL == sum_mgr)
++ if (!sum_mgr)
+ return -ENOMEM;
+
+ err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
+--- a/sound/pci/ctxfi/ctatc.c
++++ b/sound/pci/ctxfi/ctatc.c
+@@ -136,7 +136,7 @@
+ struct snd_pcm_runtime *runtime;
+ struct ct_vm *vm;
+
+- if (NULL == apcm->substream)
++ if (!apcm->substream)
+ return 0;
+
+ runtime = apcm->substream->runtime;
+@@ -144,7 +144,7 @@
+
+ apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
+
+- if (NULL == apcm->vm_block)
++ if (!apcm->vm_block)
+ return -ENOENT;
+
+ return 0;
+@@ -154,7 +154,7 @@
+ {
+ struct ct_vm *vm;
+
+- if (NULL == apcm->vm_block)
++ if (!apcm->vm_block)
+ return;
+
+ vm = atc->vm;
+@@ -231,16 +231,16 @@
+
+ static int select_rom(unsigned int pitch)
+ {
+- if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) {
++ if (pitch > 0x00428f5c && pitch < 0x01b851ec) {
+ /* 0.26 <= pitch <= 1.72 */
+ return 1;
+- } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) {
++ } else if (pitch == 0x01d66666 || pitch == 0x01d66667) {
+ /* pitch == 1.8375 */
+ return 2;
+- } else if (0x02000000 == pitch) {
++ } else if (pitch == 0x02000000) {
+ /* pitch == 2 */
+ return 3;
+- } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) {
++ } else if (pitch >= 0x0 && pitch <= 0x08000000) {
+ /* 0 <= pitch <= 8 */
+ return 0;
+ } else {
+@@ -283,7 +283,7 @@
+ /* Get AMIXER resource */
+ n_amixer = (n_amixer < 2) ? 2 : n_amixer;
+ apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+- if (NULL == apcm->amixers) {
++ if (!apcm->amixers) {
+ err = -ENOMEM;
+ goto error1;
+ }
+@@ -311,7 +311,7 @@
+ INIT_VOL, atc->pcm[i+device*2]);
+ mutex_unlock(&atc->atc_mutex);
+ src = src->ops->next_interleave(src);
+- if (NULL == src)
++ if (!src)
+ src = apcm->src;
+ }
+
+@@ -334,7 +334,7 @@
+ struct srcimp *srcimp;
+ int i;
+
+- if (NULL != apcm->srcimps) {
++ if (apcm->srcimps) {
+ for (i = 0; i < apcm->n_srcimp; i++) {
+ srcimp = apcm->srcimps[i];
+ srcimp->ops->unmap(srcimp);
+@@ -345,7 +345,7 @@
+ apcm->srcimps = NULL;
+ }
+
+- if (NULL != apcm->srccs) {
++ if (apcm->srccs) {
+ for (i = 0; i < apcm->n_srcc; i++) {
+ src_mgr->put_src(src_mgr, apcm->srccs[i]);
+ apcm->srccs[i] = NULL;
+@@ -354,7 +354,7 @@
+ apcm->srccs = NULL;
+ }
+
+- if (NULL != apcm->amixers) {
++ if (apcm->amixers) {
+ for (i = 0; i < apcm->n_amixer; i++) {
+ amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
+ apcm->amixers[i] = NULL;
+@@ -363,17 +363,17 @@
+ apcm->amixers = NULL;
+ }
+
+- if (NULL != apcm->mono) {
++ if (apcm->mono) {
+ sum_mgr->put_sum(sum_mgr, apcm->mono);
+ apcm->mono = NULL;
+ }
+
+- if (NULL != apcm->src) {
++ if (apcm->src) {
+ src_mgr->put_src(src_mgr, apcm->src);
+ apcm->src = NULL;
+ }
+
+- if (NULL != apcm->vm_block) {
++ if (apcm->vm_block) {
+ /* Undo device virtual mem map */
+ ct_unmap_audio_buffer(atc, apcm);
+ apcm->vm_block = NULL;
+@@ -419,7 +419,7 @@
+ src->ops->set_state(src, SRC_STATE_OFF);
+ src->ops->commit_write(src);
+
+- if (NULL != apcm->srccs) {
++ if (apcm->srccs) {
+ for (i = 0; i < apcm->n_srcc; i++) {
+ src = apcm->srccs[i];
+ src->ops->set_bm(src, 0);
+@@ -544,18 +544,18 @@
+
+ if (n_srcc) {
+ apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL);
+- if (NULL == apcm->srccs)
++ if (!apcm->srccs)
+ return -ENOMEM;
+ }
+ if (n_amixer) {
+ apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+- if (NULL == apcm->amixers) {
++ if (!apcm->amixers) {
+ err = -ENOMEM;
+ goto error1;
+ }
+ }
+ apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL);
+- if (NULL == apcm->srcimps) {
++ if (!apcm->srcimps) {
+ err = -ENOMEM;
+ goto error1;
+ }
+@@ -818,7 +818,7 @@
+ /* Get AMIXER resource */
+ n_amixer = (n_amixer < 2) ? 2 : n_amixer;
+ apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+- if (NULL == apcm->amixers) {
++ if (!apcm->amixers) {
+ err = -ENOMEM;
+ goto error1;
+ }
+@@ -919,7 +919,7 @@
+ amixer = apcm->amixers[i];
+ amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
+ src = src->ops->next_interleave(src);
+- if (NULL == src)
++ if (!src)
+ src = apcm->src;
+ }
+ /* Connect to SPDIFOO */
+@@ -1121,7 +1121,7 @@
+ struct ct_mixer *mixer = NULL;
+
+ /* disconnect internal mixer objects */
+- if (NULL != atc->mixer) {
++ if (atc->mixer) {
+ mixer = atc->mixer;
+ mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
+ mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
+@@ -1131,7 +1131,7 @@
+ mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
+ }
+
+- if (NULL != atc->daios) {
++ if (atc->daios) {
+ daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
+ for (i = 0; i < atc->n_daio; i++) {
+ daio = atc->daios[i];
+@@ -1149,7 +1149,7 @@
+ atc->daios = NULL;
+ }
+
+- if (NULL != atc->pcm) {
++ if (atc->pcm) {
+ sum_mgr = atc->rsc_mgrs[SUM];
+ for (i = 0; i < atc->n_pcm; i++)
+ sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
+@@ -1158,7 +1158,7 @@
+ atc->pcm = NULL;
+ }
+
+- if (NULL != atc->srcs) {
++ if (atc->srcs) {
+ src_mgr = atc->rsc_mgrs[SRC];
+ for (i = 0; i < atc->n_src; i++)
+ src_mgr->put_src(src_mgr, atc->srcs[i]);
+@@ -1167,7 +1167,7 @@
+ atc->srcs = NULL;
+ }
+
+- if (NULL != atc->srcimps) {
++ if (atc->srcimps) {
+ srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+ for (i = 0; i < atc->n_srcimp; i++) {
+ srcimp = atc->srcimps[i];
+@@ -1185,7 +1185,7 @@
+ {
+ int i = 0;
+
+- if (NULL == atc)
++ if (!atc)
+ return 0;
+
+ if (atc->timer) {
+@@ -1196,21 +1196,20 @@
+ atc_release_resources(atc);
+
+ /* Destroy internal mixer objects */
+- if (NULL != atc->mixer)
++ if (atc->mixer)
+ ct_mixer_destroy(atc->mixer);
+
+ for (i = 0; i < NUM_RSCTYP; i++) {
+- if ((NULL != rsc_mgr_funcs[i].destroy) &&
+- (NULL != atc->rsc_mgrs[i]))
++ if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i])
+ rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
+
+ }
+
+- if (NULL != atc->hw)
++ if (atc->hw)
+ destroy_hw_obj((struct hw *)atc->hw);
+
+ /* Destroy device virtual memory manager object */
+- if (NULL != atc->vm) {
++ if (atc->vm) {
+ ct_vm_destroy(atc->vm);
+ atc->vm = NULL;
+ }
+@@ -1275,7 +1274,7 @@
+ alsa_dev_funcs[MIXER].public_name = atc->chip_name;
+
+ for (i = 0; i < NUM_CTALSADEVS; i++) {
+- if (NULL == alsa_dev_funcs[i].create)
++ if (!alsa_dev_funcs[i].create)
+ continue;
+
+ err = alsa_dev_funcs[i].create(atc, i,
+@@ -1312,7 +1311,7 @@
+ return err;
+
+ for (i = 0; i < NUM_RSCTYP; i++) {
+- if (NULL == rsc_mgr_funcs[i].create)
++ if (!rsc_mgr_funcs[i].create)
+ continue;
+
+ err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
+@@ -1339,19 +1338,19 @@
+ int err, i;
+
+ atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+- if (NULL == atc->daios)
++ if (!atc->daios)
+ return -ENOMEM;
+
+ atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+- if (NULL == atc->srcs)
++ if (!atc->srcs)
+ return -ENOMEM;
+
+ atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+- if (NULL == atc->srcimps)
++ if (!atc->srcimps)
+ return -ENOMEM;
+
+ atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL);
+- if (NULL == atc->pcm)
++ if (!atc->pcm)
+ return -ENOMEM;
+
+ daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
+@@ -1648,7 +1647,7 @@
+ *ratc = NULL;
+
+ atc = kzalloc(sizeof(*atc), GFP_KERNEL);
+- if (NULL == atc)
++ if (!atc)
+ return -ENOMEM;
+
+ /* Set operations */
+--- a/sound/pci/ctxfi/ctdaio.c
++++ b/sound/pci/ctxfi/ctdaio.c
+@@ -173,7 +173,7 @@
+ int i;
+
+ entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
+- if (NULL == entry)
++ if (!entry)
+ return -ENOMEM;
+
+ /* Program master and conjugate resources */
+@@ -201,7 +201,7 @@
+ int i;
+
+ entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
+- if (NULL == entry)
++ if (!entry)
+ return -ENOMEM;
+
+ /* Program master and conjugate resources */
+@@ -228,7 +228,7 @@
+ struct daio *daio = &dao->daio;
+ int i;
+
+- if (NULL == dao->imappers[0])
++ if (!dao->imappers[0])
+ return 0;
+
+ entry = dao->imappers[0];
+@@ -252,7 +252,7 @@
+ struct daio *daio = &dao->daio;
+ int i;
+
+- if (NULL == dao->imappers[daio->rscl.msr])
++ if (!dao->imappers[daio->rscl.msr])
+ return 0;
+
+ entry = dao->imappers[daio->rscl.msr];
+@@ -408,7 +408,7 @@
+ return err;
+
+ dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL);
+- if (NULL == dao->imappers) {
++ if (!dao->imappers) {
+ err = -ENOMEM;
+ goto error1;
+ }
+@@ -442,11 +442,11 @@
+
+ static int dao_rsc_uninit(struct dao *dao)
+ {
+- if (NULL != dao->imappers) {
+- if (NULL != dao->imappers[0])
++ if (dao->imappers) {
++ if (dao->imappers[0])
+ dao_clear_left_input(dao);
+
+- if (NULL != dao->imappers[dao->daio.rscl.msr])
++ if (dao->imappers[dao->daio.rscl.msr])
+ dao_clear_right_input(dao);
+
+ kfree(dao->imappers);
+@@ -555,7 +555,7 @@
+ /* Allocate mem for daio resource */
+ if (desc->type <= DAIO_OUT_MAX) {
+ dao = kzalloc(sizeof(*dao), GFP_KERNEL);
+- if (NULL == dao) {
++ if (!dao) {
+ err = -ENOMEM;
+ goto error;
+ }
+@@ -566,7 +566,7 @@
+ *rdaio = &dao->daio;
+ } else {
+ dai = kzalloc(sizeof(*dai), GFP_KERNEL);
+- if (NULL == dai) {
++ if (!dai) {
+ err = -ENOMEM;
+ goto error;
+ }
+@@ -583,9 +583,9 @@
+ return 0;
+
+ error:
+- if (NULL != dao)
++ if (dao)
+ kfree(dao);
+- else if (NULL != dai)
++ else if (dai)
+ kfree(dai);
+
+ spin_lock_irqsave(&mgr->mgr_lock, flags);
+@@ -663,7 +663,7 @@
+ int err;
+
+ spin_lock_irqsave(&mgr->imap_lock, flags);
+- if ((0 == entry->addr) && (mgr->init_imap_added)) {
++ if (!entry->addr && mgr->init_imap_added) {
+ input_mapper_delete(&mgr->imappers, mgr->init_imap,
+ daio_map_op, mgr);
+ mgr->init_imap_added = 0;
+@@ -707,7 +707,7 @@
+
+ *rdaio_mgr = NULL;
+ daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);
+- if (NULL == daio_mgr)
++ if (!daio_mgr)
+ return -ENOMEM;
+
+ err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+@@ -718,7 +718,7 @@
+ spin_lock_init(&daio_mgr->imap_lock);
+ INIT_LIST_HEAD(&daio_mgr->imappers);
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+- if (NULL == entry) {
++ if (!entry) {
+ err = -ENOMEM;
+ goto error2;
+ }
+--- a/sound/pci/ctxfi/cthw20k1.c
++++ b/sound/pci/ctxfi/cthw20k1.c
+@@ -168,7 +168,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -494,7 +494,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -515,7 +515,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -702,7 +702,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -723,7 +723,7 @@
+
+ *rblk = NULL;
+ /*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;*/
+@@ -909,7 +909,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -958,7 +958,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -1152,7 +1152,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ blk->i2sctl = hw_read_20kx(hw, I2SCTL);
+@@ -1808,7 +1808,7 @@
+ /* By default, Hendrix card UAA Bar0 should be using memory... */
+ io_base = pci_resource_start(pci, 0);
+ mem_base = ioremap(io_base, pci_resource_len(pci, 0));
+- if (NULL == mem_base)
++ if (!mem_base)
+ return -ENOENT;
+
+ /* Read current mode from Mode Change Register */
+@@ -1977,7 +1977,7 @@
+
+ hw->irq = -1;
+
+- if (NULL != ((void *)hw->mem_base))
++ if (hw->mem_base)
+ iounmap((void *)hw->mem_base);
+
+ hw->mem_base = (unsigned long)NULL;
+@@ -2274,7 +2274,7 @@
+
+ *rhw = NULL;
+ hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
+- if (NULL == hw20k1)
++ if (!hw20k1)
+ return -ENOMEM;
+
+ spin_lock_init(&hw20k1->reg_20k1_lock);
+--- a/sound/pci/ctxfi/cthw20k2.c
++++ b/sound/pci/ctxfi/cthw20k2.c
+@@ -166,7 +166,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -492,7 +492,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -513,7 +513,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -702,7 +702,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -891,7 +891,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -941,7 +941,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ *rblk = blk;
+@@ -1092,7 +1092,7 @@
+
+ *rblk = NULL;
+ blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+- if (NULL == blk)
++ if (!blk)
+ return -ENOMEM;
+
+ for (i = 0; i < 8; i++) {
+@@ -1904,7 +1904,7 @@
+ hw->io_base = pci_resource_start(hw->pci, 2);
+ hw->mem_base = (unsigned long)ioremap(hw->io_base,
+ pci_resource_len(hw->pci, 2));
+- if (NULL == (void *)hw->mem_base) {
++ if (!hw->mem_base) {
+ err = -ENOENT;
+ goto error2;
+ }
+@@ -1962,7 +1962,7 @@
+
+ hw->irq = -1;
+
+- if (NULL != ((void *)hw->mem_base))
++ if (hw->mem_base)
+ iounmap((void *)hw->mem_base);
+
+ hw->mem_base = (unsigned long)NULL;
+--- a/sound/pci/ctxfi/ctmixer.c
++++ b/sound/pci/ctxfi/ctmixer.c
+@@ -654,7 +654,7 @@
+ int err;
+
+ kctl = snd_ctl_new1(new, mixer->atc);
+- if (NULL == kctl)
++ if (!kctl)
+ return -ENOMEM;
+
+ if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
+@@ -837,17 +837,17 @@
+ *rmixer = NULL;
+ /* Allocate mem for mixer obj */
+ mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+- if (NULL == mixer)
++ if (!mixer)
+ return -ENOMEM;
+
+ mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM),
+ GFP_KERNEL);
+- if (NULL == mixer->amixers) {
++ if (!mixer->amixers) {
+ err = -ENOMEM;
+ goto error1;
+ }
+ mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL);
+- if (NULL == mixer->sums) {
++ if (!mixer->sums) {
+ err = -ENOMEM;
+ goto error2;
+ }
+--- a/sound/pci/ctxfi/ctpcm.c
++++ b/sound/pci/ctxfi/ctpcm.c
+@@ -97,7 +97,7 @@
+ {
+ struct ct_atc_pcm *apcm = atc_pcm;
+
+- if (NULL == apcm->substream)
++ if (!apcm->substream)
+ return;
+
+ snd_pcm_period_elapsed(apcm->substream);
+@@ -123,7 +123,7 @@
+ int err;
+
+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+- if (NULL == apcm)
++ if (!apcm)
+ return -ENOMEM;
+
+ apcm->substream = substream;
+@@ -271,7 +271,7 @@
+ int err;
+
+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+- if (NULL == apcm)
++ if (!apcm)
+ return -ENOMEM;
+
+ apcm->started = 0;
+--- a/sound/pci/ctxfi/ctresource.c
++++ b/sound/pci/ctxfi/ctresource.c
+@@ -144,7 +144,7 @@
+ rsc->msr = msr;
+ rsc->hw = hw;
+ rsc->ops = &rsc_generic_ops;
+- if (NULL == hw) {
++ if (!hw) {
+ rsc->ctrl_blk = NULL;
+ return 0;
+ }
+@@ -216,7 +216,7 @@
+ mgr->type = NUM_RSCTYP;
+
+ mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
+- if (NULL == mgr->rscs)
++ if (!mgr->rscs)
+ return -ENOMEM;
+
+ switch (type) {
+--- a/sound/pci/ctxfi/ctsrc.c
++++ b/sound/pci/ctxfi/ctsrc.c
+@@ -441,7 +441,7 @@
+ else
+ src = kzalloc(sizeof(*src), GFP_KERNEL);
+
+- if (NULL == src) {
++ if (!src) {
+ err = -ENOMEM;
+ goto error1;
+ }
+@@ -550,7 +550,7 @@
+
+ *rsrc_mgr = NULL;
+ src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL);
+- if (NULL == src_mgr)
++ if (!src_mgr)
+ return -ENOMEM;
+
+ err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw);
+@@ -679,7 +679,7 @@
+ /* Reserve memory for imapper nodes */
+ srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr,
+ GFP_KERNEL);
+- if (NULL == srcimp->imappers) {
++ if (!srcimp->imappers) {
+ err = -ENOMEM;
+ goto error1;
+ }
+@@ -833,7 +833,7 @@
+
+ *rsrcimp_mgr = NULL;
+ srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL);
+- if (NULL == srcimp_mgr)
++ if (!srcimp_mgr)
+ return -ENOMEM;
+
+ err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw);
+@@ -844,7 +844,7 @@
+ spin_lock_init(&srcimp_mgr->imap_lock);
+ INIT_LIST_HEAD(&srcimp_mgr->imappers);
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+- if (NULL == entry) {
++ if (!entry) {
+ err = -ENOMEM;
+ goto error2;
+ }
+--- a/sound/pci/ctxfi/ctvmem.c
++++ b/sound/pci/ctxfi/ctvmem.c
+@@ -60,7 +60,7 @@
+ }
+
+ block = kzalloc(sizeof(*block), GFP_KERNEL);
+- if (NULL == block)
++ if (!block)
+ goto out;
+
+ block->addr = entry->addr;
+@@ -181,7 +181,7 @@
+ *rvm = NULL;
+
+ vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+- if (NULL == vm)
++ if (!vm)
+ return -ENOMEM;
+
+ mutex_init(&vm->lock);
+@@ -189,7 +189,7 @@
+ /* Allocate page table pages */
+ for (i = 0; i < CT_PTP_NUM; i++) {
+ vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
+- if (NULL == vm->ptp[i])
++ if (!vm->ptp[i])
+ break;
+ }
+ if (!i) {
diff --git a/patches.drivers/alsa-hda-01-Don-t-call-snd_hda_codec_configure b/patches.drivers/alsa-hda-01-Don-t-call-snd_hda_codec_configure
new file mode 100644
index 0000000000..968334cfbb
--- /dev/null
+++ b/patches.drivers/alsa-hda-01-Don-t-call-snd_hda_codec_configure
@@ -0,0 +1,129 @@
+From a1e21c9078fb8005e5accb921696ec9e2f38176e Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 17 Jun 2009 09:33:52 +0200
+Subject: ALSA: hda - Don't call snd_hda_codec_configure in snd_hda_codec_new()
+Patch-mainline:
+References:
+
+The codec setup call via snd_hda_codec_configure() isn't necessarily
+called in snd_hda_codec_new(). For the later added feature, it's better
+to change the code flow like:
+ - create all codec instances
+ - configure each codec
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/hda/hda_codec.c | 8 ++------
+ sound/pci/hda/hda_codec.h | 3 ++-
+ sound/pci/hda/hda_intel.c | 21 +++++++++++++++++----
+ sound/pci/hda/hda_local.h | 1 -
+ 4 files changed, 21 insertions(+), 12 deletions(-)
+
+--- a/sound/pci/hda/hda_codec.c
++++ b/sound/pci/hda/hda_codec.c
+@@ -891,7 +891,7 @@
+ * Returns 0 if successful, or a negative error code.
+ */
+ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+- int do_init, struct hda_codec **codecp)
++ struct hda_codec **codecp)
+ {
+ struct hda_codec *codec;
+ char component[31];
+@@ -984,11 +984,6 @@
+ codec->afg ? codec->afg : codec->mfg,
+ AC_PWRST_D0);
+
+- if (do_init) {
+- err = snd_hda_codec_configure(codec);
+- if (err < 0)
+- goto error;
+- }
+ snd_hda_codec_proc_new(codec);
+
+ snd_hda_create_hwdep(codec);
+@@ -1042,6 +1037,7 @@
+ err = init_unsol_queue(codec->bus);
+ return err;
+ }
++EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
+
+ /**
+ * snd_hda_codec_setup_stream - set up the codec for streaming
+--- a/sound/pci/hda/hda_codec.h
++++ b/sound/pci/hda/hda_codec.h
+@@ -830,7 +830,8 @@
+ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
+ struct hda_bus **busp);
+ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+- int do_init, struct hda_codec **codecp);
++ struct hda_codec **codecp);
++int snd_hda_codec_configure(struct hda_codec *codec);
+
+ /*
+ * low level functions
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -1286,8 +1286,7 @@
+ [AZX_DRIVER_TERA] = 1,
+ };
+
+-static int __devinit azx_codec_create(struct azx *chip, const char *model,
+- int no_init)
++static int __devinit azx_codec_create(struct azx *chip, const char *model)
+ {
+ struct hda_bus_template bus_temp;
+ int c, codecs, err;
+@@ -1346,7 +1345,7 @@
+ for (c = 0; c < max_slots; c++) {
+ if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
+ struct hda_codec *codec;
+- err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
++ err = snd_hda_codec_new(chip->bus, c, &codec);
+ if (err < 0)
+ continue;
+ codecs++;
+@@ -1356,7 +1355,16 @@
+ snd_printk(KERN_ERR SFX "no codecs initialized\n");
+ return -ENXIO;
+ }
++ return 0;
++}
+
++/* configure each codec instance */
++static int __devinit azx_codec_configure(struct azx *chip)
++{
++ struct hda_codec *codec;
++ list_for_each_entry(codec, &chip->bus->codec_list, list) {
++ snd_hda_codec_configure(codec);
++ }
+ return 0;
+ }
+
+@@ -2487,9 +2495,14 @@
+ card->private_data = chip;
+
+ /* create codec instances */
+- err = azx_codec_create(chip, model[dev], probe_only[dev]);
++ err = azx_codec_create(chip, model[dev]);
+ if (err < 0)
+ goto out_free;
++ if (!probe_only[dev]) {
++ err = azx_codec_configure(chip);
++ if (err < 0)
++ goto out_free;
++ }
+
+ /* create PCM streams */
+ err = snd_hda_build_pcms(chip->bus);
+--- a/sound/pci/hda/hda_local.h
++++ b/sound/pci/hda/hda_local.h
+@@ -99,7 +99,6 @@
+ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+ unsigned int *tlv, const char **slaves);
+ int snd_hda_codec_reset(struct hda_codec *codec);
+-int snd_hda_codec_configure(struct hda_codec *codec);
+
+ /* amp value bits */
+ #define HDA_AMP_MUTE 0x80
diff --git a/patches.drivers/alsa-hda-02-Add-patch-module-option b/patches.drivers/alsa-hda-02-Add-patch-module-option
new file mode 100644
index 0000000000..53526ae385
--- /dev/null
+++ b/patches.drivers/alsa-hda-02-Add-patch-module-option
@@ -0,0 +1,427 @@
+From 4ea6fbc8eb23c3ae5fd2fb55a340ab85c8649bce Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 17 Jun 2009 09:52:54 +0200
+Subject: ALSA: hda - Add patch module option
+Patch-mainline:
+References:
+
+Added the patch module option to apply a "patch" as a firmware to
+modify pin configurations or give additional hints to the driver
+before actually initializing and configuring the codec.
+
+This can be used as a workaround when the BIOS doesn't give sufficient
+information or give wrong information that doesn't match with the real
+hardware setup, until it's fixed statically in the driver via a quirk.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/hda/Kconfig | 14 ++
+ sound/pci/hda/hda_codec.h | 7 +
+ sound/pci/hda/hda_hwdep.c | 236 ++++++++++++++++++++++++++++++++++++++++++----
+ sound/pci/hda/hda_intel.c | 21 +++-
+ 4 files changed, 257 insertions(+), 21 deletions(-)
+
+--- a/sound/pci/hda/Kconfig
++++ b/sound/pci/hda/Kconfig
+@@ -46,6 +46,20 @@
+ Say Y here to enable the jack plugging notification via
+ input layer.
+
++config SND_HDA_PATCH_LOADER
++ bool "Support initialization patch loading for HD-audio"
++ depends on EXPERIMENTAL
++ select FW_LOADER
++ select SND_HDA_HWDEP
++ select SND_HDA_RECONFIG
++ help
++ Say Y here to allow the HD-audio driver to load a pseudo
++ firmware file ("patch") for overriding the BIOS setup at
++ start up. The "patch" file can be specified via patch module
++ option, such as patch=hda-init.
++
++ This option turns on hwdep and reconfig features automatically.
++
+ config SND_HDA_CODEC_REALTEK
+ bool "Build Realtek HD-audio codec support"
+ default y
+--- a/sound/pci/hda/hda_codec.h
++++ b/sound/pci/hda/hda_codec.h
+@@ -939,6 +939,13 @@
+ #define snd_hda_codec_needs_resume(codec) 1
+ #endif
+
++#ifdef CONFIG_SND_HDA_PATCH_LOADER
++/*
++ * patch firmware
++ */
++int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
++#endif
++
+ /*
+ * Codec modularization
+ */
+--- a/sound/pci/hda/hda_hwdep.c
++++ b/sound/pci/hda/hda_hwdep.c
+@@ -24,6 +24,7 @@
+ #include <linux/compat.h>
+ #include <linux/mutex.h>
+ #include <linux/ctype.h>
++#include <linux/firmware.h>
+ #include <sound/core.h>
+ #include "hda_codec.h"
+ #include "hda_local.h"
+@@ -312,12 +313,8 @@
+ return len;
+ }
+
+-static ssize_t init_verbs_store(struct device *dev,
+- struct device_attribute *attr,
+- const char *buf, size_t count)
++static int parse_init_verbs(struct hda_codec *codec, const char *buf)
+ {
+- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+- struct hda_codec *codec = hwdep->private_data;
+ struct hda_verb *v;
+ int nid, verb, param;
+
+@@ -331,6 +328,18 @@
+ v->nid = nid;
+ v->verb = verb;
+ v->param = param;
++ return 0;
++}
++
++static ssize_t init_verbs_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
++ struct hda_codec *codec = hwdep->private_data;
++ int err = parse_init_verbs(codec, buf);
++ if (err < 0)
++ return err;
+ return count;
+ }
+
+@@ -376,19 +385,15 @@
+
+ #define MAX_HINTS 1024
+
+-static ssize_t hints_store(struct device *dev,
+- struct device_attribute *attr,
+- const char *buf, size_t count)
++static int parse_hints(struct hda_codec *codec, const char *buf)
+ {
+- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+- struct hda_codec *codec = hwdep->private_data;
+ char *key, *val;
+ struct hda_hint *hint;
+
+ while (isspace(*buf))
+ buf++;
+ if (!*buf || *buf == '#' || *buf == '\n')
+- return count;
++ return 0;
+ if (*buf == '=')
+ return -EINVAL;
+ key = kstrndup_noeol(buf, 1024);
+@@ -411,7 +416,7 @@
+ kfree(hint->key);
+ hint->key = key;
+ hint->val = val;
+- return count;
++ return 0;
+ }
+ /* allocate a new hint entry */
+ if (codec->hints.used >= MAX_HINTS)
+@@ -424,6 +429,18 @@
+ }
+ hint->key = key;
+ hint->val = val;
++ return 0;
++}
++
++static ssize_t hints_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
++ struct hda_codec *codec = hwdep->private_data;
++ int err = parse_hints(codec, buf);
++ if (err < 0)
++ return err;
+ return count;
+ }
+
+@@ -469,20 +486,24 @@
+
+ #define MAX_PIN_CONFIGS 32
+
+-static ssize_t user_pin_configs_store(struct device *dev,
+- struct device_attribute *attr,
+- const char *buf, size_t count)
++static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
+ {
+- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+- struct hda_codec *codec = hwdep->private_data;
+ int nid, cfg;
+- int err;
+
+ if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
+ return -EINVAL;
+ if (!nid)
+ return -EINVAL;
+- err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
++ return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
++}
++
++static ssize_t user_pin_configs_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
++ struct hda_codec *codec = hwdep->private_data;
++ int err = parse_user_pin_configs(codec, buf);
+ if (err < 0)
+ return err;
+ return count;
+@@ -553,3 +574,180 @@
+ EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
+
+ #endif /* CONFIG_SND_HDA_RECONFIG */
++
++#ifdef CONFIG_SND_HDA_PATCH_LOADER
++
++/* parser mode */
++enum {
++ LINE_MODE_NONE,
++ LINE_MODE_CODEC,
++ LINE_MODE_MODEL,
++ LINE_MODE_PINCFG,
++ LINE_MODE_VERB,
++ LINE_MODE_HINT,
++ NUM_LINE_MODES,
++};
++
++static inline int strmatch(const char *a, const char *b)
++{
++ return strnicmp(a, b, strlen(b)) == 0;
++}
++
++/* parse the contents after the line "[codec]"
++ * accept only the line with three numbers, and assign the current codec
++ */
++static void parse_codec_mode(char *buf, struct hda_bus *bus,
++ struct hda_codec **codecp)
++{
++ unsigned int vendorid, subid, caddr;
++ struct hda_codec *codec;
++
++ *codecp = NULL;
++ if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
++ list_for_each_entry(codec, &bus->codec_list, list) {
++ if (codec->addr == caddr) {
++ *codecp = codec;
++ break;
++ }
++ }
++ }
++}
++
++/* parse the contents after the other command tags, [pincfg], [verb],
++ * [hint] and [model]
++ * just pass to the sysfs helper (only when any codec was specified)
++ */
++static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
++ struct hda_codec **codecp)
++{
++ if (!*codecp)
++ return;
++ parse_user_pin_configs(*codecp, buf);
++}
++
++static void parse_verb_mode(char *buf, struct hda_bus *bus,
++ struct hda_codec **codecp)
++{
++ if (!*codecp)
++ return;
++ parse_init_verbs(*codecp, buf);
++}
++
++static void parse_hint_mode(char *buf, struct hda_bus *bus,
++ struct hda_codec **codecp)
++{
++ if (!*codecp)
++ return;
++ parse_hints(*codecp, buf);
++}
++
++static void parse_model_mode(char *buf, struct hda_bus *bus,
++ struct hda_codec **codecp)
++{
++ if (!*codecp)
++ return;
++ kfree((*codecp)->modelname);
++ (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
++}
++
++struct hda_patch_item {
++ const char *tag;
++ void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
++};
++
++static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
++ [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
++ [LINE_MODE_MODEL] = { "[model]", parse_model_mode },
++ [LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
++ [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
++ [LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
++};
++
++/* check the line starting with '[' -- change the parser mode accodingly */
++static int parse_line_mode(char *buf, struct hda_bus *bus)
++{
++ int i;
++ for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
++ if (!patch_items[i].tag)
++ continue;
++ if (strmatch(buf, patch_items[i].tag))
++ return i;
++ }
++ return LINE_MODE_NONE;
++}
++
++/* copy one line from the buffer in fw, and update the fields in fw
++ * return zero if it reaches to the end of the buffer, or non-zero
++ * if successfully copied a line
++ *
++ * 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)
++{
++ int len;
++ const char *p = fw->data;
++ while (isspace(*p) && fw->size) {
++ p++;
++ fw->size--;
++ }
++ if (!fw->size)
++ return 0;
++ if (size < fw->size)
++ size = fw->size;
++
++ for (len = 0; len < fw->size; len++) {
++ if (!*p)
++ break;
++ if (*p == '\n') {
++ p++;
++ len++;
++ break;
++ }
++ if (len < size)
++ *buf++ = *p++;
++ }
++ *buf = 0;
++ fw->size -= len;
++ fw->data = p;
++ remove_trail_spaces(buf);
++ return 1;
++}
++
++/*
++ * load a "patch" firmware file and parse it
++ */
++int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
++{
++ 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)) {
++ if (!*buf || *buf == '#' || *buf == '\n')
++ continue;
++ if (*buf == '[')
++ line_mode = parse_line_mode(buf, bus);
++ else if (patch_items[line_mode].parser)
++ patch_items[line_mode].parser(buf, bus, &codec);
++ }
++ release_firmware(fw);
++ return 0;
++}
++EXPORT_SYMBOL_HDA(snd_hda_load_patch);
++#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -61,6 +61,9 @@
+ static int probe_only[SNDRV_CARDS];
+ static int single_cmd;
+ static int enable_msi;
++#ifdef CONFIG_SND_HDA_PATCH_LOADER
++static char *patch[SNDRV_CARDS];
++#endif
+
+ module_param_array(index, int, NULL, 0444);
+ MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
+@@ -84,6 +87,10 @@
+ "(for debugging only).");
+ module_param(enable_msi, int, 0444);
+ MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
++#ifdef CONFIG_SND_HDA_PATCH_LOADER
++module_param_array(patch, charp, NULL, 0444);
++MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
++#endif
+
+ #ifdef CONFIG_SND_HDA_POWER_SAVE
+ static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
+@@ -2489,6 +2496,9 @@
+ 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;
+@@ -2498,6 +2508,15 @@
+ err = azx_codec_create(chip, model[dev]);
+ if (err < 0)
+ goto out_free;
++#ifdef CONFIG_SND_HDA_PATCH_LOADER
++ if (patch[dev]) {
++ snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
++ patch[dev]);
++ err = snd_hda_load_patch(chip->bus, patch[dev]);
++ if (err < 0)
++ goto out_free;
++ }
++#endif
+ if (!probe_only[dev]) {
+ err = azx_codec_configure(chip);
+ if (err < 0)
+@@ -2514,8 +2533,6 @@
+ if (err < 0)
+ goto out_free;
+
+- snd_card_set_dev(card, &pci->dev);
+-
+ err = snd_card_register(card);
+ if (err < 0)
+ goto out_free;
diff --git a/patches.drivers/alsa-hda-03-Check-beep-hint b/patches.drivers/alsa-hda-03-Check-beep-hint
new file mode 100644
index 0000000000..e103e18e18
--- /dev/null
+++ b/patches.drivers/alsa-hda-03-Check-beep-hint
@@ -0,0 +1,36 @@
+From b7b51141b4fb6f9059a20c03dd2a5bf77c466c7e Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 29 Jun 2009 08:34:06 +0200
+Subject: ALSA: hda - Check "beep" hint
+Patch-mainline:
+References:
+
+Check the hint "beep" in snd_hda_attach_beep_device() to avoid the beep
+device creation if user doesn't want.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/hda/hda_beep.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/pci/hda/hda_beep.c
++++ b/sound/pci/hda/hda_beep.c
+@@ -24,6 +24,7 @@
+ #include <linux/workqueue.h>
+ #include <sound/core.h>
+ #include "hda_beep.h"
++#include "hda_local.h"
+
+ enum {
+ DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */
+@@ -118,6 +119,9 @@
+ struct hda_beep *beep;
+ int err;
+
++ if (!snd_hda_get_bool_hint(codec, "beep"))
++ return 0; /* disabled explicitly */
++
+ beep = kzalloc(sizeof(*beep), GFP_KERNEL);
+ if (beep == NULL)
+ return -ENOMEM;
diff --git a/patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883 b/patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883
new file mode 100644
index 0000000000..7bb129db76
--- /dev/null
+++ b/patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883
@@ -0,0 +1,2416 @@
+From 4953550a6ca399b644ef057626617465d8be9a7b Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 30 Jun 2009 15:28:30 +0200
+Subject: ALSA: hda - Merge patch_alc882() and patch_alc883()
+Patch-mainline:
+References:
+
+Merge patch_alc882() and patch_alc883() to the former one since both
+codecs have fairly similar connections but just a slight difference.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ Documentation/sound/alsa/HD-Audio-Models.txt | 12
+ sound/pci/hda/patch_realtek.c | 1982 ++++++++++-----------------
+ 2 files changed, 767 insertions(+), 1227 deletions(-)
+
+--- a/Documentation/sound/alsa/HD-Audio-Models.txt
++++ b/Documentation/sound/alsa/HD-Audio-Models.txt
+@@ -114,8 +114,8 @@
+ samsung-nc10 Samsung NC10 mini notebook
+ auto auto-config reading BIOS (default)
+
+-ALC882/885
+-==========
++ALC882/883/885/888/889
++======================
+ 3stack-dig 3-jack with SPDIF I/O
+ 6stack-dig 6-jack digital with SPDIF I/O
+ arima Arima W820Di1
+@@ -127,12 +127,8 @@
+ mbp3 Macbook Pro rev3
+ imac24 iMac 24'' with jack detection
+ w2jc ASUS W2JC
+- auto auto-config reading BIOS (default)
+-
+-ALC883/888
+-==========
+- 3stack-dig 3-jack with SPDIF I/O
+- 6stack-dig 6-jack digital with SPDIF I/O
++ 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883)
++ alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883)
+ 3stack-6ch 3-jack 6-channel
+ 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
+ 6stack-dig-demo 6-jack digital for Intel demo board
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -208,12 +208,6 @@
+ ALC885_MBP3,
+ ALC885_MB5,
+ ALC885_IMAC24,
+- ALC882_AUTO,
+- ALC882_MODEL_LAST,
+-};
+-
+-/* ALC883 models */
+-enum {
+ ALC883_3ST_2ch_DIG,
+ ALC883_3ST_6ch_DIG,
+ ALC883_3ST_6ch,
+@@ -246,8 +240,8 @@
+ ALC889A_MB31,
+ ALC1200_ASUS_P5Q,
+ ALC883_SONY_VAIO_TT,
+- ALC883_AUTO,
+- ALC883_MODEL_LAST,
++ ALC882_AUTO,
++ ALC882_MODEL_LAST,
+ };
+
+ /* for GPIO Poll */
+@@ -320,6 +314,8 @@
+ struct snd_array kctls;
+ struct hda_input_mux private_imux[3];
+ hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
++ hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
++ hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
+
+ /* hooks */
+ void (*init_hook)(struct hda_codec *codec);
+@@ -6301,7 +6297,7 @@
+
+
+ /*
+- * ALC882 support
++ * ALC882/883/885/888/889 support
+ *
+ * ALC882 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration. Each pin widget can choose any input DACs and a mixer.
+@@ -6313,22 +6309,35 @@
+ */
+ #define ALC882_DIGOUT_NID 0x06
+ #define ALC882_DIGIN_NID 0x0a
++#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
++#define ALC883_DIGIN_NID ALC882_DIGIN_NID
++#define ALC1200_DIGOUT_NID 0x10
++
+
+ static struct hda_channel_mode alc882_ch_modes[1] = {
+ { 8, NULL }
+ };
+
++/* DACs */
+ static hda_nid_t alc882_dac_nids[4] = {
+ /* front, rear, clfe, rear_surr */
+ 0x02, 0x03, 0x04, 0x05
+ };
++#define alc883_dac_nids alc882_dac_nids
+
+-/* identical with ALC880 */
++/* ADCs */
+ #define alc882_adc_nids alc880_adc_nids
+ #define alc882_adc_nids_alt alc880_adc_nids_alt
++#define alc883_adc_nids alc882_adc_nids_alt
++static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
++static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
++#define alc889_adc_nids alc880_adc_nids
+
+ static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+ static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
++#define alc883_capsrc_nids alc882_capsrc_nids_alt
++static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
++#define alc889_capsrc_nids alc882_capsrc_nids
+
+ /* input MUX */
+ /* FIXME: should be a matrix-type input source selection */
+@@ -6343,6 +6352,8 @@
+ },
+ };
+
++#define alc883_capture_source alc882_capture_source
++
+ static struct hda_input_mux mb5_capture_source = {
+ .num_items = 3,
+ .items = {
+@@ -6352,6 +6363,77 @@
+ },
+ };
+
++static struct hda_input_mux alc883_3stack_6ch_intel = {
++ .num_items = 4,
++ .items = {
++ { "Mic", 0x1 },
++ { "Front Mic", 0x0 },
++ { "Line", 0x2 },
++ { "CD", 0x4 },
++ },
++};
++
++static struct hda_input_mux alc883_lenovo_101e_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x1 },
++ { "Line", 0x2 },
++ },
++};
++
++static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
++ .num_items = 4,
++ .items = {
++ { "Mic", 0x0 },
++ { "iMic", 0x1 },
++ { "Line", 0x2 },
++ { "CD", 0x4 },
++ },
++};
++
++static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x0 },
++ { "Int Mic", 0x1 },
++ },
++};
++
++static struct hda_input_mux alc883_lenovo_sky_capture_source = {
++ .num_items = 3,
++ .items = {
++ { "Mic", 0x0 },
++ { "Front Mic", 0x1 },
++ { "Line", 0x4 },
++ },
++};
++
++static struct hda_input_mux alc883_asus_eee1601_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x0 },
++ { "Line", 0x2 },
++ },
++};
++
++static struct hda_input_mux alc889A_mb31_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x0 },
++ /* Front Mic (0x01) unused */
++ { "Line", 0x2 },
++ /* Line 2 (0x03) unused */
++ /* CD (0x04) unsused? */
++ },
++};
++
++/*
++ * 2ch mode
++ */
++static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
++ { 2, NULL }
++};
++
+ /*
+ * 2ch mode
+ */
+@@ -6364,6 +6446,18 @@
+ };
+
+ /*
++ * 4ch mode
++ */
++static struct hda_verb alc882_3ST_ch4_init[] = {
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
+ * 6ch mode
+ */
+ static struct hda_verb alc882_3ST_ch6_init[] = {
+@@ -6376,11 +6470,14 @@
+ { } /* end */
+ };
+
+-static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
++static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
+ { 2, alc882_3ST_ch2_init },
++ { 4, alc882_3ST_ch4_init },
+ { 6, alc882_3ST_ch6_init },
+ };
+
++#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
++
+ /*
+ * 6ch mode
+ */
+@@ -6468,6 +6565,143 @@
+ { 6, alc885_mb5_ch6_init },
+ };
+
++
++/*
++ * 2ch mode
++ */
++static struct hda_verb alc883_4ST_ch2_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { } /* end */
++};
++
++/*
++ * 4ch mode
++ */
++static struct hda_verb alc883_4ST_ch4_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
++ * 6ch mode
++ */
++static struct hda_verb alc883_4ST_ch6_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
++ * 8ch mode
++ */
++static struct hda_verb alc883_4ST_ch8_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
++ { 2, alc883_4ST_ch2_init },
++ { 4, alc883_4ST_ch4_init },
++ { 6, alc883_4ST_ch6_init },
++ { 8, alc883_4ST_ch8_init },
++};
++
++
++/*
++ * 2ch mode
++ */
++static struct hda_verb alc883_3ST_ch2_intel_init[] = {
++ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { } /* end */
++};
++
++/*
++ * 4ch mode
++ */
++static struct hda_verb alc883_3ST_ch4_intel_init[] = {
++ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
++ * 6ch mode
++ */
++static struct hda_verb alc883_3ST_ch6_intel_init[] = {
++ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
++ { 2, alc883_3ST_ch2_intel_init },
++ { 4, alc883_3ST_ch4_intel_init },
++ { 6, alc883_3ST_ch6_intel_init },
++};
++
++/*
++ * 6ch mode
++ */
++static struct hda_verb alc883_sixstack_ch6_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
++ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { } /* end */
++};
++
++/*
++ * 8ch mode
++ */
++static struct hda_verb alc883_sixstack_ch8_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { } /* end */
++};
++
++static struct hda_channel_mode alc883_sixstack_modes[2] = {
++ { 6, alc883_sixstack_ch6_init },
++ { 8, alc883_sixstack_ch8_init },
++};
++
++
+ /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+@@ -6603,7 +6837,7 @@
+ { } /* end */
+ };
+
+-static struct hda_verb alc882_init_verbs[] = {
++static struct hda_verb alc882_base_init_verbs[] = {
+ /* Front mixer: unmute input/output amp left and right (volume = 0) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+@@ -6655,11 +6889,6 @@
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+@@ -6670,9 +6899,6 @@
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+- /* ADC1: mute amp left and right */
+- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC2: mute amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+@@ -6683,6 +6909,21 @@
+ { }
+ };
+
++static struct hda_verb alc882_adc1_init_verbs[] = {
++ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
++ /* ADC1: mute amp left and right */
++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
++ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
++ { }
++};
++
++/* HACK - expand to two elements */
++#define alc882_init_verbs alc882_base_init_verbs, alc882_adc1_init_verbs
++
+ static struct hda_verb alc882_eapd_verbs[] = {
+ /* change to EAPD mode */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+@@ -6690,6 +6931,8 @@
+ { }
+ };
+
++#define alc883_init_verbs alc882_base_init_verbs
++
+ /* Mac Pro test */
+ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+@@ -7037,883 +7280,62 @@
+ /*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+-static struct hda_verb alc882_auto_init_verbs[] = {
++static struct hda_verb alc883_auto_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+-
+- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+- * mixer widget
+- * Note: PASD motherboards uses the Line In 2 as the input for
+- * front panel mic (mic 2)
+- */
+- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+-
+- /*
+- * Set up output mixers (0x0c - 0x0f)
+- */
+- /* set vol=0 to output mixers */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- /* set up input amps for analog loopback */
+- /* Amp Indices: DAC = 0, mixer = 1 */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+-
+- /* FIXME: use matrix-type input source selection */
+- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+- /* Input mixer2 */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+- /* Input mixer3 */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+-
+- { }
+-};
+-
+-#ifdef CONFIG_SND_HDA_POWER_SAVE
+-#define alc882_loopbacks alc880_loopbacks
+-#endif
+-
+-/* pcm configuration: identical with ALC880 */
+-#define alc882_pcm_analog_playback alc880_pcm_analog_playback
+-#define alc882_pcm_analog_capture alc880_pcm_analog_capture
+-#define alc882_pcm_digital_playback alc880_pcm_digital_playback
+-#define alc882_pcm_digital_capture alc880_pcm_digital_capture
+-
+-/*
+- * configuration and preset
+- */
+-static const char *alc882_models[ALC882_MODEL_LAST] = {
+- [ALC882_3ST_DIG] = "3stack-dig",
+- [ALC882_6ST_DIG] = "6stack-dig",
+- [ALC882_ARIMA] = "arima",
+- [ALC882_W2JC] = "w2jc",
+- [ALC882_TARGA] = "targa",
+- [ALC882_ASUS_A7J] = "asus-a7j",
+- [ALC882_ASUS_A7M] = "asus-a7m",
+- [ALC885_MACPRO] = "macpro",
+- [ALC885_MB5] = "mb5",
+- [ALC885_MBP3] = "mbp3",
+- [ALC885_IMAC24] = "imac24",
+- [ALC882_AUTO] = "auto",
+-};
+-
+-static struct snd_pci_quirk alc882_cfg_tbl[] = {
+- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+- SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
+- SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+- SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
+- SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
+- SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
+- {}
+-};
+-
+-static struct alc_config_preset alc882_presets[] = {
+- [ALC882_3ST_DIG] = {
+- .mixers = { alc882_base_mixer },
+- .init_verbs = { alc882_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+- .channel_mode = alc882_ch_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_6ST_DIG] = {
+- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+- .channel_mode = alc882_sixstack_modes,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_ARIMA] = {
+- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+- .channel_mode = alc882_sixstack_modes,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_W2JC] = {
+- .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
+- alc880_gpio1_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+- .channel_mode = alc880_threestack_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- },
+- [ALC885_MBP3] = {
+- .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc885_mbp3_init_verbs,
+- alc880_gpio1_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .channel_mode = alc885_mbp_6ch_modes,
+- .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
+- .input_mux = &alc882_capture_source,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .unsol_event = alc_automute_amp_unsol_event,
+- .init_hook = alc885_mbp3_init_hook,
+- },
+- [ALC885_MB5] = {
+- .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc885_mb5_init_verbs,
+- alc880_gpio1_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .channel_mode = alc885_mb5_6ch_modes,
+- .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
+- .input_mux = &mb5_capture_source,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- },
+- [ALC885_MACPRO] = {
+- .mixers = { alc882_macpro_mixer },
+- .init_verbs = { alc882_macpro_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+- .channel_mode = alc882_ch_modes,
+- .input_mux = &alc882_capture_source,
+- .init_hook = alc885_macpro_init_hook,
+- },
+- [ALC885_IMAC24] = {
+- .mixers = { alc885_imac24_mixer },
+- .init_verbs = { alc885_imac24_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+- .channel_mode = alc882_ch_modes,
+- .input_mux = &alc882_capture_source,
+- .unsol_event = alc_automute_amp_unsol_event,
+- .init_hook = alc885_imac24_init_hook,
+- },
+- [ALC882_TARGA] = {
+- .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc880_gpio3_init_verbs,
+- alc882_targa_verbs},
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+- .adc_nids = alc882_adc_nids,
+- .capsrc_nids = alc882_capsrc_nids,
+- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+- .channel_mode = alc882_3ST_6ch_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- .unsol_event = alc882_targa_unsol_event,
+- .init_hook = alc882_targa_init_hook,
+- },
+- [ALC882_ASUS_A7J] = {
+- .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+- .adc_nids = alc882_adc_nids,
+- .capsrc_nids = alc882_capsrc_nids,
+- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+- .channel_mode = alc882_3ST_6ch_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_ASUS_A7M] = {
+- .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
+- alc880_gpio1_init_verbs,
+- alc882_asus_a7m_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+- .channel_mode = alc880_threestack_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- },
+-};
+-
+-
+-/*
+- * Pin config fixes
+- */
+-enum {
+- PINFIX_ABIT_AW9D_MAX
+-};
+-
+-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+- { 0x15, 0x01080104 }, /* side */
+- { 0x16, 0x01011012 }, /* rear */
+- { 0x17, 0x01016011 }, /* clfe */
+- { }
+-};
+-
+-static const struct alc_pincfg *alc882_pin_fixes[] = {
+- [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+-};
+-
+-static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+- SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+- {}
+-};
+-
+-/*
+- * BIOS auto configuration
+- */
+-static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
+- hda_nid_t nid, int pin_type,
+- int dac_idx)
+-{
+- /* set as output */
+- struct alc_spec *spec = codec->spec;
+- int idx;
+-
+- alc_set_pin_output(codec, nid, pin_type);
+- if (spec->multiout.dac_nids[dac_idx] == 0x25)
+- idx = 4;
+- else
+- idx = spec->multiout.dac_nids[dac_idx] - 2;
+- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
+-
+-}
+-
+-static void alc882_auto_init_multi_out(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int i;
+-
+- for (i = 0; i <= HDA_SIDE; i++) {
+- hda_nid_t nid = spec->autocfg.line_out_pins[i];
+- int pin_type = get_pin_type(spec->autocfg.line_out_type);
+- if (nid)
+- alc882_auto_set_output_and_unmute(codec, nid, pin_type,
+- i);
+- }
+-}
+-
+-static void alc882_auto_init_hp_out(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- hda_nid_t pin;
+-
+- pin = spec->autocfg.hp_pins[0];
+- if (pin) /* connect to front */
+- /* use dac 0 */
+- alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+- pin = spec->autocfg.speaker_pins[0];
+- if (pin)
+- alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+-}
+-
+-#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
+-#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
+-
+-static void alc882_auto_init_analog_input(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int i;
+-
+- for (i = 0; i < AUTO_PIN_LAST; i++) {
+- hda_nid_t nid = spec->autocfg.input_pins[i];
+- if (!nid)
+- continue;
+- alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
+- if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+- snd_hda_codec_write(codec, nid, 0,
+- AC_VERB_SET_AMP_GAIN_MUTE,
+- AMP_OUT_MUTE);
+- }
+-}
+-
+-static void alc882_auto_init_input_src(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int c;
+-
+- for (c = 0; c < spec->num_adc_nids; c++) {
+- hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
+- hda_nid_t nid = spec->capsrc_nids[c];
+- unsigned int mux_idx;
+- const struct hda_input_mux *imux;
+- int conns, mute, idx, item;
+-
+- conns = snd_hda_get_connections(codec, nid, conn_list,
+- ARRAY_SIZE(conn_list));
+- if (conns < 0)
+- continue;
+- mux_idx = c >= spec->num_mux_defs ? 0 : c;
+- imux = &spec->input_mux[mux_idx];
+- for (idx = 0; idx < conns; idx++) {
+- /* if the current connection is the selected one,
+- * unmute it as default - otherwise mute it
+- */
+- mute = AMP_IN_MUTE(idx);
+- for (item = 0; item < imux->num_items; item++) {
+- if (imux->items[item].index == idx) {
+- if (spec->cur_mux[c] == item)
+- mute = AMP_IN_UNMUTE(idx);
+- break;
+- }
+- }
+- /* check if we have a selector or mixer
+- * we could check for the widget type instead, but
+- * just check for Amp-In presence (in case of mixer
+- * without amp-in there is something wrong, this
+- * function shouldn't be used or capsrc nid is wrong)
+- */
+- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+- snd_hda_codec_write(codec, nid, 0,
+- AC_VERB_SET_AMP_GAIN_MUTE,
+- mute);
+- else if (mute != AMP_IN_MUTE(idx))
+- snd_hda_codec_write(codec, nid, 0,
+- AC_VERB_SET_CONNECT_SEL,
+- idx);
+- }
+- }
+-}
+-
+-/* add mic boosts if needed */
+-static int alc_auto_add_mic_boost(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int err;
+- hda_nid_t nid;
+-
+- nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
+- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
+- err = add_control(spec, ALC_CTL_WIDGET_VOL,
+- "Mic Boost",
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+- if (err < 0)
+- return err;
+- }
+- nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
+- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
+- err = add_control(spec, ALC_CTL_WIDGET_VOL,
+- "Front Mic Boost",
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+- if (err < 0)
+- return err;
+- }
+- return 0;
+-}
+-
+-/* almost identical with ALC880 parser... */
+-static int alc882_parse_auto_config(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int err = alc880_parse_auto_config(codec);
+-
+- if (err < 0)
+- return err;
+- else if (!err)
+- return 0; /* no config found */
+-
+- err = alc_auto_add_mic_boost(codec);
+- if (err < 0)
+- return err;
+-
+- /* hack - override the init verbs */
+- spec->init_verbs[0] = alc882_auto_init_verbs;
+-
+- return 1; /* config found */
+-}
+-
+-/* additional initialization for auto-configuration model */
+-static void alc882_auto_init(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- alc882_auto_init_multi_out(codec);
+- alc882_auto_init_hp_out(codec);
+- alc882_auto_init_analog_input(codec);
+- alc882_auto_init_input_src(codec);
+- if (spec->unsol_event)
+- alc_inithook(codec);
+-}
+-
+-static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
+-
+-static int patch_alc882(struct hda_codec *codec)
+-{
+- struct alc_spec *spec;
+- int err, board_config;
+-
+- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+- if (spec == NULL)
+- return -ENOMEM;
+-
+- codec->spec = spec;
+-
+- board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
+- alc882_models,
+- alc882_cfg_tbl);
+-
+- if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
+- /* Pick up systems that don't supply PCI SSID */
+- switch (codec->subsystem_id) {
+- case 0x106b0c00: /* Mac Pro */
+- board_config = ALC885_MACPRO;
+- break;
+- case 0x106b1000: /* iMac 24 */
+- case 0x106b2800: /* AppleTV */
+- case 0x106b3e00: /* iMac 24 Aluminium */
+- board_config = ALC885_IMAC24;
+- break;
+- case 0x106b00a0: /* MacBookPro3,1 - Another revision */
+- case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
+- case 0x106b00a4: /* MacbookPro4,1 */
+- case 0x106b2c00: /* Macbook Pro rev3 */
+- /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */
+- case 0x106b3800: /* MacbookPro4,1 - latter revision */
+- board_config = ALC885_MBP3;
+- break;
+- case 0x106b3f00: /* Macbook 5,1 */
+- case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense
+- * seems not working, so apparently
+- * no perfect solution yet
+- */
+- board_config = ALC885_MB5;
+- break;
+- default:
+- /* ALC889A is handled better as ALC888-compatible */
+- if (codec->revision_id == 0x100101 ||
+- codec->revision_id == 0x100103) {
+- alc_free(codec);
+- return patch_alc883(codec);
+- }
+- printk(KERN_INFO "hda_codec: Unknown model for %s, "
+- "trying auto-probe from BIOS...\n",
+- codec->chip_name);
+- board_config = ALC882_AUTO;
+- }
+- }
+-
+- alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+-
+- if (board_config == ALC882_AUTO) {
+- /* automatic parse from the BIOS config */
+- err = alc882_parse_auto_config(codec);
+- if (err < 0) {
+- alc_free(codec);
+- return err;
+- } else if (!err) {
+- printk(KERN_INFO
+- "hda_codec: Cannot set up configuration "
+- "from BIOS. Using base mode...\n");
+- board_config = ALC882_3ST_DIG;
+- }
+- }
+-
+- err = snd_hda_attach_beep_device(codec, 0x1);
+- if (err < 0) {
+- alc_free(codec);
+- return err;
+- }
+-
+- if (board_config != ALC882_AUTO)
+- setup_preset(spec, &alc882_presets[board_config]);
+-
+- spec->stream_analog_playback = &alc882_pcm_analog_playback;
+- spec->stream_analog_capture = &alc882_pcm_analog_capture;
+- /* FIXME: setup DAC5 */
+- /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
+- spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
+-
+- spec->stream_digital_playback = &alc882_pcm_digital_playback;
+- spec->stream_digital_capture = &alc882_pcm_digital_capture;
+-
+- if (!spec->adc_nids && spec->input_mux) {
+- /* check whether NID 0x07 is valid */
+- unsigned int wcap = get_wcaps(codec, 0x07);
+- /* get type */
+- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+- if (wcap != AC_WID_AUD_IN) {
+- spec->adc_nids = alc882_adc_nids_alt;
+- spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
+- spec->capsrc_nids = alc882_capsrc_nids_alt;
+- } else {
+- spec->adc_nids = alc882_adc_nids;
+- spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
+- spec->capsrc_nids = alc882_capsrc_nids;
+- }
+- }
+- set_capture_mixer(spec);
+- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+-
+- spec->vmaster_nid = 0x0c;
+-
+- codec->patch_ops = alc_patch_ops;
+- if (board_config == ALC882_AUTO)
+- spec->init_hook = alc882_auto_init;
+-#ifdef CONFIG_SND_HDA_POWER_SAVE
+- if (!spec->loopback.amplist)
+- spec->loopback.amplist = alc882_loopbacks;
+-#endif
+- codec->proc_widget_hook = print_realtek_coef;
+-
+- return 0;
+-}
+-
+-/*
+- * ALC883 support
+- *
+- * ALC883 is almost identical with ALC880 but has cleaner and more flexible
+- * configuration. Each pin widget can choose any input DACs and a mixer.
+- * Each ADC is connected from a mixer of all inputs. This makes possible
+- * 6-channel independent captures.
+- *
+- * In addition, an independent DAC for the multi-playback (not used in this
+- * driver yet).
+- */
+-#define ALC883_DIGOUT_NID 0x06
+-#define ALC883_DIGIN_NID 0x0a
+-
+-#define ALC1200_DIGOUT_NID 0x10
+-
+-static hda_nid_t alc883_dac_nids[4] = {
+- /* front, rear, clfe, rear_surr */
+- 0x02, 0x03, 0x04, 0x05
+-};
+-
+-static hda_nid_t alc883_adc_nids[2] = {
+- /* ADC1-2 */
+- 0x08, 0x09,
+-};
+-
+-static hda_nid_t alc883_adc_nids_alt[1] = {
+- /* ADC1 */
+- 0x08,
+-};
+-
+-static hda_nid_t alc883_adc_nids_rev[2] = {
+- /* ADC2-1 */
+- 0x09, 0x08
+-};
+-
+-#define alc889_adc_nids alc880_adc_nids
+-
+-static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
+-
+-static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+-
+-#define alc889_capsrc_nids alc882_capsrc_nids
+-
+-/* input MUX */
+-/* FIXME: should be a matrix-type input source selection */
+-
+-static struct hda_input_mux alc883_capture_source = {
+- .num_items = 4,
+- .items = {
+- { "Mic", 0x0 },
+- { "Front Mic", 0x1 },
+- { "Line", 0x2 },
+- { "CD", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_3stack_6ch_intel = {
+- .num_items = 4,
+- .items = {
+- { "Mic", 0x1 },
+- { "Front Mic", 0x0 },
+- { "Line", 0x2 },
+- { "CD", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_lenovo_101e_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x1 },
+- { "Line", 0x2 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
+- .num_items = 4,
+- .items = {
+- { "Mic", 0x0 },
+- { "iMic", 0x1 },
+- { "Line", 0x2 },
+- { "CD", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x0 },
+- { "Int Mic", 0x1 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+- .num_items = 3,
+- .items = {
+- { "Mic", 0x0 },
+- { "Front Mic", 0x1 },
+- { "Line", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x0 },
+- { "Line", 0x2 },
+- },
+-};
+-
+-static struct hda_input_mux alc889A_mb31_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x0 },
+- /* Front Mic (0x01) unused */
+- { "Line", 0x2 },
+- /* Line 2 (0x03) unused */
+- /* CD (0x04) unsused? */
+- },
+-};
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+- { 2, NULL }
+-};
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_verb alc883_3ST_ch2_init[] = {
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { } /* end */
+-};
+-
+-/*
+- * 4ch mode
+- */
+-static struct hda_verb alc883_3ST_ch4_init[] = {
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_3ST_ch6_init[] = {
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
+- { 2, alc883_3ST_ch2_init },
+- { 4, alc883_3ST_ch4_init },
+- { 6, alc883_3ST_ch6_init },
+-};
+-
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_verb alc883_4ST_ch2_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { } /* end */
+-};
+-
+-/*
+- * 4ch mode
+- */
+-static struct hda_verb alc883_4ST_ch4_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_4ST_ch6_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 8ch mode
+- */
+-static struct hda_verb alc883_4ST_ch8_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+- { 2, alc883_4ST_ch2_init },
+- { 4, alc883_4ST_ch4_init },
+- { 6, alc883_4ST_ch6_init },
+- { 8, alc883_4ST_ch8_init },
+-};
+-
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_verb alc883_3ST_ch2_intel_init[] = {
+- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { } /* end */
+-};
+-
+-/*
+- * 4ch mode
+- */
+-static struct hda_verb alc883_3ST_ch4_intel_init[] = {
+- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_3ST_ch6_intel_init[] = {
+- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
++ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
++ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
++ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+-static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+- { 2, alc883_3ST_ch2_intel_init },
+- { 4, alc883_3ST_ch4_intel_init },
+- { 6, alc883_3ST_ch6_intel_init },
+-};
++ /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
++ * mixer widget
++ * Note: PASD motherboards uses the Line In 2 as the input for
++ * front panel mic (mic 2)
++ */
++ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_sixstack_ch6_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { } /* end */
+-};
++ /*
++ * Set up output mixers (0x0c - 0x0f)
++ */
++ /* set vol=0 to output mixers */
++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
++ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
++ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
++ /* set up input amps for analog loopback */
++ /* Amp Indices: DAC = 0, mixer = 1 */
++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
++ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+-/*
+- * 8ch mode
+- */
+-static struct hda_verb alc883_sixstack_ch8_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { } /* end */
+-};
++ /* FIXME: use matrix-type input source selection */
++ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
++ /* Input mixer2 */
++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
++ /* Input mixer3 */
++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+
+-static struct hda_channel_mode alc883_sixstack_modes[2] = {
+- { 6, alc883_sixstack_ch6_init },
+- { 8, alc883_sixstack_ch8_init },
++ { }
+ };
+
+ /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
+@@ -7966,34 +7388,7 @@
+ { }
+ };
+
+-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+- * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+- */
+-
+-static struct snd_kcontrol_new alc883_base_mixer[] = {
+- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+- { } /* end */
+-};
++#define alc883_base_mixer alc882_base_mixer
+
+ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+@@ -8312,114 +7707,36 @@
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+- { } /* end */
+-};
+-
+-static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
+- HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
+- HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
+- {
+- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+- /* .name = "Capture Source", */
+- .name = "Input Source",
+- .count = 1,
+- .info = alc_mux_enum_info,
+- .get = alc_mux_enum_get,
+- .put = alc_mux_enum_put,
+- },
+- { } /* end */
+-};
+-
+-static struct snd_kcontrol_new alc883_chmode_mixer[] = {
+- {
+- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+- .name = "Channel Mode",
+- .info = alc_ch_mode_info,
+- .get = alc_ch_mode_get,
+- .put = alc_ch_mode_put,
+- },
+- { } /* end */
+-};
+-
+-static struct hda_verb alc883_init_verbs[] = {
+- /* ADC1: mute amp left and right */
+- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* ADC2: mute amp left and right */
+- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* Front mixer: unmute input/output amp left and right (volume = 0) */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- /* Rear mixer */
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- /* CLFE mixer */
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- /* Side mixer */
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+-
+- /* mute analog input loopbacks */
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
++ { } /* end */
++};
+
+- /* Front Pin: output 0 (0x0c) */
+- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* Rear Pin: output 1 (0x0d) */
+- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+- /* CLFE Pin: output 2 (0x0e) */
+- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+- /* Side Pin: output 3 (0x0f) */
+- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+- /* Mic (rear) pin: input vref at 80% */
+- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+- /* Front Mic pin: input vref at 80% */
+- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+- /* Line In pin: input */
+- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+- /* Line-2 In: Headphone output (output 0 - 0x0c) */
+- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* CD pin widget for input */
+- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
++static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
++ HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
++ HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ /* .name = "Capture Source", */
++ .name = "Input Source",
++ .count = 1,
++ .info = alc_mux_enum_info,
++ .get = alc_mux_enum_get,
++ .put = alc_mux_enum_put,
++ },
++ { } /* end */
++};
+
+- /* FIXME: use matrix-type input source selection */
+- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer2 */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+- /* Input mixer3 */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+- { }
++static struct snd_kcontrol_new alc883_chmode_mixer[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Channel Mode",
++ .info = alc_ch_mode_info,
++ .get = alc_ch_mode_get,
++ .put = alc_ch_mode_put,
++ },
++ { } /* end */
+ };
+
+ /* toggle speaker-output according to the hp-jack state */
+@@ -8854,69 +8171,6 @@
+ alc_automute_amp(codec);
+ }
+
+-/*
+- * generic initialization of ADC, input mixers and output mixers
+- */
+-static struct hda_verb alc883_auto_init_verbs[] = {
+- /*
+- * Unmute ADC0-2 and set the default input to mic-in
+- */
+- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+-
+- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+- * mixer widget
+- * Note: PASD motherboards uses the Line In 2 as the input for
+- * front panel mic (mic 2)
+- */
+- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+-
+- /*
+- * Set up output mixers (0x0c - 0x0f)
+- */
+- /* set vol=0 to output mixers */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- /* set up input amps for analog loopback */
+- /* Amp Indices: DAC = 0, mixer = 1 */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+-
+- /* FIXME: use matrix-type input source selection */
+- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer1 */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+- /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+- /* Input mixer2 */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+- /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+-
+- { }
+-};
+-
+ static struct hda_verb alc888_asus_m90v_verbs[] = {
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+@@ -9027,25 +8281,44 @@
+ alc889A_mb31_automute(codec);
+ }
+
++
+ #ifdef CONFIG_SND_HDA_POWER_SAVE
+-#define alc883_loopbacks alc880_loopbacks
++#define alc882_loopbacks alc880_loopbacks
+ #endif
+
+ /* pcm configuration: identical with ALC880 */
+-#define alc883_pcm_analog_playback alc880_pcm_analog_playback
+-#define alc883_pcm_analog_capture alc880_pcm_analog_capture
+-#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
+-#define alc883_pcm_digital_playback alc880_pcm_digital_playback
+-#define alc883_pcm_digital_capture alc880_pcm_digital_capture
++#define alc882_pcm_analog_playback alc880_pcm_analog_playback
++#define alc882_pcm_analog_capture alc880_pcm_analog_capture
++#define alc882_pcm_digital_playback alc880_pcm_digital_playback
++#define alc882_pcm_digital_capture alc880_pcm_digital_capture
++
++static hda_nid_t alc883_slave_dig_outs[] = {
++ ALC1200_DIGOUT_NID, 0,
++};
++
++static hda_nid_t alc1200_slave_dig_outs[] = {
++ ALC883_DIGOUT_NID, 0,
++};
+
+ /*
+ * configuration and preset
+ */
+-static const char *alc883_models[ALC883_MODEL_LAST] = {
+- [ALC883_3ST_2ch_DIG] = "3stack-dig",
++static const char *alc882_models[ALC882_MODEL_LAST] = {
++ [ALC882_3ST_DIG] = "3stack-dig",
++ [ALC882_6ST_DIG] = "6stack-dig",
++ [ALC882_ARIMA] = "arima",
++ [ALC882_W2JC] = "w2jc",
++ [ALC882_TARGA] = "targa",
++ [ALC882_ASUS_A7J] = "asus-a7j",
++ [ALC882_ASUS_A7M] = "asus-a7m",
++ [ALC885_MACPRO] = "macpro",
++ [ALC885_MB5] = "mb5",
++ [ALC885_MBP3] = "mbp3",
++ [ALC885_IMAC24] = "imac24",
++ [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
+ [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
+ [ALC883_3ST_6ch] = "3stack-6ch",
+- [ALC883_6ST_DIG] = "6stack-dig",
++ [ALC883_6ST_DIG] = "alc883-6stack-dig",
+ [ALC883_TARGA_DIG] = "targa-dig",
+ [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
+ [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
+@@ -9072,11 +8345,12 @@
+ [ALC1200_ASUS_P5Q] = "asus-p5q",
+ [ALC889A_MB31] = "mb31",
+ [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
+- [ALC883_AUTO] = "auto",
++ [ALC882_AUTO] = "auto",
+ };
+
+-static struct snd_pci_quirk alc883_cfg_tbl[] = {
+- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
++static struct snd_pci_quirk alc882_cfg_tbl[] = {
++ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
++
+ SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
+@@ -9091,8 +8365,8 @@
+ ALC888_ACER_ASPIRE_8930G),
+ SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+ ALC888_ACER_ASPIRE_8930G),
+- SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
+- SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
++ SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
++ SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
+ SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+ ALC888_ACER_ASPIRE_6530G),
+ SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+@@ -9101,30 +8375,44 @@
+ * model=auto should work fine now
+ */
+ /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
++
+ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
++
+ SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
++
++ SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
++ SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
++ SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+ SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
++ SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
++ SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
++ SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
+ SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
++
++ SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
+ SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
+- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
++ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
+ SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
+ SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
+ SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+- SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
++ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
++
+ SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
++ SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
+ SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
++ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
+@@ -9146,11 +8434,13 @@
+ SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
++
+ SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
+ SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
+ SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
++ /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
+ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+ SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
+ ALC883_FUJITSU_PI2515),
+@@ -9165,24 +8455,175 @@
+ SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
+ SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
++
+ SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
+ SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
+- SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
+- {}
+-};
+
+-static hda_nid_t alc883_slave_dig_outs[] = {
+- ALC1200_DIGOUT_NID, 0,
++ {}
+ };
+
+-static hda_nid_t alc1200_slave_dig_outs[] = {
+- ALC883_DIGOUT_NID, 0,
++/* codec SSID table for Intel Mac */
++static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
++ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
++ SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
++ SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
++ SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
++ SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
++ SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
++ /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently
++ * no perfect solution yet
++ */
++ SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
++ {} /* terminator */
+ };
+
+-static struct alc_config_preset alc883_presets[] = {
++static struct alc_config_preset alc882_presets[] = {
++ [ALC882_3ST_DIG] = {
++ .mixers = { alc882_base_mixer },
++ .init_verbs = { alc882_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
++ .channel_mode = alc882_ch_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_6ST_DIG] = {
++ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
++ .channel_mode = alc882_sixstack_modes,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_ARIMA] = {
++ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
++ .channel_mode = alc882_sixstack_modes,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_W2JC] = {
++ .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
++ alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
++ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ },
++ [ALC885_MBP3] = {
++ .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc885_mbp3_init_verbs,
++ alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .channel_mode = alc885_mbp_6ch_modes,
++ .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
++ .input_mux = &alc882_capture_source,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .unsol_event = alc_automute_amp_unsol_event,
++ .init_hook = alc885_mbp3_init_hook,
++ },
++ [ALC885_MB5] = {
++ .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc885_mb5_init_verbs,
++ alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .channel_mode = alc885_mb5_6ch_modes,
++ .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
++ .input_mux = &mb5_capture_source,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ },
++ [ALC885_MACPRO] = {
++ .mixers = { alc882_macpro_mixer },
++ .init_verbs = { alc882_macpro_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
++ .channel_mode = alc882_ch_modes,
++ .input_mux = &alc882_capture_source,
++ .init_hook = alc885_macpro_init_hook,
++ },
++ [ALC885_IMAC24] = {
++ .mixers = { alc885_imac24_mixer },
++ .init_verbs = { alc885_imac24_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
++ .channel_mode = alc882_ch_modes,
++ .input_mux = &alc882_capture_source,
++ .unsol_event = alc_automute_amp_unsol_event,
++ .init_hook = alc885_imac24_init_hook,
++ },
++ [ALC882_TARGA] = {
++ .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
++ .adc_nids = alc882_adc_nids,
++ .capsrc_nids = alc882_capsrc_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
++ .channel_mode = alc882_3ST_6ch_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ .unsol_event = alc882_targa_unsol_event,
++ .init_hook = alc882_targa_init_hook,
++ },
++ [ALC882_ASUS_A7J] = {
++ .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
++ .adc_nids = alc882_adc_nids,
++ .capsrc_nids = alc882_capsrc_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
++ .channel_mode = alc882_3ST_6ch_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_ASUS_A7M] = {
++ .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
++ alc880_gpio1_init_verbs,
++ alc882_asus_a7m_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
++ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ },
+ [ALC883_3ST_2ch_DIG] = {
+ .mixers = { alc883_3ST_2ch_mixer },
+ .init_verbs = { alc883_init_verbs },
+@@ -9619,9 +9060,32 @@
+
+
+ /*
++ * Pin config fixes
++ */
++enum {
++ PINFIX_ABIT_AW9D_MAX
++};
++
++static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
++ { 0x15, 0x01080104 }, /* side */
++ { 0x16, 0x01011012 }, /* rear */
++ { 0x17, 0x01016011 }, /* clfe */
++ { }
++};
++
++static const struct alc_pincfg *alc882_pin_fixes[] = {
++ [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
++};
++
++static struct snd_pci_quirk alc882_pinfix_tbl[] = {
++ SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
++ {}
++};
++
++/*
+ * BIOS auto configuration
+ */
+-static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
++static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type,
+ int dac_idx)
+ {
+@@ -9638,7 +9102,7 @@
+
+ }
+
+-static void alc883_auto_init_multi_out(struct hda_codec *codec)
++static void alc882_auto_init_multi_out(struct hda_codec *codec)
+ {
+ struct alc_spec *spec = codec->spec;
+ int i;
+@@ -9647,12 +9111,12 @@
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ int pin_type = get_pin_type(spec->autocfg.line_out_type);
+ if (nid)
+- alc883_auto_set_output_and_unmute(codec, nid, pin_type,
++ alc882_auto_set_output_and_unmute(codec, nid, pin_type,
+ i);
+ }
+ }
+
+-static void alc883_auto_init_hp_out(struct hda_codec *codec)
++static void alc882_auto_init_hp_out(struct hda_codec *codec)
+ {
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+@@ -9660,42 +9124,114 @@
+ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ /* use dac 0 */
+- alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
++ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ pin = spec->autocfg.speaker_pins[0];
+ if (pin)
+- alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
++ alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+ }
+
+-#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
+-#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
++#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
++#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
+
+-static void alc883_auto_init_analog_input(struct hda_codec *codec)
++static void alc882_auto_init_analog_input(struct hda_codec *codec)
+ {
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t nid = spec->autocfg.input_pins[i];
+- if (alc883_is_input_pin(nid)) {
+- alc_set_input_pin(codec, nid, i);
+- if (nid != ALC883_PIN_CD_NID &&
+- (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
++ if (!nid)
++ continue;
++ alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
++ if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
++ snd_hda_codec_write(codec, nid, 0,
++ AC_VERB_SET_AMP_GAIN_MUTE,
++ AMP_OUT_MUTE);
++ }
++}
++
++static void alc882_auto_init_input_src(struct hda_codec *codec)
++{
++ struct alc_spec *spec = codec->spec;
++ int c;
++
++ for (c = 0; c < spec->num_adc_nids; c++) {
++ hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
++ hda_nid_t nid = spec->capsrc_nids[c];
++ unsigned int mux_idx;
++ const struct hda_input_mux *imux;
++ int conns, mute, idx, item;
++
++ conns = snd_hda_get_connections(codec, nid, conn_list,
++ ARRAY_SIZE(conn_list));
++ if (conns < 0)
++ continue;
++ mux_idx = c >= spec->num_mux_defs ? 0 : c;
++ imux = &spec->input_mux[mux_idx];
++ for (idx = 0; idx < conns; idx++) {
++ /* if the current connection is the selected one,
++ * unmute it as default - otherwise mute it
++ */
++ mute = AMP_IN_MUTE(idx);
++ for (item = 0; item < imux->num_items; item++) {
++ if (imux->items[item].index == idx) {
++ if (spec->cur_mux[c] == item)
++ mute = AMP_IN_UNMUTE(idx);
++ break;
++ }
++ }
++ /* check if we have a selector or mixer
++ * we could check for the widget type instead, but
++ * just check for Amp-In presence (in case of mixer
++ * without amp-in there is something wrong, this
++ * function shouldn't be used or capsrc nid is wrong)
++ */
++ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+- AMP_OUT_MUTE);
++ mute);
++ else if (mute != AMP_IN_MUTE(idx))
++ snd_hda_codec_write(codec, nid, 0,
++ AC_VERB_SET_CONNECT_SEL,
++ idx);
+ }
+ }
+ }
+
+-#define alc883_auto_init_input_src alc882_auto_init_input_src
++/* add mic boosts if needed */
++static int alc_auto_add_mic_boost(struct hda_codec *codec)
++{
++ struct alc_spec *spec = codec->spec;
++ int err;
++ hda_nid_t nid;
++
++ nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
++ if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
++ err = add_control(spec, ALC_CTL_WIDGET_VOL,
++ "Mic Boost",
++ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
++ if (err < 0)
++ return err;
++ }
++ nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
++ if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
++ err = add_control(spec, ALC_CTL_WIDGET_VOL,
++ "Front Mic Boost",
++ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
++ if (err < 0)
++ return err;
++ }
++ return 0;
++}
+
+ /* almost identical with ALC880 parser... */
+-static int alc883_parse_auto_config(struct hda_codec *codec)
++static int alc882_parse_auto_config(struct hda_codec *codec)
+ {
+ struct alc_spec *spec = codec->spec;
+- int err = alc880_parse_auto_config(codec);
+- struct auto_pin_cfg *cfg = &spec->autocfg;
++ struct auto_pin_cfg *autocfg = &spec->autocfg;
++ unsigned int wcap;
+ int i;
++ int err = alc880_parse_auto_config(codec);
+
+ if (err < 0)
+ return err;
+@@ -9708,43 +9244,45 @@
+
+ /* hack - override the init verbs */
+ spec->init_verbs[0] = alc883_auto_init_verbs;
++ /* if ADC 0x07 is available, initialize it, too */
++ wcap = get_wcaps(codec, 0x07);
++ wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
++ if (wcap == AC_WID_AUD_IN)
++ add_verb(spec, alc882_adc1_init_verbs);
+
+- /* setup input_mux for ALC889 */
+- if (codec->vendor_id == 0x10ec0889) {
+- /* digital-mic input pin is excluded in alc880_auto_create..()
+- * because it's under 0x18
+- */
+- if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+- cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+- struct hda_input_mux *imux = &spec->private_imux[0];
+- for (i = 1; i < 3; i++)
+- memcpy(&spec->private_imux[i],
+- &spec->private_imux[0],
+- sizeof(spec->private_imux[0]));
+- imux->items[imux->num_items].label = "Int DMic";
+- imux->items[imux->num_items].index = 0x0b;
+- imux->num_items++;
+- spec->num_mux_defs = 3;
+- spec->input_mux = spec->private_imux;
+- }
++ /* digital-mic input pin is excluded in alc880_auto_create..()
++ * because it's under 0x18
++ */
++ if (autocfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
++ autocfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
++ struct hda_input_mux *imux = &spec->private_imux[0];
++ for (i = 1; i < 3; i++)
++ memcpy(&spec->private_imux[i],
++ &spec->private_imux[0],
++ sizeof(spec->private_imux[0]));
++ imux->items[imux->num_items].label = "Int DMic";
++ imux->items[imux->num_items].index = 0x0b;
++ imux->num_items++;
++ spec->num_mux_defs = 3;
++ spec->input_mux = spec->private_imux;
+ }
+
+ return 1; /* config found */
+ }
+
+ /* additional initialization for auto-configuration model */
+-static void alc883_auto_init(struct hda_codec *codec)
++static void alc882_auto_init(struct hda_codec *codec)
+ {
+ struct alc_spec *spec = codec->spec;
+- alc883_auto_init_multi_out(codec);
+- alc883_auto_init_hp_out(codec);
+- alc883_auto_init_analog_input(codec);
+- alc883_auto_init_input_src(codec);
++ alc882_auto_init_multi_out(codec);
++ alc882_auto_init_hp_out(codec);
++ alc882_auto_init_analog_input(codec);
++ alc882_auto_init_input_src(codec);
+ if (spec->unsol_event)
+ alc_inithook(codec);
+ }
+
+-static int patch_alc883(struct hda_codec *codec)
++static int patch_alc882(struct hda_codec *codec)
+ {
+ struct alc_spec *spec;
+ int err, board_config;
+@@ -9755,28 +9293,36 @@
+
+ codec->spec = spec;
+
+- alc_fix_pll_init(codec, 0x20, 0x0a, 10);
++ switch (codec->vendor_id) {
++ case 0x10ec0882:
++ case 0x10ec0885:
++ break;
++ default:
++ /* ALC883 and variants */
++ alc_fix_pll_init(codec, 0x20, 0x0a, 10);
++ break;
++ }
+
+- board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
+- alc883_models,
+- alc883_cfg_tbl);
+- if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+- /* Pick up systems that don't supply PCI SSID */
+- switch (codec->subsystem_id) {
+- case 0x106b3600: /* Macbook 3.1 */
+- board_config = ALC889A_MB31;
+- break;
+- default:
+- printk(KERN_INFO
+- "hda_codec: Unknown model for %s, trying "
+- "auto-probe from BIOS...\n", codec->chip_name);
+- board_config = ALC883_AUTO;
+- }
++ board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
++ alc882_models,
++ alc882_cfg_tbl);
++
++ if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
++ board_config = snd_hda_check_board_codec_sid_config(codec,
++ ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
++
++ if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
++ printk(KERN_INFO "hda_codec: Unknown model for %s, "
++ "trying auto-probe from BIOS...\n",
++ codec->chip_name);
++ board_config = ALC882_AUTO;
+ }
+
+- if (board_config == ALC883_AUTO) {
++ alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
++
++ if (board_config == ALC882_AUTO) {
+ /* automatic parse from the BIOS config */
+- err = alc883_parse_auto_config(codec);
++ err = alc882_parse_auto_config(codec);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+@@ -9784,7 +9330,7 @@
+ printk(KERN_INFO
+ "hda_codec: Cannot set up configuration "
+ "from BIOS. Using base mode...\n");
+- board_config = ALC883_3ST_2ch_DIG;
++ board_config = ALC882_3ST_DIG;
+ }
+ }
+
+@@ -9794,63 +9340,61 @@
+ return err;
+ }
+
+- if (board_config != ALC883_AUTO)
+- setup_preset(spec, &alc883_presets[board_config]);
++ if (board_config != ALC882_AUTO)
++ setup_preset(spec, &alc882_presets[board_config]);
+
+- switch (codec->vendor_id) {
+- case 0x10ec0888:
+- if (!spec->num_adc_nids) {
+- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+- spec->adc_nids = alc883_adc_nids;
+- }
+- if (!spec->capsrc_nids)
+- spec->capsrc_nids = alc883_capsrc_nids;
++ spec->stream_analog_playback = &alc882_pcm_analog_playback;
++ spec->stream_analog_capture = &alc882_pcm_analog_capture;
++ /* FIXME: setup DAC5 */
++ /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
++ spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
++
++ spec->stream_digital_playback = &alc882_pcm_digital_playback;
++ spec->stream_digital_capture = &alc882_pcm_digital_capture;
++
++ if (codec->vendor_id == 0x10ec0888)
+ spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
+- break;
+- case 0x10ec0889:
+- if (!spec->num_adc_nids) {
+- spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
+- spec->adc_nids = alc889_adc_nids;
+- }
+- if (!spec->capsrc_nids)
+- spec->capsrc_nids = alc889_capsrc_nids;
+- break;
+- default:
+- if (!spec->num_adc_nids) {
+- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+- spec->adc_nids = alc883_adc_nids;
++
++ if (!spec->adc_nids && spec->input_mux) {
++ int i;
++ spec->num_adc_nids = 0;
++ for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
++ hda_nid_t cap;
++ hda_nid_t nid = alc882_adc_nids[i];
++ unsigned int wcap = get_wcaps(codec, nid);
++ /* get type */
++ wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
++ if (wcap != AC_WID_AUD_IN)
++ continue;
++ spec->private_adc_nids[spec->num_adc_nids] = nid;
++ err = snd_hda_get_connections(codec, nid, &cap, 1);
++ if (err < 0)
++ continue;
++ spec->private_capsrc_nids[spec->num_adc_nids] = cap;
++ spec->num_adc_nids++;
+ }
+- if (!spec->capsrc_nids)
+- spec->capsrc_nids = alc883_capsrc_nids;
+- break;
++ spec->adc_nids = spec->private_adc_nids;
++ spec->capsrc_nids = spec->private_capsrc_nids;
+ }
+
+- spec->stream_analog_playback = &alc883_pcm_analog_playback;
+- spec->stream_analog_capture = &alc883_pcm_analog_capture;
+- spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
+-
+- spec->stream_digital_playback = &alc883_pcm_digital_playback;
+- spec->stream_digital_capture = &alc883_pcm_digital_capture;
+-
+- if (!spec->cap_mixer)
+- set_capture_mixer(spec);
++ set_capture_mixer(spec);
+ set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+
+ spec->vmaster_nid = 0x0c;
+
+ codec->patch_ops = alc_patch_ops;
+- if (board_config == ALC883_AUTO)
+- spec->init_hook = alc883_auto_init;
+-
++ if (board_config == ALC882_AUTO)
++ spec->init_hook = alc882_auto_init;
+ #ifdef CONFIG_SND_HDA_POWER_SAVE
+ if (!spec->loopback.amplist)
+- spec->loopback.amplist = alc883_loopbacks;
++ spec->loopback.amplist = alc882_loopbacks;
+ #endif
+ codec->proc_widget_hook = print_realtek_coef;
+
+ return 0;
+ }
+
++
+ /*
+ * ALC262 support
+ */
+@@ -17538,23 +17082,23 @@
+ { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
+ { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
+ { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
+- .patch = patch_alc883 },
++ .patch = patch_alc882 },
+ { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
+ .patch = patch_alc662 },
+ { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
+ { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
+ { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
+- { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
++ { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
+ { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
+- .patch = patch_alc882 }, /* should be patch_alc883() in future */
++ .patch = patch_alc882 },
+ { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
+- .patch = patch_alc882 }, /* should be patch_alc883() in future */
++ .patch = patch_alc882 },
+ { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
+- { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
++ { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
+ { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
+- .patch = patch_alc883 },
+- { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
+- { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
++ .patch = patch_alc882 },
++ { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
++ { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
+ {} /* terminator */
+ };
+
diff --git a/patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883...old b/patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883...old
new file mode 100644
index 0000000000..39dbd52408
--- /dev/null
+++ b/patches.drivers/alsa-hda-04-Merge-patch_alc882-and-patch_alc883...old
@@ -0,0 +1,2244 @@
+From 4953550a6ca399b644ef057626617465d8be9a7b Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 30 Jun 2009 15:28:30 +0200
+Subject: [PATCH 04/28] ALSA: hda - Merge patch_alc882() and patch_alc883()
+
+Merge patch_alc882() and patch_alc883() to the former one since both
+codecs have fairly similar connections but just a slight difference.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/pci/hda/patch_realtek.c | 1829 ++++++++++++++++-------------------------
+ 1 files changed, 687 insertions(+), 1142 deletions(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 3a8e58c..6a899e8 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -208,12 +208,6 @@ enum {
+ ALC885_MBP3,
+ ALC885_MB5,
+ ALC885_IMAC24,
+- ALC882_AUTO,
+- ALC882_MODEL_LAST,
+-};
+-
+-/* ALC883 models */
+-enum {
+ ALC883_3ST_2ch_DIG,
+ ALC883_3ST_6ch_DIG,
+ ALC883_3ST_6ch,
+@@ -246,8 +240,8 @@ enum {
+ ALC889A_MB31,
+ ALC1200_ASUS_P5Q,
+ ALC883_SONY_VAIO_TT,
+- ALC883_AUTO,
+- ALC883_MODEL_LAST,
++ ALC882_AUTO,
++ ALC882_MODEL_LAST,
+ };
+
+ /* for GPIO Poll */
+@@ -320,6 +314,8 @@ struct alc_spec {
+ struct snd_array kctls;
+ struct hda_input_mux private_imux[3];
+ hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
++ hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
++ hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
+
+ /* hooks */
+ void (*init_hook)(struct hda_codec *codec);
+@@ -6295,7 +6291,7 @@ static int patch_alc260(struct hda_codec *codec)
+
+
+ /*
+- * ALC882 support
++ * ALC882/883/885/888/889 support
+ *
+ * ALC882 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration. Each pin widget can choose any input DACs and a mixer.
+@@ -6307,22 +6303,35 @@ static int patch_alc260(struct hda_codec *codec)
+ */
+ #define ALC882_DIGOUT_NID 0x06
+ #define ALC882_DIGIN_NID 0x0a
++#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
++#define ALC883_DIGIN_NID ALC882_DIGIN_NID
++#define ALC1200_DIGOUT_NID 0x10
++
+
+ static struct hda_channel_mode alc882_ch_modes[1] = {
+ { 8, NULL }
+ };
+
++/* DACs */
+ static hda_nid_t alc882_dac_nids[4] = {
+ /* front, rear, clfe, rear_surr */
+ 0x02, 0x03, 0x04, 0x05
+ };
++#define alc883_dac_nids alc882_dac_nids
+
+-/* identical with ALC880 */
++/* ADCs */
+ #define alc882_adc_nids alc880_adc_nids
+ #define alc882_adc_nids_alt alc880_adc_nids_alt
++#define alc883_adc_nids alc882_adc_nids_alt
++static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
++static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
++#define alc889_adc_nids alc880_adc_nids
+
+ static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+ static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
++#define alc883_capsrc_nids alc882_capsrc_nids_alt
++static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
++#define alc889_capsrc_nids alc882_capsrc_nids
+
+ /* input MUX */
+ /* FIXME: should be a matrix-type input source selection */
+@@ -6337,6 +6346,8 @@ static struct hda_input_mux alc882_capture_source = {
+ },
+ };
+
++#define alc883_capture_source alc882_capture_source
++
+ static struct hda_input_mux mb5_capture_source = {
+ .num_items = 3,
+ .items = {
+@@ -6346,6 +6357,77 @@ static struct hda_input_mux mb5_capture_source = {
+ },
+ };
+
++static struct hda_input_mux alc883_3stack_6ch_intel = {
++ .num_items = 4,
++ .items = {
++ { "Mic", 0x1 },
++ { "Front Mic", 0x0 },
++ { "Line", 0x2 },
++ { "CD", 0x4 },
++ },
++};
++
++static struct hda_input_mux alc883_lenovo_101e_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x1 },
++ { "Line", 0x2 },
++ },
++};
++
++static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
++ .num_items = 4,
++ .items = {
++ { "Mic", 0x0 },
++ { "iMic", 0x1 },
++ { "Line", 0x2 },
++ { "CD", 0x4 },
++ },
++};
++
++static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x0 },
++ { "Int Mic", 0x1 },
++ },
++};
++
++static struct hda_input_mux alc883_lenovo_sky_capture_source = {
++ .num_items = 3,
++ .items = {
++ { "Mic", 0x0 },
++ { "Front Mic", 0x1 },
++ { "Line", 0x4 },
++ },
++};
++
++static struct hda_input_mux alc883_asus_eee1601_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x0 },
++ { "Line", 0x2 },
++ },
++};
++
++static struct hda_input_mux alc889A_mb31_capture_source = {
++ .num_items = 2,
++ .items = {
++ { "Mic", 0x0 },
++ /* Front Mic (0x01) unused */
++ { "Line", 0x2 },
++ /* Line 2 (0x03) unused */
++ /* CD (0x04) unsused? */
++ },
++};
++
++/*
++ * 2ch mode
++ */
++static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
++ { 2, NULL }
++};
++
+ /*
+ * 2ch mode
+ */
+@@ -6358,6 +6440,18 @@ static struct hda_verb alc882_3ST_ch2_init[] = {
+ };
+
+ /*
++ * 4ch mode
++ */
++static struct hda_verb alc882_3ST_ch4_init[] = {
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
+ * 6ch mode
+ */
+ static struct hda_verb alc882_3ST_ch6_init[] = {
+@@ -6370,11 +6464,14 @@ static struct hda_verb alc882_3ST_ch6_init[] = {
+ { } /* end */
+ };
+
+-static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
++static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
+ { 2, alc882_3ST_ch2_init },
++ { 4, alc882_3ST_ch4_init },
+ { 6, alc882_3ST_ch6_init },
+ };
+
++#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
++
+ /*
+ * 6ch mode
+ */
+@@ -6462,6 +6559,143 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
+ { 6, alc885_mb5_ch6_init },
+ };
+
++
++/*
++ * 2ch mode
++ */
++static struct hda_verb alc883_4ST_ch2_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { } /* end */
++};
++
++/*
++ * 4ch mode
++ */
++static struct hda_verb alc883_4ST_ch4_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
++ * 6ch mode
++ */
++static struct hda_verb alc883_4ST_ch6_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
++ * 8ch mode
++ */
++static struct hda_verb alc883_4ST_ch8_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
++ { 2, alc883_4ST_ch2_init },
++ { 4, alc883_4ST_ch4_init },
++ { 6, alc883_4ST_ch6_init },
++ { 8, alc883_4ST_ch8_init },
++};
++
++
++/*
++ * 2ch mode
++ */
++static struct hda_verb alc883_3ST_ch2_intel_init[] = {
++ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { } /* end */
++};
++
++/*
++ * 4ch mode
++ */
++static struct hda_verb alc883_3ST_ch4_intel_init[] = {
++ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
++ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++/*
++ * 6ch mode
++ */
++static struct hda_verb alc883_3ST_ch6_intel_init[] = {
++ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
++ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
++ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
++ { } /* end */
++};
++
++static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
++ { 2, alc883_3ST_ch2_intel_init },
++ { 4, alc883_3ST_ch4_intel_init },
++ { 6, alc883_3ST_ch6_intel_init },
++};
++
++/*
++ * 6ch mode
++ */
++static struct hda_verb alc883_sixstack_ch6_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
++ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { } /* end */
++};
++
++/*
++ * 8ch mode
++ */
++static struct hda_verb alc883_sixstack_ch8_init[] = {
++ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
++ { } /* end */
++};
++
++static struct hda_channel_mode alc883_sixstack_modes[2] = {
++ { 6, alc883_sixstack_ch6_init },
++ { 8, alc883_sixstack_ch8_init },
++};
++
++
+ /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+@@ -6597,7 +6831,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = {
+ { } /* end */
+ };
+
+-static struct hda_verb alc882_init_verbs[] = {
++static struct hda_verb alc882_base_init_verbs[] = {
+ /* Front mixer: unmute input/output amp left and right (volume = 0) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+@@ -6649,11 +6883,6 @@ static struct hda_verb alc882_init_verbs[] = {
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+@@ -6664,9 +6893,6 @@ static struct hda_verb alc882_init_verbs[] = {
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+- /* ADC1: mute amp left and right */
+- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC2: mute amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+@@ -6677,6 +6903,21 @@ static struct hda_verb alc882_init_verbs[] = {
+ { }
+ };
+
++static struct hda_verb alc882_adc1_init_verbs[] = {
++ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
++ /* ADC1: mute amp left and right */
++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
++ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
++ { }
++};
++
++/* HACK - expand to two elements */
++#define alc882_init_verbs alc882_base_init_verbs, alc882_adc1_init_verbs
++
+ static struct hda_verb alc882_eapd_verbs[] = {
+ /* change to EAPD mode */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+@@ -6684,6 +6925,8 @@ static struct hda_verb alc882_eapd_verbs[] = {
+ { }
+ };
+
++#define alc883_init_verbs alc882_base_init_verbs
++
+ /* Mac Pro test */
+ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+@@ -7034,12 +7277,10 @@ static void alc885_imac24_init_hook(struct hda_codec *codec)
+ /*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+-static struct hda_verb alc882_auto_init_verbs[] = {
++static struct hda_verb alc883_auto_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+@@ -7080,11 +7321,6 @@ static struct hda_verb alc882_auto_init_verbs[] = {
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+@@ -7099,819 +7335,6 @@ static struct hda_verb alc882_auto_init_verbs[] = {
+ { }
+ };
+
+-#ifdef CONFIG_SND_HDA_POWER_SAVE
+-#define alc882_loopbacks alc880_loopbacks
+-#endif
+-
+-/* pcm configuration: identical with ALC880 */
+-#define alc882_pcm_analog_playback alc880_pcm_analog_playback
+-#define alc882_pcm_analog_capture alc880_pcm_analog_capture
+-#define alc882_pcm_digital_playback alc880_pcm_digital_playback
+-#define alc882_pcm_digital_capture alc880_pcm_digital_capture
+-
+-/*
+- * configuration and preset
+- */
+-static const char *alc882_models[ALC882_MODEL_LAST] = {
+- [ALC882_3ST_DIG] = "3stack-dig",
+- [ALC882_6ST_DIG] = "6stack-dig",
+- [ALC882_ARIMA] = "arima",
+- [ALC882_W2JC] = "w2jc",
+- [ALC882_TARGA] = "targa",
+- [ALC882_ASUS_A7J] = "asus-a7j",
+- [ALC882_ASUS_A7M] = "asus-a7m",
+- [ALC885_MACPRO] = "macpro",
+- [ALC885_MB5] = "mb5",
+- [ALC885_MBP3] = "mbp3",
+- [ALC885_IMAC24] = "imac24",
+- [ALC882_AUTO] = "auto",
+-};
+-
+-static struct snd_pci_quirk alc882_cfg_tbl[] = {
+- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+- SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
+- SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+- SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
+- SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
+- SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+- SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
+- {}
+-};
+-
+-static struct alc_config_preset alc882_presets[] = {
+- [ALC882_3ST_DIG] = {
+- .mixers = { alc882_base_mixer },
+- .init_verbs = { alc882_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+- .channel_mode = alc882_ch_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_6ST_DIG] = {
+- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+- .channel_mode = alc882_sixstack_modes,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_ARIMA] = {
+- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+- .channel_mode = alc882_sixstack_modes,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_W2JC] = {
+- .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
+- alc880_gpio1_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+- .channel_mode = alc880_threestack_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- },
+- [ALC885_MBP3] = {
+- .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc885_mbp3_init_verbs,
+- alc880_gpio1_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .channel_mode = alc885_mbp_6ch_modes,
+- .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
+- .input_mux = &alc882_capture_source,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .unsol_event = alc_automute_amp_unsol_event,
+- .init_hook = alc885_mbp3_init_hook,
+- },
+- [ALC885_MB5] = {
+- .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc885_mb5_init_verbs,
+- alc880_gpio1_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .channel_mode = alc885_mb5_6ch_modes,
+- .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
+- .input_mux = &mb5_capture_source,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- },
+- [ALC885_MACPRO] = {
+- .mixers = { alc882_macpro_mixer },
+- .init_verbs = { alc882_macpro_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+- .channel_mode = alc882_ch_modes,
+- .input_mux = &alc882_capture_source,
+- .init_hook = alc885_macpro_init_hook,
+- },
+- [ALC885_IMAC24] = {
+- .mixers = { alc885_imac24_mixer },
+- .init_verbs = { alc885_imac24_init_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .dig_in_nid = ALC882_DIGIN_NID,
+- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+- .channel_mode = alc882_ch_modes,
+- .input_mux = &alc882_capture_source,
+- .unsol_event = alc_automute_amp_unsol_event,
+- .init_hook = alc885_imac24_init_hook,
+- },
+- [ALC882_TARGA] = {
+- .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+- .adc_nids = alc882_adc_nids,
+- .capsrc_nids = alc882_capsrc_nids,
+- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+- .channel_mode = alc882_3ST_6ch_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- .unsol_event = alc882_targa_unsol_event,
+- .init_hook = alc882_targa_init_hook,
+- },
+- [ALC882_ASUS_A7J] = {
+- .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+- .adc_nids = alc882_adc_nids,
+- .capsrc_nids = alc882_capsrc_nids,
+- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+- .channel_mode = alc882_3ST_6ch_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- },
+- [ALC882_ASUS_A7M] = {
+- .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
+- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
+- alc880_gpio1_init_verbs,
+- alc882_asus_a7m_verbs },
+- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+- .dac_nids = alc882_dac_nids,
+- .dig_out_nid = ALC882_DIGOUT_NID,
+- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+- .channel_mode = alc880_threestack_modes,
+- .need_dac_fix = 1,
+- .input_mux = &alc882_capture_source,
+- },
+-};
+-
+-
+-/*
+- * Pin config fixes
+- */
+-enum {
+- PINFIX_ABIT_AW9D_MAX
+-};
+-
+-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+- { 0x15, 0x01080104 }, /* side */
+- { 0x16, 0x01011012 }, /* rear */
+- { 0x17, 0x01016011 }, /* clfe */
+- { }
+-};
+-
+-static const struct alc_pincfg *alc882_pin_fixes[] = {
+- [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+-};
+-
+-static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+- SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+- {}
+-};
+-
+-/*
+- * BIOS auto configuration
+- */
+-static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
+- hda_nid_t nid, int pin_type,
+- int dac_idx)
+-{
+- /* set as output */
+- struct alc_spec *spec = codec->spec;
+- int idx;
+-
+- alc_set_pin_output(codec, nid, pin_type);
+- if (spec->multiout.dac_nids[dac_idx] == 0x25)
+- idx = 4;
+- else
+- idx = spec->multiout.dac_nids[dac_idx] - 2;
+- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
+-
+-}
+-
+-static void alc882_auto_init_multi_out(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int i;
+-
+- for (i = 0; i <= HDA_SIDE; i++) {
+- hda_nid_t nid = spec->autocfg.line_out_pins[i];
+- int pin_type = get_pin_type(spec->autocfg.line_out_type);
+- if (nid)
+- alc882_auto_set_output_and_unmute(codec, nid, pin_type,
+- i);
+- }
+-}
+-
+-static void alc882_auto_init_hp_out(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- hda_nid_t pin;
+-
+- pin = spec->autocfg.hp_pins[0];
+- if (pin) /* connect to front */
+- /* use dac 0 */
+- alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+- pin = spec->autocfg.speaker_pins[0];
+- if (pin)
+- alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+-}
+-
+-#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
+-#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
+-
+-static void alc882_auto_init_analog_input(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int i;
+-
+- for (i = 0; i < AUTO_PIN_LAST; i++) {
+- hda_nid_t nid = spec->autocfg.input_pins[i];
+- if (!nid)
+- continue;
+- alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
+- if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+- snd_hda_codec_write(codec, nid, 0,
+- AC_VERB_SET_AMP_GAIN_MUTE,
+- AMP_OUT_MUTE);
+- }
+-}
+-
+-static void alc882_auto_init_input_src(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int c;
+-
+- for (c = 0; c < spec->num_adc_nids; c++) {
+- hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
+- hda_nid_t nid = spec->capsrc_nids[c];
+- unsigned int mux_idx;
+- const struct hda_input_mux *imux;
+- int conns, mute, idx, item;
+-
+- conns = snd_hda_get_connections(codec, nid, conn_list,
+- ARRAY_SIZE(conn_list));
+- if (conns < 0)
+- continue;
+- mux_idx = c >= spec->num_mux_defs ? 0 : c;
+- imux = &spec->input_mux[mux_idx];
+- for (idx = 0; idx < conns; idx++) {
+- /* if the current connection is the selected one,
+- * unmute it as default - otherwise mute it
+- */
+- mute = AMP_IN_MUTE(idx);
+- for (item = 0; item < imux->num_items; item++) {
+- if (imux->items[item].index == idx) {
+- if (spec->cur_mux[c] == item)
+- mute = AMP_IN_UNMUTE(idx);
+- break;
+- }
+- }
+- /* check if we have a selector or mixer
+- * we could check for the widget type instead, but
+- * just check for Amp-In presence (in case of mixer
+- * without amp-in there is something wrong, this
+- * function shouldn't be used or capsrc nid is wrong)
+- */
+- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+- snd_hda_codec_write(codec, nid, 0,
+- AC_VERB_SET_AMP_GAIN_MUTE,
+- mute);
+- else if (mute != AMP_IN_MUTE(idx))
+- snd_hda_codec_write(codec, nid, 0,
+- AC_VERB_SET_CONNECT_SEL,
+- idx);
+- }
+- }
+-}
+-
+-/* add mic boosts if needed */
+-static int alc_auto_add_mic_boost(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int err;
+- hda_nid_t nid;
+-
+- nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
+- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
+- err = add_control(spec, ALC_CTL_WIDGET_VOL,
+- "Mic Boost",
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+- if (err < 0)
+- return err;
+- }
+- nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
+- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
+- err = add_control(spec, ALC_CTL_WIDGET_VOL,
+- "Front Mic Boost",
+- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+- if (err < 0)
+- return err;
+- }
+- return 0;
+-}
+-
+-/* almost identical with ALC880 parser... */
+-static int alc882_parse_auto_config(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- int err = alc880_parse_auto_config(codec);
+-
+- if (err < 0)
+- return err;
+- else if (!err)
+- return 0; /* no config found */
+-
+- err = alc_auto_add_mic_boost(codec);
+- if (err < 0)
+- return err;
+-
+- /* hack - override the init verbs */
+- spec->init_verbs[0] = alc882_auto_init_verbs;
+-
+- return 1; /* config found */
+-}
+-
+-/* additional initialization for auto-configuration model */
+-static void alc882_auto_init(struct hda_codec *codec)
+-{
+- struct alc_spec *spec = codec->spec;
+- alc882_auto_init_multi_out(codec);
+- alc882_auto_init_hp_out(codec);
+- alc882_auto_init_analog_input(codec);
+- alc882_auto_init_input_src(codec);
+- if (spec->unsol_event)
+- alc_inithook(codec);
+-}
+-
+-static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
+-
+-static int patch_alc882(struct hda_codec *codec)
+-{
+- struct alc_spec *spec;
+- int err, board_config;
+-
+- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+- if (spec == NULL)
+- return -ENOMEM;
+-
+- codec->spec = spec;
+-
+- board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
+- alc882_models,
+- alc882_cfg_tbl);
+-
+- if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
+- /* Pick up systems that don't supply PCI SSID */
+- switch (codec->subsystem_id) {
+- case 0x106b0c00: /* Mac Pro */
+- board_config = ALC885_MACPRO;
+- break;
+- case 0x106b1000: /* iMac 24 */
+- case 0x106b2800: /* AppleTV */
+- case 0x106b3e00: /* iMac 24 Aluminium */
+- board_config = ALC885_IMAC24;
+- break;
+- case 0x106b00a0: /* MacBookPro3,1 - Another revision */
+- case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
+- case 0x106b00a4: /* MacbookPro4,1 */
+- case 0x106b2c00: /* Macbook Pro rev3 */
+- /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */
+- case 0x106b3800: /* MacbookPro4,1 - latter revision */
+- board_config = ALC885_MBP3;
+- break;
+- case 0x106b3f00: /* Macbook 5,1 */
+- case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense
+- * seems not working, so apparently
+- * no perfect solution yet
+- */
+- board_config = ALC885_MB5;
+- break;
+- default:
+- /* ALC889A is handled better as ALC888-compatible */
+- if (codec->revision_id == 0x100101 ||
+- codec->revision_id == 0x100103) {
+- alc_free(codec);
+- return patch_alc883(codec);
+- }
+- printk(KERN_INFO "hda_codec: Unknown model for %s, "
+- "trying auto-probe from BIOS...\n",
+- codec->chip_name);
+- board_config = ALC882_AUTO;
+- }
+- }
+-
+- alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+-
+- if (board_config == ALC882_AUTO) {
+- /* automatic parse from the BIOS config */
+- err = alc882_parse_auto_config(codec);
+- if (err < 0) {
+- alc_free(codec);
+- return err;
+- } else if (!err) {
+- printk(KERN_INFO
+- "hda_codec: Cannot set up configuration "
+- "from BIOS. Using base mode...\n");
+- board_config = ALC882_3ST_DIG;
+- }
+- }
+-
+- err = snd_hda_attach_beep_device(codec, 0x1);
+- if (err < 0) {
+- alc_free(codec);
+- return err;
+- }
+-
+- if (board_config != ALC882_AUTO)
+- setup_preset(spec, &alc882_presets[board_config]);
+-
+- spec->stream_analog_playback = &alc882_pcm_analog_playback;
+- spec->stream_analog_capture = &alc882_pcm_analog_capture;
+- /* FIXME: setup DAC5 */
+- /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
+- spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
+-
+- spec->stream_digital_playback = &alc882_pcm_digital_playback;
+- spec->stream_digital_capture = &alc882_pcm_digital_capture;
+-
+- if (!spec->adc_nids && spec->input_mux) {
+- /* check whether NID 0x07 is valid */
+- unsigned int wcap = get_wcaps(codec, 0x07);
+- /* get type */
+- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+- if (wcap != AC_WID_AUD_IN) {
+- spec->adc_nids = alc882_adc_nids_alt;
+- spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
+- spec->capsrc_nids = alc882_capsrc_nids_alt;
+- } else {
+- spec->adc_nids = alc882_adc_nids;
+- spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
+- spec->capsrc_nids = alc882_capsrc_nids;
+- }
+- }
+- set_capture_mixer(spec);
+- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+-
+- spec->vmaster_nid = 0x0c;
+-
+- codec->patch_ops = alc_patch_ops;
+- if (board_config == ALC882_AUTO)
+- spec->init_hook = alc882_auto_init;
+-#ifdef CONFIG_SND_HDA_POWER_SAVE
+- if (!spec->loopback.amplist)
+- spec->loopback.amplist = alc882_loopbacks;
+-#endif
+- codec->proc_widget_hook = print_realtek_coef;
+-
+- return 0;
+-}
+-
+-/*
+- * ALC883 support
+- *
+- * ALC883 is almost identical with ALC880 but has cleaner and more flexible
+- * configuration. Each pin widget can choose any input DACs and a mixer.
+- * Each ADC is connected from a mixer of all inputs. This makes possible
+- * 6-channel independent captures.
+- *
+- * In addition, an independent DAC for the multi-playback (not used in this
+- * driver yet).
+- */
+-#define ALC883_DIGOUT_NID 0x06
+-#define ALC883_DIGIN_NID 0x0a
+-
+-#define ALC1200_DIGOUT_NID 0x10
+-
+-static hda_nid_t alc883_dac_nids[4] = {
+- /* front, rear, clfe, rear_surr */
+- 0x02, 0x03, 0x04, 0x05
+-};
+-
+-static hda_nid_t alc883_adc_nids[2] = {
+- /* ADC1-2 */
+- 0x08, 0x09,
+-};
+-
+-static hda_nid_t alc883_adc_nids_alt[1] = {
+- /* ADC1 */
+- 0x08,
+-};
+-
+-static hda_nid_t alc883_adc_nids_rev[2] = {
+- /* ADC2-1 */
+- 0x09, 0x08
+-};
+-
+-#define alc889_adc_nids alc880_adc_nids
+-
+-static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
+-
+-static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+-
+-#define alc889_capsrc_nids alc882_capsrc_nids
+-
+-/* input MUX */
+-/* FIXME: should be a matrix-type input source selection */
+-
+-static struct hda_input_mux alc883_capture_source = {
+- .num_items = 4,
+- .items = {
+- { "Mic", 0x0 },
+- { "Front Mic", 0x1 },
+- { "Line", 0x2 },
+- { "CD", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_3stack_6ch_intel = {
+- .num_items = 4,
+- .items = {
+- { "Mic", 0x1 },
+- { "Front Mic", 0x0 },
+- { "Line", 0x2 },
+- { "CD", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_lenovo_101e_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x1 },
+- { "Line", 0x2 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
+- .num_items = 4,
+- .items = {
+- { "Mic", 0x0 },
+- { "iMic", 0x1 },
+- { "Line", 0x2 },
+- { "CD", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x0 },
+- { "Int Mic", 0x1 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+- .num_items = 3,
+- .items = {
+- { "Mic", 0x0 },
+- { "Front Mic", 0x1 },
+- { "Line", 0x4 },
+- },
+-};
+-
+-static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x0 },
+- { "Line", 0x2 },
+- },
+-};
+-
+-static struct hda_input_mux alc889A_mb31_capture_source = {
+- .num_items = 2,
+- .items = {
+- { "Mic", 0x0 },
+- /* Front Mic (0x01) unused */
+- { "Line", 0x2 },
+- /* Line 2 (0x03) unused */
+- /* CD (0x04) unsused? */
+- },
+-};
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+- { 2, NULL }
+-};
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_verb alc883_3ST_ch2_init[] = {
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { } /* end */
+-};
+-
+-/*
+- * 4ch mode
+- */
+-static struct hda_verb alc883_3ST_ch4_init[] = {
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_3ST_ch6_init[] = {
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
+- { 2, alc883_3ST_ch2_init },
+- { 4, alc883_3ST_ch4_init },
+- { 6, alc883_3ST_ch6_init },
+-};
+-
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_verb alc883_4ST_ch2_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { } /* end */
+-};
+-
+-/*
+- * 4ch mode
+- */
+-static struct hda_verb alc883_4ST_ch4_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_4ST_ch6_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 8ch mode
+- */
+-static struct hda_verb alc883_4ST_ch8_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+- { 2, alc883_4ST_ch2_init },
+- { 4, alc883_4ST_ch4_init },
+- { 6, alc883_4ST_ch6_init },
+- { 8, alc883_4ST_ch8_init },
+-};
+-
+-
+-/*
+- * 2ch mode
+- */
+-static struct hda_verb alc883_3ST_ch2_intel_init[] = {
+- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { } /* end */
+-};
+-
+-/*
+- * 4ch mode
+- */
+-static struct hda_verb alc883_3ST_ch4_intel_init[] = {
+- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_3ST_ch6_intel_init[] = {
+- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
+- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+- { } /* end */
+-};
+-
+-static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+- { 2, alc883_3ST_ch2_intel_init },
+- { 4, alc883_3ST_ch4_intel_init },
+- { 6, alc883_3ST_ch6_intel_init },
+-};
+-
+-/*
+- * 6ch mode
+- */
+-static struct hda_verb alc883_sixstack_ch6_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { } /* end */
+-};
+-
+-/*
+- * 8ch mode
+- */
+-static struct hda_verb alc883_sixstack_ch8_init[] = {
+- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+- { } /* end */
+-};
+-
+-static struct hda_channel_mode alc883_sixstack_modes[2] = {
+- { 6, alc883_sixstack_ch6_init },
+- { 8, alc883_sixstack_ch8_init },
+-};
+-
+ /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
+ static struct hda_verb alc889A_mb31_ch2_init[] = {
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
+@@ -7962,34 +7385,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = {
+ { }
+ };
+
+-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+- * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+- */
+-
+-static struct snd_kcontrol_new alc883_base_mixer[] = {
+- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+- { } /* end */
+-};
++#define alc883_base_mixer alc882_base_mixer
+
+ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+@@ -8340,84 +7736,6 @@ static struct snd_kcontrol_new alc883_chmode_mixer[] = {
+ { } /* end */
+ };
+
+-static struct hda_verb alc883_init_verbs[] = {
+- /* ADC1: mute amp left and right */
+- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* ADC2: mute amp left and right */
+- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* Front mixer: unmute input/output amp left and right (volume = 0) */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- /* Rear mixer */
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- /* CLFE mixer */
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- /* Side mixer */
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+-
+- /* mute analog input loopbacks */
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+-
+- /* Front Pin: output 0 (0x0c) */
+- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* Rear Pin: output 1 (0x0d) */
+- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+- /* CLFE Pin: output 2 (0x0e) */
+- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+- /* Side Pin: output 3 (0x0f) */
+- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+- /* Mic (rear) pin: input vref at 80% */
+- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+- /* Front Mic pin: input vref at 80% */
+- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+- /* Line In pin: input */
+- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+- /* Line-2 In: Headphone output (output 0 - 0x0c) */
+- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+- /* CD pin widget for input */
+- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+-
+- /* FIXME: use matrix-type input source selection */
+- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer2 */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+- /* Input mixer3 */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+- { }
+-};
+-
+ /* toggle speaker-output according to the hp-jack state */
+ static void alc883_mitac_init_hook(struct hda_codec *codec)
+ {
+@@ -8850,69 +8168,6 @@ static void alc883_vaiott_init_hook(struct hda_codec *codec)
+ alc_automute_amp(codec);
+ }
+
+-/*
+- * generic initialization of ADC, input mixers and output mixers
+- */
+-static struct hda_verb alc883_auto_init_verbs[] = {
+- /*
+- * Unmute ADC0-2 and set the default input to mic-in
+- */
+- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+-
+- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+- * mixer widget
+- * Note: PASD motherboards uses the Line In 2 as the input for
+- * front panel mic (mic 2)
+- */
+- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+-
+- /*
+- * Set up output mixers (0x0c - 0x0f)
+- */
+- /* set vol=0 to output mixers */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+- /* set up input amps for analog loopback */
+- /* Amp Indices: DAC = 0, mixer = 1 */
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+-
+- /* FIXME: use matrix-type input source selection */
+- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+- /* Input mixer1 */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+- /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
+- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+- /* Input mixer2 */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+- /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
+- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+-
+- { }
+-};
+-
+ static struct hda_verb alc888_asus_m90v_verbs[] = {
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+@@ -9023,25 +8278,44 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
+ alc889A_mb31_automute(codec);
+ }
+
++
+ #ifdef CONFIG_SND_HDA_POWER_SAVE
+-#define alc883_loopbacks alc880_loopbacks
++#define alc882_loopbacks alc880_loopbacks
+ #endif
+
+ /* pcm configuration: identical with ALC880 */
+-#define alc883_pcm_analog_playback alc880_pcm_analog_playback
+-#define alc883_pcm_analog_capture alc880_pcm_analog_capture
+-#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
+-#define alc883_pcm_digital_playback alc880_pcm_digital_playback
+-#define alc883_pcm_digital_capture alc880_pcm_digital_capture
++#define alc882_pcm_analog_playback alc880_pcm_analog_playback
++#define alc882_pcm_analog_capture alc880_pcm_analog_capture
++#define alc882_pcm_digital_playback alc880_pcm_digital_playback
++#define alc882_pcm_digital_capture alc880_pcm_digital_capture
++
++static hda_nid_t alc883_slave_dig_outs[] = {
++ ALC1200_DIGOUT_NID, 0,
++};
++
++static hda_nid_t alc1200_slave_dig_outs[] = {
++ ALC883_DIGOUT_NID, 0,
++};
+
+ /*
+ * configuration and preset
+ */
+-static const char *alc883_models[ALC883_MODEL_LAST] = {
+- [ALC883_3ST_2ch_DIG] = "3stack-dig",
++static const char *alc882_models[ALC882_MODEL_LAST] = {
++ [ALC882_3ST_DIG] = "3stack-dig",
++ [ALC882_6ST_DIG] = "6stack-dig",
++ [ALC882_ARIMA] = "arima",
++ [ALC882_W2JC] = "w2jc",
++ [ALC882_TARGA] = "targa",
++ [ALC882_ASUS_A7J] = "asus-a7j",
++ [ALC882_ASUS_A7M] = "asus-a7m",
++ [ALC885_MACPRO] = "macpro",
++ [ALC885_MB5] = "mb5",
++ [ALC885_MBP3] = "mbp3",
++ [ALC885_IMAC24] = "imac24",
++ [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
+ [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
+ [ALC883_3ST_6ch] = "3stack-6ch",
+- [ALC883_6ST_DIG] = "6stack-dig",
++ [ALC883_6ST_DIG] = "alc883-6stack-dig",
+ [ALC883_TARGA_DIG] = "targa-dig",
+ [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
+ [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
+@@ -9068,11 +8342,12 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
+ [ALC1200_ASUS_P5Q] = "asus-p5q",
+ [ALC889A_MB31] = "mb31",
+ [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
+- [ALC883_AUTO] = "auto",
++ [ALC882_AUTO] = "auto",
+ };
+
+-static struct snd_pci_quirk alc883_cfg_tbl[] = {
+- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
++static struct snd_pci_quirk alc882_cfg_tbl[] = {
++ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
++
+ SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
+@@ -9087,8 +8362,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
+ ALC888_ACER_ASPIRE_8930G),
+ SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+ ALC888_ACER_ASPIRE_8930G),
+- SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
+- SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
++ SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
++ SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
+ SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+ ALC888_ACER_ASPIRE_6530G),
+ SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+@@ -9097,30 +8372,44 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
+ * model=auto should work fine now
+ */
+ /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
++
+ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
++
+ SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
++
++ SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
++ SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
++ SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+ SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
++ SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
++ SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
++ SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
+ SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
++
++ SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
+ SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
+- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
++ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
+ SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
+ SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
+ SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+- SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
++ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
++
+ SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
++ SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
+ SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
++ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
+@@ -9142,11 +8431,13 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
++
+ SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
+ SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
+ SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
++ /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
+ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+ SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
+ ALC883_FUJITSU_PI2515),
+@@ -9161,24 +8452,175 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
+ SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
++
+ SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
+ SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
+- SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
+- {}
+-};
+
+-static hda_nid_t alc883_slave_dig_outs[] = {
+- ALC1200_DIGOUT_NID, 0,
++ {}
+ };
+
+-static hda_nid_t alc1200_slave_dig_outs[] = {
+- ALC883_DIGOUT_NID, 0,
++/* codec SSID table for Intel Mac */
++static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
++ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
++ SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
++ SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
++ SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
++ SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
++ SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
++ SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
++ /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently
++ * no perfect solution yet
++ */
++ SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
++ {} /* terminator */
+ };
+
+-static struct alc_config_preset alc883_presets[] = {
++static struct alc_config_preset alc882_presets[] = {
++ [ALC882_3ST_DIG] = {
++ .mixers = { alc882_base_mixer },
++ .init_verbs = { alc882_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
++ .channel_mode = alc882_ch_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_6ST_DIG] = {
++ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
++ .channel_mode = alc882_sixstack_modes,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_ARIMA] = {
++ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
++ .channel_mode = alc882_sixstack_modes,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_W2JC] = {
++ .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
++ alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
++ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ },
++ [ALC885_MBP3] = {
++ .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc885_mbp3_init_verbs,
++ alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .channel_mode = alc885_mbp_6ch_modes,
++ .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
++ .input_mux = &alc882_capture_source,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .unsol_event = alc_automute_amp_unsol_event,
++ .init_hook = alc885_mbp3_init_hook,
++ },
++ [ALC885_MB5] = {
++ .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc885_mb5_init_verbs,
++ alc880_gpio1_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .channel_mode = alc885_mb5_6ch_modes,
++ .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
++ .input_mux = &mb5_capture_source,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ },
++ [ALC885_MACPRO] = {
++ .mixers = { alc882_macpro_mixer },
++ .init_verbs = { alc882_macpro_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
++ .channel_mode = alc882_ch_modes,
++ .input_mux = &alc882_capture_source,
++ .init_hook = alc885_macpro_init_hook,
++ },
++ [ALC885_IMAC24] = {
++ .mixers = { alc885_imac24_mixer },
++ .init_verbs = { alc885_imac24_init_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .dig_in_nid = ALC882_DIGIN_NID,
++ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
++ .channel_mode = alc882_ch_modes,
++ .input_mux = &alc882_capture_source,
++ .unsol_event = alc_automute_amp_unsol_event,
++ .init_hook = alc885_imac24_init_hook,
++ },
++ [ALC882_TARGA] = {
++ .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
++ .adc_nids = alc882_adc_nids,
++ .capsrc_nids = alc882_capsrc_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
++ .channel_mode = alc882_3ST_6ch_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ .unsol_event = alc882_targa_unsol_event,
++ .init_hook = alc882_targa_init_hook,
++ },
++ [ALC882_ASUS_A7J] = {
++ .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
++ .adc_nids = alc882_adc_nids,
++ .capsrc_nids = alc882_capsrc_nids,
++ .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
++ .channel_mode = alc882_3ST_6ch_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ },
++ [ALC882_ASUS_A7M] = {
++ .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
++ .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
++ alc880_gpio1_init_verbs,
++ alc882_asus_a7m_verbs },
++ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
++ .dac_nids = alc882_dac_nids,
++ .dig_out_nid = ALC882_DIGOUT_NID,
++ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
++ .channel_mode = alc880_threestack_modes,
++ .need_dac_fix = 1,
++ .input_mux = &alc882_capture_source,
++ },
+ [ALC883_3ST_2ch_DIG] = {
+ .mixers = { alc883_3ST_2ch_mixer },
+ .init_verbs = { alc883_init_verbs },
+@@ -9613,9 +9055,32 @@ static struct alc_config_preset alc883_presets[] = {
+
+
+ /*
++ * Pin config fixes
++ */
++enum {
++ PINFIX_ABIT_AW9D_MAX
++};
++
++static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
++ { 0x15, 0x01080104 }, /* side */
++ { 0x16, 0x01011012 }, /* rear */
++ { 0x17, 0x01016011 }, /* clfe */
++ { }
++};
++
++static const struct alc_pincfg *alc882_pin_fixes[] = {
++ [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
++};
++
++static struct snd_pci_quirk alc882_pinfix_tbl[] = {
++ SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
++ {}
++};
++
++/*
+ * BIOS auto configuration
+ */
+-static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
++static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type,
+ int dac_idx)
+ {
+@@ -9632,7 +9097,7 @@ static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
+
+ }
+
+-static void alc883_auto_init_multi_out(struct hda_codec *codec)
++