Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
Linus Torvalds [Fri, 9 Feb 2007 16:24:04 +0000 (08:24 -0800)]
* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (212 commits)
  [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED
  [ALSA] version 1.0.14rc2
  [ALSA] ASoC documentation updates
  [ALSA] ca0106 - Add missing sysfs device assignment
  [ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully
  [ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880
  [ALSA] aoa: remove suspend/resume printks
  [ALSA] Fix possible deadlocks in sequencer at removal of ports
  [ALSA] emu10k1 - Fix STAC9758 front channel
  [ALSA] soc - Clean up with kmemdup()
  [ALSA] snd-ak4114: Fix two array overflows
  [ALSA] ac97_bus power management
  [ALSA] usbaudio - Add support for Edirol UA-101
  [ALSA] hda-codec - Add ALC861VD/ALC660VD support
  [ALSA] soc - ASoC 0.13 Sharp poodle machine
  [ALSA] soc - ASoC 0.13 Sharp tosa machine
  [ALSA] soc - ASoC 0.13 spitz machine
  [ALSA] soc - ASoC Sharp corgi machine
  [ALSA] soc - ASoC 0.13 pxa2xx DMA
  [ALSA] soc - ASoC 0.13 pxa2xx AC97 driver
  ...

216 files changed:
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/sound/alsa/hda_codec.txt
Documentation/sound/alsa/soc/DAI.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/clocking.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/codec.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/dapm.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/machine.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/overview.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/platform.txt [new file with mode: 0644]
Documentation/sound/alsa/soc/pops_clicks.txt [new file with mode: 0644]
MAINTAINERS
drivers/input/touchscreen/ucb1400_ts.c
include/linux/i2c-id.h
include/sound/ac97_codec.h
include/sound/ad1848.h
include/sound/ak4114.h
include/sound/ak4117.h
include/sound/ak4xxx-adda.h
include/sound/control.h
include/sound/core.h
include/sound/emu10k1.h
include/sound/pcm.h
include/sound/pt2258.h [new file with mode: 0644]
include/sound/sb16_csp.h
include/sound/snd_wavefront.h
include/sound/soc-dapm.h [new file with mode: 0644]
include/sound/soc.h [new file with mode: 0644]
include/sound/typedefs.h [deleted file]
include/sound/version.h
include/sound/vx_core.h
include/sound/ymfpci.h
sound/Kconfig
sound/Makefile
sound/ac97_bus.c
sound/aoa/aoa.h
sound/aoa/codecs/snd-aoa-codec-onyx.c
sound/aoa/core/snd-aoa-alsa.c
sound/aoa/core/snd-aoa-alsa.h
sound/aoa/core/snd-aoa-core.c
sound/aoa/fabrics/snd-aoa-fabric-layout.c
sound/aoa/soundbus/i2sbus/i2sbus-core.c
sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
sound/aoa/soundbus/i2sbus/i2sbus.h
sound/arm/aaci.h
sound/core/control.c
sound/core/control_compat.c
sound/core/device.c
sound/core/hwdep.c
sound/core/init.c
sound/core/memalloc.c
sound/core/misc.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/rawmidi.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_device.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_virmidi.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/Kconfig
sound/drivers/Makefile
sound/drivers/dummy.c
sound/drivers/portman2x4.c [new file with mode: 0644]
sound/drivers/serial-u16550.c
sound/drivers/vx/vx_mixer.c
sound/i2c/Makefile
sound/i2c/other/Makefile
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/i2c/other/ak4xxx-adda.c
sound/i2c/other/pt2258.c [new file with mode: 0644]
sound/isa/Kconfig
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848_lib.c
sound/isa/gus/gus_main.c
sound/isa/opl3sa2.c
sound/isa/sb/sb16_csp.c
sound/isa/wavefront/wavefront.c
sound/isa/wavefront/wavefront_fx.c
sound/isa/wavefront/yss225.c [new file with mode: 0644]
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ac97_patch.h
sound/pci/ac97/ak4531_codec.c
sound/pci/als300.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/cs4281.c
sound/pci/echoaudio/darla20.c
sound/pci/echoaudio/darla24.c
sound/pci/echoaudio/echo3g.c
sound/pci/echoaudio/echo3g_dsp.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/gina20.c
sound/pci/echoaudio/gina24.c
sound/pci/echoaudio/indigo.c
sound/pci/echoaudio/indigodj.c
sound/pci/echoaudio/indigoio.c
sound/pci/echoaudio/layla20.c
sound/pci/echoaudio/layla24.c
sound/pci/echoaudio/mia.c
sound/pci/echoaudio/mona.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/emuproc.c
sound/pci/emu10k1/io.c
sound/pci/emu10k1/p16v.c
sound/pci/emu10k1/p17v.h
sound/pci/emu10k1/voice.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/fm801.c
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_patch.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c [new file with mode: 0644]
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c [new file with mode: 0644]
sound/pci/ice1712/Makefile
sound/pci/ice1712/amp.c
sound/pci/ice1712/amp.h
sound/pci/ice1712/aureon.c
sound/pci/ice1712/aureon.h
sound/pci/ice1712/delta.c
sound/pci/ice1712/delta.h
sound/pci/ice1712/ews.c
sound/pci/ice1712/ews.h
sound/pci/ice1712/hoontech.c
sound/pci/ice1712/hoontech.h
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/juli.h
sound/pci/ice1712/phase.c
sound/pci/ice1712/phase.h
sound/pci/ice1712/pontis.c
sound/pci/ice1712/pontis.h
sound/pci/ice1712/prodigy192.c
sound/pci/ice1712/prodigy192.h
sound/pci/ice1712/revo.c
sound/pci/ice1712/revo.h
sound/pci/ice1712/vt1720_mobo.c
sound/pci/ice1712/vt1720_mobo.h
sound/pci/ice1712/wtm.c [new file with mode: 0644]
sound/pci/ice1712/wtm.h [new file with mode: 0644]
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart_mixer.c
sound/pci/nm256/nm256.c
sound/pci/pcxhr/pcxhr_mixer.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/vx222/vx222_ops.c
sound/pci/ymfpci/ymfpci_image.h
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/vx/vxp_mixer.c
sound/pcmcia/vx/vxpocket.c
sound/soc/Kconfig [new file with mode: 0644]
sound/soc/Makefile [new file with mode: 0644]
sound/soc/at91/Kconfig [new file with mode: 0644]
sound/soc/at91/Makefile [new file with mode: 0644]
sound/soc/at91/at91-i2s.c [new file with mode: 0644]
sound/soc/at91/at91-i2s.h [new file with mode: 0644]
sound/soc/at91/at91-pcm.c [new file with mode: 0644]
sound/soc/at91/at91-pcm.h [new file with mode: 0644]
sound/soc/at91/eti_b1_wm8731.c [new file with mode: 0644]
sound/soc/codecs/Kconfig [new file with mode: 0644]
sound/soc/codecs/Makefile [new file with mode: 0644]
sound/soc/codecs/ac97.c [new file with mode: 0644]
sound/soc/codecs/ac97.h [new file with mode: 0644]
sound/soc/codecs/wm8731.c [new file with mode: 0644]
sound/soc/codecs/wm8731.h [new file with mode: 0644]
sound/soc/codecs/wm8750.c [new file with mode: 0644]
sound/soc/codecs/wm8750.h [new file with mode: 0644]
sound/soc/codecs/wm9712.c [new file with mode: 0644]
sound/soc/codecs/wm9712.h [new file with mode: 0644]
sound/soc/pxa/Kconfig [new file with mode: 0644]
sound/soc/pxa/Makefile [new file with mode: 0644]
sound/soc/pxa/corgi.c [new file with mode: 0644]
sound/soc/pxa/poodle.c [new file with mode: 0644]
sound/soc/pxa/pxa2xx-ac97.c [new file with mode: 0644]
sound/soc/pxa/pxa2xx-ac97.h [new file with mode: 0644]
sound/soc/pxa/pxa2xx-i2s.c [new file with mode: 0644]
sound/soc/pxa/pxa2xx-i2s.h [new file with mode: 0644]
sound/soc/pxa/pxa2xx-pcm.c [new file with mode: 0644]
sound/soc/pxa/pxa2xx-pcm.h [new file with mode: 0644]
sound/soc/pxa/spitz.c [new file with mode: 0644]
sound/soc/pxa/tosa.c [new file with mode: 0644]
sound/soc/soc-core.c [new file with mode: 0644]
sound/soc/soc-dapm.c [new file with mode: 0644]
sound/sparc/dbri.c
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbquirks.h

index 9fef210..c30ff1b 100644 (file)
@@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     ac97_clock         - AC'97 clock (default = 48000)
     ac97_quirk         - AC'97 workaround for strange hardware
                          See "AC97 Quirk Option" section below.
+    ac97_codec         - Workaround to specify which AC'97 codec 
+                         instead of probing.  If this works for you
+                         file a bug with your `lspci -vn` output.
+                         -2  -- Force probing.
+                         -1  -- Default behavior.
+                         0-2 -- Use the specified codec.
     spdif_aclink       - S/PDIF transfer over AC-link (default = 1)
 
     This module supports one card and autoprobe.
@@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          asus-dig      ASUS with SPDIF out
          asus-dig2     ASUS with SPDIF out (using GPIO2)
          uniwill       3-jack
+         fujitsu       Fujitsu Laptops (Pi1536)
          F1734         2-jack
          lg            LG laptop (m1 express dual)
          lg-lw         LG LW20/LW25 laptop
@@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
        ALC262
          fujitsu       Fujitsu Laptop
          hp-bpc        HP xw4400/6400/8400/9400 laptops
+         hp-bpc-d7000  HP BPC D7000
          benq          Benq ED8
+         hippo         Hippo (ATI) with jack detection, Sony UX-90s
+         hippo_1       Hippo (Benq) with jack detection
          basic         fixed pin assignment w/o SPDIF
          auto          auto-config reading BIOS (default)
 
        ALC882/885
          3stack-dig    3-jack with SPDIF I/O
-         6stck-dig     6-jack digital with SPDIF I/O
+         6stack-dig    6-jack digital with SPDIF I/O
          arima         Arima W820Di1
+         macpro        MacPro support
          auto          auto-config reading BIOS (default)
 
        ALC883/888
@@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
          6stack-dig-demo  6-jack digital for Intel demo board
          acer          Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
+         medion        Medion Laptops
+         targa-dig     Targa/MSI
+         targa-2ch-dig Targs/MSI with 2-channel
+         laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
          auto          auto-config reading BIOS (default)
 
        ALC861/660
@@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          6stack-dig    6-jack with SPDIF I/O
          3stack-660    3-jack (for ALC660)
          uniwill-m31   Uniwill M31 laptop
+         toshiba       Toshiba laptop support
+         asus          Asus laptop support
+         asus-laptop   ASUS F2/F3 laptops
+         auto          auto-config reading BIOS (default)
+
+       ALC861VD/660VD
+         3stack        3-jack
+         3stack-dig    3-jack with SPDIF OUT
+         6stack-dig    6-jack with SPDIF OUT
+         3stack-660    3-jack (for ALC660VD)
          auto          auto-config reading BIOS (default)
 
        CMI9880
@@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack        3-stack, shared surrounds
          laptop        2-channel only (FSC V2060, Samsung M50)
          laptop-eapd   2-channel with EAPD (Samsung R65, ASUS A6J)
+         ultra         2-channel with EAPD (Samsung Ultra tablet PC)
 
        AD1988
          6stack        6-jack
@@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          laptop        3-jack with hp-jack automute
          laptop-dig    ditto with SPDIF
          auto          auto-config reading BIOS (default)
+       
+       Conexant 5045
+         laptop        Laptop config 
+         test          for testing/debugging purpose, almost all controls
+                       can be adjusted.  Appearing only when compiled with
+                       $CONFIG_SND_DEBUG=y
+
+       Conexant 5047
+         laptop        Basic Laptop config 
+         laptop-hp     Laptop config for some HP models (subdevice 30A5)
+         laptop-eapd   Laptop config with EAPD support
+         test          for testing/debugging purpose, almost all controls
+                       can be adjusted.  Appearing only when compiled with
+                       $CONFIG_SND_DEBUG=y
 
        STAC9200/9205/9220/9221/9254
          ref           Reference board
          3stack        D945 3stack
          5stack        D945 5stack + SPDIF
 
+       STAC9202/9250/9251
+         ref           Reference board, base config
+         m2-2          Some Gateway MX series laptops
+         m6            Some Gateway NX series laptops
+
        STAC9227/9228/9229/927x
          ref           Reference board
          3stack        D965 3stack
@@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
                        * MidiMan M Audio Revolution 5.1
                        * MidiMan M Audio Revolution 7.1
+                       * MidiMan M Audio Audiophile 192
                        * AMP Ltd AUDIO2000
                        * TerraTec Aureon 5.1 Sky
                        * TerraTec Aureon 7.1 Space
@@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     model       - Use the given board model, one of the following:
                  revo51, revo71, amp2000, prodigy71, prodigy71lt,
-                 prodigy192, aureon51, aureon71, universe,
+                 prodigy192, aureon51, aureon71, universe, ap192,
                  k8x800, phase22, phase28, ms300, av710
 
     This module supports multiple cards and autoprobe.
@@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     buggy_semaphore - Enable workaround for hardwares with buggy
                    semaphores (e.g. on some ASUS laptops)
                    (default off)
+    spdif_aclink  - Use S/PDIF over AC-link instead of direct connection
+                   from the controller chip
+                   (0 = off, 1 = on, -1 = default)
 
     This module supports one chip and autoprobe.
 
@@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This module supports multiple cards.
 
+  Module snd-portman2x4
+  ---------------------
+
+    Module for Midiman Portman 2x4 parallel port MIDI interface
+
+    This module supports multiple cards.
+
   Module snd-powermac (on ppc only)
   ---------------------------------
 
index 1f3ae3e..c4d2e35 100644 (file)
@@ -36,7 +36,7 @@
   </bookinfo>
 
   <chapter><title>Management of Cards and Devices</title>
-     <sect1><title>Card Managment</title>
+     <sect1><title>Card Management</title>
 !Esound/core/init.c
      </sect1>
      <sect1><title>Device Components</title>
@@ -59,7 +59,7 @@
      <sect1><title>PCM Format Helpers</title>
 !Esound/core/pcm_misc.c
      </sect1>
-     <sect1><title>PCM Memory Managment</title>
+     <sect1><title>PCM Memory Management</title>
 !Esound/core/pcm_memory.c
      </sect1>
   </chapter>
index ccd0a95..74d3a35 100644 (file)
         <informalexample>
           <programlisting>
 <![CDATA[
-  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
-                                          struct pt_regs *regs)
+  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
   {
           struct mychip *chip = dev_id;
           ....
        accessible via <constant>substream-&gt;runtime</constant>.
        This runtime pointer holds the various information; it holds
        the copy of hw_params and sw_params configurations, the buffer
-       pointers, mmap records, spinlocks, etc.  Almost everyhing you
+       pointers, mmap records, spinlocks, etc.  Almost everything you
        need for controlling the PCM can be found there.
        </para>
 
@@ -2340,7 +2339,7 @@ struct _snd_pcm_runtime {
 
        <para>
          When the PCM substreams can be synchronized (typically,
-       synchorinized start/stop of a playback and a capture streams),
+       synchronized start/stop of a playback and a capture streams),
        you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>,
        too.  In this case, you'll need to check the linked-list of
        PCM substreams in the trigger callback.  This will be
@@ -3062,8 +3061,7 @@ struct _snd_pcm_runtime {
            <title>Interrupt Handler Case #1</title>
             <programlisting>
 <![CDATA[
-  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
-                                          struct pt_regs *regs)
+  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
   {
           struct mychip *chip = dev_id;
           spin_lock(&chip->lock);
@@ -3106,8 +3104,7 @@ struct _snd_pcm_runtime {
            <title>Interrupt Handler Case #2</title>
             <programlisting>
 <![CDATA[
-  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
-                                          struct pt_regs *regs)
+  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
   {
           struct mychip *chip = dev_id;
           spin_lock(&chip->lock);
@@ -3247,7 +3244,7 @@ struct _snd_pcm_runtime {
         You can even define your own constraint rules.
         For example, let's suppose my_chip can manage a substream of 1 channel
         if and only if the format is S16_LE, otherwise it supports any format
-        specified in the <structname>snd_pcm_hardware</structname> stucture (or in any
+        specified in the <structname>snd_pcm_hardware</structname> structure (or in any
         other constraint_list). You can build a rule like this:
 
         <example>
@@ -3691,16 +3688,6 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          Here, the chip instance is retrieved via
-        <function>snd_kcontrol_chip()</function> macro.  This macro
-        just accesses to kcontrol-&gt;private_data. The
-        kcontrol-&gt;private_data field is 
-        given as the argument of <function>snd_ctl_new()</function>
-        (see the later subsection
-        <link linkend="control-interface-constructor"><citetitle>Constructor</citetitle></link>).
-        </para>
-
-        <para>
        The <structfield>value</structfield> field is depending on
         the type of control as well as on info callback.  For example,
        the sb driver uses this field to store the register offset,
@@ -3780,7 +3767,7 @@ struct _snd_pcm_runtime {
         <para>
        Like <structfield>get</structfield> callback,
        when the control has more than one elements,
-       all elemehts must be evaluated in this callback, too.
+       all elements must be evaluated in this callback, too.
         </para>
       </section>
 
@@ -5541,12 +5528,12 @@ struct _snd_pcm_runtime {
   #ifdef CONFIG_PM
   static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
   {
-          .... /* do things for suspsend */
+          .... /* do things for suspend */
           return 0;
   }
   static int snd_my_resume(struct pci_dev *pci)
   {
-          .... /* do things for suspsend */
+          .... /* do things for suspend */
           return 0;
   }
   #endif
@@ -6111,7 +6098,7 @@ struct _snd_pcm_runtime {
 <!-- ****************************************************** -->
 <!-- Acknowledgments  -->
 <!-- ****************************************************** -->
-  <chapter id="acknowledments">
+  <chapter id="acknowledgments">
     <title>Acknowledgments</title>
     <para>
       I would like to thank Phil Kerr for his help for improvement and
index 0be57ed..4eaae2a 100644 (file)
@@ -277,11 +277,11 @@ Helper Functions
 snd_hda_get_codec_name() stores the codec name on the given string.
 
 snd_hda_check_board_config() can be used to obtain the configuration
-information matching with the device.  Define the table with struct
-hda_board_config entries (zero-terminated), and pass it to the
-function.  The function checks the modelname given as a module
-parameter, and PCI subsystem IDs.  If the matching entry is found, it
-returns the config field value.
+information matching with the device.  Define the model string table
+and the table with struct snd_pci_quirk entries (zero-terminated),
+and pass it to the function.  The function checks the modelname given
+as a module parameter, and PCI subsystem IDs.  If the matching entry
+is found, it returns the config field value.
 
 snd_hda_add_new_ctls() can be used to create and add control entries.
 Pass the zero-terminated array of struct snd_kcontrol_new.  The same array
diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt
new file mode 100644 (file)
index 0000000..58cbfd0
--- /dev/null
@@ -0,0 +1,56 @@
+ASoC currently supports the three main Digital Audio Interfaces (DAI) found on
+SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM.
+
+
+AC97
+====
+
+  AC97 is a five wire interface commonly found on many PC sound cards. It is
+now also popular in many portable devices. This DAI has a reset line and time
+multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
+The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
+frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
+frame is 21uS long and is divided into 13 time slots.
+
+The AC97 specification can be found at :-
+http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
+
+
+I2S
+===
+
+ I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and
+Rx lines are used for audio transmision, whilst the bit clock (BCLK) and
+left/right clock (LRC) synchronise the link. I2S is flexible in that either the
+controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
+usually varies depending on the sample rate and the master system clock
+(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
+ADC and DAC LRCLK's, this allows for similtanious capture and playback at
+different sample rates.
+
+I2S has several different operating modes:-
+
+ o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC
+         transition.
+
+ o Left Justified - MSB is transmitted on transition of LRC.
+
+ o Right Justified - MSB is transmitted sample size BCLK's before LRC
+                     transition.
+
+PCM
+===
+
+PCM is another 4 wire interface, very similar to I2S, that can support a more
+flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used
+to synchronise the link whilst the Tx and Rx lines are used to transmit and
+receive the audio data. Bit clock usually varies depending on sample rate
+whilst sync runs at the sample rate. PCM also supports Time Division
+Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This
+is sometimes referred to as network mode).
+
+Common PCM operating modes:-
+
+ o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC.
+
+ o Mode B - MSB is transmitted on rising edge of FRAME/SYNC.
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt
new file mode 100644 (file)
index 0000000..e93960d
--- /dev/null
@@ -0,0 +1,51 @@
+Audio Clocking
+==============
+
+This text describes the audio clocking terms in ASoC and digital audio in
+general. Note: Audio clocking can be complex !
+
+
+Master Clock
+------------
+
+Every audio subsystem is driven by a master clock (sometimes refered to as MCLK
+or SYSCLK). This audio master clock can be derived from a number of sources
+(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct
+audio playback and capture sample rates.
+
+Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that
+their speed can be altered by software (depending on the system use and to save
+power). Other master clocks are fixed at at set frequency (i.e. crystals).
+
+
+DAI Clocks
+----------
+The Digital Audio Interface is usually driven by a Bit Clock (often referred to
+as BCLK). This clock is used to drive the digital audio data across the link
+between the codec and CPU.
+
+The DAI also has a frame clock to signal the start of each audio frame. This
+clock is sometimes referred to as LRC (left right clock) or FRAME. This clock
+runs at exactly the sample rate (LRC = Rate).
+
+Bit Clock can be generated as follows:-
+
+BCLK = MCLK / x
+
+ or
+
+BCLK = LRC * x
+
+ or
+
+BCLK = LRC * Channels * Word Size
+
+This relationship depends on the codec or SoC CPU in particular. In general
+it's best to configure BCLK to the lowest possible speed (depending on your
+rate, number of channels and wordsize) to save on power.
+
+It's also desireable to use the codec (if possible) to drive (or master) the
+audio clocks as it's usually gives more accurate sample rates than the CPU.
+
+
+
diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt
new file mode 100644 (file)
index 0000000..48983c7
--- /dev/null
@@ -0,0 +1,197 @@
+ASoC Codec Driver
+=================
+
+The codec driver is generic and hardware independent code that configures the
+codec to provide audio capture and playback. It should contain no code that is
+specific to the target platform or machine. All platform and machine specific
+code should be added to the platform and machine drivers respectively.
+
+Each codec driver *must* provide the following features:-
+
+ 1) Codec DAI and PCM configuration
+ 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's
+ 3) Mixers and audio controls
+ 4) Codec audio operations
+
+Optionally, codec drivers can also provide:-
+
+ 5) DAPM description.
+ 6) DAPM event handler.
+ 7) DAC Digital mute control.
+
+It's probably best to use this guide in conjuction with the existing codec
+driver code in sound/soc/codecs/
+
+ASoC Codec driver breakdown
+===========================
+
+1 - Codec DAI and PCM configuration
+-----------------------------------
+Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and
+PCM's capablities and operations. This struct is exported so that it can be
+registered with the core by your machine driver.
+
+e.g.
+
+struct snd_soc_codec_dai wm8731_dai = {
+       .name = "WM8731",
+       /* playback capabilities */
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8731_RATES,
+               .formats = WM8731_FORMATS,},
+       /* capture capabilities */
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8731_RATES,
+               .formats = WM8731_FORMATS,},
+       /* pcm operations - see section 4 below */
+       .ops = {
+               .prepare = wm8731_pcm_prepare,
+               .hw_params = wm8731_hw_params,
+               .shutdown = wm8731_shutdown,
+       },
+       /* DAI operations - see DAI.txt */
+       .dai_ops = {
+               .digital_mute = wm8731_mute,
+               .set_sysclk = wm8731_set_dai_sysclk,
+               .set_fmt = wm8731_set_dai_fmt,
+       }
+};
+EXPORT_SYMBOL_GPL(wm8731_dai);
+
+
+2 - Codec control IO
+--------------------
+The codec can ususally be controlled via an I2C or SPI style interface (AC97
+combines control with data in the DAI). The codec drivers will have to provide
+functions to read and write the codec registers along with supplying a register
+cache:-
+
+       /* IO control data and register cache */
+    void *control_data; /* codec control (i2c/3wire) data */
+    void *reg_cache;
+
+Codec read/write should do any data formatting and call the hardware read write
+below to perform the IO. These functions are called by the core and alsa when
+performing DAPM or changing the mixer:-
+
+    unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+    int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+
+Codec hardware IO functions - usually points to either the I2C, SPI or AC97
+read/write:-
+
+       hw_write_t hw_write;
+       hw_read_t hw_read;
+
+
+3 - Mixers and audio controls
+-----------------------------
+All the codec mixers and audio controls can be defined using the convenience
+macros defined in soc.h.
+
+    #define SOC_SINGLE(xname, reg, shift, mask, invert)
+
+Defines a single control as follows:-
+
+  xname = Control name e.g. "Playback Volume"
+  reg = codec register
+  shift = control bit(s) offset in register
+  mask = control bit size(s) e.g. mask of 7 = 3 bits
+  invert = the control is inverted
+
+Other macros include:-
+
+    #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert)
+
+A stereo control
+
+    #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert)
+
+A stereo control spanning 2 registers
+
+    #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)
+
+Defines an single enumerated control as follows:-
+
+   xreg = register
+   xshift = control bit(s) offset in register
+   xmask = control bit(s) size
+   xtexts = pointer to array of strings that describe each setting
+
+   #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)
+
+Defines a stereo enumerated control
+
+
+4 - Codec Audio Operations
+--------------------------
+The codec driver also supports the following alsa operations:-
+
+/* SoC audio ops */
+struct snd_soc_ops {
+       int (*startup)(struct snd_pcm_substream *);
+       void (*shutdown)(struct snd_pcm_substream *);
+       int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+       int (*hw_free)(struct snd_pcm_substream *);
+       int (*prepare)(struct snd_pcm_substream *);
+};
+
+Please refer to the alsa driver PCM documentation for details.
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+
+
+5 - DAPM description.
+---------------------
+The Dynamic Audio Power Management description describes the codec's power
+components, their relationships and registers to the ASoC core. Please read
+dapm.txt for details of building the description.
+
+Please also see the examples in other codec drivers.
+
+
+6 - DAPM event handler
+----------------------
+This function is a callback that handles codec domain PM calls and system
+domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep
+when not in use.
+
+Power states:-
+
+       SNDRV_CTL_POWER_D0: /* full On */
+       /* vref/mid, clk and osc on, active */
+
+       SNDRV_CTL_POWER_D1: /* partial On */
+       SNDRV_CTL_POWER_D2: /* partial On */
+
+       SNDRV_CTL_POWER_D3hot: /* Off, with power */
+       /* everything off except vref/vmid, inactive */
+
+       SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */
+
+
+7 - Codec DAC digital mute control.
+------------------------------------
+Most codecs have a digital mute before the DAC's that can be used to minimise
+any system noise.  The mute stops any digital data from entering the DAC.
+
+A callback can be created that is called by the core for each codec DAI when the
+mute is applied or freed.
+
+i.e.
+
+static int wm8974_mute(struct snd_soc_codec *codec,
+       struct snd_soc_codec_dai *dai, int mute)
+{
+       u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
+       if(mute)
+               wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
+       else
+               wm8974_write(codec, WM8974_DAC, mute_reg);
+       return 0;
+}
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt
new file mode 100644 (file)
index 0000000..c11877f
--- /dev/null
@@ -0,0 +1,297 @@
+Dynamic Audio Power Management for Portable Devices
+===================================================
+
+1. Description
+==============
+
+Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices
+to use the minimum amount of power within the audio subsystem at all times. It
+is independent of other kernel PM and as such, can easily co-exist with the
+other PM systems.
+
+DAPM is also completely transparent to all user space applications as all power
+switching is done within the ASoC core. No code changes or recompiling are
+required for user space applications. DAPM makes power switching descisions based
+upon any audio stream (capture/playback) activity and audio mixer settings
+within the device.
+
+DAPM spans the whole machine. It covers power control within the entire audio
+subsystem, this includes internal codec power blocks and machine level power
+systems.
+
+There are 4 power domains within DAPM
+
+   1. Codec domain - VREF, VMID (core codec and audio power)
+      Usually controlled at codec probe/remove and suspend/resume, although
+      can be set at stream time if power is not needed for sidetone, etc.
+
+   2. Platform/Machine domain - physically connected inputs and outputs
+      Is platform/machine and user action specific, is configured by the
+      machine driver and responds to asynchronous events e.g when HP
+      are inserted
+
+   3. Path domain - audio susbsystem signal paths
+      Automatically set when mixer and mux settings are changed by the user.
+      e.g. alsamixer, amixer.
+
+   4. Stream domain - DAC's and ADC's.
+      Enabled and disabled when stream playback/capture is started and
+      stopped respectively. e.g. aplay, arecord.
+
+All DAPM power switching descisons are made automatically by consulting an audio
+routing map of the whole machine. This map is specific to each machine and
+consists of the interconnections between every audio component (including
+internal codec components). All audio components that effect power are called
+widgets hereafter.
+
+
+2. DAPM Widgets
+===============
+
+Audio DAPM widgets fall into a number of types:-
+
+ o Mixer      - Mixes several analog signals into a single analog signal.
+ o Mux        - An analog switch that outputs only 1 of it's inputs.
+ o PGA        - A programmable gain amplifier or attenuation widget.
+ o ADC        - Analog to Digital Converter
+ o DAC        - Digital to Analog Converter
+ o Switch     - An analog switch
+ o Input      - A codec input pin
+ o Output     - A codec output pin
+ o Headphone  - Headphone (and optional Jack)
+ o Mic        - Mic (and optional Jack)
+ o Line       - Line Input/Output (and optional Jack)
+ o Speaker    - Speaker
+ o Pre        - Special PRE widget (exec before all others)
+ o Post       - Special POST widget (exec after all others)
+
+(Widgets are defined in include/sound/soc-dapm.h)
+
+Widgets are usually added in the codec driver and the machine driver. There are
+convience macros defined in soc-dapm.h that can be used to quickly build a
+list of widgets of the codecs and machines DAPM widgets.
+
+Most widgets have a name, register, shift and invert. Some widgets have extra
+parameters for stream name and kcontrols.
+
+
+2.1 Stream Domain Widgets
+-------------------------
+
+Stream Widgets relate to the stream power domain and only consist of ADC's
+(analog to digital converters) and DAC's (digital to analog converters).
+
+Stream widgets have the following format:-
+
+SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
+
+NOTE: the stream name must match the corresponding stream name in your codecs
+snd_soc_codec_dai.
+
+e.g. stream widgets for HiFi playback and capture
+
+SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
+SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
+
+
+2.2 Path Domain Widgets
+-----------------------
+
+Path domain widgets have a ability to control or effect the audio signal or
+audio paths within the audio subsystem. They have the following form:-
+
+SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
+
+Any widget kcontrols can be set using the controls and num_controls members.
+
+e.g. Mixer widget (the kcontrols are declared first)
+
+/* Output Mixer */
+static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
+};
+
+SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,
+       ARRAY_SIZE(wm8731_output_mixer_controls)),
+
+
+2.3 Platform/Machine domain Widgets
+-----------------------------------
+
+Machine widgets are different from codec widgets in that they don't have a
+codec register bit associated with them. A machine widget is assigned to each
+machine audio component (non codec) that can be independently powered. e.g.
+
+ o Speaker Amp
+ o Microphone Bias
+ o Jack connectors
+
+A machine widget can have an optional call back.
+
+e.g. Jack connector widget for an external Mic that enables Mic Bias
+when the Mic is inserted:-
+
+static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
+{
+       if(SND_SOC_DAPM_EVENT_ON(event))
+               set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+       else
+               reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+
+       return 0;
+}
+
+SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
+
+
+2.4 Codec Domain
+----------------
+
+The Codec power domain has no widgets and is handled by the codecs DAPM event
+handler. This handler is called when the codec powerstate is changed wrt to any
+stream event or by kernel PM events.
+
+
+2.5 Virtual Widgets
+-------------------
+
+Sometimes widgets exist in the codec or machine audio map that don't have any
+corresponding register bit for power control. In this case it's necessary to
+create a virtual widget - a widget with no control bits e.g.
+
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
+
+This can be used to merge to signal paths together in software.
+
+After all the widgets have been defined, they can then be added to the DAPM
+subsystem individually with a call to snd_soc_dapm_new_control().
+
+
+3. Codec Widget Interconnections
+================================
+
+Widgets are connected to each other within the codec and machine by audio
+paths (called interconnections). Each interconnection must be defined in order
+to create a map of all audio paths between widgets.
+This is easiest with a diagram of the codec (and schematic of the machine audio
+system), as it requires joining widgets together via their audio signal paths.
+
+i.e. from the WM8731 codec's output mixer (wm8731.c)
+
+The WM8731 output mixer has 3 inputs (sources)
+
+ 1. Line Bypass Input
+ 2. DAC (HiFi playback)
+ 3. Mic Sidetone Input
+
+Each input in this example has a kcontrol associated with it (defined in example
+above) and is connected to the output mixer via it's kcontrol name. We can now
+connect the destination widget (wrt audio signal) with it's source widgets.
+
+       /* output mixer */
+       {"Output Mixer", "Line Bypass Switch", "Line Input"},
+       {"Output Mixer", "HiFi Playback Switch", "DAC"},
+       {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+So we have :-
+
+       Destination Widget  <=== Path Name <=== Source Widget
+
+Or:-
+
+       Sink, Path, Source
+
+Or :-
+
+       "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch".
+
+When there is no path name connecting widgets (e.g. a direct connection) we
+pass NULL for the path name.
+
+Interconnections are created with a call to:-
+
+snd_soc_dapm_connect_input(codec, sink, path, source);
+
+Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and
+interconnections have been registered with the core. This causes the core to
+scan the codec and machine so that the internal DAPM state matches the
+physical state of the machine.
+
+
+3.1 Machine Widget Interconnections
+-----------------------------------
+Machine widget interconnections are created in the same way as codec ones and
+directly connect the codec pins to machine level widgets.
+
+e.g. connects the speaker out codec pins to the internal speaker.
+
+       /* ext speaker connected to codec pins LOUT2, ROUT2  */
+       {"Ext Spk", NULL , "ROUT2"},
+       {"Ext Spk", NULL , "LOUT2"},
+
+This allows the DAPM to power on and off pins that are connected (and in use)
+and pins that are NC respectively.
+
+
+4 Endpoint Widgets
+===================
+An endpoint is a start or end point (widget) of an audio signal within the
+machine and includes the codec. e.g.
+
+ o Headphone Jack
+ o Internal Speaker
+ o Internal Mic
+ o Mic Jack
+ o Codec Pins
+
+When a codec pin is NC it can be marked as not used with a call to
+
+snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
+
+The last argument is 0 for inactive and 1 for active. This way the pin and its
+input widget will never be powered up and consume power.
+
+This also applies to machine widgets. e.g. if a headphone is connected to a
+jack then the jack can be marked active. If the headphone is removed, then
+the headphone jack can be marked inactive.
+
+
+5 DAPM Widget Events
+====================
+
+Some widgets can register their interest with the DAPM core in PM events.
+e.g. A Speaker with an amplifier registers a widget so the amplifier can be
+powered only when the spk is in use.
+
+/* turn speaker amplifier on/off depending on use */
+static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+       else
+               reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+
+       return 0;
+}
+
+/* corgi machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
+       SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
+
+Please see soc-dapm.h for all other widgets that support events.
+
+
+5.1 Event types
+---------------
+
+The following event types are supported by event widgets.
+
+/* dapm event types */
+#define SND_SOC_DAPM_PRE_PMU   0x1     /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU  0x2             /* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD   0x4     /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD  0x8             /* after widget power down */
+#define SND_SOC_DAPM_PRE_REG   0x10    /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG  0x20    /* after audio path setup */
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt
new file mode 100644 (file)
index 0000000..72bd222
--- /dev/null
@@ -0,0 +1,113 @@
+ASoC Machine Driver
+===================
+
+The ASoC machine (or board) driver is the code that glues together the platform
+and codec drivers.
+
+The machine driver can contain codec and platform specific code. It registers
+the audio subsystem with the kernel as a platform device and is represented by
+the following struct:-
+
+/* SoC machine */
+struct snd_soc_machine {
+       char *name;
+
+       int (*probe)(struct platform_device *pdev);
+       int (*remove)(struct platform_device *pdev);
+
+       /* the pre and post PM functions are used to do any PM work before and
+        * after the codec and DAI's do any PM work. */
+       int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+       int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+       int (*resume_pre)(struct platform_device *pdev);
+       int (*resume_post)(struct platform_device *pdev);
+
+       /* machine stream operations */
+       struct snd_soc_ops *ops;
+
+       /* CPU <--> Codec DAI links  */
+       struct snd_soc_dai_link *dai_link;
+       int num_links;
+};
+
+probe()/remove()
+----------------
+probe/remove are optional. Do any machine specific probe here.
+
+
+suspend()/resume()
+------------------
+The machine driver has pre and post versions of suspend and resume to take care
+of any machine audio tasks that have to be done before or after the codec, DAI's
+and DMA is suspended and resumed. Optional.
+
+
+Machine operations
+------------------
+The machine specific audio operations can be set here. Again this is optional.
+
+
+Machine DAI Configuration
+-------------------------
+The machine DAI configuration glues all the codec and CPU DAI's together. It can
+also be used to set up the DAI system clock and for any machine related DAI
+initialisation e.g. the machine audio map can be connected to the codec audio
+map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c
+for examples.
+
+struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
+
+/* corgi digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link corgi_dai = {
+       .name = "WM8731",
+       .stream_name = "WM8731",
+       .cpu_dai = &pxa_i2s_dai,
+       .codec_dai = &wm8731_dai,
+       .init = corgi_wm8731_init,
+       .ops = &corgi_ops,
+};
+
+struct snd_soc_machine then sets up the machine with it's DAI's. e.g.
+
+/* corgi audio machine driver */
+static struct snd_soc_machine snd_soc_machine_corgi = {
+       .name = "Corgi",
+       .dai_link = &corgi_dai,
+       .num_links = 1,
+};
+
+
+Machine Audio Subsystem
+-----------------------
+
+The machine soc device glues the platform, machine and codec driver together.
+Private data can also be set here. e.g.
+
+/* corgi audio private data */
+static struct wm8731_setup_data corgi_wm8731_setup = {
+       .i2c_address = 0x1b,
+};
+
+/* corgi audio subsystem */
+static struct snd_soc_device corgi_snd_devdata = {
+       .machine = &snd_soc_machine_corgi,
+       .platform = &pxa2xx_soc_platform,
+       .codec_dev = &soc_codec_dev_wm8731,
+       .codec_data = &corgi_wm8731_setup,
+};
+
+
+Machine Power Map
+-----------------
+
+The machine driver can optionally extend the codec power map and to become an
+audio power map of the audio subsystem. This allows for automatic power up/down
+of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack
+sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for
+details.
+
+
+Machine Controls
+----------------
+
+Machine specific audio mixer controls can be added in the dai init function.
\ No newline at end of file
diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt
new file mode 100644 (file)
index 0000000..753c5cc
--- /dev/null
@@ -0,0 +1,83 @@
+ALSA SoC Layer
+==============
+
+The overall project goal of the ALSA System on Chip (ASoC) layer is to provide
+better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00,
+iMX, etc) and portable audio codecs. Currently there is some support in the
+kernel for SoC audio, however it has some limitations:-
+
+  * Currently, codec drivers are often tightly coupled to the underlying SoC
+    cpu. This is not ideal and leads to code duplication i.e. Linux now has 4
+    different wm8731 drivers for 4 different SoC platforms.
+
+  * There is no standard method to signal user initiated audio events.
+    e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion
+    event. These are quite common events on portable devices and ofter require
+    machine specific code to re route audio, enable amps etc after such an event.
+
+  * Current drivers tend to power up the entire codec when playing
+    (or recording) audio. This is fine for a PC, but tends to waste a lot of
+    power on portable devices. There is also no support for saving power via
+    changing codec oversampling rates, bias currents, etc.
+
+
+ASoC Design
+===========
+
+The ASoC layer is designed to address these issues and provide the following
+features :-
+
+  * Codec independence. Allows reuse of codec drivers on other platforms
+    and machines.
+
+  * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface
+    and codec registers it's audio interface capabilities with the core and are
+    subsequently matched and configured when the application hw params are known.
+
+  * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to
+    it's minimum power state at all times. This includes powering up/down
+    internal power blocks depending on the internal codec audio routing and any
+    active streams.
+
+  * Pop and click reduction. Pops and clicks can be reduced by powering the
+    codec up/down in the correct sequence (including using digital mute). ASoC
+    signals the codec when to change power states.
+
+  * Machine specific controls: Allow machines to add controls to the sound card
+    e.g. volume control for speaker amp.
+
+To achieve all this, ASoC basically splits an embedded audio system into 3
+components :-
+
+  * Codec driver: The codec driver is platform independent and contains audio
+    controls, audio interface capabilities, codec dapm definition and codec IO
+    functions.
+
+  * Platform driver: The platform driver contains the audio dma engine and audio
+    interface drivers (e.g. I2S, AC97, PCM) for that platform.
+
+  * Machine driver: The machine driver handles any machine specific controls and
+    audio events. i.e. turing on an amp at start of playback.
+
+
+Documentation
+=============
+
+The documentation is spilt into the following sections:-
+
+overview.txt: This file.
+
+codec.txt: Codec driver internals.
+
+DAI.txt: Description of Digital Audio Interface standards and how to configure
+a DAI within your codec and CPU DAI drivers.
+
+dapm.txt: Dynamic Audio Power Management
+
+platform.txt: Platform audio DMA and DAI.
+
+machine.txt: Machine driver internals.
+
+pop_clicks.txt: How to minimise audio artifacts.
+
+clocking.txt: ASoC clocking for best power performance.
\ No newline at end of file
diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt
new file mode 100644 (file)
index 0000000..e95b16d
--- /dev/null
@@ -0,0 +1,58 @@
+ASoC Platform Driver
+====================
+
+An ASoC platform driver can be divided into audio DMA and SoC DAI configuration
+and control. The platform drivers only target the SoC CPU and must have no board
+specific code.
+
+Audio DMA
+=========
+
+The platform DMA driver optionally supports the following alsa operations:-
+
+/* SoC audio ops */
+struct snd_soc_ops {
+       int (*startup)(struct snd_pcm_substream *);
+       void (*shutdown)(struct snd_pcm_substream *);
+       int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+       int (*hw_free)(struct snd_pcm_substream *);
+       int (*prepare)(struct snd_pcm_substream *);
+       int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+The platform driver exports it's DMA functionailty via struct snd_soc_platform:-
+
+struct snd_soc_platform {
+       char *name;
+
+       int (*probe)(struct platform_device *pdev);
+       int (*remove)(struct platform_device *pdev);
+       int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
+       int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
+
+       /* pcm creation and destruction */
+       int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
+       void (*pcm_free)(struct snd_pcm *);
+
+       /* platform stream ops */
+       struct snd_pcm_ops *pcm_ops;
+};
+
+Please refer to the alsa driver documentation for details of audio DMA.
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+
+An example DMA driver is soc/pxa/pxa2xx-pcm.c
+
+
+SoC DAI Drivers
+===============
+
+Each SoC DAI driver must provide the following features:-
+
+ 1) Digital audio interface (DAI) description
+ 2) Digital audio interface configuration
+ 3) PCM's description
+ 4) Sysclk configuration
+ 5) Suspend and resume (optional)
+
+Please see codec.txt for a description of items 1 - 4.
diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt
new file mode 100644 (file)
index 0000000..2cf7ee5
--- /dev/null
@@ -0,0 +1,52 @@
+Audio Pops and Clicks
+=====================
+
+Pops and clicks are unwanted audio artifacts caused by the powering up and down
+of components within the audio subsystem. This is noticable on PC's when an
+audio module is either loaded or unloaded (at module load time the sound card is
+powered up and causes a popping noise on the speakers).
+
+Pops and clicks can be more frequent on portable systems with DAPM. This is
+because the components within the subsystem are being dynamically powered
+depending on the audio usage and this can subsequently cause a small pop or
+click every time a component power state is changed.
+
+
+Minimising Playback Pops and Clicks
+===================================
+
+Playback pops in portable audio subsystems cannot be completely eliminated atm,
+however future audio codec hardware will have better pop and click supression.
+Pops can be reduced within playback by powering the audio components in a
+specific order. This order is different for startup and shutdown and follows
+some basic rules:-
+
+ Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
+
+ Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC
+
+This assumes that the codec PCM output path from the DAC is via a mixer and then
+a PGA (programmable gain amplifier) before being output to the speakers.
+
+
+Minimising Capture Pops and Clicks
+==================================
+
+Capture artifacts are somewhat easier to get rid as we can delay activating the
+ADC until all the pops have occured. This follows similar power rules to
+playback in that components are powered in a sequence depending upon stream
+startup or shutdown.
+
+ Startup Order - Input PGA --> Mixers --> ADC
+
+ Shutdown Order - ADC --> Mixers --> Input PGA
+
+
+Zipper Noise
+============
+An unwanted zipper noise can occur within the audio playback or capture stream
+when a volume control is changed near its maximum gain value. The zipper noise
+is heard when the gain increase or decrease changes the mean audio signal
+amplitude too quickly. It can be minimised by enabling the zero cross setting
+for each volume control. The ZC forces the gain change to occur when the signal
+crosses the zero amplitude line.
index 6ddae2b..f2a7948 100644 (file)
@@ -3037,6 +3037,12 @@ M:       perex@suse.cz
 L:     alsa-devel@alsa-project.org
 S:     Maintained
 
+SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
+P:     Liam Girdwood
+M:     liam.girdwood@wolfsonmicro.com
+L:     alsa-devel@alsa-project.org
+S:     Supported
+
 SPI SUBSYSTEM
 P:     David Brownell
 M:     dbrownell@users.sourceforge.net
index 4358a0a..c7db403 100644 (file)
@@ -83,7 +83,7 @@
 
 
 struct ucb1400 {
-       ac97_t                  *ac97;
+       struct snd_ac97         *ac97;
        struct input_dev        *ts_idev;
 
        int                     irq;
index d38778f..6e7ec4c 100644 (file)
 #define I2C_DRIVERID_KS0127    86      /* Samsung ks0127 video decoder */
 #define I2C_DRIVERID_TLV320AIC23B 87   /* TI TLV320AIC23B audio codec  */
 #define I2C_DRIVERID_ISL1208   88      /* Intersil ISL1208 RTC         */
+#define I2C_DRIVERID_WM8731            89      /* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750            90      /* Wolfson WM8750 audio codec */
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
index 3372039..246ac23 100644 (file)
 #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
 #define AC97_SCAP_NO_SPDIF     (1<<9)  /* don't build SPDIF controls */
 #define AC97_SCAP_EAPD_LED     (1<<10) /* EAPD as mute LED */
+#define AC97_SCAP_POWER_SAVE   (1<<11) /* capable for aggresive power-saving */
 
 /* ac97->flags */
 #define AC97_HAS_PC_BEEP       (1<<0)  /* force PC Speaker usage */
@@ -425,6 +426,7 @@ struct snd_ac97_build_ops {
 
 struct snd_ac97_bus_ops {
        void (*reset) (struct snd_ac97 *ac97);
+       void (*warm_reset)(struct snd_ac97 *ac97);
        void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
        unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg);
        void (*wait) (struct snd_ac97 *ac97);
@@ -501,6 +503,7 @@ struct snd_ac97 {
                        unsigned short id[3];           // codec IDs (lower 16-bit word)
                        unsigned short pcmreg[3];       // PCM registers
                        unsigned short codec_cfg[3];    // CODEC_CFG bits
+                       unsigned char swap_mic_linein;  // AD1986/AD1986A only
                } ad18xx;
                unsigned int dev_flags;         /* device specific */
        } spec;
@@ -510,7 +513,6 @@ struct snd_ac97 {
 
 #ifdef CONFIG_SND_AC97_POWER_SAVE
        unsigned int power_up;  /* power states */
-       struct workqueue_struct *power_workq;
        struct delayed_work power_work;
 #endif
        struct device dev;
index c8de6f8..b2c3f00 100644 (file)
@@ -185,7 +185,7 @@ struct ad1848_mix_elem {
        int index;
        int type;
        unsigned long private_value;
-       unsigned int *tlv;
+       const unsigned int *tlv;
 };
 
 #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
index 2ee0616..c149d3b 100644 (file)
@@ -181,7 +181,6 @@ struct ak4114 {
        unsigned long ccrc_errors;
        unsigned char rcs0;
        unsigned char rcs1;
-       struct workqueue_struct *workqueue;
        struct delayed_work work;
        void *change_callback_private;
        void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1);
@@ -189,7 +188,7 @@ struct ak4114 {
 
 int snd_ak4114_create(struct snd_card *card,
                      ak4114_read_t *read, ak4114_write_t *write,
-                     unsigned char pgm[7], unsigned char txcsb[5],
+                     const unsigned char pgm[7], const unsigned char txcsb[5],
                      void *private_data, struct ak4114 **r_ak4114);
 void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val);
 void snd_ak4114_reinit(struct ak4114 *ak4114);
index 2b96c32..d650d52 100644 (file)
@@ -178,7 +178,7 @@ struct ak4117 {
 };
 
 int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
-                     unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
+                     const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
 void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
 void snd_ak4117_reinit(struct ak4117 *ak4117);
 int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream);
index d0deca6..aa49dda 100644 (file)
@@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel {
        char *name;             /* capture gain volume label */
        char *switch_name;      /* capture switch */
        unsigned int num_channels;
+       char *selector_name;    /* capture source select label */
+       const char **input_names; /* capture source names (NULL terminated) */
 };
 
 struct snd_akm4xxx {
@@ -69,8 +71,8 @@ struct snd_akm4xxx {
        } type;
 
        /* (array) information of combined codecs */
-       struct snd_akm4xxx_dac_channel *dac_info;
-       struct snd_akm4xxx_adc_channel *adc_info;
+       const struct snd_akm4xxx_dac_channel *dac_info;
+       const struct snd_akm4xxx_adc_channel *adc_info;
 
        struct snd_ak4xxx_ops ops;
 };
index 1de148b..72e759f 100644 (file)
@@ -49,7 +49,7 @@ struct snd_kcontrol_new {
        snd_kcontrol_put_t *put;
        union {
                snd_kcontrol_tlv_rw_t *c;
-               unsigned int *p;
+               const unsigned int *p;
        } tlv;
        unsigned long private_value;
 };
@@ -69,7 +69,7 @@ struct snd_kcontrol {
        snd_kcontrol_put_t *put;
        union {
                snd_kcontrol_tlv_rw_t *c;
-               unsigned int *p;
+               const unsigned int *p;
        } tlv;
        unsigned long private_value;
        void *private_data;
@@ -108,7 +108,6 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
 
 void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
 
-struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol * kcontrol, unsigned int access);
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
 void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
 int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
index 521f036..4b9e609 100644 (file)
@@ -211,9 +211,40 @@ extern struct class *sound_class;
 
 void snd_request_card(int card);
 
-int snd_register_device(int type, struct snd_card *card, int dev,
-                       const struct file_operations *f_ops, void *private_data,
-                       const char *name);
+int snd_register_device_for_dev(int type, struct snd_card *card,
+                               int dev,
+                               const struct file_operations *f_ops,
+                               void *private_data,
+                               const char *name,
+                               struct device *device);
+
+/**
+ * snd_register_device - Register the ALSA device file for the card
+ * @type: the device type, SNDRV_DEVICE_TYPE_XXX
+ * @card: the card instance
+ * @dev: the device index
+ * @f_ops: the file operations
+ * @private_data: user pointer for f_ops->open()
+ * @name: the device file name
+ *
+ * Registers an ALSA device file for the given card.
+ * The operators have to be set in reg parameter.
+ *
+ * This function uses the card's device pointer to link to the
+ * correct &struct device.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+static inline int snd_register_device(int type, struct snd_card *card, int dev,
+                                     const struct file_operations *f_ops,
+                                     void *private_data,
+                                     const char *name)
+{
+       return snd_register_device_for_dev(type, card, dev, f_ops,
+                                          private_data, name,
+                                          snd_card_get_device_link(card));
+}
+
 int snd_unregister_device(int type, struct snd_card *card, int dev);
 void *snd_lookup_minor_data(unsigned int minor, int type);
 int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
@@ -396,6 +427,29 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
 #endif
 #endif
 
-#include "typedefs.h"
+/* PCI quirk list helper */
+struct snd_pci_quirk {
+       unsigned short subvendor;       /* PCI subvendor ID */
+       unsigned short subdevice;       /* PCI subdevice ID */
+       int value;                      /* value */
+#ifdef CONFIG_SND_DEBUG_DETECT
+       const char *name;               /* name of the device (optional) */
+#endif
+};
+
+#define _SND_PCI_QUIRK_ID(vend,dev) \
+       .subvendor = (vend), .subdevice = (dev)
+#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
+#ifdef CONFIG_SND_DEBUG_DETECT
+#define SND_PCI_QUIRK(vend,dev,xname,val) \
+       {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
+#else
+#define SND_PCI_QUIRK(vend,dev,xname,val) \
+       {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
+#endif
+
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
+
 
 #endif /* __SOUND_CORE_H */
index 3d3c151..eb7ce96 100644 (file)
 #define HCFG_LEGACYINT         0x00200000      /* 1 = legacy event captured. Write 1 to clear. */
                                                /* NOTE: The rest of the bits in this register  */
                                                /* _are_ relevant under Linux.                  */
-#define HCFG_CODECFORMAT_MASK  0x00070000      /* CODEC format                                 */
+#define HCFG_PUSH_BUTTON_ENABLE 0x00100000     /* Enables Volume Inc/Dec and Mute functions    */
+#define HCFG_BAUD_RATE         0x00080000      /* 0 = 48kHz, 1 = 44.1kHz                       */
+#define HCFG_EXPANDED_MEM      0x00040000      /* 1 = any 16M of 4G addr, 0 = 32M of 2G addr   */
+#define HCFG_CODECFORMAT_MASK  0x00030000      /* CODEC format                                 */
+
+/* Specific to Alice2, CA0102 */
+#define HCFG_CODECFORMAT_AC97_1        0x00000000      /* AC97 CODEC format -- Ver 1.03                */
+#define HCFG_CODECFORMAT_AC97_2        0x00010000      /* AC97 CODEC format -- Ver 2.1                 */
+#define HCFG_AUTOMUTE_ASYNC    0x00008000      /* When set, the async sample rate convertors   */
+                                               /* will automatically mute their output when    */
+                                               /* they are not rate-locked to the external     */
+                                               /* async audio source                           */
+#define HCFG_AUTOMUTE_SPDIF    0x00004000      /* When set, the async sample rate convertors   */
+                                               /* will automatically mute their output when    */
+                                               /* the SPDIF V-bit indicates invalid audio      */
+#define HCFG_EMU32_SLAVE       0x00002000      /* 0 = Master, 1 = Slave. Slave for EMU1010     */
+#define HCFG_SLOW_RAMP         0x00001000      /* Increases Send Smoothing time constant       */
+/* 0x00000800 not used on Alice2 */
+#define HCFG_PHASE_TRACK_MASK  0x00000700      /* When set, forces corresponding input to      */
+                                               /* phase track the previous input.              */
+                                               /* I2S0 can phase track the last S/PDIF input   */
+#define HCFG_I2S_ASRC_ENABLE   0x00000070      /* When set, enables asynchronous sample rate   */
+                                               /* conversion for the corresponding             */
+                                               /* I2S format input                             */
+/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc.  */
+
+
+
+/* Older chips */
 #define HCFG_CODECFORMAT_AC97  0x00000000      /* AC97 CODEC format -- Primary Output          */
 #define HCFG_CODECFORMAT_I2S   0x00010000      /* I2S CODEC format -- Secondary (Rear) Output  */
 #define HCFG_GPINPUT0          0x00004000      /* External pin112                              */
 #define FXRT_CHANNELC          0x0f000000      /* Effects send bus number for channel's effects send C */
 #define FXRT_CHANNELD          0xf0000000      /* Effects send bus number for channel's effects send D */
 
+#define A_HR                   0x0b    /* High Resolution. 24bit playback from host to DSP. */
 #define MAPA                   0x0c            /* Cache map A                                          */
 
 #define MAPB                   0x0d            /* Cache map B                                          */
 #define MAP_PTE_MASK           0xffffe000      /* The 19 MSBs of the PTE indexed by the PTI            */
 #define MAP_PTI_MASK           0x00001fff      /* The 13 bit index to one of the 8192 PTE dwords       */
 
+/* 0x0e, 0x0f: Not used */
+
 #define ENVVOL                 0x10            /* Volume envelope register                             */
 #define ENVVOL_MASK            0x0000ffff      /* Current value of volume envelope state variable      */  
                                                /* 0x8000-n == 666*n usec delay                         */
                                                /* NOTE: All channels contain internal variables; do    */
                                                /* not write to these locations.                        */
 
-/* 1f something */
+/* 0x1f: not used */
 
 #define CD0                    0x20            /* Cache data 0 register                                */
 #define CD1                    0x21            /* Cache data 1 register                                */
 #define FXWC_SPDIFLEFT          (1<<22)                /* 0x00400000 */
 #define FXWC_SPDIFRIGHT         (1<<23)                /* 0x00800000 */
 
+#define A_TBLSZ        `               0x43    /* Effects Tank Internal Table Size. Only low byte or register used */
+
 #define TCBS                   0x44            /* Tank cache buffer size register                      */
 #define TCBS_MASK              0x00000007      /* Tank cache buffer size field                         */
 #define TCBS_BUFFSIZE_16K      0x00000000
 #define FXBA                   0x47            /* FX Buffer Address */
 #define FXBA_MASK              0xfffff000      /* 20 bit base address                                  */
 
-/* 0x48 something - word access, defaults to 3f */
+#define A_HWM                  0x48    /* High PCI Water Mark - word access, defaults to 3f */
 
 #define MICBS                  0x49            /* Microphone buffer size register                      */
 
 #define ADCBS_BUFSIZE_57344    0x0000001e
 #define ADCBS_BUFSIZE_65536    0x0000001f
 
+/* Current Send B, A Amounts */
+#define A_CSBA                 0x4c
+
+/* Current Send D, C Amounts */
+#define A_CSDC                 0x4d
+
+/* Current Send F, E Amounts */
+#define A_CSFE                 0x4e
+
+/* Current Send H, G Amounts */
+#define A_CSHG                 0x4f
+
 
 #define CDCS                   0x50            /* CD-ROM digital channel status register       */
 
 
 #define DBG                    0x52            /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
 
+/* S/PDIF Input C Channel Status */
+#define A_SPSC                 0x52
+
 #define REG53                  0x53            /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
 
 #define A_DBG                   0x53
 #define SPCS_NOTAUDIODATA      0x00000002      /* 0 = Digital audio, 1 = not audio             */
 #define SPCS_PROFESSIONAL      0x00000001      /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)  */
 
+/* 0x57: Not used */
+
 /* The 32-bit CLIx and SOLx registers all have one bit per channel control/status                      */
 #define CLIEL                  0x58            /* Channel loop interrupt enable low register   */
 
 #define AC97SLOT_CNTR          0x10            /* Center enable */
 #define AC97SLOT_LFE           0x20            /* LFE enable */
 
+/* PCB Revision */
+#define A_PCB                  0x5f
+
 // NOTE: 0x60,61,62: 64-bit
 #define CDSRCS                 0x60            /* CD-ROM Sample Rate Converter status register */
 
 
 #define HLIPH                  0x69            /* Channel half loop interrupt pending high register    */
 
-// 0x6a,6b,6c used for some recording
-// 0x6d unused
-// 0x6e,6f - tanktable base / offset
+/* S/PDIF Host Record Index (bypasses SRC) */
+#define A_SPRI                 0x6a
+/* S/PDIF Host Record Address */
+#define A_SPRA                 0x6b
+/* S/PDIF Host Record Control */
+#define A_SPRC                 0x6c
+/* Delayed Interrupt Counter & Enable */
+#define A_DICE                 0x6d
+/* Tank Table Base */
+#define A_TTB                  0x6e
+/* Tank Delay Offset */
+#define A_TDOF                 0x6f
 
 /* This is the MPU port on the card (via the game port)                                                */
 #define A_MUDATA1              0x70
 #define A_FXWC1                        0x74            /* Selects 0x7f-0x60 for FX recording           */
 #define A_FXWC2                        0x75            /* Selects 0x9f-0x80 for FX recording           */
 
+/* Extended Hardware Control */
 #define A_SPDIF_SAMPLERATE     0x76            /* Set the sample rate of SPDIF output          */
 #define A_SAMPLE_RATE          0x76            /* Various sample rate settings. */
 #define A_SAMPLE_RATE_NOT_USED  0x0ffc111e     /* Bits that are not used and cannot be set.    */
 #define A_PCM_96000            0x00004000
 #define A_PCM_44100            0x00008000
 
-/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */
-/* 0x7a, 0x7b - lookup tables */
+/* I2S0 Sample Rate Tracker Status */
+#define A_SRT3                 0x77
+
+/* I2S1 Sample Rate Tracker Status */
+#define A_SRT4                 0x78
+
+/* I2S2 Sample Rate Tracker Status */
+#define A_SRT5                 0x79
+/* - default to 0x01080000 on my audigy 2 ZS --rlrevell        */
+
+/* Tank Table DMA Address */
+#define A_TTDA                 0x7a
+/* Tank Table DMA Data */
+#define A_TTDD                 0x7b
 
 #define A_FXRT2                        0x7c
 #define A_FXRT_CHANNELE                0x0000003f      /* Effects send bus number for channel's effects send E */
 #define A_FXRT_CHANNELC                0x003f0000
 #define A_FXRT_CHANNELD                0x3f000000
 
-
+/* 0x7f: Not used */
 /* Each FX general purpose register is 32 bits in length, all bits are used                    */
 #define FXGPREGBASE            0x100           /* FX general purpose registers base            */
 #define A_FXGPREGBASE          0x400           /* Audigy GPRs, 0x400 to 0x5ff                  */
 #define A_HIWORD_RESULT_MASK   0x007ff000
 #define A_HIWORD_OPA_MASK      0x000007ff
 
+/************************************************************************************************/
+/* EMU1010m HANA FPGA registers                                                                        */
+/************************************************************************************************/
+#define EMU_HANA_DESTHI                0x00    /* 0000xxx  3 bits Link Destination */
+#define EMU_HANA_DESTLO                0x01    /* 00xxxxx  5 bits */
+#define EMU_HANA_SRCHI         0x02    /* 0000xxx  3 bits Link Source */
+#define EMU_HANA_SRCLO         0x03    /* 00xxxxx  5 bits */
+#define EMU_HANA_DOCK_PWR      0x04    /* 000000x  1 bits Audio Dock power */
+#define EMU_HANA_DOCK_PWR_ON           0x01 /* Audio Dock power on */
+#define EMU_HANA_WCLOCK                0x05    /* 0000xxx  3 bits Word Clock source select  */
+                                       /* Must be written after power on to reset DLL */
+                                       /* One is unable to detect the Audio dock without this */
+#define EMU_HANA_WCLOCK_SRC_MASK       0x07
+#define EMU_HANA_WCLOCK_INT_48K                0x00
+#define EMU_HANA_WCLOCK_INT_44_1K      0x01
+#define EMU_HANA_WCLOCK_HANA_SPDIF_IN  0x02
+#define EMU_HANA_WCLOCK_HANA_ADAT_IN   0x03
+#define EMU_HANA_WCLOCK_SYNC_BNCN      0x04
+#define EMU_HANA_WCLOCK_2ND_HANA       0x05
+#define EMU_HANA_WCLOCK_SRC_RESERVED   0x06
+#define EMU_HANA_WCLOCK_OFF            0x07 /* For testing, forces fallback to DEFCLOCK */
+#define EMU_HANA_WCLOCK_MULT_MASK      0x18
+#define EMU_HANA_WCLOCK_1X             0x00
+#define EMU_HANA_WCLOCK_2X             0x08
+#define EMU_HANA_WCLOCK_4X             0x10
+#define EMU_HANA_WCLOCK_MULT_RESERVED  0x18
+
+#define EMU_HANA_DEFCLOCK      0x06    /* 000000x  1 bits Default Word Clock  */
+#define EMU_HANA_DEFCLOCK_48K          0x00
+#define EMU_HANA_DEFCLOCK_44_1K                0x01
+
+#define EMU_HANA_UNMUTE                0x07    /* 000000x  1 bits Mute all audio outputs  */
+#define EMU_MUTE                       0x00
+#define EMU_UNMUTE                     0x01
+
+#define EMU_HANA_FPGA_CONFIG   0x08    /* 00000xx  2 bits Config control of FPGAs  */
+#define EMU_HANA_FPGA_CONFIG_AUDIODOCK 0x01 /* Set in order to program FPGA on Audio Dock */
+#define EMU_HANA_FPGA_CONFIG_HANA      0x02 /* Set in order to program FPGA on Hana */
+
+#define EMU_HANA_IRQ_ENABLE    0x09    /* 000xxxx  4 bits IRQ Enable  */
+#define EMU_HANA_IRQ_WCLK_CHANGED      0x01
+#define EMU_HANA_IRQ_ADAT              0x02
+#define EMU_HANA_IRQ_DOCK              0x04
+#define EMU_HANA_IRQ_DOCK_LOST         0x08
+
+#define EMU_HANA_SPDIF_MODE    0x0a    /* 00xxxxx  5 bits SPDIF MODE  */
+#define EMU_HANA_SPDIF_MODE_TX_COMSUMER        0x00
+#define EMU_HANA_SPDIF_MODE_TX_PRO     0x01
+#define EMU_HANA_SPDIF_MODE_TX_NOCOPY  0x02
+#define EMU_HANA_SPDIF_MODE_RX_COMSUMER        0x00
+#define EMU_HANA_SPDIF_MODE_RX_PRO     0x04
+#define EMU_HANA_SPDIF_MODE_RX_NOCOPY  0x08
+#define EMU_HANA_SPDIF_MODE_RX_INVALID 0x10
+
+#define EMU_HANA_OPTICAL_TYPE  0x0b    /* 00000xx  2 bits ADAT or SPDIF in/out  */
+#define EMU_HANA_OPTICAL_IN_SPDIF      0x00
+#define EMU_HANA_OPTICAL_IN_ADAT       0x01
+#define EMU_HANA_OPTICAL_OUT_SPDIF     0x00
+#define EMU_HANA_OPTICAL_OUT_ADAT      0x02
+
+#define EMU_HANA_MIDI_IN               0x0c    /* 000000x  1 bit  Control MIDI  */
+#define EMU_HANA_MIDI_IN_FROM_HAMOA    0x00 /* HAMOA MIDI in to Alice 2 MIDI B */
+#define EMU_HANA_MIDI_IN_FROM_DOCK     0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */
+
+#define EMU_HANA_DOCK_LEDS_1   0x0d    /* 000xxxx  4 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_1_MIDI1     0x01    /* MIDI 1 LED on */
+#define EMU_HANA_DOCK_LEDS_1_MIDI2     0x02    /* MIDI 2 LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN  0x04    /* SMPTE IN LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT 0x08    /* SMPTE OUT LED on */
+
+#define EMU_HANA_DOCK_LEDS_2   0x0e    /* 0xxxxxx  6 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_2_44K       0x01    /* 44.1 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_48K       0x02    /* 48 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_96K       0x04    /* 96 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_192K      0x08    /* 192 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_LOCK      0x10    /* LOCK LED on */
+#define EMU_HANA_DOCK_LEDS_2_EXT       0x20    /* EXT LED on */
+
+#define EMU_HANA_DOCK_LEDS_3   0x0f    /* 0xxxxxx  6 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_A    0x01    /* Mic A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_B    0x02    /* Mic B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A  0x04    /* Signal A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B  0x08    /* Signal B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP       0x10    /* Manual Clip detection */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL     0x20    /* Manual Signal detection */
+
+#define EMU_HANA_ADC_PADS      0x10    /* 0000xxx  3 bit  Audio Dock ADC 14dB pads */
+#define EMU_HANA_DOCK_ADC_PAD1 0x01    /* 14dB Attenuation on Audio Dock ADC 1 */
+#define EMU_HANA_DOCK_ADC_PAD2 0x02    /* 14dB Attenuation on Audio Dock ADC 2 */
+#define EMU_HANA_DOCK_ADC_PAD3 0x04    /* 14dB Attenuation on Audio Dock ADC 3 */
+#define EMU_HANA_0202_ADC_PAD1 0x08    /* 14dB Attenuation on 0202 ADC 1 */
+
+#define EMU_HANA_DOCK_MISC     0x11    /* 0xxxxxx  6 bit  Audio Dock misc bits */
+#define EMU_HANA_DOCK_DAC1_MUTE        0x01    /* DAC 1 Mute */
+#define EMU_HANA_DOCK_DAC2_MUTE        0x02    /* DAC 2 Mute */
+#define EMU_HANA_DOCK_DAC3_MUTE        0x04    /* DAC 3 Mute */
+#define EMU_HANA_DOCK_DAC4_MUTE        0x08    /* DAC 4 Mute */
+#define EMU_HANA_DOCK_PHONES_192_DAC1  0x00    /* DAC 1 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC2  0x10    /* DAC 2 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC3  0x20    /* DAC 3 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC4  0x30    /* DAC 4 Headphones source at 192kHz */
+
+#define EMU_HANA_MIDI_OUT      0x12    /* 00xxxxx  5 bit  Source for each MIDI out port */
+#define EMU_HANA_MIDI_OUT_0202 0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK1        0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK2        0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_SYNC2        0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_LOOP 0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */
+
+#define EMU_HANA_DAC_PADS      0x13    /* 00xxxxx  5 bit  DAC 14dB attenuation pads */
+#define EMU_HANA_DOCK_DAC_PAD1 0x01    /* 14dB Attenuation on AudioDock DAC 1. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD2 0x02    /* 14dB Attenuation on AudioDock DAC 2. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD3 0x04    /* 14dB Attenuation on AudioDock DAC 3. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD4 0x08    /* 14dB Attenuation on AudioDock DAC 4. Left and Right */
+#define EMU_HANA_0202_DAC_PAD1 0x10    /* 14dB Attenuation on 0202 DAC 1. Left and Right */
+
+/* 0x14 - 0x1f Unused R/W registers */
+#define EMU_HANA_IRQ_STATUS    0x20    /* 000xxxx  4 bits IRQ Status  */
+#if 0  /* Already defined for reg 0x09 IRQ_ENABLE */
+#define EMU_HANA_IRQ_WCLK_CHANGED      0x01
+#define EMU_HANA_IRQ_ADAT              0x02
+#define EMU_HANA_IRQ_DOCK              0x04
+#define EMU_HANA_IRQ_DOCK_LOST         0x08
+#endif
+
+#define EMU_HANA_OPTION_CARDS  0x21    /* 000xxxx  4 bits Presence of option cards */
+#define EMU_HANA_OPTION_HAMOA  0x01    /* HAMOA card present */
+#define EMU_HANA_OPTION_SYNC   0x02    /* Sync card present */
+#define EMU_HANA_OPTION_DOCK_ONLINE    0x04    /* Audio Dock online and FPGA configured */
+#define EMU_HANA_OPTION_DOCK_OFFLINE   0x08    /* Audio Dock online and FPGA not configured */
+
+#define EMU_HANA_ID            0x22    /* 1010101  7 bits ID byte & 0x7f = 0x55 */
+
+#define EMU_HANA_MAJOR_REV     0x23    /* 0000xxx  3 bit  Hana FPGA Major rev */
+#define EMU_HANA_MINOR_REV     0x24    /* 0000xxx  3 bit  Hana FPGA Minor rev */
+
+#define EMU_DOCK_MAJOR_REV     0x25    /* 0000xxx  3 bit  Audio Dock FPGA Major rev */
+#define EMU_DOCK_MINOR_REV     0x26    /* 0000xxx  3 bit  Audio Dock FPGA Minor rev */
+
+#define EMU_DOCK_BOARD_ID      0x27    /* 00000xx  2 bits Audio Dock ID pins */
+#define EMU_DOCK_BOARD_ID0     0x00    /* ID bit 0 */
+#define EMU_DOCK_BOARD_ID1     0x03    /* ID bit 1 */
+
+#define EMU_HANA_WC_SPDIF_HI   0x28    /* 0xxxxxx  6 bit  SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_SPDIF_LO   0x29    /* 0xxxxxx  6 bit  SPDIF IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_ADAT_HI    0x2a    /* 0xxxxxx  6 bit  ADAT IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_ADAT_LO    0x2b    /* 0xxxxxx  6 bit  ADAT IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_BNC_LO     0x2c    /* 0xxxxxx  6 bit  BNC IN Word clock, lower 6 bits */
+#define EMU_HANA_WC_BNC_HI     0x2d    /* 0xxxxxx  6 bit  BNC IN Word clock, upper 6 bits */
+
+#define EMU_HANA2_WC_SPDIF_HI  0x2e    /* 0xxxxxx  6 bit  HANA2 SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA2_WC_SPDIF_LO  0x2f    /* 0xxxxxx  6 bit  HANA2 SPDIF IN Word clock, lower 6 bits */
+/* 0x30 - 0x3f Unused Read only registers */
+
+/************************************************************************************************/
+/* EMU1010m HANA Destinations                                                                  */
+/************************************************************************************************/
+#define EMU_DST_ALICE2_EMU32_0 0x000f  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_1 0x0000  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_2 0x0001  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_3 0x0002  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_4 0x0003  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_5 0x0004  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_6 0x0005  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_7 0x0006  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_8 0x0007  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_9 0x0008  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_A 0x0009  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_B 0x000a  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_C 0x000b  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_D 0x000c  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_E 0x000d  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_F 0x000e  /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_DOCK_DAC1_LEFT1        0x0100  /* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_LEFT2        0x0101  /* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_LEFT3        0x0102  /* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_LEFT4        0x0103  /* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT1       0x0104  /* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_RIGHT2       0x0105  /* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT3       0x0106  /* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT4       0x0107  /* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT1        0x0108  /* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_LEFT2        0x0109  /* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_LEFT3        0x010a  /* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT4        0x010b  /* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT1       0x010c  /* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_RIGHT2       0x010d  /* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT3       0x010e  /* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT4       0x010f  /* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT1        0x0110  /* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_LEFT2        0x0111  /* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_LEFT3        0x0112  /* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT4        0x0113  /* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_LEFT1      0x0112  /* Audio Dock PHONES Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_LEFT2      0x0113  /* Audio Dock PHONES Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT1       0x0114  /* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_RIGHT2       0x0115  /* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT3       0x0116  /* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT4       0x0117  /* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_RIGHT1     0x0116  /* Audio Dock PHONES Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_RIGHT2     0x0117  /* Audio Dock PHONES Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT1        0x0118  /* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_LEFT2        0x0119  /* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT3        0x011a  /* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_LEFT4        0x011b  /* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_LEFT1       0x011a  /* Audio Dock SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_LEFT2       0x011b  /* Audio Dock SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT1       0x011c  /* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_RIGHT2       0x011d  /* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT3       0x011e  /* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT4       0x011f  /* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_RIGHT1      0x011e  /* Audio Dock SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_RIGHT2      0x011f  /* Audio Dock SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_LEFT1       0x0200  /* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_LEFT2       0x0202  /* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_RIGHT1      0x0201  /* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_RIGHT2      0x0203  /* Hana SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT1        0x0300  /* Hamoa DAC Left, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_LEFT2        0x0302  /* Hamoa DAC Left, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT3        0x0304  /* Hamoa DAC Left, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_LEFT4        0x0306  /* Hamoa DAC Left, 4th or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT1       0x0301  /* Hamoa DAC Right, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_RIGHT2       0x0303  /* Hamoa DAC Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT3       0x0305  /* Hamoa DAC Right, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT4       0x0307  /* Hamoa DAC Right, 4th or 192kHz */
+#define EMU_DST_HANA_ADAT      0x0400  /* Hana ADAT 8 channel out +0 to +7 */
+#define EMU_DST_ALICE_I2S0_LEFT                0x0500  /* Alice2 I2S0 Left */
+#define EMU_DST_ALICE_I2S0_RIGHT       0x0501  /* Alice2 I2S0 Right */
+#define EMU_DST_ALICE_I2S1_LEFT                0x0600  /* Alice2 I2S1 Left */
+#define EMU_DST_ALICE_I2S1_RIGHT       0x0601  /* Alice2 I2S1 Right */
+#define EMU_DST_ALICE_I2S2_LEFT                0x0700  /* Alice2 I2S2 Left */
+#define EMU_DST_ALICE_I2S2_RIGHT       0x0701  /* Alice2 I2S2 Right */
+
+/************************************************************************************************/
+/* EMU1010m HANA Sources                                                                       */
+/************************************************************************************************/
+#define EMU_SRC_SILENCE                0x0000  /* Silence */
+#define EMU_SRC_DOCK_MIC_A1    0x0100  /* Audio Dock Mic A, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_A2    0x0101  /* Audio Dock Mic A, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_A3    0x0102  /* Audio Dock Mic A, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_A4    0x0103  /* Audio Dock Mic A, 4th or 192kHz */
+#define EMU_SRC_DOCK_MIC_B1    0x0104  /* Audio Dock Mic B, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_B2    0x0105  /* Audio Dock Mic B, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_B3    0x0106  /* Audio Dock Mic B, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_B4    0x0107  /* Audio Dock Mic B, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT1        0x0108  /* Audio Dock ADC1 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_LEFT2        0x0109  /* Audio Dock ADC1 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT3        0x010a  /* Audio Dock ADC1 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT4        0x010b  /* Audio Dock ADC1 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT1       0x010c  /* Audio Dock ADC1 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_RIGHT2       0x010d  /* Audio Dock ADC1 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT3       0x010e  /* Audio Dock ADC1 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT4       0x010f  /* Audio Dock ADC1 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT1        0x0110  /* Audio Dock ADC2 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_LEFT2        0x0111  /* Audio Dock ADC2 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT3        0x0112  /* Audio Dock ADC2 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT4        0x0113  /* Audio Dock ADC2 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT1       0x0114  /* Audio Dock ADC2 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_RIGHT2       0x0115  /* Audio Dock ADC2 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT3       0x0116  /* Audio Dock ADC2 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT4       0x0117  /* Audio Dock ADC2 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT1        0x0118  /* Audio Dock ADC3 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_LEFT2        0x0119  /* Audio Dock ADC3 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT3        0x011a  /* Audio Dock ADC3 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT4        0x011b  /* Audio Dock ADC3 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT1       0x011c  /* Audio Dock ADC3 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_RIGHT2       0x011d  /* Audio Dock ADC3 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT3       0x011e  /* Audio Dock ADC3 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT4       0x011f  /* Audio Dock ADC3 Right, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT1        0x0200  /* Hamoa ADC Left, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_LEFT2        0x0202  /* Hamoa ADC Left, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT3        0x0204  /* Hamoa ADC Left, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT4        0x0206  /* Hamoa ADC Left, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT1       0x0201  /* Hamoa ADC Right, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_RIGHT2       0x0203  /* Hamoa ADC Right, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT3       0x0205  /* Hamoa ADC Right, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT4       0x0207  /* Hamoa ADC Right, 4th or 192kHz */
+#define EMU_SRC_ALICE_EMU32A           0x0300  /* Alice2 EMU32a 16 outputs. +0 to +0xf */
+#define EMU_SRC_ALICE_EMU32B           0x0310  /* Alice2 EMU32b 16 outputs. +0 to +0xf */
+#define EMU_SRC_HANA_ADAT      0x0400  /* Hana ADAT 8 channel in +0 to +7 */
+#define EMU_SRC_HANA_SPDIF_LEFT1       0x0500  /* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_LEFT2       0x0502  /* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_SRC_HANA_SPDIF_RIGHT1      0x0501  /* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_RIGHT2      0x0503  /* Hana SPDIF Right, 2nd or 96kHz */
+/* 0x600 and 0x700 no used */
 
 /* ------------------- STRUCTURES -------------------- */
 
@@ -1063,7 +1425,7 @@ struct snd_emu_chip_details {
        unsigned char spdif_bug;    /* Has Spdif phasing bug */
        unsigned char ac97_chip;    /* Has an AC97 chip: 1 = mandatory, 2 = optional */
        unsigned char ecard;        /* APS EEPROM */
-       unsigned char emu1212m;     /* EMU 1212m card */
+       unsigned char emu1010;     /* EMU 1010m card */
        unsigned char spi_dac;      /* SPI interface for DAC */
        unsigned char i2c_adc;      /* I2C interface for ADC */
        unsigned char adc_1361t;    /* Use Philips 1361T ADC */
@@ -1072,6 +1434,14 @@ struct snd_emu_chip_details {
        const char *id;         /* for backward compatibility - can be NULL if not needed */
 };
 
+struct snd_emu1010 {
+       unsigned int output_source[64];
+       unsigned int input_source[64];
+       unsigned int adc_pads; /* bit mask */
+       unsigned int dac_pads; /* bit mask */
+       unsigned int internal_clock; /* 44100 or 48000 */
+};
+
 struct snd_emu10k1 {
        int irq;
 
@@ -1079,6 +1449,7 @@ struct snd_emu10k1 {
        unsigned int tos_link: 1,               /* tos link detected */
                rear_ac97: 1,                   /* rear channels are on AC'97 */
                enable_ir: 1;
+       unsigned int support_tlv :1;
        /* Contains profile of card capabilities */
        const struct snd_emu_chip_details *card_capabilities;
        unsigned int audigy;                    /* is Audigy? */
@@ -1104,6 +1475,8 @@ struct snd_emu10k1 {
        spinlock_t memblk_lock;
 
        unsigned int spdif_bits[3];             /* s/pdif out setup */
+       unsigned int i2c_capture_source;
+       u8 i2c_capture_volume[4][2];
 
        struct snd_emu10k1_fx8010 fx8010;               /* FX8010 info */
        int gpr_base;
@@ -1132,6 +1505,7 @@ struct snd_emu10k1 {
        int p16v_device_offset;
        u32 p16v_capture_source;
        u32 p16v_capture_channel;
+        struct snd_emu1010 emu1010;
        struct snd_emu10k1_pcm_mixer pcm_mixer[32];
        struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK];
        struct snd_kcontrol *ctl_send_routing;
@@ -1208,6 +1582,10 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
 unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
@@ -1524,11 +1902,20 @@ struct snd_emu10k1_fx8010_control_gpr {
        unsigned int value[32];         /* initial values */
        unsigned int min;               /* minimum range */
        unsigned int max;               /* maximum range */
-       union {
-               snd_kcontrol_tlv_rw_t *c;
-               unsigned int *p;
-       } tlv;
        unsigned int translation;       /* translation type (EMU10K1_GPR_TRANSLATION*) */
+       const unsigned int *tlv;
+};
+
+/* old ABI without TLV support */
+struct snd_emu10k1_fx8010_control_old_gpr {
+       struct snd_ctl_elem_id id;
+       unsigned int vcount;
+       unsigned int count;
+       unsigned short gpr[32];
+       unsigned int value[32];
+       unsigned int min;
+       unsigned int max;
+       unsigned int translation;
 };
 
 struct snd_emu10k1_fx8010_code {
@@ -1579,6 +1966,8 @@ struct snd_emu10k1_fx8010_pcm_rec {
        unsigned int res2;              /* reserved */
 };
 
+#define SNDRV_EMU10K1_VERSION          SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
 #define SNDRV_EMU10K1_IOCTL_INFO       _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info)
 #define SNDRV_EMU10K1_IOCTL_CODE_POKE  _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code)
 #define SNDRV_EMU10K1_IOCTL_CODE_PEEK  _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code)
@@ -1587,6 +1976,7 @@ struct snd_emu10k1_fx8010_pcm_rec {
 #define SNDRV_EMU10K1_IOCTL_TRAM_PEEK  _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram)
 #define SNDRV_EMU10K1_IOCTL_PCM_POKE   _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec)
 #define SNDRV_EMU10K1_IOCTL_PCM_PEEK   _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec)
+#define SNDRV_EMU10K1_IOCTL_PVERSION   _IOR ('H', 0x40, int)
 #define SNDRV_EMU10K1_IOCTL_STOP       _IO  ('H', 0x80)
 #define SNDRV_EMU10K1_IOCTL_CONTINUE   _IO  ('H', 0x81)
 #define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82)
index 2f645df..ee6bc2d 100644 (file)
@@ -56,6 +56,8 @@ struct snd_pcm_hardware {
        size_t fifo_size;               /* fifo size in bytes */
 };
 
+struct snd_pcm_substream;
+
 struct snd_pcm_ops {
        int (*open)(struct snd_pcm_substream *substream);
        int (*close)(struct snd_pcm_substream *substream);
@@ -384,6 +386,7 @@ struct snd_pcm_substream {
        struct snd_info_entry *proc_sw_params_entry;
        struct snd_info_entry *proc_status_entry;
        struct snd_info_entry *proc_prealloc_entry;
+       struct snd_info_entry *proc_prealloc_max_entry;
 #endif
        /* misc flags */
        unsigned int hw_opened: 1;
@@ -427,6 +430,7 @@ struct snd_pcm {
        wait_queue_head_t open_wait;
        void *private_data;
        void (*private_free) (struct snd_pcm *pcm);
+       struct device *dev; /* actual hw device this belongs to */
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        struct snd_pcm_oss oss;
 #endif
diff --git a/include/sound/pt2258.h b/include/sound/pt2258.h
new file mode 100644 (file)
index 0000000..160f812
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *   ALSA Driver for the PT2258 volume controller.
+ *
+ *     Copyright (c) 2006  Jochen Voss <voss@seehuhn.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#ifndef __SOUND_PT2258_H
+#define __SOUND_PT2258_H
+
+struct snd_pt2258 {
+       struct snd_card *card;
+       struct snd_i2c_bus *i2c_bus;
+       struct snd_i2c_device *i2c_dev;
+
+       unsigned char volume[6];
+       int mute;
+};
+
+extern int snd_pt2258_reset(struct snd_pt2258 *pt);
+extern int snd_pt2258_build_controls(struct snd_pt2258 *pt);
+
+#endif /* __SOUND_PT2258_H */
index caf6fe2..736eac7 100644 (file)
@@ -114,9 +114,21 @@ struct snd_sb_csp_info {
 #ifdef __KERNEL__
 #include "sb.h"
 #include "hwdep.h"
+#include <linux/firmware.h>
 
 struct snd_sb_csp;
 
+/* indices for the known CSP programs */
+enum {
+       CSP_PROGRAM_MULAW,
+       CSP_PROGRAM_ALAW,
+       CSP_PROGRAM_ADPCM_INIT,
+       CSP_PROGRAM_ADPCM_PLAYBACK,
+       CSP_PROGRAM_ADPCM_CAPTURE,
+
+       CSP_PROGRAM_COUNT
+};
+
 /*
  * CSP operators
  */
@@ -159,6 +171,8 @@ struct snd_sb_csp {
        struct snd_kcontrol *qsound_space;
 
        struct mutex access_mutex;      /* locking */
+
+       const struct firmware *csp_programs[CSP_PROGRAM_COUNT];
 };
 
 int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep);
index 0b9e5de..9688d4b 100644 (file)
@@ -85,6 +85,7 @@ struct _snd_wavefront {
        char hw_version[2];                /* major = [0], minor = [1] */
        char israw;                        /* needs Motorola microcode */
        char has_fx;                       /* has FX processor (Tropez+) */
+       char fx_initialized;               /* FX's register pages initialized */
        char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */
        char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */
        char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
@@ -94,6 +95,7 @@ struct _snd_wavefront {
        spinlock_t irq_lock;
        wait_queue_head_t interrupt_sleeper; 
        snd_wavefront_midi_t midi;         /* ICS2115 MIDI interface */
+       struct snd_card *card;
 };
 
 struct _snd_wavefront_card {
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
new file mode 100644 (file)
index 0000000..2b1ae8e
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
+ *
+ * Author:             Liam Girdwood
+ * Created:            Aug 11th 2005
+ * Copyright:  Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_DAPM_H
+#define __LINUX_SND_SOC_DAPM_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+
+/* widget has no PM register bit */
+#define SND_SOC_NOPM   -1
+
+/*
+ * SoC dynamic audio power managment
+ *
+ * We can have upto 4 power domains
+ *     1. Codec domain - VREF, VMID
+ *     Usually controlled at codec probe/remove, although can be set
+ *     at stream time if power is not needed for sidetone, etc.
+ *  2. Platform/Machine domain - physically connected inputs and outputs
+ *     Is platform/machine and user action specific, is set in the machine
+ *     driver and by userspace e.g when HP are inserted
+ *  3. Path domain - Internal codec path mixers
+ *     Are automatically set when mixer and mux settings are
+ *     changed by the user.
+ *  4. Stream domain - DAC's and ADC's.
+ *     Enabled when stream playback/capture is started.
+ */
+
+/* codec domain */
+#define SND_SOC_DAPM_VMID(wname) \
+{      .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0}
+
+/* platform domain */
+#define SND_SOC_DAPM_INPUT(wname) \
+{      .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0}
+#define SND_SOC_DAPM_OUTPUT(wname) \
+{      .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0}
+#define SND_SOC_DAPM_MIC(wname, wevent) \
+{      .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
+#define SND_SOC_DAPM_HP(wname, wevent) \
+{      .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_SPK(wname, wevent) \
+{      .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_LINE(wname, wevent) \
+{      .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+
+/* path domain */
+#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
+        wcontrols, wncontrols) \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
+        wcontrols, wncontrols)\
+{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
+{      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
+#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
+{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
+{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+
+/* path domain with event - event handler must return 0 for success */
+#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
+       wncontrols, wevent, wflags) \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+       .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
+       wncontrols, wevent, wflags) \
+{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+       .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
+{      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
+       .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
+       wevent, wflags) \
+{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \
+       .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
+       wevent, wflags) \
+{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+       .event = wevent, .event_flags = wflags}
+
+/* events that are pre and post DAPM */
+#define SND_SOC_DAPM_PRE(wname, wevent) \
+{      .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_POST(wname, wevent) \
+{      .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
+
+/* stream domain */
+#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
+{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
+       .shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
+{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
+       .shift = wshift, .invert = winvert}
+
+/* dapm kcontrol types */
+#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \
+       power) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
+                ((mask) << 16) | ((invert) << 24) }
+#define SOC_DAPM_ENUM(xname, xenum) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_enum_double, \
+       .get = snd_soc_dapm_get_enum_double, \
+       .put = snd_soc_dapm_put_enum_double, \
+       .private_value = (unsigned long)&xenum }
+
+/* dapm stream operations */
+#define SND_SOC_DAPM_STREAM_NOP                        0x0
+#define SND_SOC_DAPM_STREAM_START              0x1
+#define SND_SOC_DAPM_STREAM_STOP               0x2
+#define SND_SOC_DAPM_STREAM_SUSPEND            0x4
+#define SND_SOC_DAPM_STREAM_RESUME             0x8
+#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
+#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE      0x20
+
+/* dapm event types */
+#define SND_SOC_DAPM_PRE_PMU   0x1     /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU  0x2             /* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD   0x4     /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD  0x8             /* after widget power down */
+#define SND_SOC_DAPM_PRE_REG   0x10    /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG  0x20    /* after audio path setup */
+
+/* convenience event type detection */
+#define SND_SOC_DAPM_EVENT_ON(e)       \
+       (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
+#define SND_SOC_DAPM_EVENT_OFF(e)      \
+       (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
+
+struct snd_soc_dapm_widget;
+enum snd_soc_dapm_type;
+struct snd_soc_dapm_path;
+struct snd_soc_dapm_pin;
+
+/* dapm controls */
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+       const struct snd_soc_dapm_widget *widget);
+
+/* dapm path setup */
+int snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
+       const char *sink_name, const char *control_name, const char *src_name);
+int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
+void snd_soc_dapm_free(struct snd_soc_device *socdev);
+
+/* dapm events */
+int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
+       int event);
+
+/* dapm sys fs - used by the core */
+int snd_soc_dapm_sys_add(struct device *dev);
+
+/* dapm audio endpoint control */
+int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
+       char *pin, int status);
+int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec);
+
+/* dapm widget types */
+enum snd_soc_dapm_type {
+       snd_soc_dapm_input = 0,         /* input pin */
+       snd_soc_dapm_output,            /* output pin */
+       snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
+       snd_soc_dapm_mixer,                     /* mixes several analog signals together */
+       snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
+       snd_soc_dapm_adc,                       /* analog to digital converter */
+       snd_soc_dapm_dac,                       /* digital to analog converter */
+       snd_soc_dapm_micbias,           /* microphone bias (power) */
+       snd_soc_dapm_mic,                       /* microphone */
+       snd_soc_dapm_hp,                        /* headphones */
+       snd_soc_dapm_spk,                       /* speaker */
+       snd_soc_dapm_line,                      /* line input/output */
+       snd_soc_dapm_switch,            /* analog switch */
+       snd_soc_dapm_vmid,                      /* codec bias/vmid - to minimise pops */
+       snd_soc_dapm_pre,                       /* machine specific pre widget - exec first */
+       snd_soc_dapm_post,                      /* machine specific post widget - exec last */
+};
+
+/* dapm audio path between two widgets */
+struct snd_soc_dapm_path {
+       char *name;
+       char *long_name;
+
+       /* source (input) and sink (output) widgets */
+       struct snd_soc_dapm_widget *source;
+       struct snd_soc_dapm_widget *sink;
+       struct snd_kcontrol *kcontrol;
+
+       /* status */
+       u32 connect:1;  /* source and sink widgets are connected */
+       u32 walked:1;   /* path has been walked */
+
+       struct list_head list_source;
+       struct list_head list_sink;
+       struct list_head list;
+};
+
+/* dapm widget */
+struct snd_soc_dapm_widget {
+       enum snd_soc_dapm_type id;
+       char *name;             /* widget name */
+       char *sname;    /* stream name */
+       struct snd_soc_codec *codec;
+       struct list_head list;
+
+       /* dapm control */
+       short reg;                                              /* negative reg = no direct dapm */
+       unsigned char shift;                    /* bits to shift */
+       unsigned int saved_value;               /* widget saved value */
+       unsigned int value;                             /* widget current value */
+       unsigned char power:1;                  /* block power status */
+       unsigned char invert:1;                 /* invert the power bit */
+       unsigned char active:1;                 /* active stream on DAC, ADC's */
+       unsigned char connected:1;              /* connected codec pin */
+       unsigned char new:1;                    /* cnew complete */
+       unsigned char ext:1;                    /* has external widgets */
+       unsigned char muted:1;                  /* muted for pop reduction */
+       unsigned char suspend:1;                /* was active before suspend */
+       unsigned char pmdown:1;                 /* waiting for timeout */
+
+       /* external events */
+       unsigned short event_flags;             /* flags to specify event types */
+       int (*event)(struct snd_soc_dapm_widget*, int);
+
+       /* kcontrols that relate to this widget */
+       int num_kcontrols;
+       const struct snd_kcontrol_new *kcontrols;
+
+       /* widget input and outputs */
+       struct list_head sources;
+       struct list_head sinks;
+};
+
+#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
new file mode 100644 (file)
index 0000000..b1dc364
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * linux/sound/soc.h -- ALSA SoC Layer
+ *
+ * Author:             Liam Girdwood
+ * Created:            Aug 11th 2005
+ * Copyright:  Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_H
+#define __LINUX_SND_SOC_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/ac97_codec.h>
+
+#define SND_SOC_VERSION "0.13.0"
+
+/*
+ * Convenience kcontrol builders
+ */
+#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
+       ((shift) << 12) | ((mask) << 16) | ((invert) << 24))
+#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
+       ((invert) << 31))
+#define SOC_SINGLE(xname, reg, shift, mask, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+       .put = snd_soc_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
+       .put = snd_soc_put_volsw, \
+       .private_value = (reg) | ((shift_left) << 8) | \
+               ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_volsw_2r, \
+       .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
+       .private_value = (reg_left) | ((shift) << 8)  | \
+               ((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+{      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
+       .mask = xmask, .texts = xtexts }
+#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
+       SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
+{      .mask = xmask, .texts = xtexts }
+#define SOC_ENUM(xname, xenum) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
+       .info = snd_soc_info_enum_double, \
+       .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
+       .private_value = (unsigned long)&xenum }
+#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
+        xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_bool_ext, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = xdata }
+#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_enum_ext, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&xenum }
+
+/*
+ * Digital Audio Interface (DAI) types
+ */
+#define SND_SOC_DAI_AC97       0x1
+#define SND_SOC_DAI_I2S                0x2
+#define SND_SOC_DAI_PCM                0x4
+
+/*
+ * DAI hardware audio formats
+ */
+#define SND_SOC_DAIFMT_I2S             0       /* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J 1       /* Right justified mode */
+#define SND_SOC_DAIFMT_LEFT_J  2       /* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A   3       /* L data msb after FRM or LRC */
+#define SND_SOC_DAIFMT_DSP_B   4       /* L data msb during FRM or LRC */
+#define SND_SOC_DAIFMT_AC97            5       /* AC97 */
+
+#define SND_SOC_DAIFMT_MSB     SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB     SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI Gating
+ */
+#define SND_SOC_DAIFMT_CONT                    (0 << 4)        /* continuous clock */
+#define SND_SOC_DAIFMT_GATED           (1 << 4)        /* clock is gated when not Tx/Rx */
+
+/*
+ * DAI hardware signal inversions
+ */
+#define SND_SOC_DAIFMT_NB_NF           (0 << 8)        /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF           (1 << 8)        /* normal bclk + inv frm */
+#define SND_SOC_DAIFMT_IB_NF           (2 << 8)        /* invert bclk + nor frm */
+#define SND_SOC_DAIFMT_IB_IF           (3 << 8)        /* invert bclk + frm */
+
+/*
+ * DAI hardware clock masters
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and frm master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */
+#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK             0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK              0x00f0
+#define SND_SOC_DAIFMT_INV_MASK                        0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK             0xf000
+
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN       0
+#define SND_SOC_CLOCK_OUT      1
+
+/*
+ * AC97 codec ID's bitmask
+ */
+#define SND_SOC_DAI_AC97_ID0   (1 << 0)
+#define SND_SOC_DAI_AC97_ID1   (1 << 1)
+#define SND_SOC_DAI_AC97_ID2   (1 << 2)
+#define SND_SOC_DAI_AC97_ID3   (1 << 3)
+
+struct snd_soc_device;
+struct snd_soc_pcm_stream;
+struct snd_soc_ops;
+struct snd_soc_dai_mode;
+struct snd_soc_pcm_runtime;
+struct snd_soc_codec_dai;
+struct snd_soc_cpu_dai;
+struct snd_soc_codec;
+struct snd_soc_machine_config;
+struct soc_enum;
+struct snd_soc_ac97_ops;
+struct snd_soc_clock_info;
+
+typedef int (*hw_write_t)(void *,const char* ,int);
+typedef int (*hw_read_t)(void *,char* ,int);
+
+extern struct snd_ac97_bus_ops soc_ac97_ops;
+
+/* pcm <-> DAI connect */
+void snd_soc_free_pcms(struct snd_soc_device *socdev);
+int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
+int snd_soc_register_card(struct snd_soc_device *socdev);
+
+/* set runtime hw params */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+       const struct snd_pcm_hardware *hw);
+
+/* codec IO */
+#define snd_soc_read(codec, reg) codec->read(codec, reg)
+#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
+
+/* codec register bit access */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+                               unsigned short mask, unsigned short value);
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+                               unsigned short mask, unsigned short value);
+
+int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+       struct snd_ac97_bus_ops *ops, int num);
+void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+
+/*
+ *Controls
+ */
+struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
+       void *data, char *long_name);
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+
+/* SoC PCM stream information */
+struct snd_soc_pcm_stream {
+       char *stream_name;
+       u64 formats;                    /* SNDRV_PCM_FMTBIT_* */
+       unsigned int rates;             /* SNDRV_PCM_RATE_* */
+       unsigned int rate_min;          /* min rate */
+       unsigned int rate_max;          /* max rate */
+       unsigned int channels_min;      /* min channels */
+       unsigned int channels_max;      /* max channels */
+       unsigned int active:1;          /* stream is in use */
+};
+
+/* SoC audio ops */
+struct snd_soc_ops {
+       int (*startup)(struct snd_pcm_substream *);
+       void (*shutdown)(struct snd_pcm_substream *);
+       int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+       int (*hw_free)(struct snd_pcm_substream *);
+       int (*prepare)(struct snd_pcm_substream *);
+       int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+/* ASoC codec DAI ops */
+struct snd_soc_codec_ops {
+       /* codec DAI clocking configuration */
+       int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir);
+       int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out);
+       int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
+               int div_id, int div);
+
+       /* CPU DAI format configuration */
+       int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
+               unsigned int fmt);
+       int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
+               unsigned int mask, int slots);
+       int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
+
+       /* digital mute */
+       int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
+};
+
+/* ASoC cpu DAI ops */
+struct snd_soc_cpu_ops {
+       /* CPU DAI clocking configuration */
+       int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
+               int clk_id, unsigned int freq, int dir);
+       int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
+               int div_id, int div);
+       int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+       /* CPU DAI format configuration */
+       int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
+               unsigned int fmt);
+       int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
+               unsigned int mask, int slots);
+       int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
+};
+
+/* SoC Codec DAI */
+struct snd_soc_codec_dai {
+       char *name;
+       int id;
+
+       /* DAI capabilities */
+       struct snd_soc_pcm_stream playback;
+       struct snd_soc_pcm_stream capture;
+
+       /* DAI runtime info */
+       struct snd_soc_codec *codec;
+       unsigned int active;
+       unsigned char pop_wait:1;
+
+       /* ops */
+       struct snd_soc_ops ops;
+       struct snd_soc_codec_ops dai_ops;
+
+       /* DAI private data */
+       void *private_data;
+};
+
+/* SoC CPU DAI */
+struct snd_soc_cpu_dai {
+
+       /* DAI description */
+       char *name;
+       unsigned int id;
+       unsigned char type;
+
+       /* DAI callbacks */
+       int (*probe)(struct platform_device *pdev);
+       void (*remove)(struct platform_device *pdev);
+       int (*suspend)(struct platform_device *pdev,
+               struct snd_soc_cpu_dai *cpu_dai);
+       int (*resume)(struct platform_device *pdev,
+               struct snd_soc_cpu_dai *cpu_dai);
+
+       /* ops */
+       struct snd_soc_ops ops;
+       struct snd_soc_cpu_ops dai_ops;
+
+       /* DAI capabilities */
+       struct snd_soc_pcm_stream capture;
+       struct snd_soc_pcm_stream playback;
+
+       /* DAI runtime info */
+       struct snd_pcm_runtime *runtime;
+       unsigned char active:1;
+       void *dma_data;
+
+       /* DAI private data */
+       void *private_data;
+};
+
+/* SoC Audio Codec */
+struct snd_soc_codec {
+       char *name;
+       struct module *owner;
+       struct mutex mutex;
+
+       /* callbacks */
+       int (*dapm_event)(struct snd_soc_codec *codec, int event);
+
+       /* runtime */
+       struct snd_card *card;
+       struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
+       unsigned int active;
+       unsigned int pcm_devs;
+       void *private_data;
+
+       /* codec IO */
+       void *control_data; /* codec control (i2c/3wire) data */
+       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+       hw_write_t hw_write;
+       hw_read_t hw_read;
+       void *reg_cache;
+       short reg_cache_size;
+       short reg_cache_step;
+
+       /* dapm */
+       struct list_head dapm_widgets;
+       struct list_head dapm_paths;
+       unsigned int dapm_state;
+       unsigned int suspend_dapm_state;
+       struct delayed_work delayed_work;
+
+       /* codec DAI's */
+       struct snd_soc_codec_dai *dai;
+       unsigned int num_dai;
+};
+
+/* codec device */
+struct snd_soc_codec_device {
+       int (*probe)(struct platform_device *pdev);
+       int (*remove)(struct platform_device *pdev);
+       int (*suspend)(struct platform_device *pdev, pm_message_t state);
+       int (*resume)(struct platform_device *pdev);
+};
+
+/* SoC platform interface */
+struct snd_soc_platform {
+       char *name;
+
+       int (*probe)(struct platform_device *pdev);
+       int (*remove)(struct platform_device *pdev);
+       int (*suspend)(struct platform_device *pdev,
+               struct snd_soc_cpu_dai *cpu_dai);
+       int (*resume)(struct platform_device *pdev,
+               struct snd_soc_cpu_dai *cpu_dai);
+
+       /* pcm creation and destruction */
+       int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
+               struct snd_pcm *);
+       void (*pcm_free)(struct snd_pcm *);
+
+       /* platform stream ops */
+       struct snd_pcm_ops *pcm_ops;
+};
+
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_dai_link  {
+       char *name;                     /* Codec name */
+       char *stream_name;              /* Stream name */
+
+       /* DAI */
+       struct snd_soc_codec_dai *codec_dai;
+       struct snd_soc_cpu_dai *cpu_dai;
+
+       /* machine stream operations */
+       struct snd_soc_ops *ops;
+
+       /* codec/machine specific init - e.g. add machine controls */
+       int (*init)(struct snd_soc_codec *codec);
+};
+
+/* SoC machine */
+struct snd_soc_machine {
+       char *name;
+
+       int (*probe)(struct platform_device *pdev);
+       int (*remove)(struct platform_device *pdev);
+
+       /* the pre and post PM functions are used to do any PM work before and
+        * after the codec and DAI's do any PM work. */
+       int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+       int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+       int (*resume_pre)(struct platform_device *pdev);
+       int (*resume_post)(struct platform_device *pdev);
+
+       /* CPU <--> Codec DAI links  */
+       struct snd_soc_dai_link *dai_link;
+       int num_links;
+};
+
+/* SoC Device - the audio subsystem */
+struct snd_soc_device {
+       struct device *dev;
+       struct snd_soc_machine *machine;
+       struct snd_soc_platform *platform;
+       struct snd_soc_codec *codec;
+       struct snd_soc_codec_device *codec_dev;
+       struct delayed_work delayed_work;
+       void *codec_data;
+};
+
+/* runtime channel data */
+struct snd_soc_pcm_runtime {
+       struct snd_soc_dai_link *dai;
+       struct snd_soc_device *socdev;
+};
+
+/* enumerated kcontrol */
+struct soc_enum {
+       unsigned short reg;
+       unsigned short reg2;
+       unsigned char shift_l;
+       unsigned char shift_r;
+       unsigned int mask;
+       const char **texts;
+       void *dapm;
+};
+
+#endif
diff --git a/include/sound/typedefs.h b/include/sound/typedefs.h
deleted file mode 100644 (file)
index f454b02..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Typedef's for backward compatibility (for out-of-kernel drivers)
- *
- * This file will be removed soon in future
- */
-
-/* core stuff */
-typedef struct snd_card snd_card_t;
-typedef struct snd_device snd_device_t;
-typedef struct snd_device_ops snd_device_ops_t;
-typedef enum snd_card_type snd_card_type_t;
-typedef struct snd_minor snd_minor_t;
-
-/* info */
-typedef struct snd_info_entry snd_info_entry_t;
-typedef struct snd_info_buffer snd_info_buffer_t;
-
-/* control */
-typedef struct snd_ctl_file snd_ctl_file_t;
-typedef struct snd_kcontrol snd_kcontrol_t;
-typedef struct snd_kcontrol_new snd_kcontrol_new_t;
-typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t;
-typedef struct snd_kctl_event snd_kctl_event_t;
-typedef struct snd_aes_iec958 snd_aes_iec958_t;
-typedef struct snd_ctl_card_info snd_ctl_card_info_t;
-typedef struct snd_ctl_elem_id snd_ctl_elem_id_t;
-typedef struct snd_ctl_elem_list snd_ctl_elem_list_t;
-typedef struct snd_ctl_elem_info snd_ctl_elem_info_t;
-typedef struct snd_ctl_elem_value snd_ctl_elem_value_t;
-typedef struct snd_ctl_event snd_ctl_event_t;
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-typedef struct snd_mixer_oss snd_mixer_oss_t;
-#endif
-
-/* timer */
-typedef struct snd_timer snd_timer_t;
-typedef struct snd_timer_instance snd_timer_instance_t;
-typedef struct snd_timer_id snd_timer_id_t;
-typedef struct snd_timer_ginfo snd_timer_ginfo_t;
-typedef struct snd_timer_gparams snd_timer_gparams_t;
-typedef struct snd_timer_gstatus snd_timer_gstatus_t;
-typedef struct snd_timer_select snd_timer_select_t;
-typedef struct snd_timer_info snd_timer_info_t;
-typedef struct snd_timer_params snd_timer_params_t;
-typedef struct snd_timer_status snd_timer_status_t;
-typedef struct snd_timer_read snd_timer_read_t;
-typedef struct snd_timer_tread snd_timer_tread_t;
-
-/* PCM */
-typedef struct snd_pcm snd_pcm_t;
-typedef struct snd_pcm_str snd_pcm_str_t;
-typedef struct snd_pcm_substream snd_pcm_substream_t;
-typedef struct snd_pcm_info snd_pcm_info_t;
-typedef struct snd_pcm_hw_params snd_pcm_hw_params_t;
-typedef struct snd_pcm_sw_params snd_pcm_sw_params_t;
-typedef struct snd_pcm_channel_info snd_pcm_channel_info_t;
-typedef struct snd_pcm_status snd_pcm_status_t;
-typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t;
-typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t;
-typedef struct snd_mask snd_mask_t;
-typedef struct snd_sg_buf snd_pcm_sgbuf_t;
-
-typedef struct snd_interval snd_interval_t;
-typedef struct snd_xferi snd_xferi_t;
-typedef struct snd_xfern snd_xfern_t;
-typedef struct snd_xferv snd_xferv_t;
-
-typedef struct snd_pcm_file snd_pcm_file_t;
-typedef struct snd_pcm_runtime snd_pcm_runtime_t;
-typedef struct snd_pcm_hardware snd_pcm_hardware_t;
-typedef struct snd_pcm_ops snd_pcm_ops_t;
-typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t;
-typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t;
-typedef struct snd_ratnum ratnum_t;
-typedef struct snd_ratden ratden_t;
-typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t;
-typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t;
-typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t;
-typedef struct snd_pcm_group snd_pcm_group_t;
-typedef struct snd_pcm_notify snd_pcm_notify_t;
-
-/* rawmidi */
-typedef struct snd_rawmidi snd_rawmidi_t;
-typedef struct snd_rawmidi_info snd_rawmidi_info_t;
-typedef struct snd_rawmidi_params snd_rawmidi_params_t;
-typedef struct snd_rawmidi_status snd_rawmidi_status_t;
-typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t;
-typedef struct snd_rawmidi_substream snd_rawmidi_substream_t;
-typedef struct snd_rawmidi_str snd_rawmidi_str_t;
-typedef struct snd_rawmidi_ops snd_rawmidi_ops_t;
-typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t;
-typedef struct snd_rawmidi_file snd_rawmidi_file_t;
-
-/* hwdep */
-typedef struct snd_hwdep snd_hwdep_t;
-typedef struct snd_hwdep_info snd_hwdep_info_t;
-typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t;
-typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t;
-typedef struct snd_hwdep_ops snd_hwdep_ops_t;
-
-/* sequencer */
-typedef struct snd_seq_port_info snd_seq_port_info_t;
-typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t;
-typedef struct snd_seq_event snd_seq_event_t;
-typedef struct snd_seq_addr snd_seq_addr_t;
-typedef struct snd_seq_ev_volume snd_seq_ev_volume_t;
-typedef struct snd_seq_ev_loop snd_seq_ev_loop_t;
-typedef struct snd_seq_remove_events snd_seq_remove_events_t;
-typedef struct snd_seq_query_subs snd_seq_query_subs_t;
-typedef struct snd_seq_system_info snd_seq_system_info_t;
-typedef struct snd_seq_client_info snd_seq_client_info_t;
-typedef struct snd_seq_queue_info snd_seq_queue_info_t;
-typedef struct snd_seq_queue_status snd_seq_queue_status_t;
-typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t;
-typedef struct snd_seq_queue_owner snd_seq_queue_owner_t;
-typedef struct snd_seq_queue_timer snd_seq_queue_timer_t;
-typedef struct snd_seq_queue_client snd_seq_queue_client_t;
-typedef struct snd_seq_client_pool snd_seq_client_pool_t;
-typedef struct snd_seq_instr snd_seq_instr_t;
-typedef struct snd_seq_instr_data snd_seq_instr_data_t;
-typedef struct snd_seq_instr_header snd_seq_instr_header_t;
-
-typedef struct snd_seq_user_client user_client_t;
-typedef struct snd_seq_kernel_client kernel_client_t;
-typedef struct snd_seq_client client_t;
-typedef struct snd_seq_queue queue_t;
-
-/* seq_device */
-typedef struct snd_seq_device snd_seq_device_t;
-typedef struct snd_seq_dev_ops snd_seq_dev_ops_t;
-
-/* seq_midi */
-typedef struct snd_midi_event snd_midi_event_t;
-
-/* seq_midi_emul */
-typedef struct snd_midi_channel snd_midi_channel_t;
-typedef struct snd_midi_channel_set snd_midi_channel_set_t;
-typedef struct snd_midi_op snd_midi_op_t;
-
-/* seq_oss */
-typedef struct snd_seq_oss_arg snd_seq_oss_arg_t;
-typedef struct snd_seq_oss_callback snd_seq_oss_callback_t;
-typedef struct snd_seq_oss_reg snd_seq_oss_reg_t;
-
-/* virmidi */
-typedef struct snd_virmidi_dev snd_virmidi_dev_t;
-typedef struct snd_virmidi snd_virmidi_t;
-
-/* seq_instr */
-typedef struct snd_seq_kcluster snd_seq_kcluster_t;
-typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t;
-typedef struct snd_seq_kinstr snd_seq_kinstr_t;
-typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t;
-
-/* ac97 */
-typedef struct snd_ac97_bus ac97_bus_t;
-typedef struct snd_ac97_bus_ops ac97_bus_ops_t;
-typedef struct snd_ac97_template ac97_template_t;
-typedef struct snd_ac97 ac97_t;
-
-/* opl3/4 */
-typedef struct snd_opl3 opl3_t;
-typedef struct snd_opl4 opl4_t;
-
-/* mpu401 */
-typedef struct snd_mpu401 mpu401_t;
-
-/* i2c */
-typedef struct snd_i2c_device snd_i2c_device_t;
-typedef struct snd_i2c_bus snd_i2c_bus_t;
-
-typedef struct snd_ak4531 ak4531_t;
-
index 20f7bab..c39b380 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
-#define CONFIG_SND_VERSION "1.0.14rc1"
-#define CONFIG_SND_DATE " (Tue Jan 09 09:56:17 2007 UTC)"
+#define CONFIG_SND_VERSION "1.0.14rc2"
+#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)"
index 2173946..4830651 100644 (file)
@@ -128,7 +128,7 @@ struct snd_vx_hardware {
        unsigned int num_ins;
        unsigned int num_outs;
        unsigned int output_level_max;
-       unsigned int *output_level_db_scale;
+       const unsigned int *output_level_db_scale;
 };
 
 /* hwdep id string */
index f3514ee..203d2b4 100644 (file)
@@ -270,6 +270,7 @@ struct snd_ymfpci_pcm {
        struct snd_pcm_substream *substream;
        struct snd_ymfpci_voice *voices[2];     /* playback only */
        unsigned int running: 1,
+                    use_441_slot: 1,
                     output_front: 1,
                     output_rear: 1,
                     swap_rear: 1;
@@ -324,6 +325,7 @@ struct snd_ymfpci {
 
        u32 active_bank;
        struct snd_ymfpci_voice voices[64];
+       int src441_used;
 
        struct snd_ac97_bus *ac97_bus;
        struct snd_ac97 *ac97;
@@ -346,7 +348,7 @@ struct snd_ymfpci {
        int mode_dup4ch;
        int rear_opened;
        int spdif_opened;
-       struct {
+       struct snd_ymfpci_pcm_mixer {
                u16 left;
                u16 right;
                struct snd_kcontrol *ctl;
@@ -357,6 +359,8 @@ struct snd_ymfpci {
        wait_queue_head_t interrupt_sleep;
        atomic_t interrupt_sleep_count;
        struct snd_info_entry *proc_entry;
+       const struct firmware *dsp_microcode;
+       const struct firmware *controller_microcode;
 
 #ifdef CONFIG_PM
        u32 *saved_regs;
index 9d77300..97532bb 100644 (file)
@@ -76,6 +76,8 @@ source "sound/sparc/Kconfig"
 
 source "sound/parisc/Kconfig"
 
+source "sound/soc/Kconfig"
+
 endmenu
 
 menu "Open Sound System"
index 9aee54c..b7c7fb7 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
index 66de2c2..7fa37e1 100644 (file)
@@ -26,6 +26,7 @@ static int ac97_bus_match(struct device *dev, struct device_driver *drv)
        return 1;
 }
 
+#ifdef CONFIG_PM
 static int ac97_bus_suspend(struct device *dev, pm_message_t state)
 {
        int ret = 0;
@@ -45,12 +46,15 @@ static int ac97_bus_resume(struct device *dev)
 
        return ret;
 }
+#endif /* CONFIG_PM */
 
 struct bus_type ac97_bus_type = {
        .name           = "ac97",
        .match          = ac97_bus_match,
+#ifdef CONFIG_PM
        .suspend        = ac97_bus_suspend,
        .resume         = ac97_bus_resume,
+#endif /* CONFIG_PM */
 };
 
 static int __init ac97_bus_init(void)
index 378ef1e..541b908 100644 (file)
@@ -99,7 +99,7 @@ struct aoa_fabric {
  * that are not assigned yet are passed to the fabric
  * again for reconsideration. */
 extern int
-aoa_fabric_register(struct aoa_fabric *fabric);
+aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev);
 
 /* it is vital to call this when the fabric exits!
  * When calling, the remove_codec will be called
index 0b76507..b00fc48 100644 (file)
@@ -825,7 +825,16 @@ static int onyx_resume(struct codec_info_item *cii)
        int err = -ENXIO;
 
        mutex_lock(&onyx->mutex);
-       /* take codec out of suspend */
+
+       /* reset codec */
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+       msleep(1);
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+       msleep(1);
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+       msleep(1);
+
+       /* take codec out of suspend (if it still is after reset) */
        if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
                goto out_unlock;
        onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
index b42fdea..17fe689 100644 (file)
@@ -14,7 +14,7 @@ MODULE_PARM_DESC(index, "index for AOA sound card.");
 
 static struct aoa_card *aoa_card;
 
-int aoa_alsa_init(char *name, struct module *mod)
+int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
 {
        struct snd_card *alsa_card;
        int err;
@@ -28,6 +28,7 @@ int aoa_alsa_init(char *name, struct module *mod)
                return -ENOMEM;
        aoa_card = alsa_card->private_data;
        aoa_card->alsa_card = alsa_card;
+       alsa_card->dev = dev;
        strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
        strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
        strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
@@ -59,7 +60,7 @@ void aoa_alsa_cleanup(void)
 }
 
 int aoa_snd_device_new(snd_device_type_t type,
-        void * device_data, struct snd_device_ops * ops)
+                      void * device_data, struct snd_device_ops * ops)
 {
        struct snd_card *card = aoa_get_card();
        int err;
index 660d2f1..9669e44 100644 (file)
@@ -10,7 +10,7 @@
 #define __SND_AOA_ALSA_H
 #include "../aoa.h"
 
-extern int aoa_alsa_init(char *name, struct module *mod);
+extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev);
 extern void aoa_alsa_cleanup(void);
 
 #endif /* __SND_AOA_ALSA_H */
index ecd2d82..19fdae4 100644 (file)
@@ -82,7 +82,7 @@ void aoa_codec_unregister(struct aoa_codec *codec)
 }
 EXPORT_SYMBOL_GPL(aoa_codec_unregister);
 
-int aoa_fabric_register(struct aoa_fabric *new_fabric)
+int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
 {
        struct aoa_codec *c;
        int err;
@@ -98,7 +98,7 @@ int aoa_fabric_register(struct aoa_fabric *new_fabric)
        if (!new_fabric)
                return -EINVAL;
 
-       err = aoa_alsa_init(new_fabric->name, new_fabric->owner);
+       err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
        if (err)
                return err;
 
index 172eb95..1b94ba6 100644 (file)
@@ -1014,7 +1014,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
 
        ldev->gpio.methods->init(&ldev->gpio);
 
-       err = aoa_fabric_register(&layout_fabric);
+       err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
        if (err && err != -EALREADY) {
                printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
                                 " another fabric is active!\n");
@@ -1034,9 +1034,9 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
        list_del(&ldev->list);
        layouts_list_items--;
  outnodev:
-       if (sound) of_node_put(sound);
+       of_node_put(sound);
        layout_device = NULL;
-       if (ldev) kfree(ldev);
+       kfree(ldev);
        return -ENODEV;
 }
 
@@ -1077,8 +1077,6 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta
 {
        struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
 
-       printk("aoa_fabric_layout_suspend()\n");
-
        if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
                ldev->gpio.methods->all_amps_off(&ldev->gpio);
 
@@ -1089,8 +1087,6 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
 {
        struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
 
-       printk("aoa_fabric_layout_resume()\n");
-
        if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
                ldev->gpio.methods->all_amps_restore(&ldev->gpio);
 
@@ -1107,6 +1103,9 @@ static struct soundbus_driver aoa_soundbus_driver = {
        .suspend = aoa_fabric_layout_suspend,
        .resume = aoa_fabric_layout_resume,
 #endif
+       .driver = {
+               .owner = THIS_MODULE,
+       }
 };
 
 static int __init aoa_fabric_layout_init(void)
index e593a13..e36f6aa 100644 (file)
@@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
                                       struct dbdma_command_mem *r,
                                       int numcmds)
 {
-       /* one more for rounding */
-       r->size = (numcmds+1) * sizeof(struct dbdma_cmd);
+       /* one more for rounding, one for branch back, one for stop command */
+       r->size = (numcmds + 3) * sizeof(struct dbdma_cmd);
        /* We use the PCI APIs for now until the generic one gets fixed
         * enough or until we get some macio-specific versions
         */
@@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
                if (i2sdev->sound.pcm) {
                        /* Suspend PCM streams */
                        snd_pcm_suspend_all(i2sdev->sound.pcm);
-                       /* Probably useless as we handle
-                        * power transitions ourselves */
-                       snd_power_change_state(i2sdev->sound.pcm->card,
-                                              SNDRV_CTL_POWER_D3hot);
                }
+
                /* Notify codecs */
                list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
                        err = 0;
@@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
                        if (err)
                                ret = err;
                }
+
+               /* wait until streams are stopped */
+               i2sbus_wait_for_stop_both(i2sdev);
        }
+
        return ret;
 }
 
@@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev)
        int err, ret = 0;
 
        list_for_each_entry(i2sdev, &control->list, item) {
+               /* reset i2s bus format etc. */
+               i2sbus_pcm_prepare_both(i2sdev);
+
                /* Notify codecs so they can re-initialize */
                list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
                        err = 0;
@@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev)
                        if (err)
                                ret = err;
                }
-               /* Notify Alsa */
-               if (i2sdev->sound.pcm) {
-                       /* Same comment as above, probably useless */
-                       snd_power_change_state(i2sdev->sound.pcm->card,
-                                              SNDRV_CTL_POWER_D0);
-               }
        }
 
        return ret;
index 5eff30b..c6b42f9 100644 (file)
@@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
        }
        /* bus dependent stuff */
        hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                  SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
+                  SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
+                  SNDRV_PCM_INFO_JOINT_DUPLEX;
 
        CHECK_RATE(5512);
        CHECK_RATE(8000);
@@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
        return err;
 }
 
+static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
+                                struct pcm_info *pi)
+{
+       unsigned long flags;
+       struct completion done;
+       long timeout;
+
+       spin_lock_irqsave(&i2sdev->low_lock, flags);
+       if (pi->dbdma_ring.stopping) {
+               init_completion(&done);
+               pi->stop_completion = &done;
+               spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+               timeout = wait_for_completion_timeout(&done, HZ);
+               spin_lock_irqsave(&i2sdev->low_lock, flags);
+               pi->stop_completion = NULL;
+               if (timeout == 0) {
+                       /* timeout expired, stop dbdma forcefully */
+                       printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
+                       /* make sure RUN, PAUSE and S0 bits are cleared */
+                       out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+                       pi->dbdma_ring.stopping = 0;
+                       timeout = 10;
+                       while (in_le32(&pi->dbdma->status) & ACTIVE) {
+                               if (--timeout <= 0)
+                                       break;
+                               udelay(1);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+}
+
+#ifdef CONFIG_PM
+void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
+{
+       struct pcm_info *pi;
+
+       get_pcm_info(i2sdev, 0, &pi, NULL);
+       i2sbus_wait_for_stop(i2sdev, pi);
+       get_pcm_info(i2sdev, 1, &pi, NULL);
+       i2sbus_wait_for_stop(i2sdev, pi);
+}
+#endif
+
 static int i2sbus_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params)
 {
        return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 }
 
-static int i2sbus_hw_free(struct snd_pcm_substream *substream)
+static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
 {
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+       struct pcm_info *pi;
+
+       get_pcm_info(i2sdev, in, &pi, NULL);
+       if (pi->dbdma_ring.stopping)
+               i2sbus_wait_for_stop(i2sdev, pi);
        snd_pcm_lib_free_pages(substream);
        return 0;
 }
 
+static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
+{
+       return i2sbus_hw_free(substream, 0);
+}
+
+static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
+{
+       return i2sbus_hw_free(substream, 1);
+}
+
 static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
 {
        /* whee. Hard work now. The user has selected a bitrate
@@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
         * I2S controller appropriately. */
        struct snd_pcm_runtime *runtime;
        struct dbdma_cmd *command;
-       int i, periodsize;
+       int i, periodsize, nperiods;
        dma_addr_t offset;
        struct bus_info bi;
        struct codec_info_item *cii;
@@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
        struct pcm_info *pi, *other;
        int cnt;
        int result = 0;
+       unsigned int cmd, stopaddr;
 
        mutex_lock(&i2sdev->lock);
 
@@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
                result = -EBUSY;
                goto out_unlock;
        }
+       if (pi->dbdma_ring.stopping)
+               i2sbus_wait_for_stop(i2sdev, pi);
+
+       if (!pi->substream || !pi->substream->runtime) {
+               result = -EINVAL;
+               goto out_unlock;
+       }
 
        runtime = pi->substream->runtime;
        pi->active = 1;
@@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
        i2sdev->rate = runtime->rate;
 
        periodsize = snd_pcm_lib_period_bytes(pi->substream);
+       nperiods = pi->substream->runtime->periods;
        pi->current_period = 0;
 
        /* generate dbdma command ring first */
        command = pi->dbdma_ring.cmds;
+       memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
+
+       /* commands to DMA to/from the ring */
+       /*
+        * For input, we need to do a graceful stop; if we abort
+        * the DMA, we end up with leftover bytes that corrupt
+        * the next recording.  To do this we set the S0 status
+        * bit and wait for the DMA controller to stop.  Each
+        * command has a branch condition to
+        * make it branch to a stop command if S0 is set.
+        * On input we also need to wait for the S7 bit to be
+        * set before turning off the DMA controller.
+        * In fact we do the graceful stop for output as well.
+        */
        offset = runtime->dma_addr;
-       for (i = 0; i < pi->substream->runtime->periods;
-            i++, command++, offset += periodsize) {
-               memset(command, 0, sizeof(struct dbdma_cmd));
-               command->command =
-                   cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
+       cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
+       stopaddr = pi->dbdma_ring.bus_cmd_start +
+               (nperiods + 1) * sizeof(struct dbdma_cmd);
+       for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
+               command->command = cpu_to_le16(cmd);
+               command->cmd_dep = cpu_to_le32(stopaddr);
                command->phy_addr = cpu_to_le32(offset);
                command->req_count = cpu_to_le16(periodsize);
-               command->xfer_status = cpu_to_le16(0);
        }
-       /* last one branches back to first */
-       command--;
-       command->command |= cpu_to_le16(BR_ALWAYS);
+
+       /* branch back to beginning of ring */
+       command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
        command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
+       command++;
+
+       /* set stop command */
+       command->command = cpu_to_le16(DBDMA_STOP);
 
        /* ok, let's set the serial format and stuff */
        switch (runtime->format) {
@@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
        return result;
 }
 
-static struct dbdma_cmd STOP_CMD = {
-       .command = __constant_cpu_to_le16(DBDMA_STOP),
-};
+#ifdef CONFIG_PM
+void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
+{
+       i2sbus_pcm_prepare(i2sdev, 0);
+       i2sbus_pcm_prepare(i2sdev, 1);
+}
+#endif
 
 static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
 {
        struct codec_info_item *cii;
        struct pcm_info *pi;
-       int timeout;
-       struct dbdma_cmd tmp;
        int result = 0;
        unsigned long flags;
 
@@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
                                cii->codec->start(cii, pi->substream);
                pi->dbdma_ring.running = 1;
 
-               /* reset dma engine */
-               out_le32(&pi->dbdma->control,
-                        0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
-               timeout = 100;
-               while (in_le32(&pi->dbdma->status) & RUN && timeout--)
-                       udelay(1);
-               if (timeout <= 0) {
-                       printk(KERN_ERR
-                              "i2sbus: error waiting for dma reset\n");
-                       result = -ENXIO;
-                       goto out_unlock;
+               if (pi->dbdma_ring.stopping) {
+                       /* Clear the S0 bit, then see if we stopped yet */
+                       out_le32(&pi->dbdma->control, 1 << 16);
+                       if (in_le32(&pi->dbdma->status) & ACTIVE) {
+                               /* possible race here? */
+                               udelay(10);
+                               if (in_le32(&pi->dbdma->status) & ACTIVE) {
+                                       pi->dbdma_ring.stopping = 0;
+                                       goto out_unlock; /* keep running */
+                               }
+                       }
                }
 
+               /* make sure RUN, PAUSE and S0 bits are cleared */
+               out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+
+               /* set branch condition select register */
+               out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
+
                /* write dma command buffer address to the dbdma chip */
                out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
-               /* post PCI write */
-               mb();
-               (void)in_le32(&pi->dbdma->status);
-
-               /* change first command to STOP */
-               tmp = *pi->dbdma_ring.cmds;
-               *pi->dbdma_ring.cmds = STOP_CMD;
-
-               /* set running state, remember that the first command is STOP */
-               out_le32(&pi->dbdma->control, RUN | (RUN << 16));
-               timeout = 100;
-               /* wait for STOP to be executed */
-               while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
-                       udelay(1);
-               if (timeout <= 0) {
-                       printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
-                       result = -ENXIO;
-                       goto out_unlock;
-               }
-               /* again, write dma command buffer address to the dbdma chip,
-                * this time of the first real command */
-               *pi->dbdma_ring.cmds = tmp;
-               out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
-               /* post write */
-               mb();
-               (void)in_le32(&pi->dbdma->status);
-
-               /* reset dma engine again */
-               out_le32(&pi->dbdma->control,
-                        0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
-               timeout = 100;
-               while (in_le32(&pi->dbdma->status) & RUN && timeout--)
-                       udelay(1);
-               if (timeout <= 0) {
-                       printk(KERN_ERR
-                              "i2sbus: error waiting for dma reset\n");
-                       result = -ENXIO;
-                       goto out_unlock;
-               }
 
-               /* wake up the chip with the next descriptor */
-               out_le32(&pi->dbdma->control,
-                        (RUN | WAKE) | ((RUN | WAKE) << 16));
-               /* get the frame count  */
+               /* initialize the frame count and current period */
+               pi->current_period = 0;
                pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
 
+               /* set the DMA controller running */
+               out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
+
                /* off you go! */
                break;
+
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
                if (!pi->dbdma_ring.running) {
                        result = -EALREADY;
                        goto out_unlock;
                }
+               pi->dbdma_ring.running = 0;
 
-               /* turn off all relevant bits */
-               out_le32(&pi->dbdma->control,
-                        (RUN | WAKE | FLUSH | PAUSE) << 16);
-               {
-                       /* FIXME: move to own function */
-                       int timeout = 5000;
-                       while ((in_le32(&pi->dbdma->status) & RUN)
-                              && --timeout > 0)
-                               udelay(1);
-                       if (!timeout)
-                               printk(KERN_ERR
-                                      "i2sbus: timed out turning "
-                                      "off dbdma engine!\n");
-               }
+               /* Set the S0 bit to make the DMA branch to the stop cmd */
+               out_le32(&pi->dbdma->control, (1 << 16) | 1);
+               pi->dbdma_ring.stopping = 1;
 
-               pi->dbdma_ring.running = 0;
                list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
                        if (cii->codec->stop)
                                cii->codec->stop(cii, pi->substream);
@@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
        fc = in_le32(&i2sdev->intfregs->frame_count);
        fc = fc - pi->frame_count;
 
-       return (bytes_to_frames(pi->substream->runtime,
-                       pi->current_period *
-                       snd_pcm_lib_period_bytes(pi->substream))
-               + fc) % pi->substream->runtime->buffer_size;
+       if (fc >= pi->substream->runtime->buffer_size)
+               fc %= pi->substream->runtime->buffer_size;
+       return fc;
 }
 
 static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
 {
        struct pcm_info *pi;
-       u32 fc;
-       u32 delta;
+       u32 fc, nframes;
+       u32 status;
+       int timeout, i;
+       int dma_stopped = 0;
+       struct snd_pcm_runtime *runtime;
 
        spin_lock(&i2sdev->low_lock);
        get_pcm_info(i2sdev, in, &pi, NULL);
-
-       if (!pi->dbdma_ring.running) {
-               /* there was still an interrupt pending
-                * while we stopped. or maybe another
-                * processor (not the one that was stopping
-                * the DMA engine) was spinning above
-                * waiting for the lock. */
+       if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
                goto out_unlock;
-       }
 
-       fc = in_le32(&i2sdev->intfregs->frame_count);
-       /* a counter overflow does not change the calculation. */
-       delta = fc - pi->frame_count;
-
-       /* update current_period */
-       while (delta >= pi->substream->runtime->period_size) {
-               pi->current_period++;
-               delta = delta - pi->substream->runtime->period_size;
-       }
-
-       if (unlikely(delta)) {
-               /* Some interrupt came late, so check the dbdma.
-                * This special case exists to syncronize the frame_count with
-                * the dbdma transfer, but is hit every once in a while. */
-               int period;
-
-               period = (in_le32(&pi->dbdma->cmdptr)
-                       - pi->dbdma_ring.bus_cmd_start)
-                               / sizeof(struct dbdma_cmd);
-               pi->current_period = pi->current_period
-                                       % pi->substream->runtime->periods;
-
-               while (pi->current_period != period) {
-                       pi->current_period++;
-                       pi->current_period %= pi->substream->runtime->periods;
-                       /* Set delta to zero, as the frame_count value is too
-                        * high (otherwise the code path will not be executed).
-                        * This corrects the fact that the frame_count is too
-                        * low at the beginning due to buffering. */
-                       delta = 0;
+       i = pi->current_period;
+       runtime = pi->substream->runtime;
+       while (pi->dbdma_ring.cmds[i].xfer_status) {
+               if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
+                       /*
+                        * BT is the branch taken bit.  If it took a branch
+                        * it is because we set the S0 bit to make it
+                        * branch to the stop command.
+                        */
+                       dma_stopped = 1;
+               pi->dbdma_ring.cmds[i].xfer_status = 0;
+
+               if (++i >= runtime->periods) {
+                       i = 0;
+                       pi->frame_count += runtime->buffer_size;
                }
+               pi->current_period = i;
+
+               /*
+                * Check the frame count.  The DMA tends to get a bit
+                * ahead of the frame counter, which confuses the core.
+                */
+               fc = in_le32(&i2sdev->intfregs->frame_count);
+               nframes = i * runtime->period_size;
+               if (fc < pi->frame_count + nframes)
+                       pi->frame_count = fc - nframes;
        }
 
-       pi->frame_count = fc - delta;
-       pi->current_period %= pi->substream->runtime->periods;
+       if (dma_stopped) {
+               timeout = 1000;
+               for (;;) {
+                       status = in_le32(&pi->dbdma->status);
+                       if (!(status & ACTIVE) && (!in || (status & 0x80)))
+                               break;
+                       if (--timeout <= 0) {
+                               printk(KERN_ERR "i2sbus: timed out "
+                                      "waiting for DMA to stop!\n");
+                               break;
+                       }
+                       udelay(1);
+               }
+
+               /* Turn off DMA controller, clear S0 bit */
+               out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+
+               pi->dbdma_ring.stopping = 0;
+               if (pi->stop_completion)
+                       complete(pi->stop_completion);
+       }
 
+       if (!pi->dbdma_ring.running)
+               goto out_unlock;
        spin_unlock(&i2sdev->low_lock);
        /* may call _trigger again, hence needs to be unlocked */
        snd_pcm_period_elapsed(pi->substream);
        return;
+
  out_unlock:
        spin_unlock(&i2sdev->low_lock);
 }
@@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = {
        .close =        i2sbus_playback_close,
        .ioctl =        snd_pcm_lib_ioctl,
        .hw_params =    i2sbus_hw_params,
-       .hw_free =      i2sbus_hw_free,
+       .hw_free =      i2sbus_playback_hw_free,
        .prepare =      i2sbus_playback_prepare,
        .trigger =      i2sbus_playback_trigger,
        .pointer =      i2sbus_playback_pointer,
@@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = {
        .close =        i2sbus_record_close,
        .ioctl =        snd_pcm_lib_ioctl,
        .hw_params =    i2sbus_hw_params,
-       .hw_free =      i2sbus_hw_free,
+       .hw_free =      i2sbus_record_hw_free,
        .prepare =      i2sbus_record_prepare,
        .trigger =      i2sbus_record_trigger,
        .pointer =      i2sbus_record_pointer,
@@ -812,7 +872,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm)
        module_put(THIS_MODULE);
 }
 
-/* FIXME: this function needs an error handling strategy with labels */
 int
 i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                    struct codec_info *ci, void *data)
@@ -880,41 +939,31 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
        if (!cii->sdev) {
                printk(KERN_DEBUG
                       "i2sbus: failed to get soundbus dev reference\n");
-               kfree(cii);
-               return -ENODEV;
+               err = -ENODEV;
+               goto out_free_cii;
        }
 
        if (!try_module_get(THIS_MODULE)) {
                printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
-               soundbus_dev_put(dev);
-               kfree(cii);
-               return -EBUSY;
+               err = -EBUSY;
+               goto out_put_sdev;
        }
 
        if (!try_module_get(ci->owner)) {
                printk(KERN_DEBUG
                       "i2sbus: failed to get module reference to codec owner!\n");
-               module_put(THIS_MODULE);
-               soundbus_dev_put(dev);
-               kfree(cii);
-               return -EBUSY;
+               err = -EBUSY;
+               goto out_put_this_module;
        }
 
        if (!dev->pcm) {
-               err = snd_pcm_new(card,
-                                 dev->pcmname,
-                                 dev->pcmid,
-                                 0,
-                                 0,
+               err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0,
                                  &dev->pcm);
                if (err) {
                        printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
-                       kfree(cii);
-                       module_put(ci->owner);
-                       soundbus_dev_put(dev);
-                       module_put(THIS_MODULE);
-                       return err;
+                       goto out_put_ci_module;
                }
+               dev->pcm->dev = &dev->ofdev.dev;
        }
 
        /* ALSA yet again sucks.
@@ -926,20 +975,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                        /* eh? */
                        printk(KERN_ERR
                               "Can't attach same bus to different cards!\n");
-                       module_put(ci->owner);
-                       kfree(cii);
-                       soundbus_dev_put(dev);
-                       module_put(THIS_MODULE);
-                       return -EINVAL;
-               }
-               if ((err =
-                    snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
-                       module_put(ci->owner);
-                       kfree(cii);
-                       soundbus_dev_put(dev);
-                       module_put(THIS_MODULE);
-                       return err;
+                       err = -EINVAL;
+                       goto out_put_ci_module;
                }
+               err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+               if (err)
+                       goto out_put_ci_module;
                snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                &i2sbus_playback_ops);
                i2sdev->out.created = 1;
@@ -949,20 +990,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                if (dev->pcm->card != card) {
                        printk(KERN_ERR
                               "Can't attach same bus to different cards!\n");
-                       module_put(ci->owner);
-                       kfree(cii);
-                       soundbus_dev_put(dev);
-                       module_put(THIS_MODULE);
-                       return -EINVAL;
-               }
-               if ((err =
-                    snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
-                       module_put(ci->owner);
-                       kfree(cii);
-                       soundbus_dev_put(dev);
-                       module_put(THIS_MODULE);
-                       return err;
+                       goto out_put_ci_module;
                }
+               err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+               if (err)
+                       goto out_put_ci_module;
                snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &i2sbus_record_ops);
                i2sdev->in.created = 1;
@@ -977,11 +1009,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
        err = snd_device_register(card, dev->pcm);
        if (err) {
                printk(KERN_ERR "i2sbus: error registering new pcm\n");
-               module_put(ci->owner);
-               kfree(cii);
-               soundbus_dev_put(dev);
-               module_put(THIS_MODULE);
-               return err;
+               goto out_put_ci_module;
        }
        /* no errors any more, so let's add this to our list */
        list_add(&cii->list, &dev->codec_list);
@@ -996,6 +1024,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                64 * 1024, 64 * 1024);
 
        return 0;
+ out_put_ci_module:
+       module_put(ci->owner);
+ out_put_this_module:
+       module_put(THIS_MODULE);
+ out_put_sdev:
+       soundbus_dev_put(dev);
+ out_free_cii:
+       kfree(cii);
+       return err;
 }
 
 void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
index ec20ee6..ff29654 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/completion.h>
 
 #include <sound/pcm.h>
 
@@ -34,6 +35,7 @@ struct dbdma_command_mem {
        void *space;
        int size;
        u32 running:1;
+       u32 stopping:1;
 };
 
 struct pcm_info {
@@ -45,6 +47,7 @@ struct pcm_info {
        u32 frame_count;
        struct dbdma_command_mem dbdma_ring;
        volatile struct dbdma_regs __iomem *dbdma;
+       struct completion *stop_completion;
 };
 
 enum {
@@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid);
 extern irqreturn_t
 i2sbus_rx_intr(int irq, void *devid);
 
+extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev);
+extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev);
+
 /* control specific functions */
 extern int i2sbus_control_init(struct macio_dev* dev,
                               struct i2sbus_control **c);
index 0629519..9175ff9 100644 (file)
@@ -228,7 +228,7 @@ struct aaci {
 
        /* AC'97 */
        struct mutex            ac97_sem;
-       ac97_bus_t              *ac97_bus;
+       struct snd_ac97_bus     *ac97_bus;
 
        u32                     maincr;
        spinlock_t              lock;
index 0c7bcd6..42bcf27 100644 (file)
@@ -108,7 +108,6 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
 static int snd_ctl_release(struct inode *inode, struct file *file)
 {
        unsigned long flags;
-       struct list_head *list;
        struct snd_card *card;
        struct snd_ctl_file *ctl;
        struct snd_kcontrol *control;
@@ -122,12 +121,10 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
        list_del(&ctl->list);
        write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
        down_write(&card->controls_rwsem);
-       list_for_each(list, &card->controls) {
-               control = snd_kcontrol(list);
+       list_for_each_entry(control, &card->controls, list)
                for (idx = 0; idx < control->count; idx++)
                        if (control->vd[idx].owner == ctl)
                                control->vd[idx].owner = NULL;
-       }
        up_write(&card->controls_rwsem);
        snd_ctl_empty_read_queue(ctl);
        kfree(ctl);
@@ -140,7 +137,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
                    struct snd_ctl_elem_id *id)
 {
        unsigned long flags;
-       struct list_head *flist;
        struct snd_ctl_file *ctl;
        struct snd_kctl_event *ev;
        
@@ -149,14 +145,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
        card->mixer_oss_change_count++;
 #endif
-       list_for_each(flist, &card->ctl_files) {
-               struct list_head *elist;
-               ctl = snd_ctl_file(flist);
+       list_for_each_entry(ctl, &card->ctl_files, list) {
                if (!ctl->subscribed)
                        continue;
                spin_lock_irqsave(&ctl->read_lock, flags);
-               list_for_each(elist, &ctl->events) {
-                       ev = snd_kctl_event(elist);
+               list_for_each_entry(ev, &ctl->events, list) {
                        if (ev->id.numid == id->numid) {
                                ev->mask |= mask;
                                goto _found;
@@ -190,7 +183,8 @@ EXPORT_SYMBOL(snd_ctl_notify);
  *
  * Returns the pointer of the new instance, or NULL on failure.
  */
-struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access)
+static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
+                                       unsigned int access)
 {
        struct snd_kcontrol *kctl;
        unsigned int idx;
@@ -208,8 +202,6 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce
        return kctl;
 }
 
-EXPORT_SYMBOL(snd_ctl_new);
-
 /**
  * snd_ctl_new1 - create a control instance from the template
  * @ncontrol: the initialization record
@@ -277,11 +269,9 @@ EXPORT_SYMBOL(snd_ctl_free_one);
 static unsigned int snd_ctl_hole_check(struct snd_card *card,
                                       unsigned int count)
 {
-       struct list_head *list;
        struct snd_kcontrol *kctl;
 
-       list_for_each(list, &card->controls) {
-               kctl = snd_kcontrol(list);
+       list_for_each_entry(kctl, &card->controls, list) {
                if ((kctl->id.numid <= card->last_numid &&
                     kctl->id.numid + kctl->count > card->last_numid) ||
                    (kctl->id.numid <= card->last_numid + count - 1 &&
@@ -498,12 +488,10 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
  */
 struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
 {
-       struct list_head *list;
        struct snd_kcontrol *kctl;
 
        snd_assert(card != NULL && numid != 0, return NULL);
-       list_for_each(list, &card->controls) {
-               kctl = snd_kcontrol(list);
+       list_for_each_entry(kctl, &card->controls, list) {
                if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
                        return kctl;
        }
@@ -527,14 +515,12 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
 struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
                                     struct snd_ctl_elem_id *id)
 {
-       struct list_head *list;
        struct snd_kcontrol *kctl;
 
        snd_assert(card != NULL && id != NULL, return NULL);
        if (id->numid != 0)
                return snd_ctl_find_numid(card, id->numid);
-       list_for_each(list, &card->controls) {
-               kctl = snd_kcontrol(list);
+       list_for_each_entry(kctl, &card->controls, list) {
                if (kctl->id.iface != id->iface)
                        continue;
                if (kctl->id.device != id->device)
@@ -1182,7 +1168,6 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 {
        struct snd_ctl_file *ctl;
        struct snd_card *card;
-       struct list_head *list;
        struct snd_kctl_ioctl *p;
        void __user *argp = (void __user *)arg;
        int __user *ip = argp;
@@ -1232,8 +1217,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 #endif
        }
        down_read(&snd_ioctl_rwsem);
-       list_for_each(list, &snd_control_ioctls) {
-               p = list_entry(list, struct snd_kctl_ioctl, list);
+       list_for_each_entry(p, &snd_control_ioctls, list) {
                err = p->fioctl(card, ctl, cmd, arg);
                if (err != -ENOIOCTLCMD) {
                        up_read(&snd_ioctl_rwsem);
@@ -1357,13 +1341,11 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
 static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
                                     struct list_head *lists)
 {
-       struct list_head *list;
        struct snd_kctl_ioctl *p;
 
        snd_assert(fcn != NULL, return -EINVAL);
        down_write(&snd_ioctl_rwsem);
-       list_for_each(list, lists) {
-               p = list_entry(list, struct snd_kctl_ioctl, list);
+       list_for_each_entry(p, lists, list) {
                if (p->fioctl == fcn) {
                        list_del(&p->list);
                        up_write(&snd_ioctl_rwsem);
@@ -1453,7 +1435,6 @@ static int snd_ctl_dev_register(struct snd_device *device)
 static int snd_ctl_dev_disconnect(struct snd_device *device)
 {
        struct snd_card *card = device->device_data;
-       struct list_head *flist;
        struct snd_ctl_file *ctl;
        int err, cardnum;
 
@@ -1462,8 +1443,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
        snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
 
        down_read(&card->controls_rwsem);
-       list_for_each(flist, &card->ctl_files) {
-               ctl = snd_ctl_file(flist);
+       list_for_each_entry(ctl, &card->ctl_files, list) {
                wake_up(&ctl->change_sleep);
                kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
        }
index ab48962..9311ca3 100644 (file)
@@ -392,7 +392,7 @@ enum {
 static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct snd_ctl_file *ctl;
-       struct list_head *list;
+       struct snd_kctl_ioctl *p;
        void __user *argp = compat_ptr(arg);
        int err;
 
@@ -427,8 +427,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
        }
 
        down_read(&snd_ioctl_rwsem);
-       list_for_each(list, &snd_control_compat_ioctls) {
-               struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list);
+       list_for_each_entry(p, &snd_control_compat_ioctls, list) {
                if (p->fioctl) {
                        err = p->fioctl(ctl->card, ctl, cmd, arg);
                        if (err != -ENOIOCTLCMD) {
index ccb2581..5858b02 100644 (file)
@@ -79,13 +79,11 @@ EXPORT_SYMBOL(snd_device_new);
  */
 int snd_device_free(struct snd_card *card, void *device_data)
 {
-       struct list_head *list;
        struct snd_device *dev;
        
        snd_assert(card != NULL, return -ENXIO);
        snd_assert(device_data != NULL, return -ENXIO);
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
+       list_for_each_entry(dev, &card->devices, list) {
                if (dev->device_data != device_data)
                        continue;
                /* unlink */
@@ -124,13 +122,11 @@ EXPORT_SYMBOL(snd_device_free);
  */
 int snd_device_disconnect(struct snd_card *card, void *device_data)
 {
-       struct list_head *list;
        struct snd_device *dev;
 
        snd_assert(card != NULL, return -ENXIO);
        snd_assert(device_data != NULL, return -ENXIO);
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
+       list_for_each_entry(dev, &card->devices, list) {
                if (dev->device_data != device_data)
                        continue;
                if (dev->state == SNDRV_DEV_REGISTERED &&
@@ -161,14 +157,12 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
  */
 int snd_device_register(struct snd_card *card, void *device_data)
 {
-       struct list_head *list;
        struct snd_device *dev;
        int err;
 
        snd_assert(card != NULL, return -ENXIO);
        snd_assert(device_data != NULL, return -ENXIO);
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
+       list_for_each_entry(dev, &card->devices, list) {
                if (dev->device_data != device_data)
                        continue;
                if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
@@ -192,13 +186,11 @@ EXPORT_SYMBOL(snd_device_register);
  */
 int snd_device_register_all(struct snd_card *card)
 {
-       struct list_head *list;
        struct snd_device *dev;
        int err;
        
        snd_assert(card != NULL, return -ENXIO);
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
+       list_for_each_entry(dev, &card->devices, list) {
                if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
                        if ((err = dev->ops->dev_register(dev)) < 0)
                                return err;
@@ -215,12 +207,10 @@ int snd_device_register_all(struct snd_card *card)
 int snd_device_disconnect_all(struct snd_card *card)
 {
        struct snd_device *dev;
-       struct list_head *list;
        int err = 0;
 
        snd_assert(card != NULL, return -ENXIO);
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
+       list_for_each_entry(dev, &card->devices, list) {
                if (snd_device_disconnect(card, dev->device_data) < 0)
                        err = -ENXIO;
        }
@@ -234,7 +224,6 @@ int snd_device_disconnect_all(struct snd_card *card)
 int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
 {
        struct snd_device *dev;
-       struct list_head *list;
        int err;
        unsigned int range_low, range_high;
 
@@ -242,8 +231,7 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
        range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
        range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
       __again:
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);         
+       list_for_each_entry(dev, &card->devices, list) {
                if (dev->type >= range_low && dev->type <= range_high) {
                        if ((err = snd_device_free(card, dev->device_data)) < 0)
                                return err;
index 46b4768..39c03f3 100644 (file)
@@ -47,14 +47,11 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device);
 
 static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
 {
-       struct list_head *p;
        struct snd_hwdep *hwdep;
 
-       list_for_each(p, &snd_hwdep_devices) {
-               hwdep = list_entry(p, struct snd_hwdep, list);
+       list_for_each_entry(hwdep, &snd_hwdep_devices, list)
                if (hwdep->card == card && hwdep->device == device)
                        return hwdep;
-       }
        return NULL;
 }
 
@@ -159,15 +156,16 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
        int err = -ENXIO;
        struct snd_hwdep *hw = file->private_data;
        struct module *mod = hw->card->module;
+
        mutex_lock(&hw->open_mutex);
-       if (hw->ops.release) {
+       if (hw->ops.release)
                err = hw->ops.release(hw, file);
-               wake_up(&hw->open_wait);
-       }
        if (hw->used > 0)
                hw->used--;
-       snd_card_file_remove(hw->card, file);
        mutex_unlock(&hw->open_mutex);
+       wake_up(&hw->open_wait);
+
+       snd_card_file_remove(hw->card, file);
        module_put(mod);
        return err;
 }
@@ -468,15 +466,12 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
 static void snd_hwdep_proc_read(struct snd_info_entry *entry,
                                struct snd_info_buffer *buffer)
 {
-       struct list_head *p;
        struct snd_hwdep *hwdep;
 
        mutex_lock(&register_mutex);
-       list_for_each(p, &snd_hwdep_devices) {
-               hwdep = list_entry(p, struct snd_hwdep, list);
+       list_for_each_entry(hwdep, &snd_hwdep_devices, list)
                snd_iprintf(buffer, "%02i-%02i: %s\n",
                            hwdep->card->number, hwdep->device, hwdep->name);
-       }
        mutex_unlock(&register_mutex);
 }
 
index a4cc6b1..db61037 100644 (file)
@@ -114,22 +114,28 @@ struct snd_card *snd_card_new(int idx, const char *xid,
        if (idx < 0) {
                int idx2;
                for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+                       /* idx == -1 == 0xffff means: take any free slot */
                        if (~snd_cards_lock & idx & 1<<idx2) {
                                idx = idx2;
                                if (idx >= snd_ecards_limit)
                                        snd_ecards_limit = idx + 1;
                                break;
                        }
-       } else if (idx < snd_ecards_limit) {
-               if (snd_cards_lock & (1 << idx))
-                       err = -ENODEV;  /* invalid */
-       } else if (idx < SNDRV_CARDS)
-               snd_ecards_limit = idx + 1; /* increase the limit */
-       else
-               err = -ENODEV;
+       } else {
+                if (idx < snd_ecards_limit) {
+                       if (snd_cards_lock & (1 << idx))
+                               err = -EBUSY;   /* invalid */
+               } else {
+                       if (idx < SNDRV_CARDS)
+                               snd_ecards_limit = idx + 1; /* increase the limit */
+                       else
+                               err = -ENODEV;
+               }
+       }
        if (idx < 0 || err < 0) {
                mutex_unlock(&snd_card_mutex);
-               snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
+               snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
+                        idx, snd_ecards_limit - 1, err);
                goto __error;
        }
        snd_cards_lock |= 1 << idx;             /* lock it */
index bc0bd09..f057430 100644 (file)
@@ -406,19 +406,17 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
  */
 size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
-       struct list_head *p;
        struct snd_mem_list *mem;
 
        snd_assert(dmab, return 0);
 
        mutex_lock(&list_mutex);
-       list_for_each(p, &mem_list_head) {
-               mem = list_entry(p, struct snd_mem_list, list);
+       list_for_each_entry(mem, &mem_list_head, list) {
                if (mem->id == id &&
                    (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
                     ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
                        struct device *dev = dmab->dev.dev;
-                       list_del(p);
+                       list_del(&mem->list);
                        *dmab = mem->buffer;
                        if (dmab->dev.dev == NULL)
                                dmab->dev.dev = dev;
@@ -488,7 +486,6 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
 {
        int len = 0;
        long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
-       struct list_head *p;
        struct snd_mem_list *mem;
        int devno;
        static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
@@ -498,8 +495,7 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
                        "pages  : %li bytes (%li pages per %likB)\n",
                        pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
        devno = 0;
-       list_for_each(p, &mem_list_head) {
-               mem = list_entry(p, struct snd_mem_list, list);
+       list_for_each_entry(mem, &mem_list_head, list) {
                devno++;
                len += snprintf(page + len, count - len,
                                "buffer %d : ID %08x : type %s\n",
index 03fc711..6db86a7 100644 (file)
@@ -78,3 +78,31 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
 
 EXPORT_SYMBOL(snd_verbose_printd);
 #endif
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+/**
+ * snd_pci_quirk_lookup - look up a PCI SSID quirk list
+ * @pci: pci_dev handle
+ * @list: quirk list, terminated by a null entry
+ *
+ * Look through the given quirk list and finds a matching entry
+ * with the same PCI SSID.  When subdevice is 0, all subdevice
+ * values may match.
+ *
+ * Returns the matched entry pointer, or NULL if nothing matched.
+ */
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+       const struct snd_pci_quirk *q;
+
+       for (q = list; q->subvendor; q++)
+               if (q->subvendor == pci->subsystem_vendor &&
+                   (!q->subdevice || q->subdevice == pci->subsystem_device))
+                       return q;
+       return NULL;
+}
+
+EXPORT_SYMBOL(snd_pci_quirk_lookup);
+#endif
index 8e01898..2743414 100644 (file)
@@ -45,11 +45,9 @@ static int snd_pcm_dev_disconnect(struct snd_device *device);
 
 static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
 {
-       struct list_head *p;
        struct snd_pcm *pcm;
 
-       list_for_each(p, &snd_pcm_devices) {
-               pcm = list_entry(p, struct snd_pcm, list);
+       list_for_each_entry(pcm, &snd_pcm_devices, list) {
                if (pcm->card == card && pcm->device == device)
                        return pcm;
        }
@@ -782,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        struct snd_pcm_runtime *runtime;
        struct snd_ctl_file *kctl;
        struct snd_card *card;
-       struct list_head *list;
        int prefer_subdevice = -1;
        size_t size;
 
@@ -795,8 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 
        card = pcm->card;
        down_read(&card->controls_rwsem);
-       list_for_each(list, &card->ctl_files) {
-               kctl = snd_ctl_file(list);
+       list_for_each_entry(kctl, &card->ctl_files, list) {
                if (kctl->pid == current->pid) {
                        prefer_subdevice = kctl->prefer_pcm_subdevice;
                        if (prefer_subdevice != -1)
@@ -941,9 +937,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
 {
        int cidx, err;
        struct snd_pcm_substream *substream;
-       struct list_head *list;
+       struct snd_pcm_notify *notify;
        char str[16];
        struct snd_pcm *pcm = device->device_data;
+       struct device *dev;
 
        snd_assert(pcm != NULL && device != NULL, return -ENXIO);
        mutex_lock(&register_mutex);
@@ -966,11 +963,18 @@ static int snd_pcm_dev_register(struct snd_device *device)
                        devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
                        break;
                }
-               if ((err = snd_register_device(devtype, pcm->card,
-                                              pcm->device,
-                                              &snd_pcm_f_ops[cidx],
-                                              pcm, str)) < 0)
-               {
+               /* device pointer to use, pcm->dev takes precedence if
+                * it is assigned, otherwise fall back to card's device
+                * if possible */
+               dev = pcm->dev;
+               if (!dev)
+                       dev = snd_card_get_device_link(pcm->card);
+               /* register pcm */
+               err = snd_register_device_for_dev(devtype, pcm->card,
+                                                 pcm->device,
+                                                 &snd_pcm_f_ops[cidx],
+                                                 pcm, str, dev);
+               if (err < 0) {
                        list_del(&pcm->list);
                        mutex_unlock(&register_mutex);
                        return err;
@@ -980,11 +984,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
                        snd_pcm_timer_init(substream);
        }
-       list_for_each(list, &snd_pcm_notify_list) {
-               struct snd_pcm_notify *notify;
-               notify = list_entry(list, struct snd_pcm_notify, list);
+
+       list_for_each_entry(notify, &snd_pcm_notify_list, list)
                notify->n_register(pcm);
-       }
+
        mutex_unlock(&register_mutex);
        return 0;
 }
@@ -1027,7 +1030,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
 
 int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 {
-       struct list_head *p;
+       struct snd_pcm *pcm;
 
        snd_assert(notify != NULL &&
                   notify->n_register != NULL &&
@@ -1036,13 +1039,12 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
        mutex_lock(&register_mutex);
        if (nfree) {
                list_del(&notify->list);
-               list_for_each(p, &snd_pcm_devices)
-                       notify->n_unregister(list_entry(p,
-                                                       struct snd_pcm, list));
+               list_for_each_entry(pcm, &snd_pcm_devices, list)
+                       notify->n_unregister(pcm);
        } else {
                list_add_tail(&notify->list, &snd_pcm_notify_list);
-               list_for_each(p, &snd_pcm_devices)
-                       notify->n_register(list_entry(p, struct snd_pcm, list));
+               list_for_each_entry(pcm, &snd_pcm_devices, list)
+                       notify->n_register(pcm);
        }
        mutex_unlock(&register_mutex);
        return 0;
@@ -1058,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify);
 static void snd_pcm_proc_read(struct snd_info_entry *entry,
                              struct snd_info_buffer *buffer)
 {
-       struct list_head *p;
        struct snd_pcm *pcm;
 
        mutex_lock(&register_mutex);
-       list_for_each(p, &snd_pcm_devices) {
-               pcm = list_entry(p, struct snd_pcm, list);
+       list_for_each_entry(pcm, &snd_pcm_devices, list) {
                snd_iprintf(buffer, "%02i-%02i: %s : %s",
                            pcm->card->number, pcm->device, pcm->id, pcm->name);
                if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
index b336797..9fefcaa 100644 (file)
@@ -781,6 +781,11 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *
 {
         unsigned int k;
        int changed = 0;
+
+       if (!count) {
+               i->empty = 1;
+               return -EINVAL;
+       }
         for (k = 0; k < count; k++) {
                if (mask && !(mask & (1 << k)))
                        continue;
index be030cb..95b1b2f 100644 (file)
@@ -101,6 +101,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
 {
        snd_pcm_lib_preallocate_dma_free(substream);
 #ifdef CONFIG_SND_VERBOSE_PROCFS
+       snd_info_free_entry(substream->proc_prealloc_max_entry);
+       substream->proc_prealloc_max_entry = NULL;
        snd_info_free_entry(substream->proc_prealloc_entry);
        substream->proc_prealloc_entry = NULL;
 #endif
@@ -142,6 +144,18 @@ static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry,
 }
 
 /*
+ * read callback for prealloc_max proc file
+ *
+ * prints the maximum allowed size in kB.
+ */
+static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry,
+                                                 struct snd_info_buffer *buffer)
+{
+       struct snd_pcm_substream *substream = entry->private_data;
+       snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024);
+}
+
+/*
  * write callback for prealloc proc file
  *
  * accepts the preallocation size in kB.
@@ -203,6 +217,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream)
                }
        }
        substream->proc_prealloc_entry = entry;
+       if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {
+               entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;
+               entry->private_data = substream;
+               if (snd_info_register(entry) < 0) {
+                       snd_info_free_entry(entry);
+                       entry = NULL;
+               }
+       }
+       substream->proc_prealloc_max_entry = entry;
 }
 
 #else /* !CONFIG_SND_VERBOSE_PROCFS */
index 0f055bf..7e6ceec 100644 (file)
@@ -61,14 +61,11 @@ static DEFINE_MUTEX(register_mutex);
 
 static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
 {
-       struct list_head *p;
        struct snd_rawmidi *rawmidi;
 
-       list_for_each(p, &snd_rawmidi_devices) {
-               rawmidi = list_entry(p, struct snd_rawmidi, list);
+       list_for_each_entry(rawmidi, &snd_rawmidi_devices, list)
                if (rawmidi->card == card && rawmidi->device == device)
                        return rawmidi;
-       }
        return NULL;
 }
 
@@ -389,7 +386,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_file *rawmidi_file;
        wait_queue_t wait;
-       struct list_head *list;
        struct snd_ctl_file *kctl;
 
        if (maj == snd_major) {
@@ -426,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        while (1) {
                subdevice = -1;
                down_read(&card->controls_rwsem);
-               list_for_each(list, &card->ctl_files) {
-                       kctl = snd_ctl_file(list);
+               list_for_each_entry(kctl, &card->ctl_files, list) {
                        if (kctl->pid == current->pid) {
                                subdevice = kctl->prefer_rawmidi_subdevice;
                                if (subdevice != -1)
@@ -575,7 +570,6 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *pstr;
        struct snd_rawmidi_substream *substream;
-       struct list_head *list;
 
        mutex_lock(&register_mutex);
        rmidi = snd_rawmidi_search(card, info->device);
@@ -589,8 +583,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
                return -ENOENT;
        if (info->subdevice >= pstr->substream_count)
                return -ENXIO;
-       list_for_each(list, &pstr->substreams) {
-               substream = list_entry(list, struct snd_rawmidi_substream, list);
+       list_for_each_entry(substream, &pstr->substreams, list) {
                if ((unsigned int)substream->number == info->subdevice)
                        return snd_rawmidi_info(substream, info);
        }
@@ -1313,14 +1306,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_substream *substream;
        struct snd_rawmidi_runtime *runtime;
-       struct list_head *list;
 
        rmidi = entry->private_data;
        snd_iprintf(buffer, "%s\n\n", rmidi->name);
        mutex_lock(&rmidi->open_mutex);
        if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
-               list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
-                       substream = list_entry(list, struct snd_rawmidi_substream, list);
+               list_for_each_entry(substream,
+                                   &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
+                                   list) {
                        snd_iprintf(buffer,
                                    "Output %d\n"
                                    "  Tx bytes     : %lu\n",
@@ -1339,8 +1332,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                }
        }
        if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
-               list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
-                       substream = list_entry(list, struct snd_rawmidi_substream, list);
+               list_for_each_entry(substream,
+                                   &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
+                                   list) {
                        snd_iprintf(buffer,
                                    "Input %d\n"
                                    "  Rx bytes     : %lu\n",
@@ -1625,13 +1619,10 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
 void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
                         struct snd_rawmidi_ops *ops)
 {
-       struct list_head *list;
        struct snd_rawmidi_substream *substream;
        
-       list_for_each(list, &rmidi->streams[stream].substreams) {
-               substream = list_entry(list, struct snd_rawmidi_substream, list);
+       list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
                substream->ops = ops;
-       }
 }
 
 /*
index 532a660..bb9dd9f 100644 (file)
@@ -659,7 +659,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
        int err = 0, num_ev = 0;
        struct snd_seq_event event_saved;
        struct snd_seq_client_port *src_port;
-       struct list_head *p;
        struct snd_seq_port_subs_info *grp;
 
        src_port = snd_seq_port_use_ptr(client, event->source.port);
@@ -674,8 +673,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
                read_lock(&grp->list_lock);
        else
                down_read(&grp->list_mutex);
-       list_for_each(p, &grp->list_head) {
-               subs = list_entry(p, struct snd_seq_subscribers, src_list);
+       list_for_each_entry(subs, &grp->list_head, src_list) {
                event->dest = subs->info.dest;
                if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
                        /* convert time according to flag with subscription */
@@ -709,15 +707,14 @@ static int port_broadcast_event(struct snd_seq_client *client,
 {
        int num_ev = 0, err = 0;
        struct snd_seq_client *dest_client;
-       struct list_head *p;
+       struct snd_seq_client_port *port;
 
        dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
        if (dest_client == NULL)
                return 0; /* no matching destination */
 
        read_lock(&dest_client->ports_lock);
-       list_for_each(p, &dest_client->ports_list_head) {
-               struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
+       list_for_each_entry(port, &dest_client->ports_list_head, list) {
                event->dest.port = port->addr.port;
                /* pass NULL as source client to avoid error bounce */
                err = snd_seq_deliver_single_event(NULL, event,
@@ -2473,11 +2470,10 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
 static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
                                    struct snd_seq_client *client)
 {
-       struct list_head *l;
+       struct snd_seq_client_port *p;
 
        mutex_lock(&client->ports_mutex);
-       list_for_each(l, &client->ports_list_head) {
-               struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+       list_for_each_entry(p, &client->ports_list_head, list) {
                snd_iprintf(buffer, "  Port %3d : \"%s\" (%c%c%c%c)\n",
                            p->addr.port, p->name,
                            FLAG_PERM_RD(p->capability),
index b79d011..37852cd 100644 (file)
@@ -106,11 +106,10 @@ static void remove_drivers(void);
 static void snd_seq_device_info(struct snd_info_entry *entry,
                                struct snd_info_buffer *buffer)
 {
-       struct list_head *head;
+       struct ops_list *ops;
 
        mutex_lock(&ops_mutex);
-       list_for_each(head, &opslist) {
-               struct ops_list *ops = list_entry(head, struct ops_list, list);
+       list_for_each_entry(ops, &opslist, list) {
                snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
                                ops->id,
                                ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
@@ -143,7 +142,7 @@ void snd_seq_autoload_unlock(void)
 void snd_seq_device_load_drivers(void)
 {
 #ifdef CONFIG_KMOD
-       struct list_head *head;
+       struct ops_list *ops;
 
        /* Calling request_module during module_init()
         * may cause blocking.
@@ -155,8 +154,7 @@ void snd_seq_device_load_drivers(void)
                return;
 
        mutex_lock(&ops_mutex);
-       list_for_each(head, &opslist) {
-               struct ops_list *ops = list_entry(head, struct ops_list, list);
+       list_for_each_entry(ops, &opslist, list) {
                if (! (ops->driver & DRIVER_LOADED) &&
                    ! (ops->driver & DRIVER_REQUESTED)) {
                        ops->used++;
@@ -314,8 +312,8 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
 int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
                                   int argsize)
 {
-       struct list_head *head;
        struct ops_list *ops;
+       struct snd_seq_device *dev;
 
        if (id == NULL || entry == NULL ||
            entry->init_device == NULL || entry->free_device == NULL)
@@ -341,8 +339,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
        ops->argsize = argsize;
 
        /* initialize existing devices if necessary */
-       list_for_each(head, &ops->dev_list) {
-               struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
+       list_for_each_entry(dev, &ops->dev_list, list) {
                init_device(dev, ops);
        }
        mutex_unlock(&ops->reg_mutex);
@@ -394,8 +391,8 @@ static struct ops_list * create_driver(char *id)
  */
 int snd_seq_device_unregister_driver(char *id)
 {
-       struct list_head *head;
        struct ops_list *ops;
+       struct snd_seq_device *dev;
 
        ops = find_driver(id, 0);
        if (ops == NULL)
@@ -411,8 +408,7 @@ int snd_seq_device_unregister_driver(char *id)
        /* close and release all devices associated with this driver */
        mutex_lock(&ops->reg_mutex);
        ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
-       list_for_each(head, &ops->dev_list) {
-               struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
+       list_for_each_entry(dev, &ops->dev_list, list) {
                free_device(dev, ops);
        }
 
@@ -512,11 +508,10 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
  */
 static struct ops_list * find_driver(char *id, int create_if_empty)
 {
-       struct list_head *head;
+       struct ops_list *ops;
 
        mutex_lock(&ops_mutex);
-       list_for_each(head, &opslist) {
-               struct ops_list *ops = list_entry(head, struct ops_list, list);
+       list_for_each_entry(ops, &opslist, list) {
                if (strcmp(ops->id, id) == 0) {
                        ops->used++;
                        mutex_unlock(&ops_mutex);
index 8c64b58..eefd1cf 100644 (file)
@@ -59,14 +59,12 @@ much elements are in array.
 struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
                                                 int num)
 {
-       struct list_head *p;
        struct snd_seq_client_port *port;
 
        if (client == NULL)
                return NULL;
        read_lock(&client->ports_lock);
-       list_for_each(p, &client->ports_list_head) {
-               port = list_entry(p, struct snd_seq_client_port, list);
+       list_for_each_entry(port, &client->ports_list_head, list) {
                if (port->addr.port == num) {
                        if (port->closing)
                                break; /* deleting now */
@@ -85,14 +83,12 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
                                                       struct snd_seq_port_info *pinfo)
 {
        int num;
-       struct list_head *p;
        struct snd_seq_client_port *port, *found;
 
        num = pinfo->addr.port;
        found = NULL;
        read_lock(&client->ports_lock);
-       list_for_each(p, &client->ports_list_head) {
-               port = list_entry(p, struct snd_seq_client_port, list);
+       list_for_each_entry(port, &client->ports_list_head, list) {
                if (port->addr.port < num)
                        continue;
                if (port->addr.port == num) {
@@ -131,8 +127,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
                                                int port)
 {
        unsigned long flags;
-       struct snd_seq_client_port *new_port;
-       struct list_head *l;
+       struct snd_seq_client_port *new_port, *p;
        int num = -1;
        
        /* sanity check */
@@ -161,15 +156,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        num = port >= 0 ? port : 0;
        mutex_lock(&client->ports_mutex);
        write_lock_irqsave(&client->ports_lock, flags);
-       list_for_each(l, &client->ports_list_head) {
-               struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+       list_for_each_entry(p, &client->ports_list_head, list) {
                if (p->addr.port > num)
                        break;
                if (port < 0) /* auto-probe mode */
                        num = p->addr.port + 1;
        }
        /* insert the new port */
-       list_add_tail(&new_port->list, l);
+       list_add_tail(&new_port->list, &p->list);
        client->num_ports++;
        new_port->addr.port = num;      /* store the port number in the port */
        write_unlock_irqrestore(&client->ports_lock, flags);
@@ -251,9 +245,9 @@ static void clear_subscriber_list(struct snd_seq_client *client,
                                list_del(&subs->dest_list);
                        else
                                list_del(&subs->src_list);
+                       up_write(&agrp->list_mutex);
                        unsubscribe_port(c, aport, agrp, &subs->info, 1);
                        kfree(subs);
-                       up_write(&agrp->list_mutex);
                        snd_seq_port_unlock(aport);
                        snd_seq_client_unlock(c);
                }
@@ -287,16 +281,14 @@ static int port_delete(struct snd_seq_client *client,
 int snd_seq_delete_port(struct snd_seq_client *client, int port)
 {
        unsigned long flags;
-       struct list_head *l;
-       struct snd_seq_client_port *found = NULL;
+       struct snd_seq_client_port *found = NULL, *p;
 
        mutex_lock(&client->ports_mutex);
        write_lock_irqsave(&client->ports_lock, flags);
-       list_for_each(l, &client->ports_list_head) {
-               struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+       list_for_each_entry(p, &client->ports_list_head, list) {
                if (p->addr.port == port) {
                        /* ok found.  delete from the list at first */
-                       list_del(l);
+                       list_del(&p->list);
                        client->num_ports--;
                        found = p;
                        break;
@@ -314,7 +306,8 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
 int snd_seq_delete_all_ports(struct snd_seq_client *client)
 {
        unsigned long flags;
-       struct list_head deleted_list, *p, *n;
+       struct list_head deleted_list;
+       struct snd_seq_client_port *port, *tmp;
        
        /* move the port list to deleted_list, and
         * clear the port list in the client data.
@@ -331,9 +324,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
        write_unlock_irqrestore(&client->ports_lock, flags);
 
        /* remove each port in deleted_list */
-       list_for_each_safe(p, n, &deleted_list) {
-               struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
-               list_del(p);
+       list_for_each_entry_safe(port, tmp, &deleted_list, list) {
+               list_del(&port->list);
                snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
                port_delete(client, port);
        }
@@ -500,8 +492,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
 {
        struct snd_seq_port_subs_info *src = &src_port->c_src;
        struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
-       struct snd_seq_subscribers *subs;
-       struct list_head *p;
+       struct snd_seq_subscribers *subs, *s;
        int err, src_called = 0;
        unsigned long flags;
        int exclusive;
@@ -525,13 +516,11 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
                if (src->exclusive || dest->exclusive)
                        goto __error;
                /* check whether already exists */
-               list_for_each(p, &src->list_head) {
-                       struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list);
+               list_for_each_entry(s, &src->list_head, src_list) {
                        if (match_subs_info(info, &s->info))
                                goto __error;
                }
-               list_for_each(p, &dest->list_head) {
-                       struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list);
+               list_for_each_entry(s, &dest->list_head, dest_list) {
                        if (match_subs_info(info, &s->info))
                                goto __error;
                }
@@ -582,7 +571,6 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
        struct snd_seq_port_subs_info *src = &src_port->c_src;
        struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
        struct snd_seq_subscribers *subs;
-       struct list_head *p;
        int err = -ENOENT;
        unsigned long flags;
 
@@ -590,8 +578,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
        down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
 
        /* look for the connection */
-       list_for_each(p, &src->list_head) {
-               subs = list_entry(p, struct snd_seq_subscribers, src_list);
+       list_for_each_entry(subs, &src->list_head, src_list) {
                if (match_subs_info(info, &subs->info)) {
                        write_lock_irqsave(&src->list_lock, flags);
                        // write_lock(&dest->list_lock);  // no lock yet
@@ -620,12 +607,10 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
 struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
                                                          struct snd_seq_addr *dest_addr)
 {
-       struct list_head *p;
        struct snd_seq_subscribers *s, *found = NULL;
 
        down_read(&src_grp->list_mutex);
-       list_for_each(p, &src_grp->list_head) {
-               s = list_entry(p, struct snd_seq_subscribers, src_list);
+       list_for_each_entry(s, &src_grp->list_head, src_list) {
                if (addr_match(dest_addr, &s->info.dest)) {
                        found = s;
                        break;
index 0cfa06c..972f934 100644 (file)
@@ -81,13 +81,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
                                         struct snd_seq_event *ev)
 {
        struct snd_virmidi *vmidi;
-       struct list_head *list;
        unsigned char msg[4];
        int len;
 
        read_lock(&rdev->filelist_lock);
-       list_for_each(list, &rdev->filelist) {
-               vmidi = list_entry(list, struct snd_virmidi, list);
+       list_for_each_entry(vmidi, &rdev->filelist, list) {
                if (!vmidi->trigger)
                        continue;
                if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
index 82a61c6..4084de0 100644 (file)
@@ -219,26 +219,27 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
 #endif
 
 /**
- * snd_register_device - Register the ALSA device file for the card
+ * snd_register_device_for_dev - Register the ALSA device file for the card
  * @type: the device type, SNDRV_DEVICE_TYPE_XXX
  * @card: the card instance
  * @dev: the device index
  * @f_ops: the file operations
  * @private_data: user pointer for f_ops->open()
  * @name: the device file name
+ * @device: the &struct device to link this new device to
  *
  * Registers an ALSA device file for the given card.
  * The operators have to be set in reg parameter.
  *
- * Retrurns zero if successful, or a negative error code on failure.
+ * Returns zero if successful, or a negative error code on failure.
  */
-int snd_register_device(int type, struct snd_card *card, int dev,
-                       const struct file_operations *f_ops, void *private_data,
-                       const char *name)
+int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
+                               const struct file_operations *f_ops,
+                               void *private_data,
+                               const char *name, struct device *device)
 {
        int minor;
        struct snd_minor *preg;
-       struct device *device = snd_card_get_device_link(card);
 
        snd_assert(name, return -EINVAL);
        preg = kmalloc(sizeof *preg, GFP_KERNEL);
@@ -272,7 +273,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
        return 0;
 }
 
-EXPORT_SYMBOL(snd_register_device);
+EXPORT_SYMBOL(snd_register_device_for_dev);
 
 /* find the matching minor record
  * return the index of snd_minor, or -1 if not found
index 10a79ae..3e06383 100644 (file)
@@ -35,9 +35,6 @@
 #include <sound/minors.h>
 #include <sound/initval.h>
 #include <linux/kmod.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
 
 #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
 #define DEFAULT_TIMER_LIMIT 3
@@ -130,11 +127,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner,
 static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
 {
        struct snd_timer *timer = NULL;
-       struct list_head *p;
-
-       list_for_each(p, &snd_timer_list) {
-               timer = list_entry(p, struct snd_timer, device_list);
 
+       list_for_each_entry(timer, &snd_timer_list, device_list) {
                if (timer->tmr_class != tid->dev_class)
                        continue;
                if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
@@ -184,13 +178,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
 {
        struct snd_timer *timer;
        struct snd_timer_instance *master;
-       struct list_head *p, *q;
 
        /* FIXME: it's really dumb to look up all entries.. */
-       list_for_each(p, &snd_timer_list) {
-               timer = list_entry(p, struct snd_timer, device_list);
-               list_for_each(q, &timer->open_list_head) {
-                       master = list_entry(q, struct snd_timer_instance, open_list);
+       list_for_each_entry(timer, &snd_timer_list, device_list) {
+               list_for_each_entry(master, &timer->open_list_head, open_list) {
                        if (slave->slave_class == master->slave_class &&
                            slave->slave_id == master->slave_id) {
                                list_del(&slave->open_list);
@@ -214,16 +205,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
  */
 static void snd_timer_check_master(struct snd_timer_instance *master)
 {
-       struct snd_timer_instance *slave;
-       struct list_head *p, *n;
+       struct snd_timer_instance *slave, *tmp;
 
        /* check all pending slaves */
-       list_for_each_safe(p, n, &snd_timer_slave_list) {
-               slave = list_entry(p, struct snd_timer_instance, open_list);
+       list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
                if (slave->slave_class == master->slave_class &&
                    slave->slave_id == master->slave_id) {
-                       list_del(p);
-                       list_add_tail(p, &master->slave_list_head);
+                       list_move_tail(&slave->open_list, &master->slave_list_head);
                        spin_lock_irq(&slave_active_lock);
                        slave->master = master;
                        slave->timer = master->timer;
@@ -317,8 +305,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri,
 int snd_timer_close(struct snd_timer_instance *timeri)
 {
        struct snd_timer *timer = NULL;
-       struct list_head *p, *n;
-       struct snd_timer_instance *slave;
+       struct snd_timer_instance *slave, *tmp;
 
        snd_assert(timeri != NULL, return -ENXIO);
 
@@ -353,12 +340,11 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                    timer->hw.close)
                        timer->hw.close(timer);
                /* remove slave links */
-               list_for_each_safe(p, n, &timeri->slave_list_head) {
-                       slave = list_entry(p, struct snd_timer_instance, open_list);
+               list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
+                                        open_list) {
                        spin_lock_irq(&slave_active_lock);
                        _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
-                       list_del(p);
-                       list_add_tail(p, &snd_timer_slave_list);
+                       list_move_tail(&slave->open_list, &snd_timer_slave_list);
                        slave->master = NULL;
                        slave->timer = NULL;
                        spin_unlock_irq(&slave_active_lock);
@@ -394,7 +380,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
        unsigned long flags;
        unsigned long resolution = 0;
        struct snd_timer_instance *ts;
-       struct list_head *n;
        struct timespec tstamp;
 
        getnstimeofday(&tstamp);
@@ -413,11 +398,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
        if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
                return;
        spin_lock_irqsave(&timer->lock, flags);
-       list_for_each(n, &ti->slave_active_head) {
-               ts = list_entry(n, struct snd_timer_instance, active_list);
+       list_for_each_entry(ts, &ti->slave_active_head, active_list)
                if (ts->ccallback)
                        ts->ccallback(ti, event + 100, &tstamp, resolution);
-       }
        spin_unlock_irqrestore(&timer->lock, flags);
 }
 
@@ -593,10 +576,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
 {
        struct snd_timer_instance *ti;
        unsigned long ticks = ~0UL;
-       struct list_head *p;
 
-       list_for_each(p, &timer->active_list_head) {
-               ti = list_entry(p, struct snd_timer_instance, active_list);
+       list_for_each_entry(ti, &timer->active_list_head, active_list) {
                if (ti->flags & SNDRV_TIMER_IFLG_START) {
                        ti->flags &= ~SNDRV_TIMER_IFLG_START;
                        ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
@@ -661,9 +642,9 @@ static void snd_timer_tasklet(unsigned long arg)
  */
 void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
 {
-       struct snd_timer_instance *ti, *ts;
+       struct snd_timer_instance *ti, *ts, *tmp;
        unsigned long resolution, ticks;
-       struct list_head *p, *q, *n, *ack_list_head;
+       struct list_head *p, *ack_list_head;
        unsigned long flags;
        int use_tasklet = 0;
 
@@ -679,12 +660,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
                resolution = timer->hw.resolution;
 
        /* loop for all active instances
-        * Here we cannot use list_for_each because the active_list of a
+        * Here we cannot use list_for_each_entry because the active_list of a
         * processed instance is relinked to done_list_head before the callback
         * is called.
         */
-       list_for_each_safe(p, n, &timer->active_list_head) {
-               ti = list_entry(p, struct snd_timer_instance, active_list);
+       list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
+                                active_list) {
                if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
                        continue;
                ti->pticks += ticks_left;
@@ -700,7 +681,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
                } else {
                        ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
                        if (--timer->running)
-                               list_del(p);
+                               list_del(&ti->active_list);
                }
                if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
                    (ti->flags & SNDRV_TIMER_IFLG_FAST))
@@ -709,8 +690,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
                        ack_list_head = &timer->sack_list_head;
                if (list_empty(&ti->ack_list))
                        list_add_tail(&ti->ack_list, ack_list_head);
-               list_for_each(q, &ti->slave_active_head) {
-                       ts = list_entry(q, struct snd_timer_instance, active_list);
+               list_for_each_entry(ts, &ti->slave_active_head, active_list) {
                        ts->pticks = ti->pticks;
                        ts->resolution = resolution;
                        if (list_empty(&ts->ack_list))
@@ -844,7 +824,6 @@ static int snd_timer_dev_register(struct snd_device *dev)
 {
        struct snd_timer *timer = dev->device_data;
        struct snd_timer *timer1;
-       struct list_head *p;
 
        snd_assert(timer != NULL && timer->hw.start != NULL &&
                   timer->hw.stop != NULL, return -ENXIO);
@@ -853,8 +832,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
                return -EINVAL;
 
        mutex_lock(&register_mutex);
-       list_for_each(p, &snd_timer_list) {
-               timer1 = list_entry(p, struct snd_timer, device_list);
+       list_for_each_entry(timer1, &snd_timer_list, device_list) {
                if (timer1->tmr_class > timer->tmr_class)
                        break;
                if (timer1->tmr_class < timer->tmr_class)
@@ -877,7 +855,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
                mutex_unlock(&register_mutex);
                return -EBUSY;
        }
-       list_add_tail(&timer->device_list, p);
+       list_add_tail(&timer->device_list, &timer1->device_list);
        mutex_unlock(&register_mutex);
        return 0;
 }
@@ -896,7 +874,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
        unsigned long flags;
        unsigned long resolution = 0;
        struct snd_timer_instance *ti, *ts;
-       struct list_head *p, *n;
 
        if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
                return;
@@ -911,15 +888,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
                else
                        resolution = timer->hw.resolution;
        }
-       list_for_each(p, &timer->active_list_head) {
-               ti = list_entry(p, struct snd_timer_instance, active_list);
+       list_for_each_entry(ti, &timer->active_list_head, active_list) {
                if (ti->ccallback)
                        ti->ccallback(ti, event, tstamp, resolution);
-               list_for_each(n, &ti->slave_active_head) {
-                       ts = list_entry(n, struct snd_timer_instance, active_list);
+               list_for_each_entry(ts, &ti->slave_active_head, active_list)
                        if (ts->ccallback)
                                ts->ccallback(ts, event, tstamp, resolution);
-               }
        }
        spin_unlock_irqrestore(&timer->lock, flags);
 }
@@ -1057,11 +1031,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
 {
        struct snd_timer *timer;
        struct snd_timer_instance *ti;
-       struct list_head *p, *q;
 
        mutex_lock(&register_mutex);
-       list_for_each(p, &snd_timer_list) {
-               timer = list_entry(p, struct snd_timer, device_list);
+       list_for_each_entry(timer, &snd_timer_list, device_list) {
                switch (timer->tmr_class) {
                case SNDRV_TIMER_CLASS_GLOBAL:
                        snd_iprintf(buffer, "G%i: ", timer->tmr_device);
@@ -1088,14 +1060,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
                if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
                        snd_iprintf(buffer, " SLAVE");
                snd_iprintf(buffer, "\n");
-               list_for_each(q, &timer->open_list_head) {
-                       ti = list_entry(q, struct snd_timer_instance, open_list);
+               list_for_each_entry(ti, &timer->open_list_head, open_list)
                        snd_iprintf(buffer, "  Client %s : %s\n",
                                    ti->owner ? ti->owner : "unknown",
                                    ti->flags & (SNDRV_TIMER_IFLG_START |
                                                 SNDRV_TIMER_IFLG_RUNNING)
                                    ? "running" : "stopped");
-               }
        }
        mutex_unlock(&register_mutex);
 }
index 40ebd2f..83529b0 100644 (file)
@@ -109,4 +109,15 @@ config SND_MPU401
          To compile this driver as a module, choose M here: the module
          will be called snd-mpu401.
 
+config SND_PORTMAN2X4
+       tristate "Portman 2x4 driver"
+       depends on SND && PARPORT
+       select SND_RAWMIDI
+       help
+         Say Y here to include support for Midiman Portman 2x4 parallel
+         port MIDI device.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-portman2x4.
+
 endmenu
index c9bad6d..0411264 100644 (file)
@@ -6,6 +6,7 @@
 snd-dummy-objs := dummy.o
 snd-mtpav-objs := mtpav.o
 snd-mts64-objs := mts64.o
+snd-portman2x4-objs := portman2x4.o
 snd-serial-u16550-objs := serial-u16550.o
 snd-virmidi-objs := virmidi.o
 
@@ -15,5 +16,6 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
 obj-$(CONFIG_SND_MTS64) += snd-mts64.o
+obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
 
 obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
index 42001ef..8339bad 100644 (file)
@@ -501,7 +501,7 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
 
 #define DUMMY_CAPSRC(xname, xindex, addr) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
new file mode 100644 (file)
index 0000000..6c48772
--- /dev/null
@@ -0,0 +1,876 @@
+/*
+ *   Driver for Midiman Portman2x4 parallel port midi interface
+ *
+ *   Copyright (c) by Levent Guendogdu <levon@feature-it.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ChangeLog
+ * Jan 24 2007 Matthias Koenig <mkoenig@suse.de>
+ *      - cleanup and rewrite
+ * Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - source code cleanup
+ * Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES,
+ *        MODULE_PARM_SYNTAX and changed MODULE_DEVICES to
+ *        MODULE_SUPPORTED_DEVICE)
+ * Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - added 2.6 kernel support
+ * Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - added parport_unregister_driver to the startup routine if the driver fails to detect a portman
+ *      - added support for all 4 output ports in portman_putmidi
+ * Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - added checks for opened input device in interrupt handler
+ * Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - ported from alsa 0.5 to 1.0
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/parport.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <sound/control.h>
+
+#define CARD_NAME "Portman 2x4"
+#define DRIVER_NAME "portman"
+#define PLATFORM_DRIVER "snd_portman2x4"
+
+static int index[SNDRV_CARDS]  = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS]   = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+static struct platform_device *platform_devices[SNDRV_CARDS]; 
+static int device_count;
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, S_IRUGO);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig");
+MODULE_DESCRIPTION("Midiman Portman2x4");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}");
+
+/*********************************************************************
+ * Chip specific
+ *********************************************************************/
+#define PORTMAN_NUM_INPUT_PORTS 2
+#define PORTMAN_NUM_OUTPUT_PORTS 4
+
+struct portman {
+       spinlock_t reg_lock;
+       struct snd_card *card;
+       struct snd_rawmidi *rmidi;
+       struct pardevice *pardev;
+       int pardev_claimed;
+
+       int open_count;
+       int mode[PORTMAN_NUM_INPUT_PORTS];
+       struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS];
+};
+
+static int portman_free(struct portman *pm)
+{
+       kfree(pm);
+       return 0;
+}
+
+static int __devinit portman_create(struct snd_card *card, 
+                                   struct pardevice *pardev, 
+                                   struct portman **rchip)
+{
+       struct portman *pm;
+
+       *rchip = NULL;
+
+       pm = kzalloc(sizeof(struct portman), GFP_KERNEL);
+       if (pm == NULL) 
+               return -ENOMEM;
+
+       /* Init chip specific data */
+       spin_lock_init(&pm->reg_lock);
+       pm->card = card;
+       pm->pardev = pardev;
+
+       *rchip = pm;
+
+       return 0;
+}
+
+/*********************************************************************
+ * HW related constants
+ *********************************************************************/
+
+/* Standard PC parallel port status register equates. */
+#define        PP_STAT_BSY     0x80    /* Busy status.  Inverted. */
+#define        PP_STAT_ACK     0x40    /* Acknowledge.  Non-Inverted. */
+#define        PP_STAT_POUT    0x20    /* Paper Out.    Non-Inverted. */
+#define        PP_STAT_SEL     0x10    /* Select.       Non-Inverted. */
+#define        PP_STAT_ERR     0x08    /* Error.        Non-Inverted. */
+
+/* Standard PC parallel port command register equates. */
+#define        PP_CMD_IEN      0x10    /* IRQ Enable.   Non-Inverted. */
+#define        PP_CMD_SELI     0x08    /* Select Input. Inverted. */
+#define        PP_CMD_INIT     0x04    /* Init Printer. Non-Inverted. */
+#define        PP_CMD_FEED     0x02    /* Auto Feed.    Inverted. */
+#define        PP_CMD_STB      0x01    /* Strobe.       Inverted. */
+
+/* Parallel Port Command Register as implemented by PCP2x4. */
+#define        INT_EN          PP_CMD_IEN      /* Interrupt enable. */
+#define        STROBE          PP_CMD_STB      /* Command strobe. */
+
+/* The parallel port command register field (b1..b3) selects the 
+ * various "registers" within the PC/P 2x4.  These are the internal
+ * address of these "registers" that must be written to the parallel
+ * port command register.
+ */
+#define        RXDATA0         (0 << 1)        /* PCP RxData channel 0. */
+#define        RXDATA1         (1 << 1)        /* PCP RxData channel 1. */
+#define        GEN_CTL         (2 << 1)        /* PCP General Control Register. */
+#define        SYNC_CTL        (3 << 1)        /* PCP Sync Control Register. */
+#define        TXDATA0         (4 << 1)        /* PCP TxData channel 0. */
+#define        TXDATA1         (5 << 1)        /* PCP TxData channel 1. */
+#define        TXDATA2         (6 << 1)        /* PCP TxData channel 2. */
+#define        TXDATA3         (7 << 1)        /* PCP TxData channel 3. */
+
+/* Parallel Port Status Register as implemented by PCP2x4. */
+#define        ESTB            PP_STAT_POUT    /* Echoed strobe. */
+#define        INT_REQ         PP_STAT_ACK     /* Input data int request. */
+#define        BUSY            PP_STAT_ERR     /* Interface Busy. */
+
+/* Parallel Port Status Register BUSY and SELECT lines are multiplexed
+ * between several functions.  Depending on which 2x4 "register" is
+ * currently selected (b1..b3), the BUSY and SELECT lines are
+ * assigned as follows:
+ *
+ *   SELECT LINE:                                                    A3 A2 A1
+ *                                                                   --------
+ */
+#define        RXAVAIL         PP_STAT_SEL     /* Rx Available, channel 0.   0 0 0 */
+//  RXAVAIL1    PP_STAT_SEL             /* Rx Available, channel 1.   0 0 1 */
+#define        SYNC_STAT       PP_STAT_SEL     /* Reserved - Sync Status.    0 1 0 */
+//                                      /* Reserved.                  0 1 1 */
+#define        TXEMPTY         PP_STAT_SEL     /* Tx Empty, channel 0.       1 0 0 */
+//      TXEMPTY1        PP_STAT_SEL     /* Tx Empty, channel 1.       1 0 1 */
+//  TXEMPTY2    PP_STAT_SEL             /* Tx Empty, channel 2.       1 1 0 */
+//  TXEMPTY3    PP_STAT_SEL             /* Tx Empty, channel 3.       1 1 1 */
+
+/*   BUSY LINE:                                                      A3 A2 A1
+ *                                                                   --------
+ */
+#define        RXDATA          PP_STAT_BSY     /* Rx Input Data, channel 0.  0 0 0 */
+//      RXDATA1         PP_STAT_BSY     /* Rx Input Data, channel 1.  0 0 1 */
+#define        SYNC_DATA       PP_STAT_BSY     /* Reserved - Sync Data.      0 1 0 */
+                                       /* Reserved.                  0 1 1 */
+#define        DATA_ECHO       PP_STAT_BSY     /* Parallel Port Data Echo.   1 0 0 */
+#define        A0_ECHO         PP_STAT_BSY     /* Address 0 Echo.            1 0 1 */
+#define        A1_ECHO         PP_STAT_BSY     /* Address 1 Echo.            1 1 0 */
+#define        A2_ECHO         PP_STAT_BSY     /* Address 2 Echo.            1 1 1 */
+
+#define PORTMAN2X4_MODE_INPUT_TRIGGERED         0x01
+
+/*********************************************************************
+ * Hardware specific functions
+ *********************************************************************/
+static inline void portman_write_command(struct portman *pm, u8 value)
+{
+       parport_write_control(pm->pardev->port, value);
+}
+
+static inline u8 portman_read_command(struct portman *pm)
+{
+       return parport_read_control(pm->pardev->port);
+}
+
+static inline u8 portman_read_status(struct portman *pm)
+{
+       return parport_read_status(pm->pardev->port);
+}
+
+static inline u8 portman_read_data(struct portman *pm)
+{
+       return parport_read_data(pm->pardev->port);
+}
+
+static inline void portman_write_data(struct portman *pm, u8 value)
+{
+       parport_write_data(pm->pardev->port, value);
+}
+
+static void portman_write_midi(struct portman *pm, 
+                              int port, u8 mididata)
+{
+       int command = ((port + 4) << 1);
+
+       /* Get entering data byte and port number in BL and BH respectively.
+        * Set up Tx Channel address field for use with PP Cmd Register.
+        * Store address field in BH register.
+        * Inputs:      AH = Output port number (0..3).
+        *              AL = Data byte.
+        *    command = TXDATA0 | INT_EN;
+        * Align port num with address field (b1...b3),
+        * set address for TXDatax, Strobe=0
+        */
+       command |= INT_EN;
+
+       /* Disable interrupts so that the process is not interrupted, then 
+        * write the address associated with the current Tx channel to the 
+        * PP Command Reg.  Do not set the Strobe signal yet.
+        */
+
+       do {
+               portman_write_command(pm, command);
+
+               /* While the address lines settle, write parallel output data to 
+                * PP Data Reg.  This has no effect until Strobe signal is asserted.
+                */
+
+               portman_write_data(pm, mididata);
+               
+               /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
+                * Status Register), then go write data.  Else go back and wait.
+                */
+       } while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
+
+       /* TxEmpty is set.  Maintain PC/P destination address and assert
+        * Strobe through the PP Command Reg.  This will Strobe data into
+        * the PC/P transmitter and set the PC/P BUSY signal.
+        */
+
+       portman_write_command(pm, command | STROBE);
+
+       /* Wait for strobe line to settle and echo back through hardware.
+        * Once it has echoed back, assume that the address and data lines
+        * have settled!
+        */
+
+       while ((portman_read_status(pm) & ESTB) == 0)
+               cpu_relax();
+
+       /* Release strobe and immediately re-allow interrupts. */
+       portman_write_command(pm, command);
+
+       while ((portman_read_status(pm) & ESTB) == ESTB)
+               cpu_relax();
+
+       /* PC/P BUSY is now set.  We must wait until BUSY resets itself.
+        * We'll reenable ints while we're waiting.
+        */
+
+       while ((portman_read_status(pm) & BUSY) == BUSY)
+               cpu_relax();
+
+       /* Data sent. */
+}
+
+
+/*
+ *  Read MIDI byte from port
+ *  Attempt to read input byte from specified hardware input port (0..).
+ *  Return -1 if no data
+ */
+static int portman_read_midi(struct portman *pm, int port)
+{
+       unsigned char midi_data = 0;
+       unsigned char cmdout;   /* Saved address+IE bit. */
+
+       /* Make sure clocking edge is down before starting... */
+       portman_write_data(pm, 0);      /* Make sure edge is down. */
+
+       /* Set destination address to PCP. */
+       cmdout = (port << 1) | INT_EN;  /* Address + IE + No Strobe. */
+       portman_write_command(pm, cmdout);
+
+       while ((portman_read_status(pm) & ESTB) == ESTB)
+               cpu_relax();    /* Wait for strobe echo. */
+
+       /* After the address lines settle, check multiplexed RxAvail signal.
+        * If data is available, read it.
+        */
+       if ((portman_read_status(pm) & RXAVAIL) == 0)
+               return -1;      /* No data. */
+
+       /* Set the Strobe signal to enable the Rx clocking circuitry. */
+       portman_write_command(pm, cmdout | STROBE);     /* Write address+IE+Strobe. */
+
+       while ((portman_read_status(pm) & ESTB) == 0)
+               cpu_relax(); /* Wait for strobe echo. */
+
+       /* The first data bit (msb) is already sitting on the input line. */
+       midi_data = (portman_read_status(pm) & 128);
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 6. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 1) & 64;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 5. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 2) & 32;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 4. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 3) & 16;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 3. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 4) & 8;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 2. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 5) & 4;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 1. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 6) & 2;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+
+       /* Data bit 0. */
+       portman_write_data(pm, 0);      /* Cause falling edge while data settles. */
+       midi_data |= (portman_read_status(pm) >> 7) & 1;
+       portman_write_data(pm, 1);      /* Cause rising edge, which shifts data. */
+       portman_write_data(pm, 0);      /* Return data clock low. */
+
+
+       /* De-assert Strobe and return data. */
+       portman_write_command(pm, cmdout);      /* Output saved address+IE. */
+
+       /* Wait for strobe echo. */
+       while ((portman_read_status(pm) & ESTB) == ESTB)
+               cpu_relax();
+
+       return (midi_data & 255);       /* Shift back and return value. */
+}
+
+/*
+ *  Checks if any input data on the given channel is available
+ *  Checks RxAvail 
+ */
+static int portman_data_avail(struct portman *pm, int channel)
+{
+       int command = INT_EN;
+       switch (channel) {
+       case 0:
+               command |= RXDATA0;
+               break;
+       case 1:
+               command |= RXDATA1;
+               break;
+       }
+       /* Write hardware (assumme STROBE=0) */
+       portman_write_command(pm, command);
+       /* Check multiplexed RxAvail signal */
+       if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL)
+               return 1;       /* Data available */
+
+       /* No Data available */
+       return 0;
+}
+
+
+/*
+ *  Flushes any input
+ */
+static void portman_flush_input(struct portman *pm, unsigned char port)
+{
+       /* Local variable for counting things */
+       unsigned int i = 0;
+       unsigned char command = 0;
+
+       switch (port) {
+       case 0:
+               command = RXDATA0;
+               break;
+       case 1:
+               command = RXDATA1;
+               break;
+       default:
+               snd_printk(KERN_WARNING
+                          "portman_flush_input() Won't flush port %i\n",
+                          port);
+               return;
+       }
+
+       /* Set address for specified channel in port and allow to settle. */
+       portman_write_command(pm, command);
+
+       /* Assert the Strobe and wait for echo back. */
+       portman_write_command(pm, command | STROBE);
+
+       /* Wait for ESTB */
+       while ((portman_read_status(pm) & ESTB) == 0)
+               cpu_relax();
+
+       /* Output clock cycles to the Rx circuitry. */
+       portman_write_data(pm, 0);
+
+       /* Flush 250 bits... */
+       for (i = 0; i < 250; i++) {
+               portman_write_data(pm, 1);
+               portman_write_data(pm, 0);
+       }
+
+       /* Deassert the Strobe signal of the port and wait for it to settle. */
+       portman_write_command(pm, command | INT_EN);
+
+       /* Wait for settling */
+       while ((portman_read_status(pm) & ESTB) == ESTB)
+               cpu_relax();
+}
+
+static int portman_probe(struct parport *p)
+{
+       /* Initialize the parallel port data register.  Will set Rx clocks
+        * low in case we happen to be addressing the Rx ports at this time.
+        */
+       /* 1 */
+       parport_write_data(p, 0);
+
+       /* Initialize the parallel port command register, thus initializing
+        * hardware handshake lines to midi box:
+        *
+        *                                  Strobe = 0
+        *                                  Interrupt Enable = 0            
+        */
+       /* 2 */
+       parport_write_control(p, 0);
+
+       /* Check if Portman PC/P 2x4 is out there. */
+       /* 3 */
+       parport_write_control(p, RXDATA0);      /* Write Strobe=0 to command reg. */
+
+       /* Check for ESTB to be clear */
+       /* 4 */
+       if ((parport_read_status(p) & ESTB) == ESTB)
+               return 1;       /* CODE 1 - Strobe Failure. */
+
+       /* Set for RXDATA0 where no damage will be done. */
+       /* 5 */
+       parport_write_control(p, RXDATA0 + STROBE);     /* Write Strobe=1 to command reg. */
+
+       /* 6 */
+       if ((parport_read_status(p) & ESTB) != ESTB)
+               return 1;       /* CODE 1 - Strobe Failure. */
+
+       /* 7 */
+       parport_write_control(p, 0);    /* Reset Strobe=0. */
+
+       /* Check if Tx circuitry is functioning properly.  If initialized 
+        * unit TxEmpty is false, send out char and see if if goes true.
+        */
+       /* 8 */
+       parport_write_control(p, TXDATA0);      /* Tx channel 0, strobe off. */
+
+       /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
+        * Status Register), then go write data.  Else go back and wait.
+        */
+       /* 9 */
+       if ((parport_read_status(p) & TXEMPTY) == 0)
+               return 2;
+
+       /* Return OK status. */
+       return 0;
+}
+
+static int portman_device_init(struct portman *pm)
+{
+       portman_flush_input(pm, 0);
+       portman_flush_input(pm, 1);
+
+       return 0;
+}
+
+/*********************************************************************
+ * Rawmidi
+ *********************************************************************/
+static int snd_portman_midi_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int snd_portman_midi_close(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream,
+                                          int up)
+{
+       struct portman *pm = substream->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pm->reg_lock, flags);
+       if (up)
+               pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;
+       else
+               pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;
+       spin_unlock_irqrestore(&pm->reg_lock, flags);
+}
+
+static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,
+                                           int up)
+{
+       struct portman *pm = substream->rmidi->private_data;
+       unsigned long flags;