Merge tag 'asoc-v5.0' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Mon, 22 Oct 2018 21:26:37 +0000 (23:26 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 22 Oct 2018 21:26:37 +0000 (23:26 +0200)
ASoC: Updates for v5.0/v4.20

As ever there's a lot of small and driver specific changes going on
here, but we do also have some relatively large changes in the core
thanks to the hard work of Charles and Morimoto-san:

 - More component transitions from Morimoto-san, I think we're about
   finished with this.  Thanks for all the hard work!
 - Morimoto-san also added a bunch of for_each_foo macros
 - A bunch of cleanups and fixes for DAPM from Charles.
 - MCLK support for several different devices, including CS42L51, STM32
   SAI, and MAX98373.
 - Support for Allwinner A64 CODEC analog, Intel boards with DA7219 and
   MAX98927, Meson AXG PDM inputs, Nuvoton NAU8822, Renesas R8A7744 and
   TI PCM3060.

57 files changed:
Documentation/sound/hd-audio/models.rst
Documentation/sound/kernel-api/writing-an-alsa-driver.rst
include/sound/memalloc.h
include/sound/rawmidi.h
include/uapi/sound/asound.h
sound/aoa/soundbus/i2sbus/core.c
sound/core/memalloc.c
sound/core/oss/pcm_plugin.c
sound/core/pcm_lib.c
sound/core/rawmidi.c
sound/core/seq/oss/seq_oss_timer.c
sound/core/seq/seq_system.c
sound/core/seq/seq_virmidi.c
sound/core/sgbuf.c
sound/firewire/Kconfig
sound/firewire/amdtp-stream.c
sound/firewire/bebob/bebob.c
sound/firewire/bebob/bebob_maudio.c
sound/firewire/dice/dice.c
sound/firewire/digi00x/digi00x.c
sound/firewire/fireface/ff.c
sound/firewire/fireworks/fireworks.c
sound/firewire/isight.c
sound/firewire/motu/motu.c
sound/firewire/oxfw/oxfw-scs1x.c
sound/firewire/oxfw/oxfw-spkr.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/firewire/tascam/tascam.c
sound/hda/ext/hdac_ext_controller.c
sound/i2c/cs8427.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/sb8_main.c
sound/mips/hal2.c
sound/pci/asihpi/hpios.c
sound/pci/atiixp.c
sound/pci/au88x0/au88x0_core.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/emu10k1/emupcm.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_tegra.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/rme32.c
sound/pci/rme9652/hdspm.c
sound/usb/caiaq/device.c
sound/usb/midi.c
sound/usb/mixer_quirks.c
sound/usb/quirks-table.h
sound/x86/intel_hdmi_audio.c
sound/xen/xen_snd_front_alsa.c

index e06238131f77e027980df2bc710644c2545f8570..368a07a165f5a7d4a1c5e47213b9d7dd61516be6 100644 (file)
@@ -309,6 +309,8 @@ asus-nx50
     ASUS Nx50 fixups
 asus-nx51
     ASUS Nx51 fixups
+asus-g751
+    ASUS G751 fixups
 alc891-headset
     Headset mode support on ALC891
 alc891-headset-multi
index a0b268466cb1db1653a005de4d46cb8ebe934389..b37234afdfa1cdf9f6966480e859dd501cf3fc3e 100644 (file)
@@ -3,8 +3,6 @@ Writing an ALSA Driver
 ======================
 
 :Author: Takashi Iwai <tiwai@suse.de>
-:Date:   Oct 15, 2007
-:Edition: 0.3.7
 
 Preface
 =======
@@ -21,11 +19,6 @@ explain the general topic of linux kernel coding and doesn't cover
 low-level driver implementation details. It only describes the standard
 way to write a PCI sound driver on ALSA.
 
-If you are already familiar with the older ALSA ver.0.5.x API, you can
-check the drivers such as ``sound/pci/es1938.c`` or
-``sound/pci/maestro3.c`` which have also almost the same code-base in
-the ALSA 0.5.x tree, so you can compare the differences.
-
 This document is still a draft version. Any feedback and corrections,
 please!!
 
@@ -35,24 +28,7 @@ File Tree Structure
 General
 -------
 
-The ALSA drivers are provided in two ways.
-
-One is the trees provided as a tarball or via cvs from the ALSA's ftp
-site, and another is the 2.6 (or later) Linux kernel tree. To
-synchronize both, the ALSA driver tree is split into two different
-trees: alsa-kernel and alsa-driver. The former contains purely the
-source code for the Linux 2.6 (or later) tree. This tree is designed
-only for compilation on 2.6 or later environment. The latter,
-alsa-driver, contains many subtle files for compiling ALSA drivers
-outside of the Linux kernel tree, wrapper functions for older 2.2 and
-2.4 kernels, to adapt the latest kernel API, and additional drivers
-which are still in development or in tests. The drivers in alsa-driver
-tree will be moved to alsa-kernel (and eventually to the 2.6 kernel
-tree) when they are finished and confirmed to work fine.
-
-The file tree structure of ALSA driver is depicted below. Both
-alsa-kernel and alsa-driver have almost the same file structure, except
-for “core” directory. It's named as “acore” in alsa-driver tree.
+The file tree structure of ALSA driver is depicted below.
 
 ::
 
@@ -61,14 +37,11 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
                             /oss
                             /seq
                                     /oss
-                                    /instr
-                    /ioctl32
                     /include
                     /drivers
                             /mpu401
                             /opl3
                     /i2c
-                            /l3
                     /synth
                             /emux
                     /pci
@@ -80,6 +53,7 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
                     /sparc
                     /usb
                     /pcmcia /(cards)
+                    /soc
                     /oss
 
 
@@ -99,13 +73,6 @@ directory. The rawmidi OSS emulation is included in the ALSA rawmidi
 code since it's quite small. The sequencer code is stored in
 ``core/seq/oss`` directory (see `below <#core-seq-oss>`__).
 
-core/ioctl32
-~~~~~~~~~~~~
-
-This directory contains the 32bit-ioctl wrappers for 64bit architectures
-such like x86-64, ppc64 and sparc64. For 32bit and alpha architectures,
-these are not compiled.
-
 core/seq
 ~~~~~~~~
 
@@ -119,11 +86,6 @@ core/seq/oss
 
 This contains the OSS sequencer emulation codes.
 
-core/seq/instr
-~~~~~~~~~~~~~~
-
-This directory contains the modules for the sequencer instrument layer.
-
 include directory
 -----------------
 
@@ -161,11 +123,6 @@ Although there is a standard i2c layer on Linux, ALSA has its own i2c
 code for some cards, because the soundcard needs only a simple operation
 and the standard i2c API is too complicated for such a purpose.
 
-i2c/l3
-~~~~~~
-
-This is a sub-directory for ARM L3 i2c.
-
 synth directory
 ---------------
 
@@ -209,11 +166,19 @@ The PCMCIA, especially PCCard drivers will go here. CardBus drivers will
 be in the pci directory, because their API is identical to that of
 standard PCI cards.
 
+soc directory
+-------------
+
+This directory contains the codes for ASoC (ALSA System on Chip)
+layer including ASoC core, codec and machine drivers.
+
 oss directory
 -------------
 
-The OSS/Lite source files are stored here in Linux 2.6 (or later) tree.
-In the ALSA driver tarball, this directory is empty, of course :)
+Here contains OSS/Lite codes.
+All codes have been deprecated except for dmasound on m68k as of
+writing this.
+
 
 Basic Flow for PCI Drivers
 ==========================
@@ -352,10 +317,8 @@ to details explained in the following section.
 
               /* (3) */
               err = snd_mychip_create(card, pci, &chip);
-              if (err < 0) {
-                      snd_card_free(card);
-                      return err;
-              }
+              if (err < 0)
+                      goto error;
 
               /* (4) */
               strcpy(card->driver, "My Chip");
@@ -368,22 +331,23 @@ to details explained in the following section.
 
               /* (6) */
               err = snd_card_register(card);
-              if (err < 0) {
-                      snd_card_free(card);
-                      return err;
-              }
+              if (err < 0)
+                      goto error;
 
               /* (7) */
               pci_set_drvdata(pci, card);
               dev++;
               return 0;
+
+      error:
+              snd_card_free(card);
+             return err;
       }
 
       /* destructor -- see the "Destructor" sub-section */
       static void snd_mychip_remove(struct pci_dev *pci)
       {
               snd_card_free(pci_get_drvdata(pci));
-              pci_set_drvdata(pci, NULL);
       }
 
 
@@ -445,14 +409,26 @@ In this part, the PCI resources are allocated.
   struct mychip *chip;
   ....
   err = snd_mychip_create(card, pci, &chip);
-  if (err < 0) {
-          snd_card_free(card);
-          return err;
-  }
+  if (err < 0)
+          goto error;
 
 The details will be explained in the section `PCI Resource
 Management`_.
 
+When something goes wrong, the probe function needs to deal with the
+error.  In this example, we have a single error handling path placed
+at the end of the function.
+
+::
+
+  error:
+          snd_card_free(card);
+         return err;
+
+Since each component can be properly freed, the single
+:c:func:`snd_card_free()` call should suffice in most cases.
+
+
 4) Set the driver ID and name strings.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -486,10 +462,8 @@ too.
 ::
 
   err = snd_card_register(card);
-  if (err < 0) {
-          snd_card_free(card);
-          return err;
-  }
+  if (err < 0)
+          goto error;
 
 Will be explained in the section `Management of Cards and
 Components`_, too.
@@ -513,14 +487,13 @@ The destructor, remove callback, simply releases the card instance. Then
 the ALSA middle layer will release all the attached components
 automatically.
 
-It would be typically like the following:
+It would be typically just :c:func:`calling snd_card_free()`:
 
 ::
 
   static void snd_mychip_remove(struct pci_dev *pci)
   {
           snd_card_free(pci_get_drvdata(pci));
-          pci_set_drvdata(pci, NULL);
   }
 
 
@@ -546,7 +519,7 @@ in the source file. If the code is split into several files, the files
 without module options don't need them.
 
 In addition to these headers, you'll need ``<linux/interrupt.h>`` for
-interrupt handling, and ``<asm/io.h>`` for I/O access. If you use the
+interrupt handling, and ``<linux/io.h>`` for I/O access. If you use the
 :c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need
 to include ``<linux/delay.h>`` too.
 
@@ -720,6 +693,13 @@ function, which will call the real destructor.
 
 where :c:func:`snd_mychip_free()` is the real destructor.
 
+The demerit of this method is the obviously more amount of codes.
+The merit is, however, you can trigger the own callback at registering
+and disconnecting the card via setting in snd_device_ops.
+About the registering and disconnecting the card, see the subsections
+below.
+
+
 Registration and Release
 ------------------------
 
@@ -905,10 +885,8 @@ Resource Allocation
 -------------------
 
 The allocation of I/O ports and irqs is done via standard kernel
-functions. Unlike ALSA ver.0.5.x., there are no helpers for that. And
-these resources must be released in the destructor function (see below).
-Also, on ALSA 0.9.x, you don't need to allocate (pseudo-)DMA for PCI
-like in ALSA 0.5.x.
+functions.  These resources must be released in the destructor
+function (see below).
 
 Now assume that the PCI device has an I/O port with 8 bytes and an
 interrupt. Then :c:type:`struct mychip <mychip>` will have the
@@ -1064,7 +1042,8 @@ and the allocation would be like below:
 
 ::
 
-  if ((err = pci_request_regions(pci, "My Chip")) < 0) {
+  err = pci_request_regions(pci, "My Chip");
+  if (err < 0) {
           kfree(chip);
           return err;
   }
@@ -1086,6 +1065,21 @@ and the corresponding destructor would be:
           ....
   }
 
+Of course, a modern way with :c:func:`pci_iomap()` will make things a
+bit easier, too.
+
+::
+
+  err = pci_request_regions(pci, "My Chip");
+  if (err < 0) {
+          kfree(chip);
+          return err;
+  }
+  chip->iobase_virt = pci_iomap(pci, 0, 0);
+
+which is paired with :c:func:`pci_iounmap()` at destructor.
+
+
 PCI Entries
 -----------
 
@@ -1154,13 +1148,6 @@ And at last, the module entries:
 Note that these module entries are tagged with ``__init`` and ``__exit``
 prefixes.
 
-Oh, one thing was forgotten. If you have no exported symbols, you need
-to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels).
-
-::
-
-  EXPORT_NO_SYMBOLS;
-
 That's all!
 
 PCM Interface
@@ -2113,6 +2100,16 @@ non-contiguous buffers. The mmap calls this callback to get the page
 address. Some examples will be explained in the later section `Buffer
 and Memory Management`_, too.
 
+mmap calllback
+~~~~~~~~~~~~~~
+
+This is another optional callback for controlling mmap behavior.
+Once when defined, PCM core calls this callback when a page is
+memory-mapped instead of dealing via the standard helper.
+If you need special handling (due to some architecture or
+device-specific issues), implement everything here as you like.
+
+
 PCM Interrupt Handler
 ---------------------
 
@@ -2370,6 +2367,27 @@ to define the inverse rule:
                       hw_rule_format_by_channels, NULL,
                       SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
+One typical usage of the hw constraints is to align the buffer size
+with the period size.  As default, ALSA PCM core doesn't enforce the
+buffer size to be aligned with the period size.  For example, it'd be
+possible to have a combination like 256 period bytes with 999 buffer
+bytes.
+
+Many device chips, however, require the buffer to be a multiple of
+periods.  In such a case, call
+:c:func:`snd_pcm_hw_constraint_integer()` for
+``SNDRV_PCM_HW_PARAM_PERIODS``.
+
+::
+
+  snd_pcm_hw_constraint_integer(substream->runtime,
+                                SNDRV_PCM_HW_PARAM_PERIODS);
+
+This assures that the number of periods is integer, hence the buffer
+size is aligned with the period size.
+
+The hw constraint is a very much powerful mechanism to define the
+preferred PCM configuration, and there are relevant helpers.
 I won't give more details here, rather I would like to say, “Luke, use
 the source.”
 
@@ -3712,7 +3730,14 @@ example, for an intermediate buffer. Since the allocated pages are not
 contiguous, you need to set the ``page`` callback to obtain the physical
 address at every offset.
 
-The implementation of ``page`` callback would be like this:
+The easiest way to achieve it would be to use
+:c:func:`snd_pcm_lib_alloc_vmalloc_buffer()` for allocating the buffer
+via :c:func:`vmalloc()`, and set :c:func:`snd_pcm_sgbuf_ops_page()` to
+the ``page`` callback.  At release, you need to call
+:c:func:`snd_pcm_lib_free_vmalloc_buffer()`.
+
+If you want to implementation the ``page`` manually, it would be like
+this:
 
 ::
 
@@ -3848,7 +3873,9 @@ Power Management
 
 If the chip is supposed to work with suspend/resume functions, you need
 to add power-management code to the driver. The additional code for
-power-management should be ifdef-ed with ``CONFIG_PM``.
+power-management should be ifdef-ed with ``CONFIG_PM``, or annotated
+with __maybe_unused attribute; otherwise the compiler will complain
+you.
 
 If the driver *fully* supports suspend/resume that is, the device can be
 properly resumed to its state when suspend was called, you can set the
@@ -3879,18 +3906,16 @@ the case of PCI drivers, the callbacks look like below:
 
 ::
 
-  #ifdef CONFIG_PM
-  static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
+  static int __maybe_unused snd_my_suspend(struct device *dev)
   {
           .... /* do things for suspend */
           return 0;
   }
-  static int snd_my_resume(struct pci_dev *pci)
+  static int __maybe_unused snd_my_resume(struct device *dev)
   {
           .... /* do things for suspend */
           return 0;
   }
-  #endif
 
 The scheme of the real suspend job is as follows.
 
@@ -3909,18 +3934,14 @@ The scheme of the real suspend job is as follows.
 
 6. Stop the hardware if necessary.
 
-7. Disable the PCI device by calling
-   :c:func:`pci_disable_device()`. Then, call
-   :c:func:`pci_save_state()` at last.
-
 A typical code would be like:
 
 ::
 
-  static int mychip_suspend(struct pci_dev *pci, pm_message_t state)
+  static int __maybe_unused mychip_suspend(struct device *dev)
   {
           /* (1) */
-          struct snd_card *card = pci_get_drvdata(pci);
+          struct snd_card *card = dev_get_drvdata(dev);
           struct mychip *chip = card->private_data;
           /* (2) */
           snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
@@ -3932,9 +3953,6 @@ A typical code would be like:
           snd_mychip_save_registers(chip);
           /* (6) */
           snd_mychip_stop_hardware(chip);
-          /* (7) */
-          pci_disable_device(pci);
-          pci_save_state(pci);
           return 0;
   }
 
@@ -3943,44 +3961,35 @@ The scheme of the real resume job is as follows.
 
 1. Retrieve the card and the chip data.
 
-2. Set up PCI. First, call :c:func:`pci_restore_state()`. Then
-   enable the pci device again by calling
-   :c:func:`pci_enable_device()`. Call
-   :c:func:`pci_set_master()` if necessary, too.
+2. Re-initialize the chip.
 
-3. Re-initialize the chip.
+3. Restore the saved registers if necessary.
 
-4. Restore the saved registers if necessary.
+4. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`.
 
-5. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`.
+5. Restart the hardware (if any).
 
-6. Restart the hardware (if any).
-
-7. Call :c:func:`snd_power_change_state()` with
+6. Call :c:func:`snd_power_change_state()` with
    ``SNDRV_CTL_POWER_D0`` to notify the processes.
 
 A typical code would be like:
 
 ::
 
-  static int mychip_resume(struct pci_dev *pci)
+  static int __maybe_unused mychip_resume(struct pci_dev *pci)
   {
           /* (1) */
-          struct snd_card *card = pci_get_drvdata(pci);
+          struct snd_card *card = dev_get_drvdata(dev);
           struct mychip *chip = card->private_data;
           /* (2) */
-          pci_restore_state(pci);
-          pci_enable_device(pci);
-          pci_set_master(pci);
-          /* (3) */
           snd_mychip_reinit_chip(chip);
-          /* (4) */
+          /* (3) */
           snd_mychip_restore_registers(chip);
-          /* (5) */
+          /* (4) */
           snd_ac97_resume(chip->ac97);
-          /* (6) */
+          /* (5) */
           snd_mychip_restart_chip(chip);
-          /* (7) */
+          /* (6) */
           snd_power_change_state(card, SNDRV_CTL_POWER_D0);
           return 0;
   }
@@ -4046,15 +4055,14 @@ And next, set suspend/resume callbacks to the pci_driver.
 
 ::
 
+  static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
+
   static struct pci_driver driver = {
           .name = KBUILD_MODNAME,
           .id_table = snd_my_ids,
           .probe = snd_my_probe,
           .remove = snd_my_remove,
-  #ifdef CONFIG_PM
-          .suspend = snd_my_suspend,
-          .resume = snd_my_resume,
-  #endif
+          .driver.pm = &snd_my_pm_ops,
   };
 
 Module Parameters
@@ -4078,7 +4086,7 @@ variables, instead. ``enable`` option is not always necessary in this
 case, but it would be better to have a dummy option for compatibility.
 
 The module parameters must be declared with the standard
-``module_param()()``, ``module_param_array()()`` and
+``module_param()``, ``module_param_array()`` and
 :c:func:`MODULE_PARM_DESC()` macros.
 
 The typical coding would be like below:
@@ -4094,15 +4102,14 @@ The typical coding would be like below:
   module_param_array(enable, bool, NULL, 0444);
   MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 
-Also, don't forget to define the module description, classes, license
-and devices. Especially, the recent modprobe requires to define the
+Also, don't forget to define the module description and the license.
+Especially, the recent modprobe requires to define the
 module license as GPL, etc., otherwise the system is shown as “tainted”.
 
 ::
 
-  MODULE_DESCRIPTION("My Chip");
+  MODULE_DESCRIPTION("Sound driver for My Chip");
   MODULE_LICENSE("GPL");
-  MODULE_SUPPORTED_DEVICE("{{Vendor,My Chip Name}}");
 
 
 How To Put Your Driver Into ALSA Tree
@@ -4117,21 +4124,17 @@ a question now: how to put my own driver into the ALSA driver tree? Here
 
 Suppose that you create a new PCI driver for the card “xyz”. The card
 module name would be snd-xyz. The new driver is usually put into the
-alsa-driver tree, ``alsa-driver/pci`` directory in the case of PCI
-cards. Then the driver is evaluated, audited and tested by developers
-and users. After a certain time, the driver will go to the alsa-kernel
-tree (to the corresponding directory, such as ``alsa-kernel/pci``) and
-eventually will be integrated into the Linux 2.6 tree (the directory
-would be ``linux/sound/pci``).
+alsa-driver tree, ``sound/pci`` directory in the case of PCI
+cards.
 
 In the following sections, the driver code is supposed to be put into
-alsa-driver tree. The two cases are covered: a driver consisting of a
+Linux kernel tree. The two cases are covered: a driver consisting of a
 single source file and one consisting of several source files.
 
 Driver with A Single Source File
 --------------------------------
 
-1. Modify alsa-driver/pci/Makefile
+1. Modify sound/pci/Makefile
 
    Suppose you have a file xyz.c. Add the following two lines
 
@@ -4160,52 +4163,43 @@ Driver with A Single Source File
 
    For the details of Kconfig script, refer to the kbuild documentation.
 
-3. Run cvscompile script to re-generate the configure script and build
-   the whole stuff again.
-
 Drivers with Several Source Files
 ---------------------------------
 
 Suppose that the driver snd-xyz have several source files. They are
-located in the new subdirectory, pci/xyz.
+located in the new subdirectory, sound/pci/xyz.
 
-1. Add a new directory (``xyz``) in ``alsa-driver/pci/Makefile`` as
-   below
+1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile``
+   as below
 
 ::
 
-  obj-$(CONFIG_SND) += xyz/
+  obj-$(CONFIG_SND) += sound/pci/xyz/
 
 
-2. Under the directory ``xyz``, create a Makefile
+2. Under the directory ``sound/pci/xyz``, create a Makefile
 
 ::
 
-         ifndef SND_TOPDIR
-         SND_TOPDIR=../..
-         endif
-
-         include $(SND_TOPDIR)/toplevel.config
-         include $(SND_TOPDIR)/Makefile.conf
-
          snd-xyz-objs := xyz.o abc.o def.o
-
          obj-$(CONFIG_SND_XYZ) += snd-xyz.o
 
-         include $(SND_TOPDIR)/Rules.make
-
 3. Create the Kconfig entry
 
    This procedure is as same as in the last section.
 
-4. Run cvscompile script to re-generate the configure script and build
-   the whole stuff again.
 
 Useful Functions
 ================
 
 :c:func:`snd_printk()` and friends
----------------------------------------
+----------------------------------
+
+.. note:: This subsection describes a few helper functions for
+   decorating a bit more on the standard :c:func:`printk()` & co.
+   However, in general, the use of such helpers is no longer recommended.
+   If possible, try to stick with the standard functions like
+   :c:func:`dev_err()` or :c:func:`pr_err()`.
 
 ALSA provides a verbose version of the :c:func:`printk()` function.
 If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function
@@ -4221,13 +4215,10 @@ just like :c:func:`snd_printk()`. If the ALSA is compiled without
 the debugging flag, it's ignored.
 
 :c:func:`snd_printdd()` is compiled in only when
-``CONFIG_SND_DEBUG_VERBOSE`` is set. Please note that
-``CONFIG_SND_DEBUG_VERBOSE`` is not set as default even if you configure
-the alsa-driver with ``--with-debug=full`` option. You need to give
-explicitly ``--with-debug=detect`` option instead.
+``CONFIG_SND_DEBUG_VERBOSE`` is set.
 
 :c:func:`snd_BUG()`
-------------------------
+-------------------
 
 It shows the ``BUG?`` message and stack trace as well as
 :c:func:`snd_BUG_ON()` at the point. It's useful to show that a
@@ -4236,7 +4227,7 @@ fatal error happens there.
 When no debug flag is set, this macro is ignored.
 
 :c:func:`snd_BUG_ON()`
-----------------------------
+----------------------
 
 :c:func:`snd_BUG_ON()` macro is similar with
 :c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or
index 67561b9979150833b4b433a38a59aedc101df573..af3fa577fa066ae3aa0ed712e12d7c45eeac0b50 100644 (file)
@@ -47,10 +47,13 @@ struct snd_dma_device {
 #define SNDRV_DMA_TYPE_UNKNOWN         0       /* not defined */
 #define SNDRV_DMA_TYPE_CONTINUOUS      1       /* continuous no-DMA memory */
 #define SNDRV_DMA_TYPE_DEV             2       /* generic device continuous */
+#define SNDRV_DMA_TYPE_DEV_UC          5       /* continuous non-cahced */
 #ifdef CONFIG_SND_DMA_SGBUF
 #define SNDRV_DMA_TYPE_DEV_SG          3       /* generic device SG-buffer */
+#define SNDRV_DMA_TYPE_DEV_UC_SG       6       /* SG non-cached */
 #else
 #define SNDRV_DMA_TYPE_DEV_SG  SNDRV_DMA_TYPE_DEV /* no SG-buf support */
+#define SNDRV_DMA_TYPE_DEV_UC_SG       SNDRV_DMA_TYPE_DEV_UC
 #endif
 #ifdef CONFIG_GENERIC_ALLOCATOR
 #define SNDRV_DMA_TYPE_DEV_IRAM                4       /* generic device iram-buffer */
index 6665cb29e1a238af24b7dcb4df543c147cbad742..3b5a061132b6760c4cda087d67731b1231335900 100644 (file)
@@ -171,6 +171,7 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                              unsigned char *buffer, int count);
 int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
                               int count);
+int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
 
 /* main midi functions */
 
index ed0a120d4f084fa0cfc10b5257ea9bce0c3d3a24..404d4b9ffe7644553a1b59fba043b151d935a2e9 100644 (file)
@@ -752,7 +752,7 @@ struct snd_timer_info {
 #define SNDRV_TIMER_PSFLG_EARLY_EVENT  (1<<2)  /* write early event to the poll queue */
 
 struct snd_timer_params {
-       unsigned int flags;             /* flags - SNDRV_MIXER_PSFLG_* */
+       unsigned int flags;             /* flags - SNDRV_TIMER_PSFLG_* */
        unsigned int ticks;             /* requested resolution in ticks */
        unsigned int queue_size;        /* total size of queue (32-1024) */
        unsigned int reserved0;         /* reserved, was: failure locations */
index 000b5852210634a666b60cdc6ed2d99e6942b90a..bd7c5029fc59300ec3432d94543aa2b027f28fa8 100644 (file)
@@ -157,18 +157,19 @@ static int i2sbus_add_dev(struct macio_dev *macio,
        struct device_node *child = NULL, *sound = NULL;
        struct resource *r;
        int i, layout = 0, rlen, ok = force;
-       static const char *rnames[] = { "i2sbus: %s (control)",
-                                       "i2sbus: %s (tx)",
-                                       "i2sbus: %s (rx)" };
+       char node_name[6];
+       static const char *rnames[] = { "i2sbus: %pOFn (control)",
+                                       "i2sbus: %pOFn (tx)",
+                                       "i2sbus: %pOFn (rx)" };
        static irq_handler_t ints[] = {
                i2sbus_bus_intr,
                i2sbus_tx_intr,
                i2sbus_rx_intr
        };
 
-       if (strlen(np->name) != 5)
+       if (snprintf(node_name, sizeof(node_name), "%pOFn", np) != 5)
                return 0;
-       if (strncmp(np->name, "i2s-", 4))
+       if (strncmp(node_name, "i2s-", 4))
                return 0;
 
        dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
@@ -228,13 +229,13 @@ static int i2sbus_add_dev(struct macio_dev *macio,
        dev->sound.pcmid = -1;
        dev->macio = macio;
        dev->control = control;
-       dev->bus_number = np->name[4] - 'a';
+       dev->bus_number = node_name[4] - 'a';
        INIT_LIST_HEAD(&dev->sound.codec_list);
 
        for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
                dev->interrupts[i] = -1;
                snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
-                        rnames[i], np->name);
+                        rnames[i], np);
        }
        for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
                int irq = irq_of_parse_and_map(np, i);
index 753d5fc4b284fa66cd0f3911d4096322fd7b3bf9..59a4adc286ed77bb647788706a6ebd9323a1b640 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/genalloc.h>
+#ifdef CONFIG_X86
+#include <asm/set_memory.h>
+#endif
 #include <sound/memalloc.h>
 
 /*
@@ -82,31 +85,32 @@ EXPORT_SYMBOL(snd_free_pages);
 
 #ifdef CONFIG_HAS_DMA
 /* allocate the coherent DMA pages */
-static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
+static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size)
 {
-       int pg;
        gfp_t gfp_flags;
 
-       if (WARN_ON(!dma))
-               return NULL;
-       pg = get_order(size);
        gfp_flags = GFP_KERNEL
                | __GFP_COMP    /* compound page lets parts be mapped */
                | __GFP_NORETRY /* don't trigger OOM-killer */
                | __GFP_NOWARN; /* no stack trace print - this call is non-critical */
-       return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
+       dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
+                                       gfp_flags);
+#ifdef CONFIG_X86
+       if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
+               set_memory_wc((unsigned long)dmab->area,
+                             PAGE_ALIGN(size) >> PAGE_SHIFT);
+#endif
 }
 
 /* free the coherent DMA pages */
-static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
-                              dma_addr_t dma)
+static void snd_free_dev_pages(struct snd_dma_buffer *dmab)
 {
-       int pg;
-
-       if (ptr == NULL)
-               return;
-       pg = get_order(size);
-       dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
+#ifdef CONFIG_X86
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
+               set_memory_wb((unsigned long)dmab->area,
+                             PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
+#endif
+       dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
 }
 
 #ifdef CONFIG_GENERIC_ALLOCATOR
@@ -199,12 +203,15 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                 */
                dmab->dev.type = SNDRV_DMA_TYPE_DEV;
 #endif /* CONFIG_GENERIC_ALLOCATOR */
+               /* fall through */
        case SNDRV_DMA_TYPE_DEV:
-               dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
+       case SNDRV_DMA_TYPE_DEV_UC:
+               snd_malloc_dev_pages(dmab, size);
                break;
 #endif
 #ifdef CONFIG_SND_DMA_SGBUF
        case SNDRV_DMA_TYPE_DEV_SG:
+       case SNDRV_DMA_TYPE_DEV_UC_SG:
                snd_malloc_sgbuf_pages(device, size, dmab, NULL);
                break;
 #endif
@@ -275,11 +282,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
                break;
 #endif /* CONFIG_GENERIC_ALLOCATOR */
        case SNDRV_DMA_TYPE_DEV:
-               snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
+       case SNDRV_DMA_TYPE_DEV_UC:
+               snd_free_dev_pages(dmab);
                break;
 #endif
 #ifdef CONFIG_SND_DMA_SGBUF
        case SNDRV_DMA_TYPE_DEV_SG:
+       case SNDRV_DMA_TYPE_DEV_UC_SG:
                snd_free_sgbuf_pages(dmab);
                break;
 #endif
index 0391cb1a4f190cc399c845b388643ffd28a7a218..141c5f3a957501e0901102ce5bd519cbca73892e 100644 (file)
@@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
                while (plugin->next) {
                        if (plugin->dst_frames)
                                frames = plugin->dst_frames(plugin, frames);
-                       if (snd_BUG_ON(frames <= 0))
+                       if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
                                return -ENXIO;
                        plugin = plugin->next;
                        err = snd_pcm_plugin_alloc(plugin, frames);
@@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
                while (plugin->prev) {
                        if (plugin->src_frames)
                                frames = plugin->src_frames(plugin, frames);
-                       if (snd_BUG_ON(frames <= 0))
+                       if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
                                return -ENXIO;
                        plugin = plugin->prev;
                        err = snd_pcm_plugin_alloc(plugin, frames);
index 4e6110d778bd25c143ea325da0c823937ad019c0..40013b26f67196b23bcf94d69890b2835cde9f9d 100644 (file)
@@ -2172,18 +2172,25 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
        if (err < 0)
                goto _end_unlock;
 
+       runtime->twake = runtime->control->avail_min ? : 1;
+       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               snd_pcm_update_hw_ptr(substream);
+
        if (!is_playback &&
-           runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
-           size >= runtime->start_threshold) {
-               err = snd_pcm_start(substream);
-               if (err < 0)
+           runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
+               if (size >= runtime->start_threshold) {
+                       err = snd_pcm_start(substream);
+                       if (err < 0)
+                               goto _end_unlock;
+               } else {
+                       /* nothing to do */
+                       err = 0;
                        goto _end_unlock;
+               }
        }
 
-       runtime->twake = runtime->control->avail_min ? : 1;
-       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-               snd_pcm_update_hw_ptr(substream);
        avail = snd_pcm_avail(substream);
+
        while (size > 0) {
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t cont;
index 08d5662039e38123e349bc5352c2b674280048f3..ee601d7f092694aecd7e853845b4e3f73cd0f261 100644 (file)
@@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit);
 
+/**
+ * snd_rawmidi_proceed - Discard the all pending bytes and proceed
+ * @substream: rawmidi substream
+ *
+ * Return: the number of discarded bytes
+ */
+int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
+{
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       unsigned long flags;
+       int count = 0;
+
+       spin_lock_irqsave(&runtime->lock, flags);
+       if (runtime->avail < runtime->buffer_size) {
+               count = runtime->buffer_size - runtime->avail;
+               __snd_rawmidi_transmit_ack(substream, count);
+       }
+       spin_unlock_irqrestore(&runtime->lock, flags);
+       return count;
+}
+EXPORT_SYMBOL(snd_rawmidi_proceed);
+
 static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                                      const unsigned char __user *userbuf,
                                      const unsigned char *kernelbuf,
index ba127c22539a0ffe06e007ae5398d4e60370285b..0778d28421da438daa1097958d2000188fe46f1c 100644 (file)
@@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
                case TMR_WAIT_REL:
                        parm += rec->cur_tick;
                        rec->realtime = 0;
-                       /* fall through and continue to next */
+                       /* fall through */
                case TMR_WAIT_ABS:
                        if (parm == 0) {
                                rec->realtime = 1;
index 8ce1d0b40dce1f0821f9cf9c144fed1ed27e413d..0dc5d5a45eccdac0a84aad2d457ee2da445c3f4b 100644 (file)
@@ -123,6 +123,7 @@ int __init snd_seq_system_client_init(void)
 {
        struct snd_seq_port_callback pcallbacks;
        struct snd_seq_port_info *port;
+       int err;
 
        port = kzalloc(sizeof(*port), GFP_KERNEL);
        if (!port)
@@ -134,6 +135,10 @@ int __init snd_seq_system_client_init(void)
 
        /* register client */
        sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
+       if (sysclient < 0) {
+               kfree(port);
+               return sysclient;
+       }
 
        /* register timer */
        strcpy(port->name, "Timer");
@@ -144,7 +149,10 @@ int __init snd_seq_system_client_init(void)
        port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
        port->addr.client = sysclient;
        port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
-       snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
+       err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
+                                       port);
+       if (err < 0)
+               goto error_port;
 
        /* register announcement port */
        strcpy(port->name, "Announce");
@@ -154,16 +162,24 @@ int __init snd_seq_system_client_init(void)
        port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
        port->addr.client = sysclient;
        port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
-       snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
+       err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
+                                       port);
+       if (err < 0)
+               goto error_port;
        announce_port = port->addr.port;
 
        kfree(port);
        return 0;
+
+ error_port:
+       snd_seq_system_client_done();
+       kfree(port);
+       return err;
 }
 
 
 /* unregister our internal client */
-void __exit snd_seq_system_client_done(void)
+void snd_seq_system_client_done(void)
 {
        int oldsysclient = sysclient;
 
index cb988efd1ed0d666494f76f23797fbde6a7e833e..e5a40795914a66acd9ca1d6bb1c2aedaafb4321d 100644 (file)
@@ -149,9 +149,7 @@ static void snd_vmidi_output_work(struct work_struct *work)
        /* discard the outputs in dispatch mode unless subscribed */
        if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
            !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
-               char buf[32];
-               while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0)
-                       ; /* ignored */
+               snd_rawmidi_proceed(substream);
                return;
        }
 
index 84fffabdd129ded8373f20ea06304d8ac7473028..c1cfaa01a5cb8161989c80ec42a85c2cab7e1a07 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
+#include <asm/pgtable.h>
 #include <sound/memalloc.h>
 
 
@@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
        dmab->area = NULL;
 
        tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG)
+               tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC;
        tmpb.dev.dev = sgbuf->dev;
        for (i = 0; i < sgbuf->pages; i++) {
                if (!(sgbuf->table[i].addr & ~PAGE_MASK))
@@ -72,12 +75,20 @@ void *snd_malloc_sgbuf_pages(struct device *device,
        struct snd_dma_buffer tmpb;
        struct snd_sg_page *table;
        struct page **pgtable;
+       int type = SNDRV_DMA_TYPE_DEV;
+       pgprot_t prot = PAGE_KERNEL;
 
        dmab->area = NULL;
        dmab->addr = 0;
        dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
        if (! sgbuf)
                return NULL;
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
+               type = SNDRV_DMA_TYPE_DEV_UC;
+#ifdef pgprot_noncached
+               prot = pgprot_noncached(PAGE_KERNEL);
+#endif
+       }
        sgbuf->dev = device;
        pages = snd_sgbuf_aligned_pages(size);
        sgbuf->tblsize = sgbuf_align_table(pages);
@@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
                if (chunk > maxpages)
                        chunk = maxpages;
                chunk <<= PAGE_SHIFT;
-               if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
+               if (snd_dma_alloc_pages_fallback(type, device,
                                                 chunk, &tmpb) < 0) {
                        if (!sgbuf->pages)
                                goto _failed;
@@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
        }
 
        sgbuf->size = size;
-       dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
+       dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
        if (! dmab->area)
                goto _failed;
        if (res_size)
index 529d9f405fa9f04e5c241a35c0488b98d6e0c993..8a146b0392761402ffeb79e869fe985abb172cff 100644 (file)
@@ -147,7 +147,9 @@ config SND_FIREWIRE_MOTU
        help
         Say Y here to enable support for FireWire devices which MOTU produced:
          * 828mk2
+         * Traveler
          * 828mk3
+         * Audio Express
 
         To compile this driver as a module, choose M here: the module
         will be called snd-firewire-motu.
index cb9acfe60f6a350951d3a464969dacb3797ec64a..fcd965f1d69e820de7824de01365d95e73eb44a3 100644 (file)
@@ -140,6 +140,59 @@ const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = {
 };
 EXPORT_SYMBOL(amdtp_rate_table);
 
+static int apply_constraint_to_size(struct snd_pcm_hw_params *params,
+                                   struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *s = hw_param_interval(params, rule->var);
+       const struct snd_interval *r =
+               hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval t = {
+               .min = s->min, .max = s->max, .integer = 1,
+       };
+       int i;
+
+       for (i = 0; i < CIP_SFC_COUNT; ++i) {
+               unsigned int rate = amdtp_rate_table[i];
+               unsigned int step = amdtp_syt_intervals[i];
+
+               if (!snd_interval_test(r, rate))
+                       continue;
+
+               t.min = roundup(t.min, step);
+               t.max = rounddown(t.max, step);
+       }
+
+       if (snd_interval_checkempty(&t))
+               return -EINVAL;
+
+       return snd_interval_refine(s, &t);
+}
+
+static int apply_constraint_to_rate(struct snd_pcm_hw_params *params,
+                                   struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *r =
+                       hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       const struct snd_interval *s = hw_param_interval_c(params, rule->deps[0]);
+       struct snd_interval t = {
+               .min = UINT_MAX, .max = 0, .integer = 1,
+       };
+       int i;
+
+       for (i = 0; i < CIP_SFC_COUNT; ++i) {
+               unsigned int step = amdtp_syt_intervals[i];
+               unsigned int rate = amdtp_rate_table[i];
+
+               if (s->min % step || s->max % step)
+                       continue;
+
+               t.min = min(t.min, rate);
+               t.max = max(t.max, rate);
+       }
+
+       return snd_interval_refine(r, &t);
+}
+
 /**
  * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
  * @s:         the AMDTP stream, which must be initialized.
@@ -194,16 +247,27 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
         * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
         * depending on its sampling rate. For accurate period interrupt, it's
         * preferrable to align period/buffer sizes to current SYT_INTERVAL.
-        *
-        * TODO: These constraints can be improved with proper rules.
-        * Currently apply LCM of SYT_INTERVALs.
         */
-       err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
+       err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                 apply_constraint_to_size, NULL,
+                                 SNDRV_PCM_HW_PARAM_RATE, -1);
+       if (err < 0)
+               goto end;
+       err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                 apply_constraint_to_rate, NULL,
+                                 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+       if (err < 0)
+               goto end;
+       err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                 apply_constraint_to_size, NULL,
+                                 SNDRV_PCM_HW_PARAM_RATE, -1);
+       if (err < 0)
+               goto end;
+       err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                 apply_constraint_to_rate, NULL,
+                                 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
        if (err < 0)
                goto end;
-       err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
 end:
        return err;
 }
index 93676354f87f4e5c23d897c3d8cee568b6f69ac6..672d1348845473b67b9017d4d3270786b9986068 100644 (file)
@@ -126,23 +126,6 @@ end:
        return err;
 }
 
-static void bebob_free(struct snd_bebob *bebob)
-{
-       snd_bebob_stream_destroy_duplex(bebob);
-       fw_unit_put(bebob->unit);
-
-       kfree(bebob->maudio_special_quirk);
-
-       mutex_destroy(&bebob->mutex);
-       kfree(bebob);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
 static void
 bebob_card_free(struct snd_card *card)
 {
@@ -152,7 +135,7 @@ bebob_card_free(struct snd_card *card)
        clear_bit(bebob->card_index, devices_used);
        mutex_unlock(&devices_mutex);
 
-       bebob_free(card->private_data);
+       snd_bebob_stream_destroy_duplex(bebob);
 }
 
 static const struct snd_bebob_spec *
@@ -192,7 +175,6 @@ do_registration(struct work_struct *work)
                return;
 
        mutex_lock(&devices_mutex);
-
        for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
                if (!test_bit(card_index, devices_used) && enable[card_index])
                        break;
@@ -208,6 +190,11 @@ do_registration(struct work_struct *work)
                mutex_unlock(&devices_mutex);
                return;
        }
+       set_bit(card_index, devices_used);
+       mutex_unlock(&devices_mutex);
+
+       bebob->card->private_free = bebob_card_free;
+       bebob->card->private_data = bebob;
 
        err = name_device(bebob);
        if (err < 0)
@@ -248,23 +235,10 @@ do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       set_bit(card_index, devices_used);
-       mutex_unlock(&devices_mutex);
-
-       /*
-        * After registered, bebob instance can be released corresponding to
-        * releasing the sound card instance.
-        */
-       bebob->card->private_free = bebob_card_free;
-       bebob->card->private_data = bebob;
        bebob->registered = true;
 
        return;
 error:
-       mutex_unlock(&devices_mutex);
-       snd_bebob_stream_destroy_duplex(bebob);
-       kfree(bebob->maudio_special_quirk);
-       bebob->maudio_special_quirk = NULL;
        snd_card_free(bebob->card);
        dev_info(&bebob->unit->device,
                 "Sound card registration failed: %d\n", err);
@@ -295,15 +269,15 @@ bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
        }
 
        /* Allocate this independent of sound card instance. */
-       bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL);
-       if (bebob == NULL)
+       bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob),
+                            GFP_KERNEL);
+       if (!bebob)
                return -ENOMEM;
-
        bebob->unit = fw_unit_get(unit);
-       bebob->entry = entry;
-       bebob->spec = spec;
        dev_set_drvdata(&unit->device, bebob);
 
+       bebob->entry = entry;
+       bebob->spec = spec;
        mutex_init(&bebob->mutex);
        spin_lock_init(&bebob->lock);
        init_waitqueue_head(&bebob->hwdep_wait);
@@ -379,12 +353,12 @@ static void bebob_remove(struct fw_unit *unit)
        cancel_delayed_work_sync(&bebob->dwork);
 
        if (bebob->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(bebob->card);
-       } else {
-               /* Don't forget this case. */
-               bebob_free(bebob);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(bebob->card);
        }
+
+       mutex_destroy(&bebob->mutex);
+       fw_unit_put(bebob->unit);
 }
 
 static const struct snd_bebob_rate_spec normal_rate_spec = {
index c266997ad299d93c71632bebba2c83db6cf9bc09..51152ca4af57ba9c46eb5d0371852d94007a7650 100644 (file)
@@ -261,8 +261,9 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
        struct special_params *params;
        int err;
 
-       params = kzalloc(sizeof(struct special_params), GFP_KERNEL);
-       if (params == NULL)
+       params = devm_kzalloc(&bebob->card->card_dev,
+                             sizeof(struct special_params), GFP_KERNEL);
+       if (!params)
                return -ENOMEM;
 
        mutex_lock(&bebob->mutex);
index 774eb2205668cac941e9c44319f9a32f186ac2c5..0f6dbcffe711d62cfcba5fa7e57194f7f1a70e71 100644 (file)
@@ -122,25 +122,12 @@ static void dice_card_strings(struct snd_dice *dice)
        strcpy(card->mixername, "DICE");
 }
 
-static void dice_free(struct snd_dice *dice)
+static void dice_card_free(struct snd_card *card)
 {
+       struct snd_dice *dice = card->private_data;
+
        snd_dice_stream_destroy_duplex(dice);
        snd_dice_transaction_destroy(dice);
-       fw_unit_put(dice->unit);
-
-       mutex_destroy(&dice->mutex);
-       kfree(dice);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
-static void dice_card_free(struct snd_card *card)
-{
-       dice_free(card->private_data);
 }
 
 static void do_registration(struct work_struct *work)
@@ -155,6 +142,8 @@ static void do_registration(struct work_struct *work)
                           &dice->card);
        if (err < 0)
                return;
+       dice->card->private_free = dice_card_free;
+       dice->card->private_data = dice;
 
        err = snd_dice_transaction_init(dice);
        if (err < 0)
@@ -192,19 +181,10 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       /*
-        * After registered, dice instance can be released corresponding to
-        * releasing the sound card instance.
-        */
-       dice->card->private_free = dice_card_free;
-       dice->card->private_data = dice;
        dice->registered = true;
 
        return;
 error:
-       snd_dice_stream_destroy_duplex(dice);
-       snd_dice_transaction_destroy(dice);
-       snd_dice_stream_destroy_duplex(dice);
        snd_card_free(dice->card);
        dev_info(&dice->unit->device,
                 "Sound card registration failed: %d\n", err);
@@ -223,10 +203,9 @@ static int dice_probe(struct fw_unit *unit,
        }
 
        /* Allocate this independent of sound card instance. */
-       dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
-       if (dice == NULL)
+       dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL);
+       if (!dice)
                return -ENOMEM;
-
        dice->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, dice);
 
@@ -263,10 +242,10 @@ static void dice_remove(struct fw_unit *unit)
        if (dice->registered) {
                /* No need to wait for releasing card object in this context. */
                snd_card_free_when_closed(dice->card);
-       } else {
-               /* Don't forget this case. */
-               dice_free(dice);
        }
+
+       mutex_destroy(&dice->mutex);
+       fw_unit_put(dice->unit);
 }
 
 static void dice_bus_reset(struct fw_unit *unit)
index ef689997d6a5b55f3d273ab4f8125fc87796cdd9..6c6ea149ef6b491053324db7d2fa7d7176b2be6f 100644 (file)
@@ -41,20 +41,12 @@ static int name_card(struct snd_dg00x *dg00x)
        return 0;
 }
 
-static void dg00x_free(struct snd_dg00x *dg00x)
+static void dg00x_card_free(struct snd_card *card)
 {
+       struct snd_dg00x *dg00x = card->private_data;
+
        snd_dg00x_stream_destroy_duplex(dg00x);
        snd_dg00x_transaction_unregister(dg00x);
-
-       fw_unit_put(dg00x->unit);
-
-       mutex_destroy(&dg00x->mutex);
-       kfree(dg00x);
-}
-
-static void dg00x_card_free(struct snd_card *card)
-{
-       dg00x_free(card->private_data);
 }
 
 static void do_registration(struct work_struct *work)
@@ -70,6 +62,8 @@ static void do_registration(struct work_struct *work)
                           &dg00x->card);
        if (err < 0)
                return;
+       dg00x->card->private_free = dg00x_card_free;
+       dg00x->card->private_data = dg00x;
 
        err = name_card(dg00x);
        if (err < 0)
@@ -101,14 +95,10 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       dg00x->card->private_free = dg00x_card_free;
-       dg00x->card->private_data = dg00x;
        dg00x->registered = true;
 
        return;
 error:
-       snd_dg00x_transaction_unregister(dg00x);
-       snd_dg00x_stream_destroy_duplex(dg00x);
        snd_card_free(dg00x->card);
        dev_info(&dg00x->unit->device,
                 "Sound card registration failed: %d\n", err);
@@ -120,8 +110,9 @@ static int snd_dg00x_probe(struct fw_unit *unit,
        struct snd_dg00x *dg00x;
 
        /* Allocate this independent of sound card instance. */
-       dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL);
-       if (dg00x == NULL)
+       dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x),
+                            GFP_KERNEL);
+       if (!dg00x)
                return -ENOMEM;
 
        dg00x->unit = fw_unit_get(unit);
@@ -173,12 +164,12 @@ static void snd_dg00x_remove(struct fw_unit *unit)
        cancel_delayed_work_sync(&dg00x->dwork);
 
        if (dg00x->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(dg00x->card);
-       } else {
-               /* Don't forget this case. */
-               dg00x_free(dg00x);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(dg00x->card);
        }
+
+       mutex_destroy(&dg00x->mutex);
+       fw_unit_put(dg00x->unit);
 }
 
 static const struct ieee1394_device_id snd_dg00x_id_table[] = {
index 4974bc7980e9b476611d78cc79a48275259a12b9..3f61cfeace69e7249658d96f5ec4c108553a5c1d 100644 (file)
@@ -27,20 +27,12 @@ static void name_card(struct snd_ff *ff)
                 dev_name(&ff->unit->device), 100 << fw_dev->max_speed);
 }
 
-static void ff_free(struct snd_ff *ff)
+static void ff_card_free(struct snd_card *card)
 {
+       struct snd_ff *ff = card->private_data;
+
        snd_ff_stream_destroy_duplex(ff);
        snd_ff_transaction_unregister(ff);
-
-       fw_unit_put(ff->unit);
-
-       mutex_destroy(&ff->mutex);
-       kfree(ff);
-}
-
-static void ff_card_free(struct snd_card *card)
-{
-       ff_free(card->private_data);
 }
 
 static void do_registration(struct work_struct *work)
@@ -55,6 +47,8 @@ static void do_registration(struct work_struct *work)
                           &ff->card);
        if (err < 0)
                return;
+       ff->card->private_free = ff_card_free;
+       ff->card->private_data = ff;
 
        err = snd_ff_transaction_register(ff);
        if (err < 0)
@@ -84,14 +78,10 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       ff->card->private_free = ff_card_free;
-       ff->card->private_data = ff;
        ff->registered = true;
 
        return;
 error:
-       snd_ff_transaction_unregister(ff);
-       snd_ff_stream_destroy_duplex(ff);
        snd_card_free(ff->card);
        dev_info(&ff->unit->device,
                 "Sound card registration failed: %d\n", err);
@@ -102,11 +92,9 @@ static int snd_ff_probe(struct fw_unit *unit,
 {
        struct snd_ff *ff;
 
-       ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL);
-       if (ff == NULL)
+       ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL);
+       if (!ff)
                return -ENOMEM;
-
-       /* initialize myself */
        ff->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, ff);
 
@@ -149,12 +137,12 @@ static void snd_ff_remove(struct fw_unit *unit)
        cancel_work_sync(&ff->dwork.work);
 
        if (ff->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(ff->card);
-       } else {
-               /* Don't forget this case. */
-               ff_free(ff);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(ff->card);
        }
+
+       mutex_destroy(&ff->mutex);
+       fw_unit_put(ff->unit);
 }
 
 static const struct snd_ff_spec spec_ff400 = {
index f2d073365cf6365e5d3e5c841a7288a93c5b1ec5..faf0e001c4c5cc9b07599a1c42d236870b10cf96 100644 (file)
@@ -184,36 +184,17 @@ end:
        return err;
 }
 
-static void efw_free(struct snd_efw *efw)
-{
-       snd_efw_stream_destroy_duplex(efw);
-       snd_efw_transaction_remove_instance(efw);
-       fw_unit_put(efw->unit);
-
-       kfree(efw->resp_buf);
-
-       mutex_destroy(&efw->mutex);
-       kfree(efw);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
 static void
 efw_card_free(struct snd_card *card)
 {
        struct snd_efw *efw = card->private_data;
 
-       if (efw->card_index >= 0) {
-               mutex_lock(&devices_mutex);
-               clear_bit(efw->card_index, devices_used);
-               mutex_unlock(&devices_mutex);
-       }
+       mutex_lock(&devices_mutex);
+       clear_bit(efw->card_index, devices_used);
+       mutex_unlock(&devices_mutex);
 
-       efw_free(card->private_data);
+       snd_efw_stream_destroy_duplex(efw);
+       snd_efw_transaction_remove_instance(efw);
 }
 
 static void
@@ -226,9 +207,8 @@ do_registration(struct work_struct *work)
        if (efw->registered)
                return;
 
-       mutex_lock(&devices_mutex);
-
        /* check registered cards */
+       mutex_lock(&devices_mutex);
        for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
                if (!test_bit(card_index, devices_used) && enable[card_index])
                        break;
@@ -244,12 +224,18 @@ do_registration(struct work_struct *work)
                mutex_unlock(&devices_mutex);
                return;
        }
+       set_bit(card_index, devices_used);
+       mutex_unlock(&devices_mutex);
+
+       efw->card->private_free = efw_card_free;
+       efw->card->private_data = efw;
 
        /* prepare response buffer */
        snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
                                      SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
-       efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL);
-       if (efw->resp_buf == NULL) {
+       efw->resp_buf = devm_kzalloc(&efw->card->card_dev,
+                                    snd_efw_resp_buf_size, GFP_KERNEL);
+       if (!efw->resp_buf) {
                err = -ENOMEM;
                goto error;
        }
@@ -284,25 +270,11 @@ do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       set_bit(card_index, devices_used);
-       mutex_unlock(&devices_mutex);
-
-       /*
-        * After registered, efw instance can be released corresponding to
-        * releasing the sound card instance.
-        */
-       efw->card->private_free = efw_card_free;
-       efw->card->private_data = efw;
        efw->registered = true;
 
        return;
 error:
-       mutex_unlock(&devices_mutex);
-       snd_efw_transaction_remove_instance(efw);
-       snd_efw_stream_destroy_duplex(efw);
        snd_card_free(efw->card);
-       kfree(efw->resp_buf);
-       efw->resp_buf = NULL;
        dev_info(&efw->unit->device,
                 "Sound card registration failed: %d\n", err);
 }
@@ -312,10 +284,9 @@ efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
 {
        struct snd_efw *efw;
 
-       efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL);
+       efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL);
        if (efw == NULL)
                return -ENOMEM;
-
        efw->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, efw);
 
@@ -363,12 +334,12 @@ static void efw_remove(struct fw_unit *unit)
        cancel_delayed_work_sync(&efw->dwork);
 
        if (efw->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(efw->card);
-       } else {
-               /* Don't forget this case. */
-               efw_free(efw);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(efw->card);
        }
+
+       mutex_destroy(&efw->mutex);
+       fw_unit_put(efw->unit);
 }
 
 static const struct ieee1394_device_id efw_id_table[] = {
index 30957477e005e060016ed31f9d968963ccd66b33..9ebe510ea26b8961096f205564369ff420f2e6ea 100644 (file)
@@ -602,8 +602,6 @@ static void isight_card_free(struct snd_card *card)
        struct isight *isight = card->private_data;
 
        fw_iso_resources_destroy(&isight->resources);
-       fw_unit_put(isight->unit);
-       mutex_destroy(&isight->mutex);
 }
 
 static u64 get_unit_base(struct fw_unit *unit)
@@ -640,7 +638,7 @@ static int isight_probe(struct fw_unit *unit,
        if (!isight->audio_base) {
                dev_err(&unit->device, "audio unit base not found\n");
                err = -ENXIO;
-               goto err_unit;
+               goto error;
        }
        fw_iso_resources_init(&isight->resources, unit);
 
@@ -669,12 +667,12 @@ static int isight_probe(struct fw_unit *unit,
        dev_set_drvdata(&unit->device, isight);
 
        return 0;
-
-err_unit:
-       fw_unit_put(isight->unit);
-       mutex_destroy(&isight->mutex);
 error:
        snd_card_free(card);
+
+       mutex_destroy(&isight->mutex);
+       fw_unit_put(isight->unit);
+
        return err;
 }
 
@@ -703,7 +701,11 @@ static void isight_remove(struct fw_unit *unit)
        isight_stop_streaming(isight);
        mutex_unlock(&isight->mutex);
 
-       snd_card_free_when_closed(isight->card);
+       // Block till all of ALSA character devices are released.
+       snd_card_free(isight->card);
+
+       mutex_destroy(&isight->mutex);
+       fw_unit_put(isight->unit);
 }
 
 static const struct ieee1394_device_id isight_id_table[] = {
index 300d31b6f1918917cee1f1fc9e32b6b86b1f8f81..220e61926ea4193c02f66e3d6b8265d15be8d28b 100644 (file)
@@ -52,26 +52,12 @@ static void name_card(struct snd_motu *motu)
                 dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
 }
 
-static void motu_free(struct snd_motu *motu)
+static void motu_card_free(struct snd_card *card)
 {
-       snd_motu_transaction_unregister(motu);
+       struct snd_motu *motu = card->private_data;
 
+       snd_motu_transaction_unregister(motu);
        snd_motu_stream_destroy_duplex(motu);
-       fw_unit_put(motu->unit);
-
-       mutex_destroy(&motu->mutex);
-       kfree(motu);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
-static void motu_card_free(struct snd_card *card)
-{
-       motu_free(card->private_data);
 }
 
 static void do_registration(struct work_struct *work)
@@ -86,6 +72,8 @@ static void do_registration(struct work_struct *work)
                           &motu->card);
        if (err < 0)
                return;
+       motu->card->private_free = motu_card_free;
+       motu->card->private_data = motu;
 
        name_card(motu);
 
@@ -120,18 +108,10 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       /*
-        * After registered, motu instance can be released corresponding to
-        * releasing the sound card instance.
-        */
-       motu->card->private_free = motu_card_free;
-       motu->card->private_data = motu;
        motu->registered = true;
 
        return;
 error:
-       snd_motu_transaction_unregister(motu);
-       snd_motu_stream_destroy_duplex(motu);
        snd_card_free(motu->card);
        dev_info(&motu->unit->device,
                 "Sound card registration failed: %d\n", err);
@@ -143,14 +123,13 @@ static int motu_probe(struct fw_unit *unit,
        struct snd_motu *motu;
 
        /* Allocate this independently of sound card instance. */
-       motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
-       if (motu == NULL)
+       motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL);
+       if (!motu)
                return -ENOMEM;
-
-       motu->spec = (const struct snd_motu_spec *)entry->driver_data;
        motu->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, motu);
 
+       motu->spec = (const struct snd_motu_spec *)entry->driver_data;
        mutex_init(&motu->mutex);
        spin_lock_init(&motu->lock);
        init_waitqueue_head(&motu->hwdep_wait);
@@ -174,12 +153,12 @@ static void motu_remove(struct fw_unit *unit)
        cancel_delayed_work_sync(&motu->dwork);
 
        if (motu->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(motu->card);
-       } else {
-               /* Don't forget this case. */
-               motu_free(motu);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(motu->card);
        }
+
+       mutex_destroy(&motu->mutex);
+       fw_unit_put(motu->unit);
 }
 
 static void motu_bus_update(struct fw_unit *unit)
index f33497cdc706e65584c2dfdecad43862b3906b27..9d9545880a28a4908e79f26e75e1a75470984a3c 100644 (file)
@@ -372,8 +372,9 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
        struct fw_scs1x *scs;
        int err;
 
-       scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL);
-       if (scs == NULL)
+       scs = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_scs1x),
+                          GFP_KERNEL);
+       if (!scs)
                return -ENOMEM;
        scs->fw_dev = fw_parent_device(oxfw->unit);
        oxfw->spec = scs;
index cb905af0660dd29b119fcc2de8bc876fff004308..66d4b1f73f0fcb88e8fa0120b83468fbaf345b6d 100644 (file)
@@ -270,8 +270,9 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
        unsigned int i, first_ch;
        int err;
 
-       spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL);
-       if (spkr == NULL)
+       spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr),
+                           GFP_KERNEL);
+       if (!spkr)
                return -ENOMEM;
        oxfw->spec = spkr;
 
index d9361f3521338bce3befa1ddaa422a4e935680b4..f230a9e44c3c0f65f5ece0c73ae774a7ac5cfe77 100644 (file)
@@ -517,8 +517,9 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
        if (err < 0)
                goto end;
 
-       formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
-       if (formats[eid] == NULL) {
+       formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
+                                   GFP_KERNEL);
+       if (!formats[eid]) {
                err = -ENOMEM;
                goto end;
        }
@@ -535,7 +536,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
                        continue;
 
                eid++;
-               formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
+               formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
+                                           GFP_KERNEL);
                if (formats[eid] == NULL) {
                        err = -ENOMEM;
                        goto end;
@@ -597,8 +599,9 @@ static int fill_stream_formats(struct snd_oxfw *oxfw,
                if (err < 0)
                        break;
 
-               formats[eid] = kmemdup(buf, len, GFP_KERNEL);
-               if (formats[eid] == NULL) {
+               formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
+                                           GFP_KERNEL);
+               if (!formats[eid]) {
                        err = -ENOMEM;
                        break;
                }
index 2ea8be6c858460dfb7c2b55fd380ca313d69c652..afb78d90384b80b3368a0e8a4621174469435e6f 100644 (file)
@@ -113,35 +113,13 @@ end:
        return err;
 }
 
-static void oxfw_free(struct snd_oxfw *oxfw)
+static void oxfw_card_free(struct snd_card *card)
 {
-       unsigned int i;
+       struct snd_oxfw *oxfw = card->private_data;
 
        snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
        if (oxfw->has_output)
                snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-
-       fw_unit_put(oxfw->unit);
-
-       for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
-               kfree(oxfw->tx_stream_formats[i]);
-               kfree(oxfw->rx_stream_formats[i]);
-       }
-
-       kfree(oxfw->spec);
-       mutex_destroy(&oxfw->mutex);
-       kfree(oxfw);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
-static void oxfw_card_free(struct snd_card *card)
-{
-       oxfw_free(card->private_data);
 }
 
 static int detect_quirks(struct snd_oxfw *oxfw)
@@ -208,7 +186,6 @@ static int detect_quirks(struct snd_oxfw *oxfw)
 static void do_registration(struct work_struct *work)
 {
        struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
-       int i;
        int err;
 
        if (oxfw->registered)
@@ -218,6 +195,8 @@ static void do_registration(struct work_struct *work)
                           &oxfw->card);
        if (err < 0)
                return;
+       oxfw->card->private_free = oxfw_card_free;
+       oxfw->card->private_data = oxfw;
 
        err = name_card(oxfw);
        if (err < 0)
@@ -258,28 +237,11 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       /*
-        * After registered, oxfw instance can be released corresponding to
-        * releasing the sound card instance.
-        */
-       oxfw->card->private_free = oxfw_card_free;
-       oxfw->card->private_data = oxfw;
        oxfw->registered = true;
 
        return;
 error:
-       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
-       if (oxfw->has_output)
-               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-       for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; ++i) {
-               kfree(oxfw->tx_stream_formats[i]);
-               oxfw->tx_stream_formats[i] = NULL;
-               kfree(oxfw->rx_stream_formats[i]);
-               oxfw->rx_stream_formats[i] = NULL;
-       }
        snd_card_free(oxfw->card);
-       kfree(oxfw->spec);
-       oxfw->spec = NULL;
        dev_info(&oxfw->unit->device,
                 "Sound card registration failed: %d\n", err);
 }
@@ -293,14 +255,13 @@ static int oxfw_probe(struct fw_unit *unit,
                return -ENODEV;
 
        /* Allocate this independent of sound card instance. */
-       oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL);
-       if (oxfw == NULL)
+       oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL);
+       if (!oxfw)
                return -ENOMEM;
-
-       oxfw->entry = entry;
        oxfw->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, oxfw);
 
+       oxfw->entry = entry;
        mutex_init(&oxfw->mutex);
        spin_lock_init(&oxfw->lock);
        init_waitqueue_head(&oxfw->hwdep_wait);
@@ -347,12 +308,12 @@ static void oxfw_remove(struct fw_unit *unit)
        cancel_delayed_work_sync(&oxfw->dwork);
 
        if (oxfw->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(oxfw->card);
-       } else {
-               /* Don't forget this case. */
-               oxfw_free(oxfw);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(oxfw->card);
        }
+
+       mutex_destroy(&oxfw->mutex);
+       fw_unit_put(oxfw->unit);
 }
 
 static const struct compat_info griffin_firewave = {
index d3fdc463a884e31e15518f2780c4ca080573a9de..ef57fa4db3235b9f28d5486dfa14f4c0375a09a8 100644 (file)
@@ -85,20 +85,12 @@ static int identify_model(struct snd_tscm *tscm)
        return 0;
 }
 
-static void tscm_free(struct snd_tscm *tscm)
+static void tscm_card_free(struct snd_card *card)
 {
+       struct snd_tscm *tscm = card->private_data;
+
        snd_tscm_transaction_unregister(tscm);
        snd_tscm_stream_destroy_duplex(tscm);
-
-       fw_unit_put(tscm->unit);
-
-       mutex_destroy(&tscm->mutex);
-       kfree(tscm);
-}
-
-static void tscm_card_free(struct snd_card *card)
-{
-       tscm_free(card->private_data);
 }
 
 static void do_registration(struct work_struct *work)
@@ -110,6 +102,8 @@ static void do_registration(struct work_struct *work)
                           &tscm->card);
        if (err < 0)
                return;
+       tscm->card->private_free = tscm_card_free;
+       tscm->card->private_data = tscm;
 
        err = identify_model(tscm);
        if (err < 0)
@@ -141,18 +135,10 @@ static void do_registration(struct work_struct *work)
        if (err < 0)
                goto error;
 
-       /*
-        * After registered, tscm instance can be released corresponding to
-        * releasing the sound card instance.
-        */
-       tscm->card->private_free = tscm_card_free;
-       tscm->card->private_data = tscm;
        tscm->registered = true;
 
        return;
 error:
-       snd_tscm_transaction_unregister(tscm);
-       snd_tscm_stream_destroy_duplex(tscm);
        snd_card_free(tscm->card);
        dev_info(&tscm->unit->device,
                 "Sound card registration failed: %d\n", err);
@@ -164,11 +150,9 @@ static int snd_tscm_probe(struct fw_unit *unit,
        struct snd_tscm *tscm;
 
        /* Allocate this independent of sound card instance. */
-       tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL);
-       if (tscm == NULL)
+       tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL);
+       if (!tscm)
                return -ENOMEM;
-
-       /* initialize myself */
        tscm->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, tscm);
 
@@ -216,12 +200,12 @@ static void snd_tscm_remove(struct fw_unit *unit)
        cancel_delayed_work_sync(&tscm->dwork);
 
        if (tscm->registered) {
-               /* No need to wait for releasing card object in this context. */
-               snd_card_free_when_closed(tscm->card);
-       } else {
-               /* Don't forget this case. */
-               tscm_free(tscm);
+               // Block till all of ALSA character devices are released.
+               snd_card_free(tscm->card);
        }
+
+       mutex_destroy(&tscm->mutex);
+       fw_unit_put(tscm->unit);
 }
 
 static const struct ieee1394_device_id snd_tscm_id_table[] = {
index 5bc4a1d587d4f13121ca82433aeafa4b6594576c..60cb00fd0c6936a4a3db6751496c15eab2af2e3d 100644 (file)
@@ -48,9 +48,11 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
        }
 
        if (enable)
-               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
+               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+                                AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN);
        else
-               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
+               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+                                AZX_PPCTL_GPROCEN, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
 
@@ -68,9 +70,11 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
        }
 
        if (enable)
-               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
+               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+                                AZX_PPCTL_PIE, AZX_PPCTL_PIE);
        else
-               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
+               snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+                                AZX_PPCTL_PIE, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
 
@@ -194,7 +198,8 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
  */
 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
 {
-       snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+       snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
+                        AZX_MLCTL_SPA, AZX_MLCTL_SPA);
 
        return check_hdac_link_power_active(link, true);
 }
@@ -222,8 +227,8 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
        int ret;
 
        list_for_each_entry(hlink, &bus->hlink_list, list) {
-               snd_hdac_updatel(hlink->ml_addr,
-                               AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+               snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
+                                AZX_MLCTL_SPA, AZX_MLCTL_SPA);
                ret = check_hdac_link_power_active(hlink, true);
                if (ret < 0)
                        return ret;
@@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
        int ret;
 
        list_for_each_entry(hlink, &bus->hlink_list, list) {
-               snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
+               snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
+                                AZX_MLCTL_SPA, 0);
                ret = check_hdac_link_power_active(hlink, false);
                if (ret < 0)
                        return ret;
index 2647309bc67571011a75987218cd82e17c0556d7..8afa2f8884660fe186b682c984387e80dda8b759 100644 (file)
@@ -118,7 +118,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
        struct cs8427 *chip = device->private_data;
        char *hw_data = udata ?
                chip->playback.hw_udata : chip->playback.hw_status;
-       char data[32];
+       unsigned char data[32];
        int err, idx;
 
        if (!memcmp(hw_data, ndata, count))
index ac0ab6eb40f07ea8f1a857806818f69733c42deb..47e0b2820ace502eeb0c235afd6cb67393e1aaf4 100644 (file)
@@ -389,7 +389,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
        case OPTi9XX_HW_82C931:
                /* disable 3D sound (set GPIO1 as output, low) */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
-       case OPTi9XX_HW_82C933: /* FALL THROUGH */
+               /* fall through */
+       case OPTi9XX_HW_82C933:
                /*
                 * The BTC 1817DW has QS1000 wavetable which is connected
                 * to the serial digital input of the OPTI931.
@@ -400,7 +401,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
                 * or digital input signal.
                 */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
-       case OPTi9XX_HW_82C930: /* FALL THROUGH */
+               /* fall through */
+       case OPTi9XX_HW_82C930:
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
index 481797744b3ccb77298887c507ea0cf31d4a7209..8288fae90085c8c4d36f793a5fb8791ca43076f4 100644 (file)
@@ -130,13 +130,13 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
                        chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
                        break;
                }
-               /* fallthru */
+               /* fall through */
        case SB_HW_201:
                if (rate > 23000) {
                        chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
                        break;
                }
-               /* fallthru */
+               /* fall through */
        case SB_HW_20:
                chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
                break;
@@ -287,7 +287,7 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
                        chip->capture_format = SB_DSP_HI_INPUT_AUTO;
                        break;
                }
-               /* fallthru */
+               /* fall through */
        case SB_HW_20:
                chip->capture_format = SB_DSP_LO_INPUT_AUTO;
                break;
@@ -387,7 +387,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
        case SB_MODE_PLAYBACK_16:       /* ok.. playback is active */
                if (chip->hardware != SB_HW_JAZZ16)
                        break;
-               /* fallthru */
+               /* fall through */
        case SB_MODE_PLAYBACK_8:
                substream = chip->playback_substream;
                if (chip->playback_format == SB_DSP_OUTPUT)
@@ -397,7 +397,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
        case SB_MODE_CAPTURE_16:
                if (chip->hardware != SB_HW_JAZZ16)
                        break;
-               /* fallthru */
+               /* fall through */
        case SB_MODE_CAPTURE_8:
                substream = chip->capture_substream;
                if (chip->capture_format == SB_DSP_INPUT)
index c8904e732aaa5f1dbb365ca66bf742e616c25b13..a4ed54aeaf1de60ccb9f9b3c4ffb179d6de73277 100644 (file)
@@ -500,7 +500,8 @@ static const struct snd_pcm_hardware hal2_pcm_hw = {
        .info = (SNDRV_PCM_INFO_MMAP |
                 SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_INTERLEAVED |
-                SNDRV_PCM_INFO_BLOCK_TRANSFER),
+                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats =          SNDRV_PCM_FMTBIT_S16_BE,
        .rates =            SNDRV_PCM_RATE_8000_48000,
        .rate_min =         8000,
@@ -563,6 +564,8 @@ static int hal2_playback_prepare(struct snd_pcm_substream *substream)
        dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
        memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
        dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
+       dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
+       dac->pcm_indirect.hw_io = dac->buffer_dma;
        dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
        dac->substream = substream;
        hal2_setup_dac(hal2);
@@ -575,9 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma;
-               hal2->dac.pcm_indirect.hw_data = 0;
-               substream->ops->ack(substream);
                hal2_start_dac(hal2);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
@@ -615,7 +615,6 @@ static int hal2_playback_ack(struct snd_pcm_substream *substream)
        struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
        struct hal2_codec *dac = &hal2->dac;
 
-       dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
        return snd_pcm_indirect_playback_transfer(substream,
                                                  &dac->pcm_indirect,
                                                  hal2_playback_transfer);
@@ -655,6 +654,7 @@ static int hal2_capture_prepare(struct snd_pcm_substream *substream)
        memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
        adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
        adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
+       adc->pcm_indirect.hw_io = adc->buffer_dma;
        adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
        adc->substream = substream;
        hal2_setup_adc(hal2);
@@ -667,9 +667,6 @@ static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma;
-               hal2->adc.pcm_indirect.hw_data = 0;
-               printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma);
                hal2_start_adc(hal2);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
index 5ef4fe964366e6e1c69d9cc71b7794e866ca0a6a..7c91330af7192e3733304d3229c1a4edc080ff18 100644 (file)
@@ -49,7 +49,7 @@ u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
        /*?? any benefit in using managed dmam_alloc_coherent? */
        p_mem_area->vaddr =
                dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
-               GFP_DMA32 | GFP_KERNEL);
+               GFP_KERNEL);
 
        if (p_mem_area->vaddr) {
                HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",
index a1e4944dcfe86f8e2931547354577cffb891b8c2..1a41f8c802436c92dbe91e4a2993ea33913367b0 100644 (file)
@@ -903,15 +903,15 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
        case 8:
                data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
                        ATI_REG_OUT_DMA_SLOT_BIT(11);
-               /* fallthru */
+               /* fall through */
        case 6:
                data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
                        ATI_REG_OUT_DMA_SLOT_BIT(8);
-               /* fallthru */
+               /* fall through */
        case 4:
                data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
                        ATI_REG_OUT_DMA_SLOT_BIT(9);
-               /* fallthru */
+               /* fall through */
        default:
                data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
                        ATI_REG_OUT_DMA_SLOT_BIT(4);
index 2e5b460a847c678c7af2b2945e34be906e91299d..96ece1a71cf157573ec01fec1acde2d24e784cf6 100644 (file)
@@ -1115,6 +1115,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
                        snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
+               /* fall through */
                /* 3 pages */
        case 3:
                dma->cfg0 |= 0x12000000;
@@ -1122,12 +1123,14 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
                        snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
+               /* fall through */
                /* 2 pages */
        case 2:
                dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
                        snd_pcm_sgbuf_get_addr(dma->substream, psize));
+               /* fall through */
                /* 1 page */
        case 1:
                dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
@@ -1390,17 +1393,20 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
                dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
                        snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
+               /* fall through */
                /* 3 pages */
        case 3:
                dma->cfg0 |= 0x12000000;
                dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4)  + 0x8,
                        snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
+               /* fall through */
                /* 2 pages */
        case 2:
                dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
                        snd_pcm_sgbuf_get_addr(dma->substream, psize));
+               /* fall through */
                /* 1 page */
        case 1:
                dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
index 146e1a3498c7352c53751871fb1dfd166df8dac1..750eec437a795757d109e8ced727f2df36910777 100644 (file)
@@ -1443,7 +1443,8 @@ static const struct snd_pcm_hardware snd_cs46xx_playback =
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED | 
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
-                                /*SNDRV_PCM_INFO_RESUME*/),
+                                /*SNDRV_PCM_INFO_RESUME*/ |
+                                SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats =              (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
                                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
                                 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
@@ -1465,7 +1466,8 @@ static const struct snd_pcm_hardware snd_cs46xx_capture =
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
-                                /*SNDRV_PCM_INFO_RESUME*/),
+                                /*SNDRV_PCM_INFO_RESUME*/ |
+                                SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5500,
index 9f2b6097f486d1ae065e3b9680e1c81e8091740c..30b3472d0b75b4f82a227535ab5ac6ff6b6747b6 100644 (file)
@@ -1753,7 +1753,8 @@ static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_RESUME |
-                                /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE),
+                                /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE |
+                                SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
index a12e594d4e3b3a23d78cc0b75531b845c7b6e331..fe2506672a72049b2dd7fb1c4f69d1f288ce4634 100644 (file)
@@ -130,8 +130,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
        azx_dev->core.bufsize = 0;
        azx_dev->core.period_bytes = 0;
        azx_dev->core.format_val = 0;
-       ret = chip->ops->substream_alloc_pages(chip, substream,
-                                         params_buffer_bytes(hw_params));
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+
 unlock:
        dsp_unlock(azx_dev);
        return ret;
@@ -141,7 +142,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx_dev *azx_dev = get_azx_dev(substream);
-       struct azx *chip = apcm->chip;
        struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
        int err;
 
@@ -152,7 +152,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 
        snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
 
-       err = chip->ops->substream_free_pages(chip, substream);
+       err = snd_pcm_lib_free_pages(substream);
        azx_stream(azx_dev)->prepared = 0;
        dsp_unlock(azx_dev);
        return err;
@@ -732,6 +732,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
        int pcm_dev = cpcm->device;
        unsigned int size;
        int s, err;
+       int type = SNDRV_DMA_TYPE_DEV_SG;
 
        list_for_each_entry(apcm, &chip->pcm_list, list) {
                if (apcm->pcm->device == pcm_dev) {
@@ -770,7 +771,9 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
        size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
        if (size > MAX_PREALLOC_SIZE)
                size = MAX_PREALLOC_SIZE;
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+       if (chip->uc_buffer)
+               type = SNDRV_DMA_TYPE_DEV_UC_SG;
+       snd_pcm_lib_preallocate_pages_for_all(pcm, type,
                                              chip->card->dev,
                                              size, MAX_PREALLOC_SIZE);
        return 0;
@@ -1220,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus)
        bus->in_reset = 0;
 }
 
-static int get_jackpoll_interval(struct azx *chip)
-{
-       int i;
-       unsigned int j;
-
-       if (!chip->jackpoll_ms)
-               return 0;
-
-       i = chip->jackpoll_ms[chip->dev_index];
-       if (i == 0)
-               return 0;
-       if (i < 50 || i > 60000)
-               j = 0;
-       else
-               j = msecs_to_jiffies(i);
-       if (j == 0)
-               dev_warn(chip->card->dev,
-                        "jackpoll_ms value out of range: %d\n", i);
-       return j;
-}
-
 /* HD-audio bus initialization */
 int azx_bus_init(struct azx *chip, const char *model,
                 const struct hdac_io_ops *io_ops)
@@ -1323,7 +1305,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
                        err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
                        if (err < 0)
                                continue;
-                       codec->jackpoll_interval = get_jackpoll_interval(chip);
+                       codec->jackpoll_interval = chip->jackpoll_interval;
                        codec->beep_mode = chip->beep_mode;
                        codecs++;
                }
index 55760e5231e62b65bce8a8da5b702ff432161add..c95097bb5a0c0312a03cce011a0ca16c34462d83 100644 (file)
@@ -76,7 +76,6 @@ struct azx_dev {
         *  when link position is not greater than FIFO size
         */
        unsigned int insufficient:1;
-       unsigned int wc_marked:1;
 };
 
 #define azx_stream(dev)                (&(dev)->core)
@@ -88,11 +87,6 @@ struct azx;
 struct hda_controller_ops {
        /* Disable msi if supported, PCI only */
        int (*disable_msi_reset_irq)(struct azx *);
-       int (*substream_alloc_pages)(struct azx *chip,
-                                    struct snd_pcm_substream *substream,
-                                    size_t size);
-       int (*substream_free_pages)(struct azx *chip,
-                                   struct snd_pcm_substream *substream);
        void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
                                 struct vm_area_struct *area);
        /* Check if current position is acceptable */
@@ -127,7 +121,7 @@ struct azx {
        int capture_streams;
        int capture_index_offset;
        int num_streams;
-       const int *jackpoll_ms; /* per-card jack poll interval */
+       int jackpoll_interval; /* jack poll interval in jiffies */
 
        /* Register interaction. */
        const struct hda_controller_ops *ops;
@@ -160,6 +154,7 @@ struct azx {
        unsigned int msi:1;
        unsigned int probing:1; /* codec probing phase */
        unsigned int snoop:1;
+       unsigned int uc_buffer:1; /* non-cached pages for stream buffers */
        unsigned int align_buffer_size:1;
        unsigned int region_requested:1;
        unsigned int disabled:1; /* disabled by vga_switcheroo */
@@ -175,11 +170,10 @@ struct azx {
 #define azx_bus(chip)  (&(chip)->bus.core)
 #define bus_to_azx(_bus)       container_of(_bus, struct azx, bus.core)
 
-#ifdef CONFIG_X86
-#define azx_snoop(chip)                ((chip)->snoop)
-#else
-#define azx_snoop(chip)                true
-#endif
+static inline bool azx_snoop(struct azx *chip)
+{
+       return !IS_ENABLED(CONFIG_X86) || chip->snoop;
+}
 
 /*
  * macros for easy use
index 4b7666e0374cb2e339a55d5888da5b56563ff3cf..d8eb2b5f51ae7f59e3f905f092190f898f92242d 100644 (file)
@@ -399,61 +399,6 @@ static char *driver_short_names[] = {
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
-#ifdef CONFIG_X86
-static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
-{
-       int pages;
-
-       if (azx_snoop(chip))
-               return;
-       if (!dmab || !dmab->area || !dmab->bytes)
-               return;
-
-#ifdef CONFIG_SND_DMA_SGBUF
-       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
-               struct snd_sg_buf *sgbuf = dmab->private_data;
-               if (chip->driver_type == AZX_DRIVER_CMEDIA)
-                       return; /* deal with only CORB/RIRB buffers */
-               if (on)
-                       set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
-               else
-                       set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
-               return;
-       }
-#endif
-
-       pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       if (on)
-               set_memory_wc((unsigned long)dmab->area, pages);
-       else
-               set_memory_wb((unsigned long)dmab->area, pages);
-}
-
-static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
-                                bool on)
-{
-       __mark_pages_wc(chip, buf, on);
-}
-static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-                                  struct snd_pcm_substream *substream, bool on)
-{
-       if (azx_dev->wc_marked != on) {
-               __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on);
-               azx_dev->wc_marked = on;
-       }
-}
-#else
-/* NOP for other archs */
-static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
-                                bool on)
-{
-}
-static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-                                  struct snd_pcm_substream *substream, bool on)
-{
-}
-#endif
-
 static int azx_acquire_irq(struct azx *chip, int do_disconnect);
 static void set_default_power_save(struct azx *chip);
 
@@ -1678,6 +1623,7 @@ static void azx_check_snoop_available(struct azx *chip)
                dev_info(chip->card->dev, "Force to %s mode by module option\n",
                         snoop ? "snoop" : "non-snoop");
                chip->snoop = snoop;
+               chip->uc_buffer = !snoop;
                return;
        }
 
@@ -1698,8 +1644,12 @@ static void azx_check_snoop_available(struct azx *chip)
                snoop = false;
 
        chip->snoop = snoop;
-       if (!snoop)
+       if (!snoop) {
                dev_info(chip->card->dev, "Force to non-snoop mode\n");
+               /* C-Media requires non-cached pages only for CORB/RIRB */
+               if (chip->driver_type != AZX_DRIVER_CMEDIA)
+                       chip->uc_buffer = true;
+       }
 }
 
 static void azx_probe_work(struct work_struct *work)
@@ -1767,7 +1717,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->driver_type = driver_caps & 0xff;
        check_msi(chip);
        chip->dev_index = dev;
-       chip->jackpoll_ms = jackpoll_ms;
+       if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
+               chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
        INIT_LIST_HEAD(&chip->pcm_list);
        INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
        INIT_LIST_HEAD(&hda->list);
@@ -2090,55 +2041,24 @@ static int dma_alloc_pages(struct hdac_bus *bus,
                           struct snd_dma_buffer *buf)
 {
        struct azx *chip = bus_to_azx(bus);
-       int err;
 
-       err = snd_dma_alloc_pages(type,
-                                 bus->dev,
-                                 size, buf);
-       if (err < 0)
-               return err;
-       mark_pages_wc(chip, buf, true);
-       return 0;
+       if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV)
+               type = SNDRV_DMA_TYPE_DEV_UC;
+       return snd_dma_alloc_pages(type, bus->dev, size, buf);
 }
 
 static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
 {
-       struct azx *chip = bus_to_azx(bus);
-
-       mark_pages_wc(chip, buf, false);
        snd_dma_free_pages(buf);
 }
 
-static int substream_alloc_pages(struct azx *chip,
-                                struct snd_pcm_substream *substream,
-                                size_t size)
-{
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       int ret;
-
-       mark_runtime_wc(chip, azx_dev, substream, false);
-       ret = snd_pcm_lib_malloc_pages(substream, size);
-       if (ret < 0)
-               return ret;
-       mark_runtime_wc(chip, azx_dev, substream, true);
-       return 0;
-}
-
-static int substream_free_pages(struct azx *chip,
-                               struct snd_pcm_substream *substream)
-{
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       mark_runtime_wc(chip, azx_dev, substream, false);
-       return snd_pcm_lib_free_pages(substream);
-}
-
 static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
                             struct vm_area_struct *area)
 {
 #ifdef CONFIG_X86
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx *chip = apcm->chip;
-       if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA)
+       if (chip->uc_buffer)
                area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
 #endif
 }
@@ -2156,8 +2076,6 @@ static const struct hdac_io_ops pci_hda_io_ops = {
 
 static const struct hda_controller_ops pci_hda_ops = {
        .disable_msi_reset_irq = disable_msi_reset_irq,
-       .substream_alloc_pages = substream_alloc_pages,
-       .substream_free_pages = substream_free_pages,
        .pcm_mmap_prepare = pcm_mmap_prepare,
        .position_check = azx_position_check,
        .link_power = azx_intel_link_power,
@@ -2257,8 +2175,12 @@ static struct snd_pci_quirk power_save_blacklist[] = {
        /* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
        SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
        /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+       SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
+       /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
        /* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
+       /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+       SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0),
        /* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
        SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
        /* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
index 4bc5232eac1cb435b4ecae42f568c39c4b78a484..dd7d4242d6d2afeec5cfb5a813ef43d813c0b6be 100644 (file)
@@ -99,19 +99,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
        snd_dma_free_pages(buf);
 }
 
-static int substream_alloc_pages(struct azx *chip,
-                                struct snd_pcm_substream *substream,
-                                size_t size)
-{
-       return snd_pcm_lib_malloc_pages(substream, size);
-}
-
-static int substream_free_pages(struct azx *chip,
-                               struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
 /*
  * Register access ops. Tegra HDA register access is DWORD only.
  */
@@ -180,10 +167,7 @@ static const struct hdac_io_ops hda_tegra_io_ops = {
        .dma_free_pages = dma_free_pages,
 };
 
-static const struct hda_controller_ops hda_tegra_ops = {
-       .substream_alloc_pages = substream_alloc_pages,
-       .substream_free_pages = substream_free_pages,
-};
+static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
 
 static void hda_tegra_init(struct hda_tegra *hda)
 {
index 6ea04f8898096bf0f8689d966219760a78762fcf..0a24037184c33e2cd53554d7cf9e4dd6586dd19b 100644 (file)
 #define SCP_GET    1
 
 #define EFX_FILE   "ctefx.bin"
-#define SBZ_EFX_FILE   "ctefx-sbz.bin"
+#define DESKTOP_EFX_FILE   "ctefx-desktop.bin"
 #define R3DI_EFX_FILE  "ctefx-r3di.bin"
 
 #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
 MODULE_FIRMWARE(EFX_FILE);
-MODULE_FIRMWARE(SBZ_EFX_FILE);
+MODULE_FIRMWARE(DESKTOP_EFX_FILE);
 MODULE_FIRMWARE(R3DI_EFX_FILE);
 #endif
 
@@ -153,7 +153,10 @@ enum {
        XBASS_XOVER,
        EQ_PRESET_ENUM,
        SMART_VOLUME_ENUM,
-       MIC_BOOST_ENUM
+       MIC_BOOST_ENUM,
+       AE5_HEADPHONE_GAIN_ENUM,
+       AE5_SOUND_FILTER_ENUM,
+       ZXR_HEADPHONE_GAIN
 #define EFFECTS_COUNT  (EFFECT_END_NID - EFFECT_START_NID)
 };
 
@@ -667,6 +670,65 @@ static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = {
        }
 };
 
+/* Values for ca0113_mmio_command_set for selecting output. */
+#define AE5_CA0113_OUT_SET_COMMANDS 6
+struct ae5_ca0113_output_set {
+       unsigned int group[AE5_CA0113_OUT_SET_COMMANDS];
+       unsigned int target[AE5_CA0113_OUT_SET_COMMANDS];
+       unsigned int vals[AE5_CA0113_OUT_SET_COMMANDS];
+};
+
+static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = {
+       { .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+         .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+         .vals =   { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }
+       },
+       { .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+         .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+         .vals =   { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 }
+       },
+       { .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+         .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+         .vals =   { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }
+       }
+};
+
+/* ae5 ca0113 command sequences to set headphone gain levels. */
+#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4
+struct ae5_headphone_gain_set {
+       char *name;
+       unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS];
+};
+
+static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = {
+       { .name = "Low (16-31",
+         .vals = { 0xff, 0x2c, 0xf5, 0x32 }
+       },
+       { .name = "Medium (32-149",
+         .vals = { 0x38, 0xa8, 0x3e, 0x4c }
+       },
+       { .name = "High (150-600",
+         .vals = { 0xff, 0xff, 0xff, 0x7f }
+       }
+};
+
+struct ae5_filter_set {
+       char *name;
+       unsigned int val;
+};
+
+static const struct ae5_filter_set ae5_filter_presets[] = {
+       { .name = "Slow Roll Off",
+         .val = 0xa0
+       },
+       { .name = "Minimum Phase",
+         .val = 0xc0
+       },
+       { .name = "Fast Roll Off",
+         .val = 0x80
+       }
+};
+
 enum hda_cmd_vendor_io {
        /* for DspIO node */
        VENDOR_DSPIO_SCP_WRITE_DATA_LOW      = 0x000,
@@ -686,6 +748,9 @@ enum hda_cmd_vendor_io {
        VENDOR_CHIPIO_DATA_LOW               = 0x300,
        VENDOR_CHIPIO_DATA_HIGH              = 0x400,
 
+       VENDOR_CHIPIO_8051_WRITE_DIRECT      = 0x500,
+       VENDOR_CHIPIO_8051_READ_DIRECT       = 0xD00,
+
        VENDOR_CHIPIO_GET_PARAMETER          = 0xF00,
        VENDOR_CHIPIO_STATUS                 = 0xF01,
        VENDOR_CHIPIO_HIC_POST_READ          = 0x702,
@@ -693,6 +758,9 @@ enum hda_cmd_vendor_io {
 
        VENDOR_CHIPIO_8051_DATA_WRITE        = 0x707,
        VENDOR_CHIPIO_8051_DATA_READ         = 0xF07,
+       VENDOR_CHIPIO_8051_PMEM_READ         = 0xF08,
+       VENDOR_CHIPIO_8051_IRAM_WRITE        = 0x709,
+       VENDOR_CHIPIO_8051_IRAM_READ         = 0xF09,
 
        VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE   = 0x70A,
        VENDOR_CHIPIO_CT_EXTENSIONS_GET      = 0xF0A,
@@ -799,6 +867,12 @@ enum control_param_id {
         * impedance is selected*/
        CONTROL_PARAM_PORTD_160OHM_GAIN        = 10,
 
+       /*
+        * This control param name was found in the 8051 memory, and makes
+        * sense given the fact the AE-5 uses it and has the ASI flag set.
+        */
+       CONTROL_PARAM_ASI                      = 23,
+
        /* Stream Control */
 
        /* Select stream with the given ID */
@@ -956,7 +1030,11 @@ struct ca0132_spec {
        long eq_preset_val;
        unsigned int tlv[4];
        struct hda_vmaster_mute_hook vmaster_mute;
-
+       /* AE-5 Control values */
+       unsigned char ae5_headphone_gain_val;
+       unsigned char ae5_filter_val;
+       /* ZxR Control Values */
+       unsigned char zxr_gain_set;
 
        struct hda_codec *codec;
        struct delayed_work unsol_hp_work;
@@ -996,8 +1074,11 @@ enum {
        QUIRK_ALIENWARE,
        QUIRK_ALIENWARE_M17XR4,
        QUIRK_SBZ,
+       QUIRK_ZXR,
+       QUIRK_ZXR_DBPRO,
        QUIRK_R3DI,
        QUIRK_R3D,
+       QUIRK_AE5,
 };
 
 static const struct hda_pintbl alienware_pincfgs[] = {
@@ -1029,6 +1110,21 @@ static const struct hda_pintbl sbz_pincfgs[] = {
        {}
 };
 
+/* Sound Blaster ZxR pin configs taken from Windows Driver */
+static const struct hda_pintbl zxr_pincfgs[] = {
+       { 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
+       { 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
+       { 0x10, 0x01017111 }, /* Port D -- Center/LFE */
+       { 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
+       { 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x50d000f0 }, /* N/A */
+       {}
+};
+
 /* Recon3D pin configs taken from Windows Driver */
 static const struct hda_pintbl r3d_pincfgs[] = {
        { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1044,6 +1140,21 @@ static const struct hda_pintbl r3d_pincfgs[] = {
        {}
 };
 
+/* Sound Blaster AE-5 pin configs taken from Windows Driver */
+static const struct hda_pintbl ae5_pincfgs[] = {
+       { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x01c510f0 }, /* SPDIF In */
+       { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
+       { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
+       { 0x11, 0x01a170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
+       { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x50d000f0 }, /* N/A */
+       {}
+};
+
 /* Recon3D integrated pin configs taken from Windows Driver */
 static const struct hda_pintbl r3di_pincfgs[] = {
        { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1070,6 +1181,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
        SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
        SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
        SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
+       SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
        {}
 };
 
@@ -1454,6 +1566,20 @@ static void chipio_set_conn_rate(struct hda_codec *codec,
                                 rate);
 }
 
+/*
+ * Writes to the 8051's internal address space directly instead of indirectly,
+ * giving access to the special function registers located at addresses
+ * 0x80-0xFF.
+ */
+static void chipio_8051_write_direct(struct hda_codec *codec,
+               unsigned int addr, unsigned int data)
+{
+       unsigned int verb;
+
+       verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data;
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr);
+}
+
 /*
  * Enable clocks.
  */
@@ -3089,7 +3215,9 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
 }
 
 /*
- * Setup GPIO for the other variants of Core3D.
+ * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e
+ * based cards, and has a second mmio region, region2, that's used for special
+ * commands.
  */
 
 /*
@@ -3097,8 +3225,11 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
  * the mmio address 0x320 is used to set GPIO pins. The format for the data
  * The first eight bits are just the number of the pin. So far, I've only seen
  * this number go to 7.
+ * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value
+ * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and
+ * then off to send that bit.
  */
-static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
+static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
                bool enable)
 {
        struct ca0132_spec *spec = codec->spec;
@@ -3110,6 +3241,89 @@ static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
        writew(gpio_data, spec->mem_base + 0x320);
 }
 
+/*
+ * Special pci region2 commands that are only used by the AE-5. They follow
+ * a set format, and require reads at certain points to seemingly 'clear'
+ * the response data. My first tests didn't do these reads, and would cause
+ * the card to get locked up until the memory was read. These commands
+ * seem to work with three distinct values that I've taken to calling group,
+ * target-id, and value.
+ */
+static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group,
+               unsigned int target, unsigned int value)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int write_val;
+
+       writel(0x0000007e, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       writel(0x0000005a, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+
+       writel(0x00800005, spec->mem_base + 0x20c);
+       writel(group, spec->mem_base + 0x804);
+
+       writel(0x00800005, spec->mem_base + 0x20c);
+       write_val = (target & 0xff);
+       write_val |= (value << 8);
+
+
+       writel(write_val, spec->mem_base + 0x204);
+       /*
+        * Need delay here or else it goes too fast and works inconsistently.
+        */
+       msleep(20);
+
+       readl(spec->mem_base + 0x860);
+       readl(spec->mem_base + 0x854);
+       readl(spec->mem_base + 0x840);
+
+       writel(0x00800004, spec->mem_base + 0x20c);
+       writel(0x00000000, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+}
+
+/*
+ * This second type of command is used for setting the sound filter type.
+ */
+static void ca0113_mmio_command_set_type2(struct hda_codec *codec,
+               unsigned int group, unsigned int target, unsigned int value)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int write_val;
+
+       writel(0x0000007e, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       writel(0x0000005a, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+
+       writel(0x00800003, spec->mem_base + 0x20c);
+       writel(group, spec->mem_base + 0x804);
+
+       writel(0x00800005, spec->mem_base + 0x20c);
+       write_val = (target & 0xff);
+       write_val |= (value << 8);
+
+
+       writel(write_val, spec->mem_base + 0x204);
+       msleep(20);
+       readl(spec->mem_base + 0x860);
+       readl(spec->mem_base + 0x854);
+       readl(spec->mem_base + 0x840);
+
+       writel(0x00800004, spec->mem_base + 0x20c);
+       writel(0x00000000, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+}
+
+/*
+ * Setup GPIO for the other variants of Core3D.
+ */
+
 /*
  * Sets up the GPIO pins so that they are discoverable. If this isn't done,
  * the card shows as having no GPIO pins.
@@ -3120,6 +3334,7 @@ static void ca0132_gpio_init(struct hda_codec *codec)
 
        switch (spec->quirk) {
        case QUIRK_SBZ:
+       case QUIRK_AE5:
                snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
                snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
                snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23);
@@ -3929,6 +4144,138 @@ exit:
        return err < 0 ? err : 0;
 }
 
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val);
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val);
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
+
+static void ae5_mmio_select_out(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int i;
+
+       for (i = 0; i < AE5_CA0113_OUT_SET_COMMANDS; i++)
+               ca0113_mmio_command_set(codec,
+                       ae5_ca0113_output_presets[spec->cur_out_type].group[i],
+                       ae5_ca0113_output_presets[spec->cur_out_type].target[i],
+                       ae5_ca0113_output_presets[spec->cur_out_type].vals[i]);
+}
+
+/*
+ * These are the commands needed to setup output on each of the different card
+ * types.
+ */
+static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       switch (spec->cur_out_type) {
+       case SPEAKER_OUT:
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
+                       ca0113_mmio_gpio_set(codec, 7, false);
+                       ca0113_mmio_gpio_set(codec, 4, true);
+                       ca0113_mmio_gpio_set(codec, 1, true);
+                       chipio_set_control_param(codec, 0x0d, 0x18);
+                       break;
+               case QUIRK_ZXR:
+                       ca0113_mmio_gpio_set(codec, 2, true);
+                       ca0113_mmio_gpio_set(codec, 3, true);
+                       ca0113_mmio_gpio_set(codec, 5, false);
+                       zxr_headphone_gain_set(codec, 0);
+                       chipio_set_control_param(codec, 0x0d, 0x24);
+                       break;
+               case QUIRK_R3DI:
+                       chipio_set_control_param(codec, 0x0d, 0x24);
+                       r3di_gpio_out_set(codec, R3DI_LINE_OUT);
+                       break;
+               case QUIRK_R3D:
+                       chipio_set_control_param(codec, 0x0d, 0x24);
+                       ca0113_mmio_gpio_set(codec, 1, true);
+                       break;
+               case QUIRK_AE5:
+                       ae5_mmio_select_out(codec);
+                       ae5_headphone_gain_set(codec, 2);
+                       tmp = FLOAT_ZERO;
+                       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+                       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+                       chipio_set_control_param(codec, 0x0d, 0xa4);
+                       chipio_write(codec, 0x18b03c, 0x00000012);
+                       break;
+               }
+               break;
+       case HEADPHONE_OUT:
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
+                       ca0113_mmio_gpio_set(codec, 7, true);
+                       ca0113_mmio_gpio_set(codec, 4, true);
+                       ca0113_mmio_gpio_set(codec, 1, false);
+                       chipio_set_control_param(codec, 0x0d, 0x12);
+                       break;
+               case QUIRK_ZXR:
+                       ca0113_mmio_gpio_set(codec, 2, false);
+                       ca0113_mmio_gpio_set(codec, 3, false);
+                       ca0113_mmio_gpio_set(codec, 5, true);
+                       zxr_headphone_gain_set(codec, spec->zxr_gain_set);
+                       chipio_set_control_param(codec, 0x0d, 0x21);
+                       break;
+               case QUIRK_R3DI:
+                       chipio_set_control_param(codec, 0x0d, 0x21);
+                       r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
+                       break;
+               case QUIRK_R3D:
+                       chipio_set_control_param(codec, 0x0d, 0x21);
+                       ca0113_mmio_gpio_set(codec, 0x1, false);
+                       break;
+               case QUIRK_AE5:
+                       ae5_mmio_select_out(codec);
+                       ae5_headphone_gain_set(codec,
+                                       spec->ae5_headphone_gain_val);
+                       tmp = FLOAT_ONE;
+                       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+                       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+                       chipio_set_control_param(codec, 0x0d, 0xa1);
+                       chipio_write(codec, 0x18b03c, 0x00000012);
+                       break;
+               }
+               break;
+       case SURROUND_OUT:
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
+                       ca0113_mmio_gpio_set(codec, 7, false);
+                       ca0113_mmio_gpio_set(codec, 4, true);
+                       ca0113_mmio_gpio_set(codec, 1, true);
+                       chipio_set_control_param(codec, 0x0d, 0x18);
+                       break;
+               case QUIRK_ZXR:
+                       ca0113_mmio_gpio_set(codec, 2, true);
+                       ca0113_mmio_gpio_set(codec, 3, true);
+                       ca0113_mmio_gpio_set(codec, 5, false);
+                       zxr_headphone_gain_set(codec, 0);
+                       chipio_set_control_param(codec, 0x0d, 0x24);
+                       break;
+               case QUIRK_R3DI:
+                       chipio_set_control_param(codec, 0x0d, 0x24);
+                       r3di_gpio_out_set(codec, R3DI_LINE_OUT);
+                       break;
+               case QUIRK_R3D:
+                       ca0113_mmio_gpio_set(codec, 1, true);
+                       chipio_set_control_param(codec, 0x0d, 0x24);
+                       break;
+               case QUIRK_AE5:
+                       ae5_mmio_select_out(codec);
+                       ae5_headphone_gain_set(codec, 2);
+                       tmp = FLOAT_ZERO;
+                       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+                       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+                       chipio_set_control_param(codec, 0x0d, 0xa4);
+                       chipio_write(codec, 0x18b03c, 0x00000012);
+                       break;
+               }
+               break;
+       }
+}
+
 /*
  * This function behaves similarly to the ca0132_select_out funciton above,
  * except with a few differences. It adds the ability to select the current
@@ -3979,26 +4326,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
        if (err < 0)
                goto exit;
 
+       ca0132_alt_select_out_quirk_handler(codec);
+
        switch (spec->cur_out_type) {
        case SPEAKER_OUT:
                codec_dbg(codec, "%s speaker\n", __func__);
-               /*speaker out config*/
-               switch (spec->quirk) {
-               case QUIRK_SBZ:
-                       ca0132_mmio_gpio_set(codec, 7, false);
-                       ca0132_mmio_gpio_set(codec, 4, true);
-                       ca0132_mmio_gpio_set(codec, 1, true);
-                       chipio_set_control_param(codec, 0x0D, 0x18);
-                       break;
-               case QUIRK_R3DI:
-                       chipio_set_control_param(codec, 0x0D, 0x24);
-                       r3di_gpio_out_set(codec, R3DI_LINE_OUT);
-                       break;
-               case QUIRK_R3D:
-                       chipio_set_control_param(codec, 0x0D, 0x24);
-                       ca0132_mmio_gpio_set(codec, 1, true);
-                       break;
-               }
 
                /* disable headphone node */
                pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
@@ -4022,23 +4354,6 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
                break;
        case HEADPHONE_OUT:
                codec_dbg(codec, "%s hp\n", __func__);
-               /* Headphone out config*/
-               switch (spec->quirk) {
-               case QUIRK_SBZ:
-                       ca0132_mmio_gpio_set(codec, 7, true);
-                       ca0132_mmio_gpio_set(codec, 4, true);
-                       ca0132_mmio_gpio_set(codec, 1, false);
-                       chipio_set_control_param(codec, 0x0D, 0x12);
-                       break;
-               case QUIRK_R3DI:
-                       chipio_set_control_param(codec, 0x0D, 0x21);
-                       r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
-                       break;
-               case QUIRK_R3D:
-                       chipio_set_control_param(codec, 0x0D, 0x21);
-                       ca0132_mmio_gpio_set(codec, 0x1, false);
-                       break;
-               }
 
                snd_hda_codec_write(codec, spec->out_pins[0], 0,
                        AC_VERB_SET_EAPD_BTLENABLE, 0x00);
@@ -4068,23 +4383,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
                break;
        case SURROUND_OUT:
                codec_dbg(codec, "%s surround\n", __func__);
-               /* Surround out config*/
-               switch (spec->quirk) {
-               case QUIRK_SBZ:
-                       ca0132_mmio_gpio_set(codec, 7, false);
-                       ca0132_mmio_gpio_set(codec, 4, true);
-                       ca0132_mmio_gpio_set(codec, 1, true);
-                       chipio_set_control_param(codec, 0x0D, 0x18);
-                       break;
-               case QUIRK_R3DI:
-                       chipio_set_control_param(codec, 0x0D, 0x24);
-                       r3di_gpio_out_set(codec, R3DI_LINE_OUT);
-                       break;
-               case QUIRK_R3D:
-                       ca0132_mmio_gpio_set(codec, 1, true);
-                       chipio_set_control_param(codec, 0x0D, 0x24);
-                       break;
-               }
+
                /* enable line out node */
                pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
                                AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -4109,14 +4408,21 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
                snd_hda_set_pin_ctl(codec, spec->out_pins[3],
                                    pin_ctl | PIN_OUT);
 
-               if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
-                       dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE);
-               else
-                       dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT);
+               dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT);
                break;
        }
+       /*
+        * Surround always sets it's scp command to req 0x04 to FLOAT_EIGHT.
+        * With this set though, X_BASS cannot be enabled. So, if we have OutFX
+        * enabled, we need to make sure X_BASS is off, otherwise everything
+        * sounds all muffled. Running ca0132_effects_set with X_BASS as the
+        * effect should sort this out.
+        */
+       if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
+               ca0132_effects_set(codec, X_BASS,
+                       spec->effects_switch[X_BASS - EFFECT_START_NID]);
 
-       /* run through the output dsp commands for line-out */
+       /* run through the output dsp commands for the selected output. */
        for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) {
                err = dspio_set_uint_param(codec,
                alt_out_presets[spec->cur_out_type].mids[i],
@@ -4153,7 +4459,6 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
 
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
 static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
-static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
 static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
 static int stop_mic1(struct hda_codec *codec);
 static int ca0132_cvoice_switch_set(struct hda_codec *codec);
@@ -4342,13 +4647,20 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                switch (spec->quirk) {
                case QUIRK_SBZ:
                case QUIRK_R3D:
-                       ca0132_mmio_gpio_set(codec, 0, false);
+                       ca0113_mmio_gpio_set(codec, 0, false);
+                       tmp = FLOAT_THREE;
+                       break;
+               case QUIRK_ZXR:
                        tmp = FLOAT_THREE;
                        break;
                case QUIRK_R3DI:
                        r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
                        tmp = FLOAT_ONE;
                        break;
+               case QUIRK_AE5:
+                       ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
+                       tmp = FLOAT_THREE;
+                       break;
                default:
                        tmp = FLOAT_ONE;
                        break;
@@ -4363,10 +4675,19 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
                chipio_set_stream_control(codec, 0x03, 1);
                chipio_set_stream_control(codec, 0x04, 1);
-
-               if (spec->quirk == QUIRK_SBZ) {
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x0000000C);
+                       break;
+               case QUIRK_ZXR:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x000000CC);
+                       break;
+               case QUIRK_AE5:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x0000004C);
+                       break;
                }
                ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
                break;
@@ -4375,11 +4696,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                switch (spec->quirk) {
                case QUIRK_SBZ:
                case QUIRK_R3D:
-                       ca0132_mmio_gpio_set(codec, 0, false);
+                       ca0113_mmio_gpio_set(codec, 0, false);
                        break;
                case QUIRK_R3DI:
                        r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
                        break;
+               case QUIRK_AE5:
+                       ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
+                       break;
                }
 
                chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
@@ -4390,11 +4714,13 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                tmp = FLOAT_ZERO;
                dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 
-               if (spec->quirk == QUIRK_SBZ) {
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
+               case QUIRK_AE5:
                        chipio_write(codec, 0x18B098, 0x00000000);
                        chipio_write(codec, 0x18B09C, 0x00000000);
+                       break;
                }
-
                chipio_set_stream_control(codec, 0x03, 1);
                chipio_set_stream_control(codec, 0x04, 1);
                break;
@@ -4402,14 +4728,18 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                switch (spec->quirk) {
                case QUIRK_SBZ:
                case QUIRK_R3D:
-                       ca0132_mmio_gpio_set(codec, 0, true);
-                       ca0132_mmio_gpio_set(codec, 5, false);
+                       ca0113_mmio_gpio_set(codec, 0, true);
+                       ca0113_mmio_gpio_set(codec, 5, false);
                        tmp = FLOAT_THREE;
                        break;
                case QUIRK_R3DI:
                        r3di_gpio_mic_set(codec, R3DI_FRONT_MIC);
                        tmp = FLOAT_ONE;
                        break;
+               case QUIRK_AE5:
+                       ca0113_mmio_command_set(codec, 0x48, 0x28, 0x3f);
+                       tmp = FLOAT_THREE;
+                       break;
                default:
                        tmp = FLOAT_ONE;
                        break;
@@ -4425,9 +4755,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                chipio_set_stream_control(codec, 0x03, 1);
                chipio_set_stream_control(codec, 0x04, 1);
 
-               if (spec->quirk == QUIRK_SBZ) {
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x000000CC);
+                       break;
+               case QUIRK_AE5:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x0000004C);
+                       break;
                }
                ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
                break;
@@ -4436,7 +4772,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
        snd_hda_power_down_pm(codec);
        return 0;
-
 }
 
 /*
@@ -4508,6 +4843,8 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                /* if PE if off, turn off out effects. */
                if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
                        val = 0;
+               if (spec->cur_out_type == SURROUND_OUT && nid == X_BASS)
+                       val = 0;
        }
 
        /* for in effect, qualify with CrystalVoice */
@@ -4521,7 +4858,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                        val = 0;
 
                /* If Voice Focus on SBZ, set to two channel. */
-               if ((nid == VOICE_FOCUS) && (spec->quirk == QUIRK_SBZ)
+               if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio)
                                && (spec->cur_mic_type != REAR_LINE_IN)) {
                        if (spec->effects_switch[CRYSTAL_VOICE -
                                                 EFFECT_START_NID]) {
@@ -4540,7 +4877,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                 * For SBZ noise reduction, there's an extra command
                 * to module ID 0x47. No clue why.
                 */
-               if ((nid == NOISE_REDUCTION) && (spec->quirk == QUIRK_SBZ)
+               if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio)
                                && (spec->cur_mic_type != REAR_LINE_IN)) {
                        if (spec->effects_switch[CRYSTAL_VOICE -
                                                 EFFECT_START_NID]) {
@@ -4679,6 +5016,27 @@ static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
        return ret;
 }
 
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val)
+{
+       unsigned int i;
+
+       for (i = 0; i < 4; i++)
+               ca0113_mmio_command_set(codec, 0x48, 0x11 + i,
+                               ae5_headphone_gain_presets[val].vals[i]);
+       return 0;
+}
+
+/*
+ * gpio pin 1 is a relay that switches on/off, apparently setting the headphone
+ * amplifier to handle a 600 ohm load.
+ */
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
+{
+       ca0113_mmio_gpio_set(codec, 1, val);
+
+       return 0;
+}
+
 static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
@@ -4943,66 +5301,172 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-
 /*
- * Input Select Control for alternative ca0132 codecs. This exists because
- * front microphone has no auto-detect, and we need a way to set the rear
- * as line-in
+ * Sound BlasterX AE-5 Headphone Gain Controls.
  */
-static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
+#define AE5_HEADPHONE_GAIN_MAX 3
+static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
 {
+       char *sfx = " Ohms)";
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
-       uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
-       if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
-               uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       in_src_str[uinfo->value.enumerated.item]);
+       uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
+       if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
+               uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
+       sprintf(namestr, "%s %s",
+               ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
+               sfx);
+       strcpy(uinfo->value.enumerated.name, namestr);
        return 0;
 }
 
-static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol,
+static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct ca0132_spec *spec = codec->spec;
 
-       ucontrol->value.enumerated.item[0] = spec->in_enum_val;
+       ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val;
        return 0;
 }
 
-static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol,
+static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct ca0132_spec *spec = codec->spec;
        int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = IN_SRC_NUM_OF_INPUTS;
+       unsigned int items = AE5_HEADPHONE_GAIN_MAX;
 
        if (sel >= items)
                return 0;
 
-       codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n",
-                   sel, in_src_str[sel]);
+       codec_dbg(codec, "ae5_headphone_gain: boost=%d\n",
+                   sel);
 
-       spec->in_enum_val = sel;
+       spec->ae5_headphone_gain_val = sel;
 
-       ca0132_alt_select_in(codec);
+       if (spec->out_enum_val == HEADPHONE_OUT)
+               ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val);
 
        return 1;
 }
 
-/* Sound Blaster Z Output Select Control */
-static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
+/*
+ * Sound BlasterX AE-5 sound filter enumerated control.
+ */
+#define AE5_SOUND_FILTER_MAX 3
+
+static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
 {
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
-       uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
-       if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
-               uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
-       strcpy(uinfo->value.enumerated.name,
+       uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
+       if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
+               uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
+       sprintf(namestr, "%s",
+                       ae5_filter_presets[uinfo->value.enumerated.item].name);
+       strcpy(uinfo->value.enumerated.name, namestr);
+       return 0;
+}
+
+static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->ae5_filter_val;
+       return 0;
+}
+
+static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = AE5_SOUND_FILTER_MAX;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ae5_sound_filter: %s\n",
+                       ae5_filter_presets[sel].name);
+
+       spec->ae5_filter_val = sel;
+
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07,
+                       ae5_filter_presets[sel].val);
+
+       return 1;
+}
+
+/*
+ * Input Select Control for alternative ca0132 codecs. This exists because
+ * front microphone has no auto-detect, and we need a way to set the rear
+ * as line-in
+ */
+static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
+       if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
+               uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       in_src_str[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->in_enum_val;
+       return 0;
+}
+
+static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = IN_SRC_NUM_OF_INPUTS;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n",
+                   sel, in_src_str[sel]);
+
+       spec->in_enum_val = sel;
+
+       ca0132_alt_select_in(codec);
+
+       return 1;
+}
+
+/* Sound Blaster Z Output Select Control */
+static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
+       if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
+               uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
+       strcpy(uinfo->value.enumerated.name,
                        alt_out_presets[uinfo->value.enumerated.item].name);
        return 0;
 }
@@ -5331,6 +5795,16 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
                goto exit;
        }
 
+       if (nid == ZXR_HEADPHONE_GAIN) {
+               spec->zxr_gain_set = *valp;
+               if (spec->cur_out_type == HEADPHONE_OUT)
+                       changed = zxr_headphone_gain_set(codec, *valp);
+               else
+                       changed = 0;
+
+               goto exit;
+       }
+
 exit:
        snd_hda_power_down(codec);
        return changed;
@@ -5705,6 +6179,50 @@ static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
 
 }
 
+/*
+ * Add headphone gain enumerated control for the AE-5. This switches between
+ * three modes, low, medium, and high. When non-headphone outputs are selected,
+ * it is automatically set to high. This is the same behavior as Windows.
+ */
+static int ae5_add_headphone_gain_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain",
+                                   AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ae5_headphone_gain_info;
+       knew.get = ae5_headphone_gain_get;
+       knew.put = ae5_headphone_gain_put;
+       return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add sound filter enumerated control for the AE-5. This adds three different
+ * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've
+ * read into it, it changes the DAC's interpolation filter.
+ */
+static int ae5_add_sound_filter_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("AE-5: Sound Filter",
+                                   AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ae5_sound_filter_info;
+       knew.get = ae5_sound_filter_get;
+       knew.put = ae5_sound_filter_put;
+       return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+static int zxr_add_headphone_gain_switch(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain",
+                                   ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT);
+
+       return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN,
+                               snd_ctl_new1(&knew, codec));
+}
+
 /*
  * Need to create slave controls for the alternate codecs that have surround
  * capabilities.
@@ -5848,7 +6366,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
                                            NULL, ca0132_alt_slave_pfxs,
                                            "Playback Switch",
                                            true, &spec->vmaster_mute.sw_kctl);
-
+               if (err < 0)
+                       return err;
        }
 
        /* Add in and out effects controls.
@@ -5856,8 +6375,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
         */
        num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
        for (i = 0; i < num_fx; i++) {
-               /* SBZ and R3D break if Echo Cancellation is used. */
-               if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) {
+               /* Desktop cards break if Echo Cancellation is used. */
+               if (spec->use_pci_mmio) {
                        if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
                                                OUT_EFFECTS_COUNT))
                                continue;
@@ -5875,8 +6394,14 @@ static int ca0132_build_controls(struct hda_codec *codec)
         * prefix, and change PlayEnhancement and CrystalVoice to match.
         */
        if (spec->use_alt_controls) {
-               ca0132_alt_add_svm_enum(codec);
-               add_ca0132_alt_eq_presets(codec);
+               err = ca0132_alt_add_svm_enum(codec);
+               if (err < 0)
+                       return err;
+
+               err = add_ca0132_alt_eq_presets(codec);
+               if (err < 0)
+                       return err;
+
                err = add_fx_switch(codec, PLAY_ENHANCEMENT,
                                        "Enable OutFX", 0);
                if (err < 0)
@@ -5913,7 +6438,9 @@ static int ca0132_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
-       add_voicefx(codec);
+       err = add_voicefx(codec);
+       if (err < 0)
+               return err;
 
        /*
         * If the codec uses alt_functions, you need the enumerated controls
@@ -5921,9 +6448,36 @@ static int ca0132_build_controls(struct hda_codec *codec)
         * setting control.
         */
        if (spec->use_alt_functions) {
-               ca0132_alt_add_output_enum(codec);
-               ca0132_alt_add_input_enum(codec);
-               ca0132_alt_add_mic_boost_enum(codec);
+               err = ca0132_alt_add_output_enum(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_mic_boost_enum(codec);
+               if (err < 0)
+                       return err;
+               /*
+                * ZxR only has microphone input, there is no front panel
+                * header on the card, and aux-in is handled by the DBPro board.
+                */
+               if (spec->quirk != QUIRK_ZXR) {
+                       err = ca0132_alt_add_input_enum(codec);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       if (spec->quirk == QUIRK_AE5) {
+               err = ae5_add_headphone_gain_enum(codec);
+               if (err < 0)
+                       return err;
+               err = ae5_add_sound_filter_enum(codec);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->quirk == QUIRK_ZXR) {
+               err = zxr_add_headphone_gain_switch(codec);
+               if (err < 0)
+                       return err;
        }
 #ifdef ENABLE_TUNING_CONTROLS
        add_tuning_ctls(codec);
@@ -5956,6 +6510,27 @@ static int ca0132_build_controls(struct hda_codec *codec)
        return 0;
 }
 
+static int dbpro_build_controls(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int err = 0;
+
+       if (spec->dig_out) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+                               spec->dig_out);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->dig_in) {
+               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
 /*
  * PCM
  */
@@ -6059,6 +6634,40 @@ static int ca0132_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
+static int dbpro_build_pcms(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct hda_pcm *info;
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog");
+       if (!info)
+               return -ENOMEM;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+
+
+       if (!spec->dig_out && !spec->dig_in)
+               return 0;
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+       if (!info)
+               return -ENOMEM;
+       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+       if (spec->dig_out) {
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                       ca0132_pcm_digital_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+       }
+       if (spec->dig_in) {
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       ca0132_pcm_digital_capture;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+       }
+
+       return 0;
+}
+
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 {
        if (pin) {
@@ -6239,69 +6848,48 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
 }
 
 /*
- * Recon3D r3d_setup_defaults sub functions.
+ * Creates a dummy stream to bind the output to. This seems to have to be done
+ * after changing the main outputs source and destination streams.
  */
-
-static void r3d_dsp_scp_startup(struct hda_codec *codec)
+static void ca0132_alt_create_dummy_stream(struct hda_codec *codec)
 {
-       unsigned int tmp;
-
-       tmp = 0x00000000;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
-
-       tmp = 0x00000001;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
-
-       tmp = 0x00000004;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-       tmp = 0x00000005;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-       tmp = 0x00000000;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-}
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int stream_format;
 
-static void r3d_dsp_initial_mic_setup(struct hda_codec *codec)
-{
-       unsigned int tmp;
+       stream_format = snd_hdac_calc_stream_format(48000, 2,
+                       SNDRV_PCM_FORMAT_S32_LE, 32, 0);
 
-       /* Mic 1 Setup */
-       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-       /* This ConnPointID is unique to Recon3Di. Haven't seen it elsewhere */
-       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-       tmp = FLOAT_ONE;
-       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+       snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
+                                       0, stream_format);
 
-       /* Mic 2 Setup, even though it isn't connected on SBZ */
-       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
-       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x80, 0x01, tmp);
+       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
 }
 
 /*
- * Initialize Sound Blaster Z analog microphones.
+ * Initialize mic for non-chromebook ca0132 implementations.
  */
-static void sbz_init_analog_mics(struct hda_codec *codec)
+static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
 {
+       struct ca0132_spec *spec = codec->spec;
        unsigned int tmp;
 
        /* Mic 1 Setup */
        chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
        chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-       tmp = FLOAT_THREE;
+       if (spec->quirk == QUIRK_R3DI) {
+               chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+               tmp = FLOAT_ONE;
+       } else
+               tmp = FLOAT_THREE;
        dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 
-       /* Mic 2 Setup, even though it isn't connected on SBZ */
+       /* Mic 2 setup (not present on desktop cards) */
        chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
        chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
+       if (spec->quirk == QUIRK_R3DI)
+               chipio_set_conn_rate(codec, 0x0F, SR_96_000);
        tmp = FLOAT_ZERO;
        dspio_set_uint_param(codec, 0x80, 0x01, tmp);
-
 }
 
 /*
@@ -6334,7 +6922,6 @@ static void sbz_connect_streams(struct hda_codec *codec)
        codec_dbg(codec, "Connect Streams exited, mutex released.\n");
 
        mutex_unlock(&spec->chipio_mutex);
-
 }
 
 /*
@@ -6361,19 +6948,29 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
        chipio_set_stream_channels(codec, 0x0C, 6);
        chipio_set_stream_control(codec, 0x0C, 1);
        /* No clue what these control */
-       chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
-       chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
-       chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
-       chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3);
-       chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4);
-       chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5);
-       chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6);
-       chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7);
-       chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8);
-       chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
-       chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
-       chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
-
+       if (spec->quirk == QUIRK_SBZ) {
+               chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
+               chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
+               chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
+               chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3);
+               chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4);
+               chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5);
+               chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6);
+               chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7);
+               chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8);
+               chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
+               chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
+               chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
+       } else if (spec->quirk == QUIRK_ZXR) {
+               chipio_write_no_mutex(codec, 0x190038, 0x000140c2);
+               chipio_write_no_mutex(codec, 0x19003c, 0x000141c3);
+               chipio_write_no_mutex(codec, 0x190040, 0x000150c4);
+               chipio_write_no_mutex(codec, 0x190044, 0x000151c5);
+               chipio_write_no_mutex(codec, 0x190050, 0x000142c8);
+               chipio_write_no_mutex(codec, 0x190054, 0x000143c9);
+               chipio_write_no_mutex(codec, 0x190058, 0x000152ca);
+               chipio_write_no_mutex(codec, 0x19005c, 0x000153cb);
+       }
        chipio_write_no_mutex(codec, 0x19042c, 0x00000001);
 
        codec_dbg(codec, "Startup Data exited, mutex released.\n");
@@ -6381,35 +6978,56 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
 }
 
 /*
- * Sound Blaster Z uses these after DSP is loaded. Weird SCP commands
- * without a 0x20 source like normal.
+ * Custom DSP SCP commands where the src value is 0x00 instead of 0x20. This is
+ * done after the DSP is loaded.
  */
-static void sbz_dsp_scp_startup(struct hda_codec *codec)
+static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
 {
-       unsigned int tmp;
-
-       tmp = 0x00000003;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-       tmp = 0x00000000;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
-
-       tmp = 0x00000001;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
-
-       tmp = 0x00000004;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-       tmp = 0x00000005;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-       tmp = 0x00000000;
-       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp, i;
 
+       /*
+        * Gotta run these twice, or else mic works inconsistently. Not clear
+        * why this is, but multiple tests have confirmed it.
+        */
+       for (i = 0; i < 2; i++) {
+               switch (spec->quirk) {
+               case QUIRK_SBZ:
+               case QUIRK_AE5:
+                       tmp = 0x00000003;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       tmp = 0x00000000;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
+                       tmp = 0x00000001;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
+                       tmp = 0x00000004;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       tmp = 0x00000005;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       tmp = 0x00000000;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       break;
+               case QUIRK_R3D:
+               case QUIRK_R3DI:
+                       tmp = 0x00000000;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
+                       tmp = 0x00000001;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
+                       tmp = 0x00000004;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       tmp = 0x00000005;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       tmp = 0x00000000;
+                       dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+                       break;
+               }
+               msleep(100);
+       }
 }
 
-static void sbz_dsp_initial_mic_setup(struct hda_codec *codec)
+static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
 {
+       struct ca0132_spec *spec = codec->spec;
        unsigned int tmp;
 
        chipio_set_stream_control(codec, 0x03, 0);
@@ -6424,17 +7042,170 @@ static void sbz_dsp_initial_mic_setup(struct hda_codec *codec)
        chipio_set_stream_control(codec, 0x03, 1);
        chipio_set_stream_control(codec, 0x04, 1);
 
-       chipio_write(codec, 0x18b098, 0x0000000c);
-       chipio_write(codec, 0x18b09C, 0x0000000c);
+       switch (spec->quirk) {
+       case QUIRK_SBZ:
+               chipio_write(codec, 0x18b098, 0x0000000c);
+               chipio_write(codec, 0x18b09C, 0x0000000c);
+               break;
+       case QUIRK_AE5:
+               chipio_write(codec, 0x18b098, 0x0000000c);
+               chipio_write(codec, 0x18b09c, 0x0000004c);
+               break;
+       }
 }
 
-/*
- * Setup default parameters for DSP
- */
-static void ca0132_setup_defaults(struct hda_codec *codec)
+static void ae5_post_dsp_register_set(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
+
+       chipio_8051_write_direct(codec, 0x93, 0x10);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2);
+
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f);
+       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+}
+
+static void ae5_post_dsp_param_setup(struct hda_codec *codec)
+{
+       /*
+        * Param3 in the 8051's memory is represented by the ascii string 'mch'
+        * which seems to be 'multichannel'. This is also mentioned in the
+        * AE-5's registry values in Windows.
+        */
+       chipio_set_control_param(codec, 3, 0);
+       /*
+        * I believe ASI is 'audio serial interface' and that it's used to
+        * change colors on the external LED strip connected to the AE-5.
+        */
+       chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_DATA_WRITE, 0x22);
+}
+
+static void ae5_post_dsp_pll_setup(struct hda_codec *codec)
+{
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x45);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcc);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x40);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcb);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x51);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0x8d);
+}
+
+static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
+
+       chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
+
+       chipio_set_stream_channels(codec, 0x0C, 6);
+       chipio_set_stream_control(codec, 0x0C, 1);
+
+       chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0);
+
+       chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0);
+       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
+       chipio_set_stream_channels(codec, 0x18, 6);
+       chipio_set_stream_control(codec, 0x18, 1);
+
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae5_post_dsp_startup_data(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
+       chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
+       chipio_write_no_mutex(codec, 0x189024, 0x00014004);
+       chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
+       ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12);
+       ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48);
+       ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+       ca0113_mmio_gpio_set(codec, 0, true);
+       ca0113_mmio_gpio_set(codec, 1, true);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80);
+
+       chipio_write_no_mutex(codec, 0x18b03c, 0x00000012);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+/*
+ * Setup default parameters for DSP
+ */
+static void ca0132_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
        int num_fx;
        int idx, i;
 
@@ -6486,9 +7257,8 @@ static void r3d_setup_defaults(struct hda_codec *codec)
        if (spec->dsp_state != DSP_DOWNLOADED)
                return;
 
-       r3d_dsp_scp_startup(codec);
-
-       r3d_dsp_initial_mic_setup(codec);
+       ca0132_alt_dsp_scp_startup(codec);
+       ca0132_alt_init_analog_mics(codec);
 
        /*remove DSP headroom*/
        tmp = FLOAT_ZERO;
@@ -6524,19 +7294,16 @@ static void r3d_setup_defaults(struct hda_codec *codec)
 static void sbz_setup_defaults(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp, stream_format;
+       unsigned int tmp;
        int num_fx;
        int idx, i;
 
        if (spec->dsp_state != DSP_DOWNLOADED)
                return;
 
-       sbz_dsp_scp_startup(codec);
-
-       sbz_init_analog_mics(codec);
-
+       ca0132_alt_dsp_scp_startup(codec);
+       ca0132_alt_init_analog_mics(codec);
        sbz_connect_streams(codec);
-
        sbz_chipio_startup_data(codec);
 
        chipio_set_stream_control(codec, 0x03, 1);
@@ -6562,8 +7329,7 @@ static void sbz_setup_defaults(struct hda_codec *codec)
        /* Set speaker source? */
        dspio_set_uint_param(codec, 0x32, 0x00, tmp);
 
-       sbz_dsp_initial_mic_setup(codec);
-
+       ca0132_alt_dsp_initial_mic_setup(codec);
 
        /* out, in effects + voicefx */
        num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
@@ -6576,23 +7342,74 @@ static void sbz_setup_defaults(struct hda_codec *codec)
                }
        }
 
-       /*
-        * Have to make a stream to bind the sound output to, otherwise
-        * you'll get dead audio. Before I did this, it would bind to an
-        * audio input, and would never work
-        */
-       stream_format = snd_hdac_calc_stream_format(48000, 2,
-                       SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+       ca0132_alt_create_dummy_stream(codec);
+}
 
-       snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
-                                       0, stream_format);
+/*
+ * Setup default parameters for the Sound BlasterX AE-5 DSP.
+ */
+static void ae5_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int num_fx;
+       int idx, i;
 
-       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return;
 
-       snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
-                                       0, stream_format);
+       ca0132_alt_dsp_scp_startup(codec);
+       ca0132_alt_init_analog_mics(codec);
+       chipio_set_stream_control(codec, 0x03, 1);
+       chipio_set_stream_control(codec, 0x04, 1);
 
-       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+       /* New, unknown SCP req's */
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+       dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
+       dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+
+       /* Internal loopback off */
+       tmp = FLOAT_ONE;
+       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
+       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
+
+       /*remove DSP headroom*/
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+       /* set WUH source */
+       tmp = FLOAT_TWO;
+       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+       /* Set speaker source? */
+       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+
+       ca0132_alt_dsp_initial_mic_setup(codec);
+       ae5_post_dsp_register_set(codec);
+       ae5_post_dsp_param_setup(codec);
+       ae5_post_dsp_pll_setup(codec);
+       ae5_post_dsp_stream_setup(codec);
+       ae5_post_dsp_startup_data(codec);
+
+       /* out, in effects + voicefx */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+       for (idx = 0; idx < num_fx; idx++) {
+               for (i = 0; i <= ca0132_effects[idx].params; i++) {
+                       dspio_set_uint_param(codec,
+                                       ca0132_effects[idx].mid,
+                                       ca0132_effects[idx].reqs[i],
+                                       ca0132_effects[idx].def_vals[i]);
+               }
+       }
+
+       ca0132_alt_create_dummy_stream(codec);
 }
 
 /*
@@ -6674,12 +7491,14 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
         */
        switch (spec->quirk) {
        case QUIRK_SBZ:
-               if (request_firmware(&fw_entry, SBZ_EFX_FILE,
+       case QUIRK_R3D:
+       case QUIRK_AE5:
+               if (request_firmware(&fw_entry, DESKTOP_EFX_FILE,
                                        codec->card->dev) != 0) {
-                       codec_dbg(codec, "SBZ alt firmware not detected. ");
+                       codec_dbg(codec, "Desktop firmware not found.");
                        spec->alt_firmware_present = false;
                } else {
-                       codec_dbg(codec, "Sound Blaster Z firmware selected.");
+                       codec_dbg(codec, "Desktop firmware selected.");
                        spec->alt_firmware_present = true;
                }
                break;
@@ -6922,6 +7741,14 @@ static void ca0132_init_chip(struct hda_codec *codec)
        spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
        spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
 
+       /*
+        * The ZxR doesn't have a front panel header, and it's line-in is on
+        * the daughter board. So, there is no input enum control, and we need
+        * to make sure that spec->in_enum_val is set properly.
+        */
+       if (spec->quirk == QUIRK_ZXR)
+               spec->in_enum_val = REAR_MIC;
+
 #ifdef ENABLE_TUNING_CONTROLS
        ca0132_init_tuning_defaults(codec);
 #endif
@@ -6949,11 +7776,11 @@ static void sbz_region2_exit(struct hda_codec *codec)
        for (i = 0; i < 8; i++)
                writeb(0xb3, spec->mem_base + 0x304);
 
-       ca0132_mmio_gpio_set(codec, 0, false);
-       ca0132_mmio_gpio_set(codec, 1, false);
-       ca0132_mmio_gpio_set(codec, 4, true);
-       ca0132_mmio_gpio_set(codec, 5, false);
-       ca0132_mmio_gpio_set(codec, 7, false);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 1, false);
+       ca0113_mmio_gpio_set(codec, 4, true);
+       ca0113_mmio_gpio_set(codec, 5, false);
+       ca0113_mmio_gpio_set(codec, 7, false);
 }
 
 static void sbz_set_pin_ctl_default(struct hda_codec *codec)
@@ -6996,6 +7823,16 @@ static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir,
                                AC_VERB_SET_GPIO_DATA, data);
 }
 
+static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec)
+{
+       hda_nid_t pins[7] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01};
+       unsigned int i;
+
+       for (i = 0; i < 7; i++)
+               snd_hda_codec_write(codec, pins[i], 0,
+                               AC_VERB_SET_POWER_STATE, 0x03);
+}
+
 static void sbz_exit_chip(struct hda_codec *codec)
 {
        chipio_set_stream_control(codec, 0x03, 0);
@@ -7038,6 +7875,61 @@ static void r3d_exit_chip(struct hda_codec *codec)
        snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
 }
 
+static void ae5_exit_chip(struct hda_codec *codec)
+{
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
+       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
+       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 1, false);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+       chipio_set_stream_control(codec, 0x18, 0);
+       chipio_set_stream_control(codec, 0x0c, 0);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83);
+}
+
+static void zxr_exit_chip(struct hda_codec *codec)
+{
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+       chipio_set_stream_control(codec, 0x14, 0);
+       chipio_set_stream_control(codec, 0x0C, 0);
+
+       chipio_set_conn_rate(codec, 0x41, SR_192_000);
+       chipio_set_conn_rate(codec, 0x91, SR_192_000);
+
+       chipio_write(codec, 0x18a020, 0x00000083);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+       ca0132_clear_unsolicited(codec);
+       sbz_set_pin_ctl_default(codec);
+       snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+
+       ca0113_mmio_gpio_set(codec, 5, false);
+       ca0113_mmio_gpio_set(codec, 2, false);
+       ca0113_mmio_gpio_set(codec, 3, false);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 4, true);
+       ca0113_mmio_gpio_set(codec, 0, true);
+       ca0113_mmio_gpio_set(codec, 5, true);
+       ca0113_mmio_gpio_set(codec, 2, false);
+       ca0113_mmio_gpio_set(codec, 3, false);
+}
+
 static void ca0132_exit_chip(struct hda_codec *codec)
 {
        /* put any chip cleanup stuffs here. */
@@ -7141,11 +8033,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
        writel(0x00820680, spec->mem_base + 0x01C);
        writel(0x00820680, spec->mem_base + 0x01C);
 
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
-
        chipio_write(codec, 0x18b0a4, 0x000000c2);
 
        snd_hda_codec_write(codec, 0x11, 0,
@@ -7154,12 +8041,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
 
 static void r3d_pre_dsp_setup(struct hda_codec *codec)
 {
-
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
-       snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
-
        chipio_write(codec, 0x18b0a4, 0x000000c2);
 
        snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
@@ -7206,23 +8087,116 @@ static void ca0132_mmio_init(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       writel(0x00000000, spec->mem_base + 0x400);
-       writel(0x00000000, spec->mem_base + 0x408);
-       writel(0x00000000, spec->mem_base + 0x40C);
-       writel(0x00880680, spec->mem_base + 0x01C);
-       writel(0x00000083, spec->mem_base + 0xC0C);
+       if (spec->quirk == QUIRK_AE5)
+               writel(0x00000001, spec->mem_base + 0x400);
+       else
+               writel(0x00000000, spec->mem_base + 0x400);
+
+       if (spec->quirk == QUIRK_AE5)
+               writel(0x00000001, spec->mem_base + 0x408);
+       else
+               writel(0x00000000, spec->mem_base + 0x408);
+
+       if (spec->quirk == QUIRK_AE5)
+               writel(0x00000001, spec->mem_base + 0x40c);
+       else
+               writel(0x00000000, spec->mem_base + 0x40C);
+
+       if (spec->quirk == QUIRK_ZXR)
+               writel(0x00880640, spec->mem_base + 0x01C);
+       else
+               writel(0x00880680, spec->mem_base + 0x01C);
+
+       if (spec->quirk == QUIRK_AE5)
+               writel(0x00000080, spec->mem_base + 0xC0C);
+       else
+               writel(0x00000083, spec->mem_base + 0xC0C);
+
        writel(0x00000030, spec->mem_base + 0xC00);
        writel(0x00000000, spec->mem_base + 0xC04);
+
+       if (spec->quirk == QUIRK_AE5)
+               writel(0x00000000, spec->mem_base + 0xC0C);
+       else
+               writel(0x00000003, spec->mem_base + 0xC0C);
+
        writel(0x00000003, spec->mem_base + 0xC0C);
        writel(0x00000003, spec->mem_base + 0xC0C);
        writel(0x00000003, spec->mem_base + 0xC0C);
-       writel(0x00000003, spec->mem_base + 0xC0C);
-       writel(0x000000C1, spec->mem_base + 0xC08);
+
+       if (spec->quirk == QUIRK_AE5)
+               writel(0x00000001, spec->mem_base + 0xC08);
+       else
+               writel(0x000000C1, spec->mem_base + 0xC08);
+
        writel(0x000000F1, spec->mem_base + 0xC08);
        writel(0x00000001, spec->mem_base + 0xC08);
        writel(0x000000C7, spec->mem_base + 0xC08);
        writel(0x000000C1, spec->mem_base + 0xC08);
        writel(0x00000080, spec->mem_base + 0xC04);
+
+       if (spec->quirk == QUIRK_AE5) {
+               writel(0x00000000, spec->mem_base + 0x42c);
+               writel(0x00000000, spec->mem_base + 0x46c);
+               writel(0x00000000, spec->mem_base + 0x4ac);
+               writel(0x00000000, spec->mem_base + 0x4ec);
+               writel(0x00000000, spec->mem_base + 0x43c);
+               writel(0x00000000, spec->mem_base + 0x47c);
+               writel(0x00000000, spec->mem_base + 0x4bc);
+               writel(0x00000000, spec->mem_base + 0x4fc);
+               writel(0x00000600, spec->mem_base + 0x100);
+               writel(0x00000014, spec->mem_base + 0x410);
+               writel(0x0000060f, spec->mem_base + 0x100);
+               writel(0x0000070f, spec->mem_base + 0x100);
+               writel(0x00000aff, spec->mem_base + 0x830);
+               writel(0x00000000, spec->mem_base + 0x86c);
+               writel(0x0000006b, spec->mem_base + 0x800);
+               writel(0x00000001, spec->mem_base + 0x86c);
+               writel(0x0000006b, spec->mem_base + 0x800);
+               writel(0x00000057, spec->mem_base + 0x804);
+               writel(0x00800000, spec->mem_base + 0x20c);
+       }
+}
+
+/*
+ * This function writes to some SFR's, does some region2 writes, and then
+ * eventually resets the codec with the 0x7ff verb. Not quite sure why it does
+ * what it does.
+ */
+static void ae5_register_set(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       chipio_8051_write_direct(codec, 0x93, 0x10);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2);
+
+       writeb(0x0f, spec->mem_base + 0x304);
+       writeb(0x0f, spec->mem_base + 0x304);
+       writeb(0x0f, spec->mem_base + 0x304);
+       writeb(0x0f, spec->mem_base + 0x304);
+       writeb(0x0e, spec->mem_base + 0x100);
+       writeb(0x1f, spec->mem_base + 0x304);
+       writeb(0x0c, spec->mem_base + 0x100);
+       writeb(0x3f, spec->mem_base + 0x304);
+       writeb(0x08, spec->mem_base + 0x100);
+       writeb(0x7f, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+
+       chipio_8051_write_direct(codec, 0x90, 0x00);
+       chipio_8051_write_direct(codec, 0x90, 0x10);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+
+       chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00);
 }
 
 /*
@@ -7258,6 +8232,21 @@ static void ca0132_alt_init(struct hda_codec *codec)
                snd_hda_sequence_write(codec, spec->chip_init_verbs);
                snd_hda_sequence_write(codec, spec->desktop_init_verbs);
                break;
+       case QUIRK_AE5:
+               ca0132_gpio_init(codec);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                               VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                               VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88);
+               chipio_write(codec, 0x18b030, 0x00000020);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+               break;
+       case QUIRK_ZXR:
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               break;
        }
 }
 
@@ -7299,6 +8288,9 @@ static int ca0132_init(struct hda_codec *codec)
 
        snd_hda_power_up_pm(codec);
 
+       if (spec->quirk == QUIRK_AE5)
+               ae5_register_set(codec);
+
        ca0132_init_unsol(codec);
        ca0132_init_params(codec);
        ca0132_init_flags(codec);
@@ -7318,8 +8310,12 @@ static int ca0132_init(struct hda_codec *codec)
                r3d_setup_defaults(codec);
                break;
        case QUIRK_SBZ:
+       case QUIRK_ZXR:
                sbz_setup_defaults(codec);
                break;
+       case QUIRK_AE5:
+               ae5_setup_defaults(codec);
+               break;
        default:
                ca0132_setup_defaults(codec);
                ca0132_init_analog_mic2(codec);
@@ -7373,6 +8369,21 @@ static int ca0132_init(struct hda_codec *codec)
        return 0;
 }
 
+static int dbpro_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int i;
+
+       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+       init_input(codec, cfg->dig_in_pin, spec->dig_in);
+
+       for (i = 0; i < spec->num_inputs; i++)
+               init_input(codec, spec->input_pins[i], spec->adcs[i]);
+
+       return 0;
+}
+
 static void ca0132_free(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
@@ -7383,9 +8394,15 @@ static void ca0132_free(struct hda_codec *codec)
        case QUIRK_SBZ:
                sbz_exit_chip(codec);
                break;
+       case QUIRK_ZXR:
+               zxr_exit_chip(codec);
+               break;
        case QUIRK_R3D:
                r3d_exit_chip(codec);
                break;
+       case QUIRK_AE5:
+               ae5_exit_chip(codec);
+               break;
        case QUIRK_R3DI:
                r3di_gpio_shutdown(codec);
                break;
@@ -7401,6 +8418,16 @@ static void ca0132_free(struct hda_codec *codec)
        kfree(codec->spec);
 }
 
+static void dbpro_free(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       zxr_dbpro_power_state_shutdown(codec);
+
+       kfree(spec->spec_init_verbs);
+       kfree(codec->spec);
+}
+
 static void ca0132_reboot_notify(struct hda_codec *codec)
 {
        codec->patch_ops.free(codec);
@@ -7415,6 +8442,13 @@ static const struct hda_codec_ops ca0132_patch_ops = {
        .reboot_notify = ca0132_reboot_notify,
 };
 
+static const struct hda_codec_ops dbpro_patch_ops = {
+       .build_controls = dbpro_build_controls,
+       .build_pcms = dbpro_build_pcms,
+       .init = dbpro_init,
+       .free = dbpro_free,
+};
+
 static void ca0132_config(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
@@ -7433,9 +8467,33 @@ static void ca0132_config(struct hda_codec *codec)
 
        switch (spec->quirk) {
        case QUIRK_ALIENWARE:
-               codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n");
+               codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
                snd_hda_apply_pincfgs(codec, alienware_pincfgs);
+               break;
+       case QUIRK_SBZ:
+               codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, sbz_pincfgs);
+               break;
+       case QUIRK_ZXR:
+               codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, zxr_pincfgs);
+               break;
+       case QUIRK_R3D:
+               codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, r3d_pincfgs);
+               break;
+       case QUIRK_R3DI:
+               codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+               break;
+       case QUIRK_AE5:
+               codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+               break;
+       }
 
+       switch (spec->quirk) {
+       case QUIRK_ALIENWARE:
                spec->num_outputs = 2;
                spec->out_pins[0] = 0x0b; /* speaker out */
                spec->out_pins[1] = 0x0f;
@@ -7455,15 +8513,6 @@ static void ca0132_config(struct hda_codec *codec)
                break;
        case QUIRK_SBZ:
        case QUIRK_R3D:
-               if (spec->quirk == QUIRK_SBZ) {
-                       codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
-                       snd_hda_apply_pincfgs(codec, sbz_pincfgs);
-               }
-               if (spec->quirk == QUIRK_R3D) {
-                       codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
-                       snd_hda_apply_pincfgs(codec, r3d_pincfgs);
-               }
-
                spec->num_outputs = 2;
                spec->out_pins[0] = 0x0B; /* Line out */
                spec->out_pins[1] = 0x0F; /* Rear headphone out */
@@ -7488,10 +8537,62 @@ static void ca0132_config(struct hda_codec *codec)
                spec->multiout.dig_out_nid = spec->dig_out;
                spec->dig_in = 0x09;
                break;
-       case QUIRK_R3DI:
-               codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+       case QUIRK_ZXR:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0B; /* Line out */
+               spec->out_pins[1] = 0x0F; /* Rear headphone out */
+               spec->out_pins[2] = 0x10; /* Center/LFE */
+               spec->out_pins[3] = 0x11; /* Rear surround */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+               spec->unsol_tag_front_hp = spec->out_pins[2];
 
+               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+               spec->adcs[1] = 0x8; /* Not connected, no front mic */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 2;
+               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+               spec->input_pins[1] = 0x13; /* What U Hear */
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+               break;
+       case QUIRK_ZXR_DBPRO:
+               spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */
+
+               spec->num_inputs = 1;
+               spec->input_pins[0] = 0x11; /* RCA Line-in */
+
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+
+               spec->dig_in = 0x09;
+               break;
+       case QUIRK_AE5:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0B; /* Line out */
+               spec->out_pins[1] = 0x11; /* Rear headphone out */
+               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
+               spec->out_pins[3] = 0x0F; /* Rear surround */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+               spec->unsol_tag_front_hp = spec->out_pins[2];
+
+               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+               spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 2;
+               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+               spec->input_pins[1] = 0x13; /* What U Hear */
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+
+               /* SPDIF I/O */
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+               break;
+       case QUIRK_R3DI:
                spec->num_outputs = 2;
                spec->out_pins[0] = 0x0B; /* Line out */
                spec->out_pins[1] = 0x0F; /* Rear headphone out */
@@ -7548,7 +8649,11 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
        struct ca0132_spec *spec = codec->spec;
 
        spec->chip_init_verbs = ca0132_init_verbs0;
-       if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D)
+       /*
+        * Since desktop cards use pci_mmio, this can be used to determine
+        * whether or not to use these verbs instead of a separate bool.
+        */
+       if (spec->use_pci_mmio)
                spec->desktop_init_verbs = ca0132_init_verbs1;
        spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
                                        sizeof(struct hda_verb),
@@ -7580,6 +8685,29 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular
+ * Sound Blaster Z cards. However, they have different HDA codec subsystem
+ * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro
+ * daughter boards ID.
+ */
+static void sbz_detect_quirk(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       switch (codec->core.subsystem_id) {
+       case 0x11020033:
+               spec->quirk = QUIRK_ZXR;
+               break;
+       case 0x1102003f:
+               spec->quirk = QUIRK_ZXR_DBPRO;
+               break;
+       default:
+               spec->quirk = QUIRK_SBZ;
+               break;
+       }
+}
+
 static int patch_ca0132(struct hda_codec *codec)
 {
        struct ca0132_spec *spec;
@@ -7594,10 +8722,6 @@ static int patch_ca0132(struct hda_codec *codec)
        codec->spec = spec;
        spec->codec = codec;
 
-       codec->patch_ops = ca0132_patch_ops;
-       codec->pcm_format_first = 1;
-       codec->no_sticky_stream = 1;
-
        /* Detect codec quirk */
        quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
        if (quirk)
@@ -7605,6 +8729,18 @@ static int patch_ca0132(struct hda_codec *codec)
        else
                spec->quirk = QUIRK_NONE;
 
+       if (spec->quirk == QUIRK_SBZ)
+               sbz_detect_quirk(codec);
+
+       if (spec->quirk == QUIRK_ZXR_DBPRO)
+               codec->patch_ops = dbpro_patch_ops;
+       else
+               codec->patch_ops = ca0132_patch_ops;
+
+       codec->pcm_format_first = 1;
+       codec->no_sticky_stream = 1;
+
+
        spec->dsp_state = DSP_DOWNLOAD_INIT;
        spec->num_mixers = 1;
 
@@ -7614,6 +8750,12 @@ static int patch_ca0132(struct hda_codec *codec)
                spec->mixers[0] = desktop_mixer;
                snd_hda_codec_set_name(codec, "Sound Blaster Z");
                break;
+       case QUIRK_ZXR:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Sound Blaster ZxR");
+               break;
+       case QUIRK_ZXR_DBPRO:
+               break;
        case QUIRK_R3D:
                spec->mixers[0] = desktop_mixer;
                snd_hda_codec_set_name(codec, "Recon3D");
@@ -7622,6 +8764,10 @@ static int patch_ca0132(struct hda_codec *codec)
                spec->mixers[0] = r3di_mixer;
                snd_hda_codec_set_name(codec, "Recon3Di");
                break;
+       case QUIRK_AE5:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Sound BlasterX AE-5");
+               break;
        default:
                spec->mixers[0] = ca0132_mixer;
                break;
@@ -7631,6 +8777,8 @@ static int patch_ca0132(struct hda_codec *codec)
        switch (spec->quirk) {
        case QUIRK_SBZ:
        case QUIRK_R3D:
+       case QUIRK_AE5:
+       case QUIRK_ZXR:
                spec->use_alt_controls = true;
                spec->use_alt_functions = true;
                spec->use_pci_mmio = true;
index 5592557fe50e4edc34da074663b5640ce6874ed0..950e02e717669a7b80ba774ff9d250b9bbb9940e 100644 (file)
@@ -943,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
+       SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
index 69283633ae9108e96e98dfbc4fc244a75d326a9f..fa61674a560504224b9ee8ef35da2d4ddf85c6fe 100644 (file)
@@ -6841,6 +6841,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x1a, 0x02a11040},
                {0x1b, 0x01014020},
                {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+               {0x14, 0x90170110},
+               {0x19, 0x02a11030},
+               {0x1a, 0x02a11040},
+               {0x1b, 0x01011020},
+               {0x21, 0x0221101f}),
        SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
                {0x14, 0x90170110},
                {0x19, 0x02a11020},
@@ -7738,6 +7744,8 @@ enum {
        ALC662_FIXUP_ASUS_Nx50,
        ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
        ALC668_FIXUP_ASUS_Nx51,
+       ALC668_FIXUP_MIC_COEF,
+       ALC668_FIXUP_ASUS_G751,
        ALC891_FIXUP_HEADSET_MODE,
        ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
        ALC662_FIXUP_ACER_VERITON,
@@ -8007,6 +8015,23 @@ static const struct hda_fixup alc662_fixups[] = {
                .chained = true,
                .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
        },
+       [ALC668_FIXUP_MIC_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
+                       {}
+               },
+       },
+       [ALC668_FIXUP_ASUS_G751] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x0421101f }, /* HP */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC668_FIXUP_MIC_COEF
+       },
        [ALC891_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode,
@@ -8080,6 +8105,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
        SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
        SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
+       SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
        SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
        SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
        SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
@@ -8184,6 +8210,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
        {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
        {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
        {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+       {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
        {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
        {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
        {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
index d16a25a395c95c501f0707032678c5038a3ee5e5..1b6ecfb01759a8b398d3a5a7676e3707b9316927 100644 (file)
@@ -77,6 +77,7 @@ enum {
        STAC_DELL_M6_BOTH,
        STAC_DELL_EQ,
        STAC_ALIENWARE_M17X,
+       STAC_ELO_VUPOINT_15MX,
        STAC_92HD89XX_HP_FRONT_JACK,
        STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
        STAC_92HD73XX_ASUS_MOBO,
@@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
                codec->no_jack_detect = 1;
 }
 
+
+static void stac92hd73xx_disable_automute(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       spec->gen.suppress_auto_mute = 1;
+}
+
 static const struct hda_fixup stac92hd73xx_fixups[] = {
        [STAC_92HD73XX_REF] = {
                .type = HDA_FIXUP_FUNC,
@@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = stac92hd73xx_fixup_alienware_m17x,
        },
+       [STAC_ELO_VUPOINT_15MX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_disable_automute,
+       },
        [STAC_92HD73XX_INTEL] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = intel_dg45id_pin_configs,
@@ -1942,6 +1959,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
        { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
        { .id = STAC_DELL_EQ, .name = "dell-eq" },
        { .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+       { .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
        { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
        {}
 };
@@ -1991,6 +2009,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
                      "Alienware M17x", STAC_ALIENWARE_M17X),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
                      "Alienware M17x R3", STAC_DELL_EQ),
+       SND_PCI_QUIRK(0x1059, 0x1011,
+                     "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
                                "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
index 5ee468d1aefe7ed970672defae281bc69b0a47c3..ffddcdfe0c6688efa4a027cc702cea82aa8876c6 100644 (file)
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/initval.h>
-/* for 440MX workaround */
-#include <asm/pgtable.h>
-#ifdef CONFIG_X86
-#include <asm/set_memory.h>
-#endif
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
@@ -374,7 +369,6 @@ struct ichdev {
        unsigned int ali_slot;                  /* ALI DMA slot */
        struct ac97_pcm *pcm;
        int pcm_open_flag;
-       unsigned int page_attr_changed: 1;
        unsigned int suspended: 1;
 };
 
@@ -724,25 +718,6 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
        iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
 }
 
-#ifdef __i386__
-/*
- * Intel 82443MX running a 100MHz processor system bus has a hardware bug,
- * which aborts PCI busmaster for audio transfer.  A workaround is to set
- * the pages as non-cached.  For details, see the errata in
- *     http://download.intel.com/design/chipsets/specupdt/24505108.pdf
- */
-static void fill_nocache(void *buf, int size, int nocache)
-{
-       size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       if (nocache)
-               set_pages_uc(virt_to_page(buf), size);
-       else
-               set_pages_wb(virt_to_page(buf), size);
-}
-#else
-#define fill_nocache(buf, size, nocache) do { ; } while (0)
-#endif
-
 /*
  *  Interrupt handler
  */
@@ -850,7 +825,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_RESUME:
                ichdev->suspended = 0;
-               /* fallthru */
+               /* fall through */
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                val = ICH_IOCE | ICH_STARTBM;
@@ -858,7 +833,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
                ichdev->suspended = 1;
-               /* fallthru */
+               /* fall through */
        case SNDRV_PCM_TRIGGER_STOP:
                val = 0;
                break;
@@ -892,7 +867,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_RESUME:
                ichdev->suspended = 0;
-               /* fallthru */
+               /* fall through */
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -909,7 +884,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
                ichdev->suspended = 1;
-               /* fallthru */
+               /* fall through */
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                /* pause */
@@ -938,23 +913,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
 {
        struct intel8x0 *chip = snd_pcm_substream_chip(substream);
        struct ichdev *ichdev = get_ichdev(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int dbl = params_rate(hw_params) > 48000;
        int err;
 
-       if (chip->fix_nocache && ichdev->page_attr_changed) {
-               fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */
-               ichdev->page_attr_changed = 0;
-       }
        err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
        if (err < 0)
                return err;
-       if (chip->fix_nocache) {
-               if (runtime->dma_area && ! ichdev->page_attr_changed) {
-                       fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
-                       ichdev->page_attr_changed = 1;
-               }
-       }
        if (ichdev->pcm_open_flag) {
                snd_ac97_pcm_close(ichdev->pcm);
                ichdev->pcm_open_flag = 0;
@@ -974,17 +938,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
 
 static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
 {
-       struct intel8x0 *chip = snd_pcm_substream_chip(substream);
        struct ichdev *ichdev = get_ichdev(substream);
 
        if (ichdev->pcm_open_flag) {
                snd_ac97_pcm_close(ichdev->pcm);
                ichdev->pcm_open_flag = 0;
        }
-       if (chip->fix_nocache && ichdev->page_attr_changed) {
-               fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0);
-               ichdev->page_attr_changed = 0;
-       }
        return snd_pcm_lib_free_pages(substream);
 }
 
@@ -1510,6 +1469,9 @@ struct ich_pcm_table {
        int ac97_idx;
 };
 
+#define intel8x0_dma_type(chip) \
+       ((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV)
+
 static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
                             struct ich_pcm_table *rec)
 {
@@ -1540,7 +1502,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
                strcpy(pcm->name, chip->card->shortname);
        chip->pcm[device] = pcm;
 
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+       snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip),
                                              snd_dma_pci_data(chip->pci),
                                              rec->prealloc_size, rec->prealloc_max_size);
 
@@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
       __hw_end:
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       if (chip->bdbars.area) {
-               if (chip->fix_nocache)
-                       fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
+       if (chip->bdbars.area)
                snd_dma_free_pages(&chip->bdbars);
-       }
        if (chip->addr)
                pci_iounmap(chip->pci, chip->addr);
        if (chip->bmaddr)
@@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev)
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        for (i = 0; i < chip->pcm_devs; i++)
                snd_pcm_suspend_all(chip->pcm[i]);
-       /* clear nocache */
-       if (chip->fix_nocache) {
-               for (i = 0; i < chip->bdbars_count; i++) {
-                       struct ichdev *ichdev = &chip->ichd[i];
-                       if (ichdev->substream && ichdev->page_attr_changed) {
-                               struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
-                               if (runtime->dma_area)
-                                       fill_nocache(runtime->dma_area, runtime->dma_bytes, 0);
-                       }
-               }
-       }
        for (i = 0; i < chip->ncodecs; i++)
                snd_ac97_suspend(chip->ac97[i]);
        if (chip->device_type == DEVICE_INTEL_ICH4)
@@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev)
                          ICH_PCM_SPDIF_1011);
        }
 
-       /* refill nocache */
-       if (chip->fix_nocache)
-               fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
-
        for (i = 0; i < chip->ncodecs; i++)
                snd_ac97_resume(chip->ac97[i]);
 
-       /* refill nocache */
-       if (chip->fix_nocache) {
-               for (i = 0; i < chip->bdbars_count; i++) {
-                       struct ichdev *ichdev = &chip->ichd[i];
-                       if (ichdev->substream && ichdev->page_attr_changed) {
-                               struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
-                               if (runtime->dma_area)
-                                       fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
-                       }
-               }
-       }
-
        /* resume status */
        for (i = 0; i < chip->bdbars_count; i++) {
                struct ichdev *ichdev = &chip->ichd[i];
@@ -3057,6 +2989,12 @@ static int snd_intel8x0_create(struct snd_card *card,
 
        chip->inside_vm = snd_intel8x0_inside_vm(pci);
 
+       /*
+        * Intel 82443MX running a 100MHz processor system bus has a hardware
+        * bug, which aborts PCI busmaster for audio transfer.  A workaround
+        * is to set the pages as non-cached.  For details, see the errata in
+        *     http://download.intel.com/design/chipsets/specupdt/24505108.pdf
+        */
        if (pci->vendor == PCI_VENDOR_ID_INTEL &&
            pci->device == PCI_DEVICE_ID_INTEL_440MX)
                chip->fix_nocache = 1; /* enable workaround */
@@ -3128,7 +3066,7 @@ static int snd_intel8x0_create(struct snd_card *card,
 
        /* allocate buffer descriptor lists */
        /* the start of each lists must be aligned to 8 bytes */
-       if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+       if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci),
                                chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
                                &chip->bdbars) < 0) {
                snd_intel8x0_free(chip);
@@ -3137,9 +3075,6 @@ static int snd_intel8x0_create(struct snd_card *card,
        }
        /* tables must be aligned to 8 bytes here, but the kernel pages
           are much bigger, so we don't care (on i386) */
-       /* workaround for 440MX */
-       if (chip->fix_nocache)
-               fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
        int_sta_masks = 0;
        for (i = 0; i < chip->bdbars_count; i++) {
                ichdev = &chip->ichd[i];
index 943a726b1c1b066bc2339d1e410b5af154473309..c84629190cbaf72fecb4769b5fd596a25fce1fbc 100644 (file)
@@ -1171,16 +1171,6 @@ static int snd_intel8x0m_create(struct snd_card *card,
        }
 
  port_inited:
-       if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, chip)) {
-               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
-               snd_intel8x0m_free(chip);
-               return -EBUSY;
-       }
-       chip->irq = pci->irq;
-       pci_set_master(pci);
-       synchronize_irq(chip->irq);
-
        /* initialize offsets */
        chip->bdbars_count = 2;
        tbl = intel_regs;
@@ -1224,11 +1214,21 @@ static int snd_intel8x0m_create(struct snd_card *card,
        chip->int_sta_reg = ICH_REG_GLOB_STA;
        chip->int_sta_mask = int_sta_masks;
 
+       pci_set_master(pci);
+
        if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
                snd_intel8x0m_free(chip);
                return err;
        }
 
+       if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
+                       KBUILD_MODNAME, chip)) {
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
+               snd_intel8x0m_free(chip);
+               return -EBUSY;
+       }
+       chip->irq = pci->irq;
+
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
                snd_intel8x0m_free(chip);
                return err;
index f0906ba416d42f3330d40f796c368ce6e9b5f82b..3ac8c71d567c8758070cb3d8f8734335ad75180b 100644 (file)
@@ -319,7 +319,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_info = {
                         SNDRV_PCM_INFO_MMAP_VALID |
                         SNDRV_PCM_INFO_INTERLEAVED | 
                         SNDRV_PCM_INFO_PAUSE |
-                        SNDRV_PCM_INFO_SYNC_START),
+                        SNDRV_PCM_INFO_SYNC_START |
+                        SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats =      (SNDRV_PCM_FMTBIT_S16_LE | 
                         SNDRV_PCM_FMTBIT_S32_LE),
        .rates =        (SNDRV_PCM_RATE_32000 |
@@ -346,7 +347,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_info =
                              SNDRV_PCM_INFO_MMAP_VALID |
                              SNDRV_PCM_INFO_INTERLEAVED |
                              SNDRV_PCM_INFO_PAUSE |
-                             SNDRV_PCM_INFO_SYNC_START),
+                             SNDRV_PCM_INFO_SYNC_START |
+                             SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats=            SNDRV_PCM_FMTBIT_S16_LE,
        .rates =             (SNDRV_PCM_RATE_44100 | 
                              SNDRV_PCM_RATE_48000),
@@ -370,7 +372,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_fd_info = {
                         SNDRV_PCM_INFO_MMAP_VALID |
                         SNDRV_PCM_INFO_INTERLEAVED | 
                         SNDRV_PCM_INFO_PAUSE |
-                        SNDRV_PCM_INFO_SYNC_START),
+                        SNDRV_PCM_INFO_SYNC_START |
+                        SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats =      (SNDRV_PCM_FMTBIT_S16_LE | 
                         SNDRV_PCM_FMTBIT_S32_LE),
        .rates =        (SNDRV_PCM_RATE_32000 |
@@ -397,7 +400,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_fd_info =
                              SNDRV_PCM_INFO_MMAP_VALID |
                              SNDRV_PCM_INFO_INTERLEAVED |
                              SNDRV_PCM_INFO_PAUSE |
-                             SNDRV_PCM_INFO_SYNC_START),
+                             SNDRV_PCM_INFO_SYNC_START |
+                             SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats=            SNDRV_PCM_FMTBIT_S16_LE,
        .rates =             (SNDRV_PCM_RATE_44100 | 
                              SNDRV_PCM_RATE_48000),
@@ -1104,16 +1108,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                snd_pcm_trigger_done(s, substream);
        }
        
-       /* prefill playback buffer */
-       if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) {
-               snd_pcm_group_for_each_entry(s, substream) {
-                       if (s == rme32->playback_substream) {
-                               s->ops->ack(s);
-                               break;
-                       }
-               }
-       }
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                if (rme32->running && ! RME32_ISWORKING(rme32))
index 11b5b5e0e0580fd3a3d33cf99dd71728db1bdd3a..679ad0415e3b30461b53ce08e22dfd48b0f4a27d 100644 (file)
@@ -6534,7 +6534,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
        dev_dbg(card->dev, "Update mixer controls...\n");
        hdspm_update_simple_mixer_controls(hdspm);
 
-       dev_dbg(card->dev, "Initializeing complete ???\n");
+       dev_dbg(card->dev, "Initializing complete?\n");
 
        err = snd_card_register(card);
        if (err < 0) {
index d55ca48de3ea3ae7b8c04fad5b3c288e76d7ae27..f4a72e39ffa97239ea627b99e2c0b30b6ad7478e 100644 (file)
@@ -200,6 +200,7 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb)
                        break;
                }
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
+               /* fall through */
        case EP1_CMD_READ_ERP:
        case EP1_CMD_READ_ANALOG:
                snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length);
index dcfc546d81b924f455172e32557db3140880d5e1..b737f0ec77d090bf4abc5f87e388941912b3deb6 100644 (file)
@@ -1175,8 +1175,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
                if (port->ep->umidi->disconnected) {
                        /* gobble up remaining bytes to prevent wait in
                         * snd_rawmidi_drain_output */
-                       while (!snd_rawmidi_transmit_empty(substream))
-                               snd_rawmidi_transmit_ack(substream, 1);
+                       snd_rawmidi_proceed(substream);
                        return;
                }
                tasklet_schedule(&port->ep->tasklet);
index cbfb48bdea51d8b7dcd680f607f343f0e5535247..85ae0ff2382a28433f3d30bfc69e490e654438d9 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/hid.h>
 #include <linux/init.h>
+#include <linux/math64.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
@@ -1817,6 +1818,380 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
        return 0;
 }
 
+/* RME Class Compliant device quirks */
+
+#define SND_RME_GET_STATUS1                    23
+#define SND_RME_GET_CURRENT_FREQ               17
+#define SND_RME_CLK_SYSTEM_SHIFT               16
+#define SND_RME_CLK_SYSTEM_MASK                        0x1f
+#define SND_RME_CLK_AES_SHIFT                  8
+#define SND_RME_CLK_SPDIF_SHIFT                        12
+#define SND_RME_CLK_AES_SPDIF_MASK             0xf
+#define SND_RME_CLK_SYNC_SHIFT                 6
+#define SND_RME_CLK_SYNC_MASK                  0x3
+#define SND_RME_CLK_FREQMUL_SHIFT              18
+#define SND_RME_CLK_FREQMUL_MASK               0x7
+#define SND_RME_CLK_SYSTEM(x) \
+       ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK)
+#define SND_RME_CLK_AES(x) \
+       ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK)
+#define SND_RME_CLK_SPDIF(x) \
+       ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK)
+#define SND_RME_CLK_SYNC(x) \
+       ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK)
+#define SND_RME_CLK_FREQMUL(x) \
+       ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK)
+#define SND_RME_CLK_AES_LOCK                   0x1
+#define SND_RME_CLK_AES_SYNC                   0x4
+#define SND_RME_CLK_SPDIF_LOCK                 0x2
+#define SND_RME_CLK_SPDIF_SYNC                 0x8
+#define SND_RME_SPDIF_IF_SHIFT                 4
+#define SND_RME_SPDIF_FORMAT_SHIFT             5
+#define SND_RME_BINARY_MASK                    0x1
+#define SND_RME_SPDIF_IF(x) \
+       ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK)
+#define SND_RME_SPDIF_FORMAT(x) \
+       ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK)
+
+static const u32 snd_rme_rate_table[] = {
+       32000, 44100, 48000, 50000,
+       64000, 88200, 96000, 100000,
+       128000, 176400, 192000, 200000,
+       256000, 352800, 384000, 400000,
+       512000, 705600, 768000, 800000
+};
+/* maximum number of items for AES and S/PDIF rates for above table */
+#define SND_RME_RATE_IDX_AES_SPDIF_NUM         12
+
+enum snd_rme_domain {
+       SND_RME_DOMAIN_SYSTEM,
+       SND_RME_DOMAIN_AES,
+       SND_RME_DOMAIN_SPDIF
+};
+
+enum snd_rme_clock_status {
+       SND_RME_CLOCK_NOLOCK,
+       SND_RME_CLOCK_LOCK,
+       SND_RME_CLOCK_SYNC
+};
+
+static int snd_rme_read_value(struct snd_usb_audio *chip,
+                             unsigned int item,
+                             u32 *value)
+{
+       struct usb_device *dev = chip->dev;
+       int err;
+
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+                             item,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, 0,
+                             value, sizeof(*value));
+       if (err < 0)
+               dev_err(&dev->dev,
+                       "unable to issue vendor read request %d (ret = %d)",
+                       item, err);
+       return err;
+}
+
+static int snd_rme_get_status1(struct snd_kcontrol *kcontrol,
+                              u32 *status1)
+{
+       struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+       struct snd_usb_audio *chip = list->mixer->chip;
+       int err;
+
+       err = snd_usb_lock_shutdown(chip);
+       if (err < 0)
+               return err;
+       err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1);
+       snd_usb_unlock_shutdown(chip);
+       return err;
+}
+
+static int snd_rme_rate_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       u32 status1;
+       u32 rate = 0;
+       int idx;
+       int err;
+
+       err = snd_rme_get_status1(kcontrol, &status1);
+       if (err < 0)
+               return err;
+       switch (kcontrol->private_value) {
+       case SND_RME_DOMAIN_SYSTEM:
+               idx = SND_RME_CLK_SYSTEM(status1);
+               if (idx < ARRAY_SIZE(snd_rme_rate_table))
+                       rate = snd_rme_rate_table[idx];
+               break;
+       case SND_RME_DOMAIN_AES:
+               idx = SND_RME_CLK_AES(status1);
+               if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM)
+                       rate = snd_rme_rate_table[idx];
+               break;
+       case SND_RME_DOMAIN_SPDIF:
+               idx = SND_RME_CLK_SPDIF(status1);
+               if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM)
+                       rate = snd_rme_rate_table[idx];
+               break;
+       default:
+               return -EINVAL;
+       }
+       ucontrol->value.integer.value[0] = rate;
+       return 0;
+}
+
+static int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       u32 status1;
+       int idx = SND_RME_CLOCK_NOLOCK;
+       int err;
+
+       err = snd_rme_get_status1(kcontrol, &status1);
+       if (err < 0)
+               return err;
+       switch (kcontrol->private_value) {
+       case SND_RME_DOMAIN_AES:  /* AES */
+               if (status1 & SND_RME_CLK_AES_SYNC)
+                       idx = SND_RME_CLOCK_SYNC;
+               else if (status1 & SND_RME_CLK_AES_LOCK)
+                       idx = SND_RME_CLOCK_LOCK;
+               break;
+       case SND_RME_DOMAIN_SPDIF:  /* SPDIF */
+               if (status1 & SND_RME_CLK_SPDIF_SYNC)
+                       idx = SND_RME_CLOCK_SYNC;
+               else if (status1 & SND_RME_CLK_SPDIF_LOCK)
+                       idx = SND_RME_CLOCK_LOCK;
+               break;
+       default:
+               return -EINVAL;
+       }
+       ucontrol->value.enumerated.item[0] = idx;
+       return 0;
+}
+
+static int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       u32 status1;
+       int err;
+
+       err = snd_rme_get_status1(kcontrol, &status1);
+       if (err < 0)
+               return err;
+       ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1);
+       return 0;
+}
+
+static int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       u32 status1;
+       int err;
+
+       err = snd_rme_get_status1(kcontrol, &status1);
+       if (err < 0)
+               return err;
+       ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1);
+       return 0;
+}
+
+static int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       u32 status1;
+       int err;
+
+       err = snd_rme_get_status1(kcontrol, &status1);
+       if (err < 0)
+               return err;
+       ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1);
+       return 0;
+}
+
+static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+       struct snd_usb_audio *chip = list->mixer->chip;
+       u32 status1;
+       const u64 num = 104857600000000ULL;
+       u32 den;
+       unsigned int freq;
+       int err;
+
+       err = snd_usb_lock_shutdown(chip);
+       if (err < 0)
+               return err;
+       err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1);
+       if (err < 0)
+               goto end;
+       err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den);
+       if (err < 0)
+               goto end;
+       freq = (den == 0) ? 0 : div64_u64(num, den);
+       freq <<= SND_RME_CLK_FREQMUL(status1);
+       ucontrol->value.integer.value[0] = freq;
+
+end:
+       snd_usb_unlock_shutdown(chip);
+       return err;
+}
+
+static int snd_rme_rate_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       switch (kcontrol->private_value) {
+       case SND_RME_DOMAIN_SYSTEM:
+               uinfo->value.integer.min = 32000;
+               uinfo->value.integer.max = 800000;
+               break;
+       case SND_RME_DOMAIN_AES:
+       case SND_RME_DOMAIN_SPDIF:
+       default:
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = 200000;
+       }
+       uinfo->value.integer.step = 0;
+       return 0;
+}
+
+static int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       static const char *const sync_states[] = {
+               "No Lock", "Lock", "Sync"
+       };
+
+       return snd_ctl_enum_info(uinfo, 1,
+                                ARRAY_SIZE(sync_states), sync_states);
+}
+
+static int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       static const char *const spdif_if[] = {
+               "Coaxial", "Optical"
+       };
+
+       return snd_ctl_enum_info(uinfo, 1,
+                                ARRAY_SIZE(spdif_if), spdif_if);
+}
+
+static int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       static const char *const optical_type[] = {
+               "Consumer", "Professional"
+       };
+
+       return snd_ctl_enum_info(uinfo, 1,
+                                ARRAY_SIZE(optical_type), optical_type);
+}
+
+static int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       static const char *const sync_sources[] = {
+               "Internal", "AES", "SPDIF", "Internal"
+       };
+
+       return snd_ctl_enum_info(uinfo, 1,
+                                ARRAY_SIZE(sync_sources), sync_sources);
+}
+
+static struct snd_kcontrol_new snd_rme_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "AES Rate",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_rate_info,
+               .get = snd_rme_rate_get,
+               .private_value = SND_RME_DOMAIN_AES
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "AES Sync",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_sync_state_info,
+               .get = snd_rme_sync_state_get,
+               .private_value = SND_RME_DOMAIN_AES
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "SPDIF Rate",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_rate_info,
+               .get = snd_rme_rate_get,
+               .private_value = SND_RME_DOMAIN_SPDIF
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "SPDIF Sync",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_sync_state_info,
+               .get = snd_rme_sync_state_get,
+               .private_value = SND_RME_DOMAIN_SPDIF
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "SPDIF Interface",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_spdif_if_info,
+               .get = snd_rme_spdif_if_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "SPDIF Format",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_spdif_format_info,
+               .get = snd_rme_spdif_format_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Sync Source",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_sync_source_info,
+               .get = snd_rme_sync_source_get
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "System Rate",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_rate_info,
+               .get = snd_rme_rate_get,
+               .private_value = SND_RME_DOMAIN_SYSTEM
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Current Frequency",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_rme_rate_info,
+               .get = snd_rme_current_freq_get
+       }
+};
+
+static int snd_rme_controls_create(struct usb_mixer_interface *mixer)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) {
+               err = add_single_ctl_with_resume(mixer, 0,
+                                                NULL,
+                                                &snd_rme_controls[i],
+                                                NULL);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
 int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 {
        int err = 0;
@@ -1904,6 +2279,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
        case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */
                err = dell_dock_mixer_init(mixer);
                break;
+
+       case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */
+       case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */
+       case USB_ID(0x2a39, 0x3fd4): /* RME */
+               err = snd_rme_controls_create(mixer);
+               break;
        }
 
        return err;
index 08aa780070204ae4dbf0aeb68bec1ffe316fe803..849953e5775c27a32ebd6f1e942bd6283a9cf2e7 100644 (file)
@@ -3346,19 +3346,14 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
                                .ifnum = 0,
                                .type = QUIRK_AUDIO_STANDARD_MIXER,
                        },
-                       /* Capture */
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_IGNORE_INTERFACE,
-                       },
                        /* Playback */
                        {
-                               .ifnum = 2,
+                               .ifnum = 1,
                                .type = QUIRK_AUDIO_FIXED_ENDPOINT,
                                .data = &(const struct audioformat) {
                                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                                        .channels = 2,
-                                       .iface = 2,
+                                       .iface = 1,
                                        .altsetting = 1,
                                        .altset_idx = 1,
                                        .attributes = UAC_EP_CS_ATTR_FILL_MAX |
index fa7dca5a68c897ebd201953f4be7040f9124786c..83d76c345940557f25a6e2b08150bacbd3dc404f 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
-#include <asm/set_memory.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/pcm.h>
@@ -1141,8 +1140,7 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *hw_params)
 {
        struct snd_intelhad *intelhaddata;
-       unsigned long addr;
-       int pages, buf_size, retval;
+       int buf_size, retval;
 
        intelhaddata = snd_pcm_substream_chip(substream);
        buf_size = params_buffer_bytes(hw_params);
@@ -1151,17 +1149,6 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream,
                return retval;
        dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n",
                __func__, buf_size);
-       /* mark the pages as uncached region */
-       addr = (unsigned long) substream->runtime->dma_area;
-       pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
-       retval = set_memory_uc(addr, pages);
-       if (retval) {
-               dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n",
-                       retval);
-               return retval;
-       }
-       memset(substream->runtime->dma_area, 0, buf_size);
-
        return retval;
 }
 
@@ -1171,21 +1158,11 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream,
 static int had_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_intelhad *intelhaddata;
-       unsigned long addr;
-       u32 pages;
 
        intelhaddata = snd_pcm_substream_chip(substream);
        had_do_reset(intelhaddata);
 
-       /* mark back the pages as cached/writeback region before the free */
-       if (substream->runtime->dma_area != NULL) {
-               addr = (unsigned long) substream->runtime->dma_area;
-               pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
-                                                               PAGE_SIZE;
-               set_memory_wb(addr, pages);
-               return snd_pcm_lib_free_pages(substream);
-       }
-       return 0;
+       return snd_pcm_lib_free_pages(substream);
 }
 
 /*
@@ -1860,7 +1837,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
                 * try to allocate 600k buffer as default which is large enough
                 */
                snd_pcm_lib_preallocate_pages_for_all(pcm,
-                                                     SNDRV_DMA_TYPE_DEV, NULL,
+                                                     SNDRV_DMA_TYPE_DEV_UC, NULL,
                                                      HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER);
 
                /* create controls */
index 129180e17db1c9a77e91957249023603a6171ec9..2cbd9679aca138bc02c652f4a0d60b5ade8c4233 100644 (file)
@@ -637,31 +637,31 @@ static int alsa_pb_fill_silence(struct snd_pcm_substream *substream,
  * to know when the buffer can be transferred to the backend.
  */
 
-static struct snd_pcm_ops snd_drv_alsa_playback_ops = {
-       .open = alsa_open,
-       .close = alsa_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = alsa_hw_params,
-       .hw_free = alsa_hw_free,
-       .prepare = alsa_prepare,
-       .trigger = alsa_trigger,
-       .pointer = alsa_pointer,
-       .copy_user = alsa_pb_copy_user,
-       .copy_kernel = alsa_pb_copy_kernel,
-       .fill_silence = alsa_pb_fill_silence,
+static const struct snd_pcm_ops snd_drv_alsa_playback_ops = {
+       .open           = alsa_open,
+       .close          = alsa_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = alsa_hw_params,
+       .hw_free        = alsa_hw_free,
+       .prepare        = alsa_prepare,
+       .trigger        = alsa_trigger,
+       .pointer        = alsa_pointer,
+       .copy_user      = alsa_pb_copy_user,
+       .copy_kernel    = alsa_pb_copy_kernel,
+       .fill_silence   = alsa_pb_fill_silence,
 };
 
-static struct snd_pcm_ops snd_drv_alsa_capture_ops = {
-       .open = alsa_open,
-       .close = alsa_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = alsa_hw_params,
-       .hw_free = alsa_hw_free,
-       .prepare = alsa_prepare,
-       .trigger = alsa_trigger,
-       .pointer = alsa_pointer,
-       .copy_user = alsa_cap_copy_user,
-       .copy_kernel = alsa_cap_copy_kernel,
+static const struct snd_pcm_ops snd_drv_alsa_capture_ops = {
+       .open           = alsa_open,
+       .close          = alsa_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = alsa_hw_params,
+       .hw_free        = alsa_hw_free,
+       .prepare        = alsa_prepare,
+       .trigger        = alsa_trigger,
+       .pointer        = alsa_pointer,
+       .copy_user      = alsa_cap_copy_user,
+       .copy_kernel    = alsa_cap_copy_kernel,
 };
 
 static int new_pcm_instance(struct xen_snd_front_card_info *card_info,