]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-linus' of git://git.alsa-project.org/alsa-kernel
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Oct 2008 16:16:54 +0000 (09:16 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Oct 2008 16:16:54 +0000 (09:16 -0700)
* 'for-linus' of git://git.alsa-project.org/alsa-kernel: (258 commits)
  ALSA: hda: VREF powerdown for headphones
  ALSA: hda: STAC_HP_M4
  ALSA: ASoC: Check for machine type in GTA01 machine driver
  ALSA: mtpav - Fix race in probe
  ALSA: usb-audio: dynamic detection of MIDI interfaces in uaxx-quirk
  ALSA: Add a note on dependency of RTC stuff
  ALSA: ASoC: add new param mux to dapm_mux_update_power
  ALSA: Increase components array size
  ALSA: ASoC: Correct inverted Mic PGA Switch control in wm8510 driver
  ALSA: hda: comment typo fix
  ALSA: hda: comment typo fix
  ALSA: hda - Fix PCI SSID for ASROCK K18N78FullHD-hSLI
  ALSA: snd-usb-audio: support for Edirol UA-4FX device
  ALSA: usb - Fix possible Oops at USB-MIDI disconnection
  ALSA: hda - Fix another ALC889A (rev 0x100101)
  ALSA: hda: add more board-specific information for Realtek ALC662 rev1
  ALSA: Correct Vladimir Barinov's e-mail address
  ALSA: cs46xx: Add PCI IDs for TerraTec and Hercules cards
  ALSA: hda: SPDIF stream muting support
  ALSA: hda: appletv support
  ...

356 files changed:
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
MAINTAINERS
arch/arm/plat-omap/include/mach/mtd-xip.h
arch/um/Kconfig.char
drivers/media/video/saa7134/saa7134-alsa.c
drivers/usb/host/ehci-ixp4xx.c
include/sound/ad1848.h [deleted file]
include/sound/asound.h
include/sound/asoundef.h
include/sound/core.h
include/sound/cs4231.h [deleted file]
include/sound/jack.h [new file with mode: 0644]
include/sound/memalloc.h
include/sound/minors.h
include/sound/pcm.h
include/sound/pxa2xx-lib.h [new file with mode: 0644]
include/sound/sb.h
include/sound/snd_wavefront.h
include/sound/soc-of-simple.h [new file with mode: 0644]
include/sound/soc.h
include/sound/version.h
include/sound/vx_core.h
include/sound/wss.h [new file with mode: 0644]
sound/Kconfig
sound/aoa/codecs/snd-aoa-codec-tas.c
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/aaci.c
sound/arm/pxa2xx-ac97-lib.c [new file with mode: 0644]
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm-lib.c [new file with mode: 0644]
sound/arm/pxa2xx-pcm.c
sound/arm/pxa2xx-pcm.h
sound/arm/sa11xx-uda1341.c
sound/core/Kconfig
sound/core/Makefile
sound/core/control.c
sound/core/control_compat.c
sound/core/device.c
sound/core/hwdep.c
sound/core/info.c
sound/core/info_oss.c
sound/core/init.c
sound/core/jack.c [new file with mode: 0644]
sound/core/memalloc.c
sound/core/oss/copy.c
sound/core/oss/io.c
sound/core/oss/linear.c
sound/core/oss/mixer_oss.c
sound/core/oss/mulaw.c
sound/core/oss/pcm_oss.c
sound/core/oss/pcm_plugin.c
sound/core/oss/rate.c
sound/core/oss/route.c
sound/core/pcm.c
sound/core/pcm_compat.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_native.c
sound/core/pcm_timer.c
sound/core/rawmidi.c
sound/core/rtctimer.c
sound/core/seq/oss/seq_oss.c
sound/core/seq/oss/seq_oss_synth.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_compat.c
sound/core/seq/seq_device.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_timer.c
sound/core/sgbuf.c
sound/core/sound.c
sound/core/sound_oss.c
sound/core/timer.c
sound/core/timer_compat.c
sound/drivers/dummy.c
sound/drivers/mtpav.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_midi.c
sound/drivers/opl3/opl3_oss.c
sound/drivers/opl3/opl3_synth.c
sound/drivers/opl4/opl4_synth.c
sound/drivers/vx/vx_cmd.c
sound/drivers/vx/vx_core.c
sound/drivers/vx/vx_hwdep.c
sound/drivers/vx/vx_mixer.c
sound/drivers/vx/vx_pcm.c
sound/drivers/vx/vx_uer.c
sound/i2c/cs8427.c
sound/i2c/i2c.c
sound/i2c/l3/uda1341.c
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/Kconfig
sound/isa/Makefile
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/Makefile
sound/isa/ad1848/ad1848.c
sound/isa/ad1848/ad1848_lib.c [deleted file]
sound/isa/azt2320.c
sound/isa/cmi8330.c
sound/isa/cs423x/Makefile
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4231_lib.c [deleted file]
sound/isa/cs423x/cs4236.c
sound/isa/cs423x/cs4236_lib.c
sound/isa/es1688/es1688_lib.c
sound/isa/gus/gus_main.c
sound/isa/gus/gus_mixer.c
sound/isa/gus/gus_pcm.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/emu8000.c
sound/isa/sb/emu8000_patch.c
sound/isa/sb/sb16_csp.c
sound/isa/sb/sb16_main.c
sound/isa/sb/sb8_main.c
sound/isa/sb/sb_common.c
sound/isa/sb/sb_mixer.c
sound/isa/sc6000.c
sound/isa/sgalaxy.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/isa/wavefront/wavefront_fx.c
sound/isa/wavefront/wavefront_midi.c
sound/isa/wavefront/wavefront_synth.c
sound/isa/wss/Makefile [new file with mode: 0644]
sound/isa/wss/wss_lib.c [new file with mode: 0644]
sound/mips/au1x00.c
sound/oss/Kconfig
sound/oss/Makefile
sound/oss/aedsp16.c
sound/oss/dmasound/Kconfig
sound/oss/hal2.c [deleted file]
sound/oss/hal2.h [deleted file]
sound/oss/mpu401.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ad1889.c
sound/pci/ak4531_codec.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.h
sound/pci/au88x0/au88x0_core.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca_midi.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/echoaudio/darla20_dsp.c
sound/pci/echoaudio/darla24_dsp.c
sound/pci/echoaudio/echo3g_dsp.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio_3g.c
sound/pci/echoaudio/echoaudio_dsp.c
sound/pci/echoaudio/echoaudio_gml.c
sound/pci/echoaudio/gina20_dsp.c
sound/pci/echoaudio/gina24_dsp.c
sound/pci/echoaudio/indigo_dsp.c
sound/pci/echoaudio/indigodj_dsp.c
sound/pci/echoaudio/indigoio_dsp.c
sound/pci/echoaudio/layla20_dsp.c
sound/pci/echoaudio/layla24_dsp.c
sound/pci/echoaudio/mia_dsp.c
sound/pci/echoaudio/midi.c
sound/pci/echoaudio/mona_dsp.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1_patch.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumpu401.c
sound/pci/emu10k1/memory.c
sound/pci/emu10k1/voice.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/hda/Makefile
sound/pci/hda/hda_beep.c [new file with mode: 0644]
sound/pci/hda/hda_beep.h [new file with mode: 0644]
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_patch.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c
sound/pci/hda/patch_nvhdmi.c [new file with mode: 0644]
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ak4xxx.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/delta.c
sound/pci/ice1712/delta.h
sound/pci/ice1712/ews.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/phase.c
sound/pci/ice1712/phase.h
sound/pci/ice1712/pontis.c
sound/pci/ice1712/revo.c
sound/pci/ice1712/wtm.c
sound/pci/ice1712/wtm.h
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/mixart/mixart_core.c
sound/pci/mixart/mixart_hwdep.c
sound/pci/mixart/mixart_mixer.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/hifier.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/virtuoso.c
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr_core.c
sound/pci/pcxhr/pcxhr_hwdep.c
sound/pci/riptide/riptide.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sonicvibes.c
sound/pci/trident/trident_main.c
sound/pci/trident/trident_memory.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222_ops.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/vx/vxp_ops.c
sound/ppc/awacs.c
sound/ppc/beep.c
sound/ppc/tumbler.c
sound/sh/aica.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/at32/playpaq_wm8510.c
sound/soc/at91/at91-ssc.c
sound/soc/at91/eti_b1_wm8731.c
sound/soc/blackfin/Kconfig [new file with mode: 0644]
sound/soc/blackfin/Makefile [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ac97-pcm.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ac97-pcm.h [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ac97.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ac97.h [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ad1980.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-i2s-pcm.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-i2s-pcm.h [new file with mode: 0644]
sound/soc/blackfin/bf5xx-i2s.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-i2s.h [new file with mode: 0644]
sound/soc/blackfin/bf5xx-sport.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-sport.h [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ssm2602.c [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad1980.c [new file with mode: 0644]
sound/soc/codecs/ad1980.h [new file with mode: 0644]
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4535.h
sound/soc/codecs/ssm2602.c [new file with mode: 0644]
sound/soc/codecs/ssm2602.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic26.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic26.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/uda1380.c
sound/soc/codecs/uda1380.h
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8510.h
sound/soc/codecs/wm8580.c [new file with mode: 0644]
sound/soc/codecs/wm8580.h [new file with mode: 0644]
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8731.h
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8750.h
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8900.c [new file with mode: 0644]
sound/soc/codecs/wm8900.h [new file with mode: 0644]
sound/soc/codecs/wm8903.c [new file with mode: 0644]
sound/soc/codecs/wm8903.h [new file with mode: 0644]
sound/soc/codecs/wm8971.c [new file with mode: 0644]
sound/soc/codecs/wm8971.h [new file with mode: 0644]
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8990.h
sound/soc/codecs/wm9713.c
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-i2s.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/mpc5200_psc_i2s.c [new file with mode: 0644]
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/soc-of-simple.c [new file with mode: 0644]
sound/soc/omap/n810.c
sound/soc/pxa/Kconfig
sound/soc/pxa/corgi.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/pxa2xx-pcm.h
sound/soc/pxa/spitz.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/sound_core.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/synth/emux/emux.c
sound/synth/emux/emux_nrpn.c
sound/synth/emux/emux_oss.c
sound/synth/emux/emux_seq.c
sound/synth/emux/emux_synth.c
sound/synth/util_mem.c
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbmidi.c
sound/usb/usbmixer.c
sound/usb/usbquirks.h
sound/usb/usx2y/Makefile
sound/usb/usx2y/us122l.c [new file with mode: 0644]
sound/usb/usx2y/us122l.h [new file with mode: 0644]
sound/usb/usx2y/usb_stream.c [new file with mode: 0644]
sound/usb/usx2y/usb_stream.h [new file with mode: 0644]

index b117e42a616686e6ef6156a80e07ee4ff2d2e485..e0e54a27fc10905a62bd649605ad2dbe8f8bfdbf 100644 (file)
@@ -746,8 +746,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-hda-intel
   --------------------
 
-    Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8),
-               ATI SB450, SB600, RS600,
+    Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8, ICH9, ICH10,
+                       PCH, SCH),
+               ATI SB450, SB600, R600, RS600, RS690, RS780, RV610, RV620,
+                       RV630, RV635, RV670, RV770,
                VIA VT8251/VT8237A,
                SIS966, ULI M5461
 
@@ -807,6 +809,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
        ALC260
          hp            HP machines
          hp-3013       HP machines (3013-variant)
+         hp-dc7600     HP DC7600
          fujitsu       Fujitsu S7020
          acer          Acer TravelMate
          will          Will laptops (PB V7900)
@@ -828,8 +831,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          hippo         Hippo (ATI) with jack detection, Sony UX-90s
          hippo_1       Hippo (Benq) with jack detection
          sony-assamd   Sony ASSAMD
+         toshiba-s06   Toshiba S06
+         toshiba-rx1   Toshiba RX1
          ultra         Samsung Q1 Ultra Vista model
          lenovo-3000   Lenovo 3000 y410
+         nec           NEC Versa S9100
          basic         fixed pin assignment w/o SPDIF
          auto          auto-config reading BIOS (default)
 
@@ -838,6 +844,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack        3-stack model
          toshiba       Toshiba A205
          acer          Acer laptops
+         acer-aspire   Acer Aspire One
          dell          Dell OEM laptops (Vostro 1200)
          zepto         Zepto laptops
          test          for testing/debugging purpose, almost all controls can
@@ -847,6 +854,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
        ALC269
          basic         Basic preset
+         quanta        Quanta FL1
+         eeepc-p703    ASUS Eeepc P703 P900A
+         eeepc-p901    ASUS Eeepc P901 S101
 
        ALC662/663
          3stack-dig    3-stack (2-channel) with SPDIF
@@ -856,10 +866,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          lenovo-101e    Lenovo laptop
          eeepc-p701    ASUS Eeepc P701
          eeepc-ep20    ASUS Eeepc EP20
+         ecs           ECS/Foxconn mobo
          m51va         ASUS M51VA
          g71v          ASUS G71V
          h13           ASUS H13
          g50v          ASUS G50V
+         asus-mode1    ASUS
+         asus-mode2    ASUS
+         asus-mode3    ASUS
+         asus-mode4    ASUS
+         asus-mode5    ASUS
+         asus-mode6    ASUS
          auto          auto-config reading BIOS (default)
 
        ALC882/885
@@ -891,12 +908,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          lenovo-101e   Lenovo 101E
          lenovo-nb0763 Lenovo NB0763
          lenovo-ms7195-dig Lenovo MS7195
+         lenovo-sky    Lenovo Sky
          haier-w66     Haier W66
          3stack-hp     HP machines with 3stack (Lucknow, Samba boards)
          6stack-dell   Dell machines with 6stack (Inspiron 530)
          mitac         Mitac 8252D
          clevo-m720    Clevo M720 laptop series
          fujitsu-pi2515 Fujitsu AMILO Pi2515
+         3stack-6ch-intel Intel DG33* boards
          auto          auto-config reading BIOS (default)
 
        ALC861/660
@@ -929,7 +948,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          allout        5-jack in back, 2-jack in front, SPDIF out
          auto          auto-config reading BIOS (default)
 
-       AD1882
+       AD1882 / AD1882A
          3stack        3-stack mode (default)
          6stack        6-stack mode
 
@@ -1079,7 +1098,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
            register value without FIFO size correction as the current
            DMA pointer.  position_fix=2 will make the driver to use
            the position buffer instead of reading SD_LPIB register.
-           (Usually SD_LPLIB register is more accurate than the
+           (Usually SD_LPIB register is more accurate than the
            position buffer.)
 
     NB: If you get many "azx_get_response timeout" messages at
@@ -1166,6 +1185,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        * Event Electronics, EZ8
                         * Digigram VX442
                        * Lionstracs, Mediastaton
+                       * Terrasoniq TS 88
 
     model       - Use the given board model, one of the following:
                  delta1010, dio2496, delta66, delta44, audiophile, delta410,
@@ -1200,7 +1220,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        * TerraTec Phase 22
                        * TerraTec Phase 28
                        * AudioTrak Prodigy 7.1
-                       * AudioTrak Prodigy 7.1LT
+                       * AudioTrak Prodigy 7.1 LT
+                       * AudioTrak Prodigy 7.1 XT
+                       * AudioTrak Prodigy 7.1 HIFI
+                       * AudioTrak Prodigy 7.1 HD2
                        * AudioTrak Prodigy 192
                        * Pontis MS300
                        * Albatron K8X800 Pro II 
@@ -1211,12 +1234,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        * Shuttle SN25P
                        * Onkyo SE-90PCI
                        * Onkyo SE-200PCI
+                       * ESI Juli@
+                       * Hercules Fortissimo IV
+                       * EGO-SYS WaveTerminal 192M
 
     model       - Use the given board model, one of the following:
                  revo51, revo71, amp2000, prodigy71, prodigy71lt,
-                 prodigy192, aureon51, aureon71, universe, ap192,
-                 k8x800, phase22, phase28, ms300, av710, se200pci,
-                 se90pci
+                 prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192,
+                 juli, aureon51, aureon71, universe, ap192, k8x800,
+                 phase22, phase28, ms300, av710, se200pci, se90pci,
+                 fortissimo4, sn25p, WT192M
 
     This module supports multiple cards and autoprobe.
 
@@ -1255,7 +1282,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for AC'97 motherboards from Intel and compatibles.
                        * Intel i810/810E, i815, i820, i830, i84x, MX440
-                               ICH5, ICH6, ICH7, ESB2
+                               ICH5, ICH6, ICH7, 6300ESB, ESB2
                        * SiS 7012 (SiS 735)
                        * NVidia NForce, NForce2, NForce3, MCP04, CK804
                                 CK8, CK8S, MCP501
@@ -1951,6 +1978,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        * CHIC  True Sound 4Dwave
                        * Shark  Predator4D-PCI
                        * Jaton  SonicWave 4D
+                       * SiS SI7018 PCI Audio
+                       * Hoontech SoundTrack Digital 4DWave NX
 
     pcm_channels   - max channels (voices) reserved for PCM
     wavetable_size - max wavetable size in kB (4-?kb)
@@ -1966,12 +1995,25 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     vid             - Vendor ID for the device (optional)
     pid             - Product ID for the device (optional)
+    nrpacks        - Max. number of packets per URB (default: 8)
+    async_unlink    - Use async unlink mode (default: yes)
     device_setup    - Device specific magic number (optional)
                     - Influence depends on the device
                     - Default: 0x0000 
+    ignore_ctl_error - Ignore any USB-controller regarding mixer
+                      interface (default: no)
 
     This module supports multiple devices, autoprobe and hotplugging.
 
+    NB: nrpacks parameter can be modified dynamically via sysfs.
+        Don't put the value over 20.  Changing via sysfs has no sanity
+       check.
+    NB: async_unlink=0 would cause Oops.  It remains just for
+        debugging purpose (if any).
+    NB: ignore_ctl_error=1 may help when you get an error at accessing
+        the mixer element such as URB error -22.  This happens on some
+        buggy USB device or the controller.
+
   Module snd-usb-caiaq
   --------------------
 
@@ -2078,7 +2120,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   -------------------
 
     Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2 and D2X.
+    i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe).
 
     This module supports autoprobe and multiple cards.
 
index e13c4e67029f497899d4cbc545f67fd073d36e1f..b54cb5048dfa8c1f23176382cf31d2f1b409e15b 100644 (file)
@@ -6135,44 +6135,58 @@ struct _snd_pcm_runtime {
       </para>
     </section>
 
-    <section id="useful-functions-snd-assert">
-      <title><function>snd_assert()</function></title>
+    <section id="useful-functions-snd-bug">
+      <title><function>snd_BUG()</function></title>
       <para>
-        <function>snd_assert()</function> macro is similar with the
-      normal <function>assert()</function> macro. For example,  
+        It shows the <computeroutput>BUG?</computeroutput> message and
+      stack trace as well as <function>snd_BUG_ON</function> at the point.
+      It's useful to show that a fatal error happens there. 
+      </para>
+      <para>
+        When no debug flag is set, this macro is ignored. 
+      </para>
+    </section>
+
+    <section id="useful-functions-snd-bug-on">
+      <title><function>snd_BUG_ON()</function></title>
+      <para>
+        <function>snd_BUG_ON()</function> macro is similar with
+       <function>WARN_ON()</function> macro. For example,  
 
         <informalexample>
           <programlisting>
 <![CDATA[
-  snd_assert(pointer != NULL, return -EINVAL);
+  snd_BUG_ON(!pointer);
 ]]>
           </programlisting>
         </informalexample>
-      </para>
 
-      <para>
-        The first argument is the expression to evaluate, and the
-      second argument is the action if it fails. When
-      <constant>CONFIG_SND_DEBUG</constant>, is set, it will show an
-      error message such as <computeroutput>BUG? (xxx)</computeroutput>
-      together with stack trace.
-      </para>
-      <para>
-        When no debug flag is set, this macro is ignored. 
-      </para>
-    </section>
+       or it can be used as the condition,
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  if (snd_BUG_ON(non_zero_is_bug))
+          return -EINVAL;
+]]>
+          </programlisting>
+        </informalexample>
 
-    <section id="useful-functions-snd-bug">
-      <title><function>snd_BUG()</function></title>
-      <para>
-        It shows the <computeroutput>BUG?</computeroutput> message and
-      stack trace as well as <function>snd_assert</function> at the point.
-      It's useful to show that a fatal error happens there. 
       </para>
+
       <para>
-        When no debug flag is set, this macro is ignored. 
+        The macro takes an conditional expression to evaluate.
+       When <constant>CONFIG_SND_DEBUG</constant>, is set, the
+       expression is actually evaluated. If it's non-zero, it shows
+       the warning message such as
+       <computeroutput>BUG? (xxx)</computeroutput>
+       normally followed by stack trace.  It returns the evaluated
+       value.
+       When no <constant>CONFIG_SND_DEBUG</constant> is set, this
+       macro always returns zero.
       </para>
+
     </section>
+
   </chapter>
 
 
index 7a03bd5a91a3eb37586c13cde383c9a162f08ee0..ece4e27f997217d6fe82d63dff85f7b1e23e5461 100644 (file)
@@ -3828,6 +3828,8 @@ S:        Maintained
 SOUND
 P:     Jaroslav Kysela
 M:     perex@perex.cz
+P:     Takashi Iwai
+M:     tiwai@suse.de
 L:     alsa-devel@alsa-project.org (subscribers-only)
 S:     Maintained
 
index 5cee7e16a1b44398fc671fb46e9dbb18f8c37cdf..39b591ff54bb3062fb5ce135e63429e51f8a200c 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Do not include this file directly. It's included from linux/mtd/xip.h
  *
- * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ * Author: Vladimir Barinov <vbarinov@embeddedalley.com>
  *
  * (c) 2005 MontaVista Software, Inc.  This file is licensed under the
  * terms of the GNU General Public License version 2.  This program is
index 1b238ebae6b39973cbf7d57b0d7dbe8a40f49a06..70dabd1e0652a1a0725962b28a67abcc729010f9 100644 (file)
@@ -203,6 +203,10 @@ config SOUND
        tristate
        default UML_SOUND
 
+config SOUND_OSS_CORE
+       bool
+       default UML_SOUND
+
 config HOSTAUDIO
        tristate
        default UML_SOUND
index 9929d20320b485b7f5f9740360d599db799ca6ce..26194a0ce927c4e414c66c89dbabf29d8a00fdbd 100644 (file)
@@ -488,10 +488,12 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
        period_size = params_period_bytes(hw_params);
        periods = params_periods(hw_params);
 
-       snd_assert(period_size >= 0x100 && period_size <= 0x10000,
-                  return -EINVAL);
-       snd_assert(periods >= 4, return -EINVAL);
-       snd_assert(period_size * periods <= 1024 * 1024, return -EINVAL);
+       if (period_size < 0x100 || period_size > 0x10000)
+               return -EINVAL;
+       if (periods < 4)
+               return -EINVAL;
+       if (period_size * periods > 1024 * 1024)
+               return -EINVAL;
 
        dev = saa7134->dev;
 
@@ -942,7 +944,8 @@ static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
        unsigned int idx;
        int err;
 
-       snd_assert(chip != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
        strcpy(card->mixername, "SAA7134 Mixer");
 
        for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
index f9575c4091240ef364a4ca0b2d1bfac5099ccf25..9c32063a0c2f6611fc938760ea84906d1f3f9666 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * IXP4XX EHCI Host Controller Driver
  *
- * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ * Author: Vladimir Barinov <vbarinov@embeddedalley.com>
  *
  * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com>
  *
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
deleted file mode 100644 (file)
index d9aebdf..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-#ifndef __SOUND_AD1848_H
-#define __SOUND_AD1848_H
-
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Definitions for AD1847/AD1848/CS4248 chips
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include "pcm.h"
-#include <linux/interrupt.h>
-
-/* IO ports */
-
-#define AD1848P( chip, x ) ( (chip) -> port + c_d_c_AD1848##x )
-
-#define c_d_c_AD1848REGSEL     0
-#define c_d_c_AD1848REG                1
-#define c_d_c_AD1848STATUS     2
-#define c_d_c_AD1848PIO                3
-
-/* codec registers */
-
-#define AD1848_LEFT_INPUT      0x00    /* left input control */
-#define AD1848_RIGHT_INPUT     0x01    /* right input control */
-#define AD1848_AUX1_LEFT_INPUT 0x02    /* left AUX1 input control */
-#define AD1848_AUX1_RIGHT_INPUT        0x03    /* right AUX1 input control */
-#define AD1848_AUX2_LEFT_INPUT 0x04    /* left AUX2 input control */
-#define AD1848_AUX2_RIGHT_INPUT        0x05    /* right AUX2 input control */
-#define AD1848_LEFT_OUTPUT     0x06    /* left output control register */
-#define AD1848_RIGHT_OUTPUT    0x07    /* right output control register */
-#define AD1848_DATA_FORMAT     0x08    /* clock and data format - playback/capture - bits 7-0 MCE */
-#define AD1848_IFACE_CTRL      0x09    /* interface control - bits 7-2 MCE */
-#define AD1848_PIN_CTRL                0x0a    /* pin control */
-#define AD1848_TEST_INIT       0x0b    /* test and initialization */
-#define AD1848_MISC_INFO       0x0c    /* miscellaneous information */
-#define AD1848_LOOPBACK                0x0d    /* loopback control */
-#define AD1848_DATA_UPR_CNT    0x0e    /* playback/capture upper base count */
-#define AD1848_DATA_LWR_CNT    0x0f    /* playback/capture lower base count */
-
-/* definitions for codec register select port - CODECP( REGSEL ) */
-
-#define AD1848_INIT            0x80    /* CODEC is initializing */
-#define AD1848_MCE             0x40    /* mode change enable */
-#define AD1848_TRD             0x20    /* transfer request disable */
-
-/* definitions for codec status register - CODECP( STATUS ) */
-
-#define AD1848_GLOBALIRQ       0x01    /* IRQ is active */
-
-/* definitions for AD1848_LEFT_INPUT and AD1848_RIGHT_INPUT registers */
-
-#define AD1848_ENABLE_MIC_GAIN 0x20
-
-#define AD1848_MIXS_LINE1      0x00
-#define AD1848_MIXS_AUX1       0x40
-#define AD1848_MIXS_LINE2      0x80
-#define AD1848_MIXS_ALL                0xc0
-
-/* definitions for clock and data format register - AD1848_PLAYBK_FORMAT */
-
-#define AD1848_LINEAR_8                0x00    /* 8-bit unsigned data */
-#define AD1848_ALAW_8          0x60    /* 8-bit A-law companded */
-#define AD1848_ULAW_8          0x20    /* 8-bit U-law companded */
-#define AD1848_LINEAR_16       0x40    /* 16-bit twos complement data - little endian */
-#define AD1848_STEREO          0x10    /* stereo mode */
-/* bits 3-1 define frequency divisor */
-#define AD1848_XTAL1           0x00    /* 24.576 crystal */
-#define AD1848_XTAL2           0x01    /* 16.9344 crystal */
-
-/* definitions for interface control register - AD1848_IFACE_CTRL */
-
-#define AD1848_CAPTURE_PIO     0x80    /* capture PIO enable */
-#define AD1848_PLAYBACK_PIO    0x40    /* playback PIO enable */
-#define AD1848_CALIB_MODE      0x18    /* calibration mode bits */
-#define AD1848_AUTOCALIB       0x08    /* auto calibrate */
-#define AD1848_SINGLE_DMA      0x04    /* use single DMA channel */
-#define AD1848_CAPTURE_ENABLE  0x02    /* capture enable */
-#define AD1848_PLAYBACK_ENABLE 0x01    /* playback enable */
-
-/* definitions for pin control register - AD1848_PIN_CTRL */
-
-#define AD1848_IRQ_ENABLE      0x02    /* enable IRQ */
-#define AD1848_XCTL1           0x40    /* external control #1 */
-#define AD1848_XCTL0           0x80    /* external control #0 */
-
-/* definitions for test and init register - AD1848_TEST_INIT */
-
-#define AD1848_CALIB_IN_PROGRESS 0x20  /* auto calibrate in progress */
-#define AD1848_DMA_REQUEST     0x10    /* DMA request in progress */
-
-/* defines for codec.mode */
-
-#define AD1848_MODE_NONE       0x0000
-#define AD1848_MODE_PLAY       0x0001
-#define AD1848_MODE_CAPTURE    0x0002
-#define AD1848_MODE_TIMER      0x0004
-#define AD1848_MODE_OPEN       (AD1848_MODE_PLAY|AD1848_MODE_CAPTURE|AD1848_MODE_TIMER)
-#define AD1848_MODE_RUNNING    0x0010
-
-/* defines for codec.hardware */
-
-#define AD1848_HW_DETECT       0x0000  /* let AD1848 driver detect chip */
-#define AD1848_HW_AD1847       0x0001  /* AD1847 chip */
-#define AD1848_HW_AD1848       0x0002  /* AD1848 chip */
-#define AD1848_HW_CS4248       0x0003  /* CS4248 chip */
-#define AD1848_HW_CMI8330      0x0004  /* CMI8330 chip */
-#define AD1848_HW_THINKPAD     0x0005  /* Thinkpad 360/750/755 */
-
-/* IBM Thinkpad specific stuff */
-#define AD1848_THINKPAD_CTL_PORT1              0x15e8
-#define AD1848_THINKPAD_CTL_PORT2              0x15e9
-#define AD1848_THINKPAD_CS4248_ENABLE_BIT      0x02
-
-struct snd_ad1848 {
-       unsigned long port;             /* i/o port */
-       struct resource *res_port;
-       int irq;                        /* IRQ line */
-       int dma;                        /* data DMA */
-       unsigned short version;         /* version of CODEC chip */
-       unsigned short mode;            /* see to AD1848_MODE_XXXX */
-       unsigned short hardware;        /* see to AD1848_HW_XXXX */
-       unsigned short single_dma:1;    /* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
-
-       struct snd_pcm *pcm;
-       struct snd_pcm_substream *playback_substream;
-       struct snd_pcm_substream *capture_substream;
-       struct snd_card *card;
-
-       unsigned char image[32];        /* SGalaxy needs an access to extended registers */
-       int mce_bit;
-       int calibrate_mute;
-       int dma_size;
-       int thinkpad_flag;              /* Thinkpad CS4248 needs some extra help */
-
-#ifdef CONFIG_PM
-       void (*suspend)(struct snd_ad1848 *chip);
-       void (*resume)(struct snd_ad1848 *chip);
-#endif
-
-       spinlock_t reg_lock;
-};
-
-/* exported functions */
-
-void snd_ad1848_out(struct snd_ad1848 *chip, unsigned char reg, unsigned char value);
-
-int snd_ad1848_create(struct snd_card *card,
-                     unsigned long port,
-                     int irq, int dma,
-                     unsigned short hardware,
-                     struct snd_ad1848 ** chip);
-
-int snd_ad1848_pcm(struct snd_ad1848 * chip, int device, struct snd_pcm **rpcm);
-const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction);
-int snd_ad1848_mixer(struct snd_ad1848 * chip);
-
-/* exported mixer stuffs */
-enum { AD1848_MIX_SINGLE, AD1848_MIX_DOUBLE, AD1848_MIX_CAPTURE };
-
-#define AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) \
-       ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24))
-#define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \
-       ((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22))
-
-/* for ease of use */
-struct ad1848_mix_elem {
-       const char *name;
-       int index;
-       int type;
-       unsigned long private_value;
-       const unsigned int *tlv;
-};
-
-#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_SINGLE, \
-  .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) }
-
-#define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_SINGLE, \
-  .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert), \
-  .tlv = xtlv }
-
-#define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_DOUBLE, \
-  .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) }
-
-#define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
-{ .name = xname, \
-  .index = xindex, \
-  .type = AD1848_MIX_DOUBLE, \
-  .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert), \
-  .tlv = xtlv }
-
-int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c);
-
-#endif /* __SOUND_AD1848_H */
index 3eaf155b850d8b0c266ea0d930823317033948c8..2c4dc908a54a5f2ce6b63c95c59f9ba3924fa0ee 100644 (file)
@@ -93,9 +93,10 @@ enum {
        SNDRV_HWDEP_IFACE_PCXHR,        /* Digigram PCXHR */
        SNDRV_HWDEP_IFACE_SB_RC,        /* SB Extigy/Audigy2NX remote control */
        SNDRV_HWDEP_IFACE_HDA,          /* HD-audio */
+       SNDRV_HWDEP_IFACE_USB_STREAM,   /* direct access to usb stream */
 
        /* Don't forget to change the following: */
-       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_HDA
+       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
 };
 
 struct snd_hwdep_info {
@@ -296,29 +297,39 @@ struct snd_pcm_info {
        unsigned char reserved[64];     /* reserved for future... */
 };
 
-typedef int __bitwise snd_pcm_hw_param_t;
-#define        SNDRV_PCM_HW_PARAM_ACCESS       ((__force snd_pcm_hw_param_t) 0) /* Access type */
-#define        SNDRV_PCM_HW_PARAM_FORMAT       ((__force snd_pcm_hw_param_t) 1) /* Format */
-#define        SNDRV_PCM_HW_PARAM_SUBFORMAT    ((__force snd_pcm_hw_param_t) 2) /* Subformat */
+typedef int snd_pcm_hw_param_t;
+#define        SNDRV_PCM_HW_PARAM_ACCESS       0       /* Access type */
+#define        SNDRV_PCM_HW_PARAM_FORMAT       1       /* Format */
+#define        SNDRV_PCM_HW_PARAM_SUBFORMAT    2       /* Subformat */
 #define        SNDRV_PCM_HW_PARAM_FIRST_MASK   SNDRV_PCM_HW_PARAM_ACCESS
 #define        SNDRV_PCM_HW_PARAM_LAST_MASK    SNDRV_PCM_HW_PARAM_SUBFORMAT
 
-#define        SNDRV_PCM_HW_PARAM_SAMPLE_BITS  ((__force snd_pcm_hw_param_t) 8) /* Bits per sample */
-#define        SNDRV_PCM_HW_PARAM_FRAME_BITS   ((__force snd_pcm_hw_param_t) 9) /* Bits per frame */
-#define        SNDRV_PCM_HW_PARAM_CHANNELS     ((__force snd_pcm_hw_param_t) 10) /* Channels */
-#define        SNDRV_PCM_HW_PARAM_RATE         ((__force snd_pcm_hw_param_t) 11) /* Approx rate */
-#define        SNDRV_PCM_HW_PARAM_PERIOD_TIME  ((__force snd_pcm_hw_param_t) 12) /* Approx distance between interrupts in us */
-#define        SNDRV_PCM_HW_PARAM_PERIOD_SIZE  ((__force snd_pcm_hw_param_t) 13) /* Approx frames between interrupts */
-#define        SNDRV_PCM_HW_PARAM_PERIOD_BYTES ((__force snd_pcm_hw_param_t) 14) /* Approx bytes between interrupts */
-#define        SNDRV_PCM_HW_PARAM_PERIODS      ((__force snd_pcm_hw_param_t) 15) /* Approx interrupts per buffer */
-#define        SNDRV_PCM_HW_PARAM_BUFFER_TIME  ((__force snd_pcm_hw_param_t) 16) /* Approx duration of buffer in us */
-#define        SNDRV_PCM_HW_PARAM_BUFFER_SIZE  ((__force snd_pcm_hw_param_t) 17) /* Size of buffer in frames */
-#define        SNDRV_PCM_HW_PARAM_BUFFER_BYTES ((__force snd_pcm_hw_param_t) 18) /* Size of buffer in bytes */
-#define        SNDRV_PCM_HW_PARAM_TICK_TIME    ((__force snd_pcm_hw_param_t) 19) /* Approx tick duration in us */
+#define        SNDRV_PCM_HW_PARAM_SAMPLE_BITS  8       /* Bits per sample */
+#define        SNDRV_PCM_HW_PARAM_FRAME_BITS   9       /* Bits per frame */
+#define        SNDRV_PCM_HW_PARAM_CHANNELS     10      /* Channels */
+#define        SNDRV_PCM_HW_PARAM_RATE         11      /* Approx rate */
+#define        SNDRV_PCM_HW_PARAM_PERIOD_TIME  12      /* Approx distance between
+                                                * interrupts in us
+                                                */
+#define        SNDRV_PCM_HW_PARAM_PERIOD_SIZE  13      /* Approx frames between
+                                                * interrupts
+                                                */
+#define        SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14      /* Approx bytes between
+                                                * interrupts
+                                                */
+#define        SNDRV_PCM_HW_PARAM_PERIODS      15      /* Approx interrupts per
+                                                * buffer
+                                                */
+#define        SNDRV_PCM_HW_PARAM_BUFFER_TIME  16      /* Approx duration of buffer
+                                                * in us
+                                                */
+#define        SNDRV_PCM_HW_PARAM_BUFFER_SIZE  17      /* Size of buffer in frames */
+#define        SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18      /* Size of buffer in bytes */
+#define        SNDRV_PCM_HW_PARAM_TICK_TIME    19      /* Approx tick duration in us */
 #define        SNDRV_PCM_HW_PARAM_FIRST_INTERVAL       SNDRV_PCM_HW_PARAM_SAMPLE_BITS
 #define        SNDRV_PCM_HW_PARAM_LAST_INTERVAL        SNDRV_PCM_HW_PARAM_TICK_TIME
 
-#define SNDRV_PCM_HW_PARAMS_NORESAMPLE         (1<<0)  /* avoid rate resampling */
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)  /* avoid rate resampling */
 
 struct snd_interval {
        unsigned int min, max;
@@ -696,7 +707,7 @@ struct snd_timer_tread {
  *                                                                          *
  ****************************************************************************/
 
-#define SNDRV_CTL_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 5)
+#define SNDRV_CTL_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 6)
 
 struct snd_ctl_card_info {
        int card;                       /* card number */
@@ -707,8 +718,7 @@ struct snd_ctl_card_info {
        unsigned char longname[80];     /* name + info text about soundcard */
        unsigned char reserved_[16];    /* reserved for future (was ID of mixer) */
        unsigned char mixername[80];    /* visual mixer identification */
-       unsigned char components[80];   /* card components / fine identification, delimited with one space (AC97 etc..) */
-       unsigned char reserved[48];     /* reserved for future */
+       unsigned char components[128];  /* card components / fine identification, delimited with one space (AC97 etc..) */
 };
 
 typedef int __bitwise snd_ctl_elem_type_t;
index a6e0facf8a37ecf616910690c59f78a8eee7a03c..20ebf3298eba56273021957b738073001e528959 100644 (file)
 #define IEC958_AES1_PRO_USERBITS_UDEF  (12<<4) /* user defined application */
 #define IEC958_AES1_CON_CATEGORY       0x7f
 #define IEC958_AES1_CON_GENERAL                0x00
-#define IEC958_AES1_CON_EXPERIMENTAL   0x40
-#define IEC958_AES1_CON_SOLIDMEM_MASK  0x0f
-#define IEC958_AES1_CON_SOLIDMEM_ID    0x08
-#define IEC958_AES1_CON_BROADCAST1_MASK 0x07
-#define IEC958_AES1_CON_BROADCAST1_ID  0x04
-#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07
-#define IEC958_AES1_CON_DIGDIGCONV_ID  0x02
-#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
-#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x06
-#define IEC958_AES1_CON_ADC_MASK       0x1f
-#define IEC958_AES1_CON_ADC_ID         0x16
-#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f
-#define IEC958_AES1_CON_BROADCAST2_ID  0x0e
 #define IEC958_AES1_CON_LASEROPT_MASK  0x07
 #define IEC958_AES1_CON_LASEROPT_ID    0x01
-#define IEC958_AES1_CON_MUSICAL_MASK   0x07
-#define IEC958_AES1_CON_MUSICAL_ID     0x05
-#define IEC958_AES1_CON_MAGNETIC_MASK  0x07
-#define IEC958_AES1_CON_MAGNETIC_ID    0x03
 #define IEC958_AES1_CON_IEC908_CD      (IEC958_AES1_CON_LASEROPT_ID|0x00)
 #define IEC958_AES1_CON_NON_IEC908_CD  (IEC958_AES1_CON_LASEROPT_ID|0x08)
+#define IEC958_AES1_CON_MINI_DISC      (IEC958_AES1_CON_LASEROPT_ID|0x48)
+#define IEC958_AES1_CON_DVD            (IEC958_AES1_CON_LASEROPT_ID|0x18)
+#define IEC958_AES1_CON_LASTEROPT_OTHER        (IEC958_AES1_CON_LASEROPT_ID|0x78)
+#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07
+#define IEC958_AES1_CON_DIGDIGCONV_ID  0x02
 #define IEC958_AES1_CON_PCM_CODER      (IEC958_AES1_CON_DIGDIGCONV_ID|0x00)
-#define IEC958_AES1_CON_SAMPLER                (IEC958_AES1_CON_DIGDIGCONV_ID|0x20)
 #define IEC958_AES1_CON_MIXER          (IEC958_AES1_CON_DIGDIGCONV_ID|0x10)
 #define IEC958_AES1_CON_RATE_CONVERTER (IEC958_AES1_CON_DIGDIGCONV_ID|0x18)
-#define IEC958_AES1_CON_SYNTHESIZER    (IEC958_AES1_CON_MUSICAL_ID|0x00)
-#define IEC958_AES1_CON_MICROPHONE     (IEC958_AES1_CON_MUSICAL_ID|0x08)
+#define IEC958_AES1_CON_SAMPLER                (IEC958_AES1_CON_DIGDIGCONV_ID|0x20)
+#define IEC958_AES1_CON_DSP            (IEC958_AES1_CON_DIGDIGCONV_ID|0x28)
+#define IEC958_AES1_CON_DIGDIGCONV_OTHER (IEC958_AES1_CON_DIGDIGCONV_ID|0x78)
+#define IEC958_AES1_CON_MAGNETIC_MASK  0x07
+#define IEC958_AES1_CON_MAGNETIC_ID    0x03
 #define IEC958_AES1_CON_DAT            (IEC958_AES1_CON_MAGNETIC_ID|0x00)
 #define IEC958_AES1_CON_VCR            (IEC958_AES1_CON_MAGNETIC_ID|0x08)
+#define IEC958_AES1_CON_DCC            (IEC958_AES1_CON_MAGNETIC_ID|0x40)
+#define IEC958_AES1_CON_MAGNETIC_DISC  (IEC958_AES1_CON_MAGNETIC_ID|0x18)
+#define IEC958_AES1_CON_MAGNETIC_OTHER (IEC958_AES1_CON_MAGNETIC_ID|0x78)
+#define IEC958_AES1_CON_BROADCAST1_MASK 0x07
+#define IEC958_AES1_CON_BROADCAST1_ID  0x04
+#define IEC958_AES1_CON_DAB_JAPAN      (IEC958_AES1_CON_BROADCAST1_ID|0x00)
+#define IEC958_AES1_CON_DAB_EUROPE     (IEC958_AES1_CON_BROADCAST1_ID|0x08)
+#define IEC958_AES1_CON_DAB_USA                (IEC958_AES1_CON_BROADCAST1_ID|0x60)
+#define IEC958_AES1_CON_SOFTWARE       (IEC958_AES1_CON_BROADCAST1_ID|0x40)
+#define IEC958_AES1_CON_IEC62105       (IEC958_AES1_CON_BROADCAST1_ID|0x20)
+#define IEC958_AES1_CON_BROADCAST1_OTHER (IEC958_AES1_CON_BROADCAST1_ID|0x78)
+#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f
+#define IEC958_AES1_CON_BROADCAST2_ID  0x0e
+#define IEC958_AES1_CON_MUSICAL_MASK   0x07
+#define IEC958_AES1_CON_MUSICAL_ID     0x05
+#define IEC958_AES1_CON_SYNTHESIZER    (IEC958_AES1_CON_MUSICAL_ID|0x00)
+#define IEC958_AES1_CON_MICROPHONE     (IEC958_AES1_CON_MUSICAL_ID|0x08)
+#define IEC958_AES1_CON_MUSICAL_OTHER  (IEC958_AES1_CON_MUSICAL_ID|0x78)
+#define IEC958_AES1_CON_ADC_MASK       0x1f
+#define IEC958_AES1_CON_ADC_ID         0x06
+#define IEC958_AES1_CON_ADC            (IEC958_AES1_CON_ADC_ID|0x00)
+#define IEC958_AES1_CON_ADC_OTHER      (IEC958_AES1_CON_ADC_ID|0x60)
+#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
+#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x16
+#define IEC958_AES1_CON_ADC_COPYRIGHT  (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x00)
+#define IEC958_AES1_CON_ADC_COPYRIGHT_OTHER (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x60)
+#define IEC958_AES1_CON_SOLIDMEM_MASK  0x0f
+#define IEC958_AES1_CON_SOLIDMEM_ID    0x08
+#define IEC958_AES1_CON_SOLIDMEM_DIGITAL_RECORDER_PLAYER (IEC958_AES1_CON_SOLIDMEM_ID|0x00)
+#define IEC958_AES1_CON_SOLIDMEM_OTHER (IEC958_AES1_CON_SOLIDMEM_ID|0x70)
+#define IEC958_AES1_CON_EXPERIMENTAL   0x40
 #define IEC958_AES1_CON_ORIGINAL       (1<<7)  /* this bits depends on the category code */
 #define IEC958_AES2_PRO_SBITS          (7<<0)  /* mask - sample bits */
 #define IEC958_AES2_PRO_SBITS_20       (2<<0)  /* 20-bit - coordination */
 #define IEC958_AES2_CON_CHANNEL_UNSPEC (0<<4)  /* unspecified */
 #define IEC958_AES3_CON_FS             (15<<0) /* mask - sample frequency */
 #define IEC958_AES3_CON_FS_44100       (0<<0)  /* 44.1kHz */
+#define IEC958_AES3_CON_FS_NOTID       (1<<0)  /* non indicated */
 #define IEC958_AES3_CON_FS_48000       (2<<0)  /* 48kHz */
 #define IEC958_AES3_CON_FS_32000       (3<<0)  /* 32kHz */
+#define IEC958_AES3_CON_FS_22050       (4<<0)  /* 22.05kHz */
+#define IEC958_AES3_CON_FS_24000       (6<<0)  /* 24kHz */
+#define IEC958_AES3_CON_FS_88200       (8<<0)  /* 88.2kHz */
+#define IEC958_AES3_CON_FS_768000      (9<<0)  /* 768kHz */
+#define IEC958_AES3_CON_FS_96000       (10<<0) /* 96kHz */
+#define IEC958_AES3_CON_FS_176400      (12<<0) /* 176.4kHz */
+#define IEC958_AES3_CON_FS_192000      (14<<0) /* 192kHz */
 #define IEC958_AES3_CON_CLOCK          (3<<4)  /* mask - clock accuracy */
 #define IEC958_AES3_CON_CLOCK_1000PPM  (0<<4)  /* 1000 ppm */
 #define IEC958_AES3_CON_CLOCK_50PPM    (1<<4)  /* 50 ppm */
 #define IEC958_AES4_CON_WORDLEN_23_19  (4<<1)  /* 23-bit or 19-bit */
 #define IEC958_AES4_CON_WORDLEN_24_20  (5<<1)  /* 24-bit or 20-bit */
 #define IEC958_AES4_CON_WORDLEN_21_17  (6<<1)  /* 21-bit or 17-bit */
+#define IEC958_AES4_CON_ORIGFS         (15<<4) /* mask - original sample frequency */
+#define IEC958_AES4_CON_ORIGFS_NOTID   (0<<4)  /* not indicated */
+#define IEC958_AES4_CON_ORIGFS_192000  (1<<4)  /* 192kHz */
+#define IEC958_AES4_CON_ORIGFS_12000   (2<<4)  /* 12kHz */
+#define IEC958_AES4_CON_ORIGFS_176400  (3<<4)  /* 176.4kHz */
+#define IEC958_AES4_CON_ORIGFS_96000   (5<<4)  /* 96kHz */
+#define IEC958_AES4_CON_ORIGFS_8000    (6<<4)  /* 8kHz */
+#define IEC958_AES4_CON_ORIGFS_88200   (7<<4)  /* 88.2kHz */
+#define IEC958_AES4_CON_ORIGFS_16000   (8<<4)  /* 16kHz */
+#define IEC958_AES4_CON_ORIGFS_24000   (9<<4)  /* 24kHz */
+#define IEC958_AES4_CON_ORIGFS_11025   (10<<4) /* 11.025kHz */
+#define IEC958_AES4_CON_ORIGFS_22050   (11<<4) /* 22.05kHz */
+#define IEC958_AES4_CON_ORIGFS_32000   (12<<4) /* 32kHz */
+#define IEC958_AES4_CON_ORIGFS_48000   (13<<4) /* 48kHz */
+#define IEC958_AES4_CON_ORIGFS_44100   (15<<4) /* 44.1kHz */
+#define IEC958_AES5_CON_CGMSA          (3<<0)  /* mask - CGMS-A */
+#define IEC958_AES5_CON_CGMSA_COPYFREELY (0<<0)        /* copying is permitted without restriction */
+#define IEC958_AES5_CON_CGMSA_COPYONCE (1<<0)  /* one generation of copies may be made */
+#define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0)        /* condition not be used */
+#define IEC958_AES5_CON_CGMSA_COPYNEVER        (3<<0)  /* no copying is permitted */
 
 /*****************************************************************************
  *                                                                           *
index 558b96284bd22eba399ff2e8f28147a5c46b2eb0..e5eec5f7350213c8fda3d6f76c3f0a725c22b1e0 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/rwsem.h>               /* struct rw_semaphore */
 #include <linux/pm.h>                  /* pm_message_t */
 #include <linux/device.h>
+#include <linux/stringify.h>
 
 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -63,6 +64,7 @@ typedef int __bitwise snd_device_type_t;
 #define        SNDRV_DEV_INFO          ((__force snd_device_type_t) 0x1006)
 #define        SNDRV_DEV_BUS           ((__force snd_device_type_t) 0x1007)
 #define        SNDRV_DEV_CODEC         ((__force snd_device_type_t) 0x1008)
+#define        SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
 #define        SNDRV_DEV_LOWLEVEL      ((__force snd_device_type_t) 0x2000)
 
 typedef int __bitwise snd_device_state_t;
@@ -114,7 +116,7 @@ struct snd_card {
        char shortname[32];             /* short name of this soundcard */
        char longname[80];              /* name of this soundcard */
        char mixername[80];             /* mixer name */
-       char components[80];            /* card components delimited with
+       char components[128];           /* card components delimited with
                                                                space */
        struct module *module;          /* top-level module */
 
@@ -366,8 +368,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
 
 #ifdef CONFIG_SND_DEBUG
 
-#define __ASTRING__(x) #x
-
 #ifdef CONFIG_SND_VERBOSE_PRINTK
 /**
  * snd_printd - debug printk
@@ -382,33 +382,15 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
 #define snd_printd(fmt, args...) \
        printk(fmt ,##args)
 #endif
-/**
- * snd_assert - run-time assertion macro
- * @expr: expression
- *
- * This macro checks the expression in run-time and invokes the commands
- * given in the rest arguments if the assertion is failed.
- * When CONFIG_SND_DEBUG is not set, the expression is executed but
- * not checked.
- */
-#define snd_assert(expr, args...) do {                                 \
-       if (unlikely(!(expr))) {                                        \
-               snd_printk(KERN_ERR "BUG? (%s)\n", __ASTRING__(expr));  \
-               dump_stack();                                           \
-               args;                                                   \
-       }                                                               \
-} while (0)
-
-#define snd_BUG() do {                         \
-       snd_printk(KERN_ERR "BUG?\n");          \
-       dump_stack();                           \
-} while (0)
+
+#define snd_BUG()              WARN(1, "BUG?\n")
+#define snd_BUG_ON(cond)       WARN((cond), "BUG? (%s)\n", __stringify(cond))
 
 #else /* !CONFIG_SND_DEBUG */
 
 #define snd_printd(fmt, args...)       /* nothing */
-#define snd_assert(expr, args...)      (void)(expr)
 #define snd_BUG()                      /* nothing */
+#define snd_BUG_ON(cond)       ({/*(void)(cond);*/ 0;})  /* always false */
 
 #endif /* CONFIG_SND_DEBUG */
 
diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h
deleted file mode 100644 (file)
index f0785f9..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef __SOUND_CS4231_H
-#define __SOUND_CS4231_H
-
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Definitions for CS4231 & InterWave chips & compatible chips
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include "control.h"
-#include "pcm.h"
-#include "timer.h"
-
-#include "cs4231-regs.h"
-
-/* defines for codec.mode */
-
-#define CS4231_MODE_NONE       0x0000
-#define CS4231_MODE_PLAY       0x0001
-#define CS4231_MODE_RECORD     0x0002
-#define CS4231_MODE_TIMER      0x0004
-#define CS4231_MODE_OPEN       (CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)
-
-/* defines for codec.hardware */
-
-#define CS4231_HW_DETECT        0x0000 /* let CS4231 driver detect chip */
-#define CS4231_HW_DETECT3      0x0001  /* allow mode 3 */
-#define CS4231_HW_TYPE_MASK    0xff00  /* type mask */
-#define CS4231_HW_CS4231_MASK   0x0100 /* CS4231 serie */
-#define CS4231_HW_CS4231        0x0100 /* CS4231 chip */
-#define CS4231_HW_CS4231A       0x0101 /* CS4231A chip */
-#define CS4231_HW_AD1845       0x0102  /* AD1845 chip */
-#define CS4231_HW_CS4232_MASK   0x0200 /* CS4232 serie (has control ports) */
-#define CS4231_HW_CS4232        0x0200 /* CS4232 */
-#define CS4231_HW_CS4232A       0x0201 /* CS4232A */
-#define CS4231_HW_CS4236       0x0202  /* CS4236 */
-#define CS4231_HW_CS4236B_MASK 0x0400  /* CS4236B serie (has extended control regs) */
-#define CS4231_HW_CS4235       0x0400  /* CS4235 - Crystal Clear (tm) stereo enhancement */
-#define CS4231_HW_CS4236B       0x0401 /* CS4236B */
-#define CS4231_HW_CS4237B       0x0402 /* CS4237B - SRS 3D */
-#define CS4231_HW_CS4238B      0x0403  /* CS4238B - QSOUND 3D */
-#define CS4231_HW_CS4239       0x0404  /* CS4239 - Crystal Clear (tm) stereo enhancement */
-/* compatible, but clones */
-#define CS4231_HW_INTERWAVE     0x1000 /* InterWave chip */
-#define CS4231_HW_OPL3SA2       0x1101 /* OPL3-SA2 chip, similar to cs4231 */
-#define CS4231_HW_OPTI93X      0x1102  /* Opti 930/931/933 */
-
-/* defines for codec.hwshare */
-#define CS4231_HWSHARE_IRQ     (1<<0)
-#define CS4231_HWSHARE_DMA1    (1<<1)
-#define CS4231_HWSHARE_DMA2    (1<<2)
-
-struct snd_cs4231 {
-       unsigned long port;             /* base i/o port */
-       struct resource *res_port;
-       unsigned long cport;            /* control base i/o port (CS4236) */
-       struct resource *res_cport;
-       int irq;                        /* IRQ line */
-       int dma1;                       /* playback DMA */
-       int dma2;                       /* record DMA */
-       unsigned short version;         /* version of CODEC chip */
-       unsigned short mode;            /* see to CS4231_MODE_XXXX */
-       unsigned short hardware;        /* see to CS4231_HW_XXXX */
-       unsigned short hwshare;         /* shared resources */
-       unsigned short single_dma:1,    /* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
-                      ebus_flag:1;     /* SPARC: EBUS present */
-
-       struct snd_card *card;
-       struct snd_pcm *pcm;
-       struct snd_pcm_substream *playback_substream;
-       struct snd_pcm_substream *capture_substream;
-       struct snd_timer *timer;
-
-       unsigned char image[32];        /* registers image */
-       unsigned char eimage[32];       /* extended registers image */
-       unsigned char cimage[16];       /* control registers image */
-       int mce_bit;
-       int calibrate_mute;
-       int sw_3d_bit;
-       unsigned int p_dma_size;
-       unsigned int c_dma_size;
-
-       spinlock_t reg_lock;
-       struct mutex mce_mutex;
-       struct mutex open_mutex;
-
-       int (*rate_constraint) (struct snd_pcm_runtime *runtime);
-       void (*set_playback_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char pdfr);
-       void (*set_capture_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char cdfr);
-       void (*trigger) (struct snd_cs4231 *chip, unsigned int what, int start);
-#ifdef CONFIG_PM
-       void (*suspend) (struct snd_cs4231 *chip);
-       void (*resume) (struct snd_cs4231 *chip);
-#endif
-       void *dma_private_data;
-       int (*claim_dma) (struct snd_cs4231 *chip, void *dma_private_data, int dma);
-       int (*release_dma) (struct snd_cs4231 *chip, void *dma_private_data, int dma);
-};
-
-/* exported functions */
-
-void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val);
-unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg);
-void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val);
-unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg);
-void snd_cs4231_mce_up(struct snd_cs4231 *chip);
-void snd_cs4231_mce_down(struct snd_cs4231 *chip);
-
-void snd_cs4231_overrange(struct snd_cs4231 *chip);
-
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id);
-
-const char *snd_cs4231_chip_id(struct snd_cs4231 *chip);
-
-int snd_cs4231_create(struct snd_card *card,
-                     unsigned long port,
-                     unsigned long cport,
-                     int irq, int dma1, int dma2,
-                     unsigned short hardware,
-                     unsigned short hwshare,
-                     struct snd_cs4231 ** rchip);
-int snd_cs4231_pcm(struct snd_cs4231 * chip, int device, struct snd_pcm **rpcm);
-int snd_cs4231_timer(struct snd_cs4231 * chip, int device, struct snd_timer **rtimer);
-int snd_cs4231_mixer(struct snd_cs4231 * chip);
-
-int snd_cs4236_create(struct snd_card *card,
-                     unsigned long port,
-                     unsigned long cport,
-                     int irq, int dma1, int dma2,
-                     unsigned short hardware,
-                     unsigned short hwshare,
-                     struct snd_cs4231 ** rchip);
-int snd_cs4236_pcm(struct snd_cs4231 * chip, int device, struct snd_pcm **rpcm);
-int snd_cs4236_mixer(struct snd_cs4231 * chip);
-
-/*
- *  mixer library
- */
-
-#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_cs4231_info_single, \
-  .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \
-  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
-
-int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
-int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-
-#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_cs4231_info_double, \
-  .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \
-  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
-
-int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
-int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-
-#endif /* __SOUND_CS4231_H */
diff --git a/include/sound/jack.h b/include/sound/jack.h
new file mode 100644 (file)
index 0000000..b1b2b8b
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef __SOUND_JACK_H
+#define __SOUND_JACK_H
+
+/*
+ *  Jack abstraction layer
+ *
+ *  Copyright 2008 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 as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/core.h>
+
+struct input_dev;
+
+/**
+ * Jack types which can be reported.  These values are used as a
+ * bitmask.
+ */
+enum snd_jack_types {
+       SND_JACK_HEADPHONE      = 0x0001,
+       SND_JACK_MICROPHONE     = 0x0002,
+       SND_JACK_HEADSET        = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
+};
+
+struct snd_jack {
+       struct input_dev *input_dev;
+       int registered;
+       int type;
+       const char *id;
+       char name[100];
+};
+
+#ifdef CONFIG_SND_JACK
+
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+                struct snd_jack **jack);
+void snd_jack_set_parent(struct snd_jack *jack, struct device *parent);
+
+void snd_jack_report(struct snd_jack *jack, int status);
+
+#else
+
+static inline int snd_jack_new(struct snd_card *card, const char *id, int type,
+                              struct snd_jack **jack)
+{
+       return 0;
+}
+
+static inline void snd_jack_set_parent(struct snd_jack *jack,
+                                      struct device *parent)
+{
+}
+
+static inline void snd_jack_report(struct snd_jack *jack, int status)
+{
+}
+
+#endif
+
+#endif
index ae2921d9ddcc24f6712b1653598502235a38c757..d787a6b4a10123006f1384ffc61153ec9c9a733c 100644 (file)
@@ -65,6 +65,11 @@ struct snd_dma_buffer {
 /*
  * Scatter-Gather generic device pages
  */
+void *snd_malloc_sgbuf_pages(struct device *device,
+                            size_t size, struct snd_dma_buffer *dmab,
+                            size_t *res_size);
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
+
 struct snd_sg_page {
        void *buf;
        dma_addr_t addr;
@@ -92,9 +97,18 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
  */
 static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
 {
-       return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
+       dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
+       addr &= PAGE_MASK;
+       return addr + offset % PAGE_SIZE;
 }
 
+/*
+ * return the virtual address at the corresponding offset
+ */
+static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset)
+{
+       return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
+}
 
 /* allocate/release a buffer */
 int snd_dma_alloc_pages(int type, struct device *dev, size_t size,
index 46bcd2023ed8e7d7e55f305d100168108414b8b4..a81798ab73edc1bcdeb8e39ff9068febd2647b51 100644 (file)
@@ -21,6 +21,8 @@
  *
  */
 
+#define SNDRV_OS_MINORS                        256
+
 #define SNDRV_MINOR_DEVICES            32
 #define SNDRV_MINOR_CARD(minor)                ((minor) >> 5)
 #define SNDRV_MINOR_DEVICE(minor)      ((minor) & 0x001f)
index 51d58ccda2d82d7158cbca22fb338bafa393c0e0..40c5a6fa6bcd3635334f0405ee0d53f37c3944c7 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <sound/asound.h>
 #include <sound/memalloc.h>
+#include <sound/minors.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
@@ -84,7 +85,11 @@ struct snd_pcm_ops {
  *
  */
 
-#define SNDRV_PCM_DEVICES              8
+#if defined(CONFIG_SND_DYNAMIC_MINORS)
+#define SNDRV_PCM_DEVICES      (SNDRV_OS_MINORS-2)
+#else
+#define SNDRV_PCM_DEVICES      8
+#endif
 
 #define SNDRV_PCM_IOCTL1_FALSE         ((void *)0)
 #define SNDRV_PCM_IOCTL1_TRUE          ((void *)1)
@@ -416,7 +421,7 @@ struct snd_pcm_str {
 struct snd_pcm {
        struct snd_card *card;
        struct list_head list;
-       unsigned int device;    /* device number */
+       int device; /* device number */
        unsigned int info_flags;
        unsigned short dev_class;
        unsigned short dev_subclass;
@@ -969,10 +974,30 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
 int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
 
-#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_buffer_p->private_data)
-#define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
-#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
-struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset);
+/*
+ * SG-buffer handling
+ */
+#define snd_pcm_substream_sgbuf(substream) \
+       ((substream)->runtime->dma_buffer_p->private_data)
+
+static inline dma_addr_t
+snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
+{
+       struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
+       return snd_sgbuf_get_addr(sg, ofs);
+}
+
+static inline void *
+snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
+{
+       struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
+       return snd_sgbuf_get_ptr(sg, ofs);
+}
+
+struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
+                                   unsigned long offset);
+unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
+                                         unsigned int ofs, unsigned int size);
 
 /* handle mmap counter - PCM mmap callback should handle this counter properly */
 static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
@@ -1010,4 +1035,6 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
                                         (IEC958_AES1_CON_PCM_CODER<<8)|\
                                         (IEC958_AES3_CON_FS_48000<<24))
 
+#define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
+
 #endif /* __SOUND_PCM_H */
diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h
new file mode 100644 (file)
index 0000000..2fd3d25
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef PXA2XX_LIB_H
+#define PXA2XX_LIB_H
+
+#include <linux/platform_device.h>
+#include <sound/ac97_codec.h>
+
+/* PCM */
+
+struct pxa2xx_pcm_dma_params {
+       char *name;                     /* stream identifier */
+       u32 dcmd;                       /* DMA descriptor dcmd field */
+       volatile u32 *drcmr;            /* the DMA request channel to use */
+       u32 dev_addr;                   /* device physical address for DMA */
+};
+
+extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params);
+extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
+extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
+extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id);
+extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream);
+extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma);
+extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream);
+extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm);
+
+/* AC97 */
+
+extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
+extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
+
+extern bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97);
+extern bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97);
+extern void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97);
+
+extern int pxa2xx_ac97_hw_suspend(void);
+extern int pxa2xx_ac97_hw_resume(void);
+
+extern int pxa2xx_ac97_hw_probe(struct platform_device *dev);
+extern void pxa2xx_ac97_hw_remove(struct platform_device *dev);
+
+#endif
index d0c9ed3546c89d8d12687b413d2744daaad19334..85f93c5fe1e4030b297a1381819db5aafa82c235 100644 (file)
@@ -240,11 +240,15 @@ struct snd_sb {
 #define SB_DT019X_CAP_MAIN     0x07
 
 #define SB_ALS4000_MONO_IO_CTRL        0x4b
+#define SB_ALS4000_OUT_MIXER_CTRL_2    0x4c
 #define SB_ALS4000_MIC_IN_GAIN 0x4d
+#define SB_ALS4000_ANALOG_REFRNC_VOLT_CTRL 0x4e
 #define SB_ALS4000_FMDAC       0x4f
 #define SB_ALS4000_3D_SND_FX   0x50
 #define SB_ALS4000_3D_TIME_DELAY       0x51
 #define SB_ALS4000_3D_AUTO_MUTE        0x52
+#define SB_ALS4000_ANALOG_BLOCK_CTRL 0x53
+#define SB_ALS4000_3D_DELAYLINE_PATTERN 0x54
 #define SB_ALS4000_QSOUND      0xdb
 
 /* IRQ setting bitmap */
@@ -257,6 +261,7 @@ struct snd_sb {
 #define SB_IRQTYPE_8BIT                0x01
 #define SB_IRQTYPE_16BIT       0x02
 #define SB_IRQTYPE_MPUIN       0x04
+#define ALS4K_IRQTYPE_CR1E_DMA 0x20
 
 /* DMA setting bitmap */
 #define SB_DMASETUP_DMA0       0x01
index 9688d4be918ecd660dc7a7d2f2fbbaa7b9c9016a..fa149ca77e4bea93b17ce07d4399a95c9cd111ca 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __SOUND_SND_WAVEFRONT_H__
 #define __SOUND_SND_WAVEFRONT_H__
 
-#include "cs4231.h"
 #include "mpu401.h"
 #include "hwdep.h"
 #include "rawmidi.h"
diff --git a/include/sound/soc-of-simple.h b/include/sound/soc-of-simple.h
new file mode 100644 (file)
index 0000000..a064e19
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * OF helpers for ALSA SoC
+ *
+ * Copyright (C) 2008, Secret Lab Technologies Ltd.
+ */
+
+#ifndef _INCLUDE_SOC_OF_H_
+#define _INCLUDE_SOC_OF_H_
+
+#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
+
+#include <linux/of.h>
+#include <sound/soc.h>
+
+int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
+                             void *codec_data, struct snd_soc_dai *dai,
+                             struct device_node *node);
+
+int of_snd_soc_register_platform(struct snd_soc_platform *platform,
+                                struct device_node *node,
+                                struct snd_soc_dai *cpu_dai);
+
+#endif
+
+#endif /* _INCLUDE_SOC_OF_H_ */
index 1890d87c52042adc4d375953195a350d20e198ea..a1e0357a84d724856b741d5ed2a76c5bc8876769 100644 (file)
 /*
  * Convenience kcontrol builders
  */
-#define SOC_SINGLE_VALUE(reg, shift, max, invert) ((reg) | ((shift) << 8) |\
-       ((shift) << 12) | ((max) << 16) | ((invert) << 24))
-#define SOC_SINGLE_VALUE_EXT(reg, max, invert) ((reg) | ((max) << 16) |\
-       ((invert) << 31))
+#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
+       ((unsigned long)&(struct soc_mixer_control) \
+       {.reg = xreg, .shift = xshift, .max = xmax, .invert = xinvert})
+#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
+       ((unsigned long)&(struct soc_mixer_control) \
+       {.reg = xreg, .max = xmax, .invert = xinvert})
 #define SOC_SINGLE(xname, reg, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .put = snd_soc_put_volsw, \
        .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
-#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
+#define SOC_DOUBLE(xname, xreg, shift_left, shift_right, xmax, xinvert) \
 {      .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) | ((max) << 16) | ((invert) << 24) }
-#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, max, invert) \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .shift = shift_left, .rshift = shift_right, \
+                .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {      .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)  | \
-               ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
-#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+               .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
                 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
        .tlv.p = (tlv_array), \
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
        .put = snd_soc_put_volsw, \
-       .private_value = (reg) | ((shift_left) << 8) | \
-               ((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
-#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .shift = shift_left, .rshift = shift_right,\
+                .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
                 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
        .tlv.p = (tlv_array), \
        .info = snd_soc_info_volsw_2r, \
        .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
-       .private_value = (reg_left) | ((shift) << 8)  | \
-               ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
-#define SOC_DOUBLE_S8_TLV(xname, reg, min, max, tlv_array) \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+               .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {      .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
                  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
        .tlv.p  = (tlv_array), \
        .info   = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
        .put    = snd_soc_put_volsw_s8, \
-       .private_value = (reg) | (((signed char)max) << 16) | \
-                        (((signed char)min) << 24) }
-#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .min = xmin, .max = xmax} }
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, 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 }
+       .max = xmax, .texts = xtexts }
+#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
+       SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
+{      .max = xmax, .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,\
+#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, 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_EXT_TLV(xname, xreg, xshift, xmask, xinvert,\
+       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
        .tlv.p = (tlv_array), \
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
-       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, 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, \
@@ -410,6 +416,8 @@ struct snd_soc_codec {
        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);
+       int (*display_register)(struct snd_soc_codec *, char *,
+                               size_t, unsigned int);
        hw_write_t hw_write;
        hw_read_t hw_read;
        void *reg_cache;
@@ -516,13 +524,19 @@ struct snd_soc_pcm_runtime {
        struct snd_soc_device *socdev;
 };
 
+/* mixer control */
+struct soc_mixer_control {
+       int min, max;
+       unsigned int reg, rreg, shift, rshift, invert;
+};
+
 /* enumerated kcontrol */
 struct soc_enum {
        unsigned short reg;
        unsigned short reg2;
        unsigned char shift_l;
        unsigned char shift_r;
-       unsigned int mask;
+       unsigned int max;
        const char **texts;
        void *dapm;
 };
index 6b78aff273a8a812fd303baa7b2f7f2bae1ca969..4aafeda886347d58da257313c9f4d8fbabdf8fa2 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.17"
+#define CONFIG_SND_VERSION "1.0.18rc3"
 #define CONFIG_SND_DATE ""
index 4830651cc4cffd5dfafc1c29c5d5fd00c905ecac..5456343ebe4c056957a7670847eae114fe4ab74f 100644 (file)
@@ -235,37 +235,31 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev);
  */
 static inline int vx_test_and_ack(struct vx_core *chip)
 {
-       snd_assert(chip->ops->test_and_ack, return -ENXIO);
        return chip->ops->test_and_ack(chip);
 }
 
 static inline void vx_validate_irq(struct vx_core *chip, int enable)
 {
-       snd_assert(chip->ops->validate_irq, return);
        chip->ops->validate_irq(chip, enable);
 }
 
 static inline unsigned char snd_vx_inb(struct vx_core *chip, int reg)
 {
-       snd_assert(chip->ops->in8, return 0);
        return chip->ops->in8(chip, reg);
 }
 
 static inline unsigned int snd_vx_inl(struct vx_core *chip, int reg)
 {
-       snd_assert(chip->ops->in32, return 0);
        return chip->ops->in32(chip, reg);
 }
 
 static inline void snd_vx_outb(struct vx_core *chip, int reg, unsigned char val)
 {
-       snd_assert(chip->ops->out8, return);
        chip->ops->out8(chip, reg, val);
 }
 
 static inline void snd_vx_outl(struct vx_core *chip, int reg, unsigned int val)
 {
-       snd_assert(chip->ops->out32, return);
        chip->ops->out32(chip, reg, val);
 }
 
@@ -276,7 +270,6 @@ static inline void snd_vx_outl(struct vx_core *chip, int reg, unsigned int val)
 
 static inline void vx_reset_dsp(struct vx_core *chip)
 {
-       snd_assert(chip->ops->reset_dsp, return);
        chip->ops->reset_dsp(chip);
 }
 
@@ -304,14 +297,12 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
 static inline void vx_pseudo_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
                                       struct vx_pipe *pipe, int count)
 {
-       snd_assert(chip->ops->dma_write, return);
        chip->ops->dma_write(chip, runtime, pipe, count);
 }
 
 static inline void vx_pseudo_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
                                      struct vx_pipe *pipe, int count)
 {
-       snd_assert(chip->ops->dma_read, return);
        chip->ops->dma_read(chip, runtime, pipe, count);
 }
 
diff --git a/include/sound/wss.h b/include/sound/wss.h
new file mode 100644 (file)
index 0000000..fd01f22
--- /dev/null
@@ -0,0 +1,235 @@
+#ifndef __SOUND_WSS_H
+#define __SOUND_WSS_H
+
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Definitions for CS4231 & InterWave chips & compatible chips
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include "control.h"
+#include "pcm.h"
+#include "timer.h"
+
+#include "cs4231-regs.h"
+
+/* defines for codec.mode */
+
+#define WSS_MODE_NONE  0x0000
+#define WSS_MODE_PLAY  0x0001
+#define WSS_MODE_RECORD        0x0002
+#define WSS_MODE_TIMER 0x0004
+#define WSS_MODE_OPEN  (WSS_MODE_PLAY|WSS_MODE_RECORD|WSS_MODE_TIMER)
+
+/* defines for codec.hardware */
+
+#define WSS_HW_DETECT        0x0000    /* let CS4231 driver detect chip */
+#define WSS_HW_DETECT3 0x0001  /* allow mode 3 */
+#define WSS_HW_TYPE_MASK       0xff00  /* type mask */
+#define WSS_HW_CS4231_MASK   0x0100    /* CS4231 serie */
+#define WSS_HW_CS4231        0x0100    /* CS4231 chip */
+#define WSS_HW_CS4231A       0x0101    /* CS4231A chip */
+#define WSS_HW_AD1845  0x0102  /* AD1845 chip */
+#define WSS_HW_CS4232_MASK   0x0200    /* CS4232 serie (has control ports) */
+#define WSS_HW_CS4232        0x0200    /* CS4232 */
+#define WSS_HW_CS4232A       0x0201    /* CS4232A */
+#define WSS_HW_CS4236  0x0202  /* CS4236 */
+#define WSS_HW_CS4236B_MASK    0x0400  /* CS4236B serie (has extended control regs) */
+#define WSS_HW_CS4235  0x0400  /* CS4235 - Crystal Clear (tm) stereo enhancement */
+#define WSS_HW_CS4236B       0x0401    /* CS4236B */
+#define WSS_HW_CS4237B       0x0402    /* CS4237B - SRS 3D */
+#define WSS_HW_CS4238B 0x0403  /* CS4238B - QSOUND 3D */
+#define WSS_HW_CS4239  0x0404  /* CS4239 - Crystal Clear (tm) stereo enhancement */
+#define WSS_HW_AD1848_MASK     0x0800  /* AD1848 serie (half duplex) */
+#define WSS_HW_AD1847          0x0801  /* AD1847 chip */
+#define WSS_HW_AD1848          0x0802  /* AD1848 chip */
+#define WSS_HW_CS4248          0x0803  /* CS4248 chip */
+#define WSS_HW_CMI8330         0x0804  /* CMI8330 chip */
+#define WSS_HW_THINKPAD                0x0805  /* Thinkpad 360/750/755 */
+/* compatible, but clones */
+#define WSS_HW_INTERWAVE     0x1000    /* InterWave chip */
+#define WSS_HW_OPL3SA2       0x1101    /* OPL3-SA2 chip, similar to cs4231 */
+#define WSS_HW_OPTI93X         0x1102  /* Opti 930/931/933 */
+
+/* defines for codec.hwshare */
+#define WSS_HWSHARE_IRQ        (1<<0)
+#define WSS_HWSHARE_DMA1       (1<<1)
+#define WSS_HWSHARE_DMA2       (1<<2)
+
+/* IBM Thinkpad specific stuff */
+#define AD1848_THINKPAD_CTL_PORT1              0x15e8
+#define AD1848_THINKPAD_CTL_PORT2              0x15e9
+#define AD1848_THINKPAD_CS4248_ENABLE_BIT      0x02
+
+struct snd_wss {
+       unsigned long port;             /* base i/o port */
+       struct resource *res_port;
+       unsigned long cport;            /* control base i/o port (CS4236) */
+       struct resource *res_cport;
+       int irq;                        /* IRQ line */
+       int dma1;                       /* playback DMA */
+       int dma2;                       /* record DMA */
+       unsigned short version;         /* version of CODEC chip */
+       unsigned short mode;            /* see to WSS_MODE_XXXX */
+       unsigned short hardware;        /* see to WSS_HW_XXXX */
+       unsigned short hwshare;         /* shared resources */
+       unsigned short single_dma:1,    /* forced single DMA mode (GUS 16-bit */
+                                       /* daughter board) or dma1 == dma2 */
+                      ebus_flag:1,     /* SPARC: EBUS present */
+                      thinkpad_flag:1; /* Thinkpad CS4248 needs extra help */
+
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *playback_substream;
+       struct snd_pcm_substream *capture_substream;
+       struct snd_timer *timer;
+
+       unsigned char image[32];        /* registers image */
+       unsigned char eimage[32];       /* extended registers image */
+       unsigned char cimage[16];       /* control registers image */
+       int mce_bit;
+       int calibrate_mute;
+       int sw_3d_bit;
+       unsigned int p_dma_size;
+       unsigned int c_dma_size;
+
+       spinlock_t reg_lock;
+       struct mutex mce_mutex;
+       struct mutex open_mutex;
+
+       int (*rate_constraint) (struct snd_pcm_runtime *runtime);
+       void (*set_playback_format) (struct snd_wss *chip,
+                                    struct snd_pcm_hw_params *hw_params,
+                                    unsigned char pdfr);
+       void (*set_capture_format) (struct snd_wss *chip,
+                                   struct snd_pcm_hw_params *hw_params,
+                                   unsigned char cdfr);
+       void (*trigger) (struct snd_wss *chip, unsigned int what, int start);
+#ifdef CONFIG_PM
+       void (*suspend) (struct snd_wss *chip);
+       void (*resume) (struct snd_wss *chip);
+#endif
+       void *dma_private_data;
+       int (*claim_dma) (struct snd_wss *chip,
+                         void *dma_private_data, int dma);
+       int (*release_dma) (struct snd_wss *chip,
+                           void *dma_private_data, int dma);
+};
+
+/* exported functions */
+
+void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char val);
+unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg);
+void snd_cs4236_ext_out(struct snd_wss *chip,
+                       unsigned char reg, unsigned char val);
+unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg);
+void snd_wss_mce_up(struct snd_wss *chip);
+void snd_wss_mce_down(struct snd_wss *chip);
+
+void snd_wss_overrange(struct snd_wss *chip);
+
+irqreturn_t snd_wss_interrupt(int irq, void *dev_id);
+
+const char *snd_wss_chip_id(struct snd_wss *chip);
+
+int snd_wss_create(struct snd_card *card,
+                     unsigned long port,
+                     unsigned long cport,
+                     int irq, int dma1, int dma2,
+                     unsigned short hardware,
+                     unsigned short hwshare,
+                     struct snd_wss **rchip);
+int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
+int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
+int snd_wss_mixer(struct snd_wss *chip);
+
+const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction);
+
+int snd_cs4236_create(struct snd_card *card,
+                     unsigned long port,
+                     unsigned long cport,
+                     int irq, int dma1, int dma2,
+                     unsigned short hardware,
+                     unsigned short hwshare,
+                     struct snd_wss **rchip);
+int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
+int snd_cs4236_mixer(struct snd_wss *chip);
+
+/*
+ *  mixer library
+ */
+
+#define WSS_SINGLE(xname, xindex, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_single, \
+  .get = snd_wss_get_single, \
+  .put = snd_wss_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+int snd_wss_info_single(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo);
+int snd_wss_get_single(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+int snd_wss_put_single(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+
+#define WSS_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_double, \
+  .get = snd_wss_get_double, \
+  .put = snd_wss_put_double, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+                  (shift_right << 19) | (mask << 24) | (invert << 22) }
+
+#define WSS_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_single, \
+  .get = snd_wss_get_single, \
+  .put = snd_wss_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
+  .tlv = { .p = (xtlv) } }
+
+#define WSS_DOUBLE_TLV(xname, xindex, left_reg, right_reg, \
+                       shift_left, shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_wss_info_double, \
+  .get = snd_wss_get_double, \
+  .put = snd_wss_put_double, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+                  (shift_right << 19) | (mask << 24) | (invert << 22), \
+  .tlv = { .p = (xtlv) } }
+
+
+int snd_wss_info_double(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo);
+int snd_wss_get_double(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+int snd_wss_put_double(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol);
+
+#endif /* __SOUND_WSS_H */
index 8ebf512ced6caacee8f0f0a8aafa80772e530889..200aca1faa7112f0413f3cd92ab0a55cec48f588 100644 (file)
@@ -28,6 +28,10 @@ menuconfig SOUND
 
 if SOUND
 
+config SOUND_OSS_CORE
+       bool
+       default n
+
 source "sound/oss/dmasound/Kconfig"
 
 if !M68K
@@ -80,6 +84,7 @@ endif # SND
 
 menuconfig SOUND_PRIME
        tristate "Open Sound System (DEPRECATED)"
+       select SOUND_OSS_CORE
        help
          Say 'Y' or 'M' to enable Open Sound System drivers.
 
index 7a16a3331f7e9efc6f12918cdb97f82e3d833b14..6c515b2b8bbd00309f0baec15cebc9307ff3807d 100644 (file)
@@ -654,15 +654,13 @@ static struct snd_kcontrol_new bass_control = {
 static struct transfer_info tas_transfers[] = {
        {
                /* input */
-               .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
-                          SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+               .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_BE,
                .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
                .transfer_in = 1,
        },
        {
                /* output */
-               .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
-                          SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+               .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_BE,
                .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
                .transfer_in = 0,
        },
index 351e19ea3785ce7159fe6957abc97a1b1c963971..f8e6de48d816a49d4451b88b8417069ae1062510 100644 (file)
@@ -32,11 +32,20 @@ config SND_PXA2XX_PCM
        tristate
        select SND_PCM
 
+config SND_PXA2XX_LIB
+       tristate
+       select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
+
+config SND_PXA2XX_LIB_AC97
+       bool
+
 config SND_PXA2XX_AC97
        tristate "AC97 driver for the Intel PXA2xx chip"
        depends on ARCH_PXA
        select SND_PXA2XX_PCM
        select SND_AC97_CODEC
+       select SND_PXA2XX_LIB
+       select SND_PXA2XX_LIB_AC97
        help
          Say Y or M if you want to support any AC97 codec attached to
          the PXA2xx AC97 interface.
index 4ef6dd00c6eeafb9916378ad7098b642a309a0cc..2054de11de8a2140ce7f4052c0233ba5fb183fb6 100644 (file)
@@ -11,5 +11,9 @@ snd-aaci-objs                 := aaci.o devdma.o
 obj-$(CONFIG_SND_PXA2XX_PCM)   += snd-pxa2xx-pcm.o
 snd-pxa2xx-pcm-objs            := pxa2xx-pcm.o
 
+obj-$(CONFIG_SND_PXA2XX_LIB)   += snd-pxa2xx-lib.o
+snd-pxa2xx-lib-y               := pxa2xx-pcm-lib.o
+snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97)   += pxa2xx-ac97-lib.o
+
 obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
index b0a474494966d42b97b5547c4b250b65e4face8e..89096e811a4bc47dbe1458c2faba375220ec5bbb 100644 (file)
@@ -999,7 +999,7 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
        card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                            THIS_MODULE, sizeof(struct aaci));
        if (card == NULL)
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
        card->private_free = aaci_free_card;
 
@@ -1083,8 +1083,8 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id)
                return ret;
 
        aaci = aaci_init_card(dev);
-       if (IS_ERR(aaci)) {
-               ret = PTR_ERR(aaci);
+       if (!aaci) {
+               ret = -ENOMEM;
                goto out;
        }
 
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
new file mode 100644 (file)
index 0000000..99026df
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c
+ * which contain:
+ *
+ * Author:     Nicolas Pitre
+ * Created:    Dec 02, 2004
+ * Copyright:  MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <sound/ac97_codec.h>
+#include <sound/pxa2xx-lib.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-gpio.h>
+#include <mach/audio.h>
+
+static DEFINE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+static struct clk *ac97_clk;
+static struct clk *ac97conf_clk;
+
+/*
+ * Beware PXA27x bugs:
+ *
+ *   o Slot 12 read from modem space will hang controller.
+ *   o CDONE, SDONE interrupt fails after any slot 12 IO.
+ *
+ * We therefore have an hybrid approach for waiting on SDONE (interrupt or
+ * 1 jiffy timeout if interrupt never comes).
+ */
+
+unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+       unsigned short val = -1;
+       volatile u32 *reg_addr;
+
+       mutex_lock(&car_mutex);
+
+       /* set up primary or secondary codec space */
+       if ((cpu_is_pxa21x() || cpu_is_pxa25x()) && reg == AC97_GPIO_STATUS)
+               reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+       else
+               reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+       reg_addr += (reg >> 1);
+
+       /* start read access across the ac97 link */
+       GSR = GSR_CDONE | GSR_SDONE;
+       gsr_bits = 0;
+       val = *reg_addr;
+       if (reg == AC97_GPIO_STATUS)
+               goto out;
+       if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
+           !((GSR | gsr_bits) & GSR_SDONE)) {
+               printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
+                               __func__, reg, GSR | gsr_bits);
+               val = -1;
+               goto out;
+       }
+
+       /* valid data now */
+       GSR = GSR_CDONE | GSR_SDONE;
+       gsr_bits = 0;
+       val = *reg_addr;
+       /* but we've just started another cycle... */
+       wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
+
+out:   mutex_unlock(&car_mutex);
+       return val;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
+
+void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                       unsigned short val)
+{
+       volatile u32 *reg_addr;
+
+       mutex_lock(&car_mutex);
+
+       /* set up primary or secondary codec space */
+       if ((cpu_is_pxa21x() || cpu_is_pxa25x()) && reg == AC97_GPIO_STATUS)
+               reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+       else
+               reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+       reg_addr += (reg >> 1);
+
+       GSR = GSR_CDONE | GSR_SDONE;
+       gsr_bits = 0;
+       *reg_addr = val;
+       if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
+           !((GSR | gsr_bits) & GSR_CDONE))
+               printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
+                               __func__, reg, GSR | gsr_bits);
+
+       mutex_unlock(&car_mutex);
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
+
+#ifdef CONFIG_PXA25x
+static inline void pxa_ac97_warm_pxa25x(void)
+{
+       gsr_bits = 0;
+
+       GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
+       wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+}
+
+static inline void pxa_ac97_cold_pxa25x(void)
+{
+       GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+       GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+       gsr_bits = 0;
+
+       GCR = GCR_COLD_RST;
+       GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
+       wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+}
+#endif
+
+#ifdef CONFIG_PXA27x
+static inline void pxa_ac97_warm_pxa27x(void)
+{
+       gsr_bits = 0;
+
+       /* warm reset broken on Bulverde,
+          so manually keep AC97 reset high */
+       pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+       udelay(10);
+       GCR |= GCR_WARM_RST;
+       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+       udelay(500);
+}
+
+static inline void pxa_ac97_cold_pxa27x(void)
+{
+       GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+       GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+       gsr_bits = 0;
+
+       /* PXA27x Developers Manual section 13.5.2.2.1 */
+       clk_enable(ac97conf_clk);
+       udelay(5);
+       clk_disable(ac97conf_clk);
+       GCR = GCR_COLD_RST;
+       udelay(50);
+}
+#endif
+
+#ifdef CONFIG_PXA3xx
+static inline void pxa_ac97_warm_pxa3xx(void)
+{
+       int timeout = 100;
+
+       gsr_bits = 0;
+
+       /* Can't use interrupts */
+       GCR |= GCR_WARM_RST;
+       while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+               mdelay(1);
+}
+
+static inline void pxa_ac97_cold_pxa3xx(void)
+{
+       int timeout = 1000;
+
+       /* Hold CLKBPB for 100us */
+       GCR = 0;
+       GCR = GCR_CLKBPB;
+       udelay(100);
+       GCR = 0;
+
+       GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+       GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+       gsr_bits = 0;
+
+       /* Can't use interrupts on PXA3xx */
+       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+
+       GCR = GCR_WARM_RST | GCR_COLD_RST;
+       while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
+               mdelay(10);
+}
+#endif
+
+bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
+{
+#ifdef CONFIG_PXA25x
+       if (cpu_is_pxa21x() || cpu_is_pxa25x())
+               pxa_ac97_warm_pxa25x();
+       else
+#endif
+#ifdef CONFIG_PXA27x
+       if (cpu_is_pxa27x())
+               pxa_ac97_warm_pxa27x();
+       else
+#endif
+#ifdef CONFIG_PXA3xx
+       if (cpu_is_pxa3xx())
+               pxa_ac97_warm_pxa3xx();
+       else
+#endif
+               BUG();
+
+       if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
+               printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
+                                __func__, gsr_bits);
+
+               return false;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
+
+bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
+{
+#ifdef CONFIG_PXA25x
+       if (cpu_is_pxa21x() || cpu_is_pxa25x())
+               pxa_ac97_cold_pxa25x();
+       else
+#endif
+#ifdef CONFIG_PXA27x
+       if (cpu_is_pxa27x())
+               pxa_ac97_cold_pxa27x();
+       else
+#endif
+#ifdef CONFIG_PXA3xx
+       if (cpu_is_pxa3xx())
+               pxa_ac97_cold_pxa3xx();
+       else
+#endif
+               BUG();
+
+       if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
+               printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
+                                __func__, gsr_bits);
+
+               return false;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
+
+
+void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97)
+{
+       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+       GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset);
+
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
+{
+       long status;
+
+       status = GSR;
+       if (status) {
+               GSR = status;
+               gsr_bits |= status;
+               wake_up(&gsr_wq);
+
+               /* Although we don't use those we still need to clear them
+                  since they tend to spuriously trigger when MMC is used
+                  (hardware bug? go figure)... */
+               if (cpu_is_pxa27x()) {
+                       MISR = MISR_EOC;
+                       PISR = PISR_EOC;
+                       MCSR = MCSR_EOC;
+               }
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+#ifdef CONFIG_PM
+int pxa2xx_ac97_hw_suspend(void)
+{
+       GCR |= GCR_ACLINK_OFF;
+       clk_disable(ac97_clk);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);
+
+int pxa2xx_ac97_hw_resume(void)
+{
+       if (cpu_is_pxa21x() || cpu_is_pxa25x() || cpu_is_pxa27x()) {
+               pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+               pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+               pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+               pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+       }
+       if (cpu_is_pxa27x()) {
+               /* Use GPIO 113 as AC97 Reset on Bulverde */
+               pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+       }
+       clk_enable(ac97_clk);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
+#endif
+
+int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
+{
+       int ret;
+
+       ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
+       if (ret < 0)
+               goto err;
+
+       if (cpu_is_pxa21x() || cpu_is_pxa25x() || cpu_is_pxa27x()) {
+               pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+               pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+               pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+               pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+       }
+
+       if (cpu_is_pxa27x()) {
+               /* Use GPIO 113 as AC97 Reset on Bulverde */
+               pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+               ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
+               if (IS_ERR(ac97conf_clk)) {
+                       ret = PTR_ERR(ac97conf_clk);
+                       ac97conf_clk = NULL;
+                       goto err_irq;
+               }
+       }
+
+       ac97_clk = clk_get(&dev->dev, "AC97CLK");
+       if (IS_ERR(ac97_clk)) {
+               ret = PTR_ERR(ac97_clk);
+               ac97_clk = NULL;
+               goto err_irq;
+       }
+
+       return clk_enable(ac97_clk);
+
+err_irq:
+       GCR |= GCR_ACLINK_OFF;
+       if (ac97conf_clk) {
+               clk_put(ac97conf_clk);
+               ac97conf_clk = NULL;
+       }
+       free_irq(IRQ_AC97, NULL);
+err:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
+
+void pxa2xx_ac97_hw_remove(struct platform_device *dev)
+{
+       GCR |= GCR_ACLINK_OFF;
+       free_irq(IRQ_AC97, NULL);
+       if (ac97conf_clk) {
+               clk_put(ac97conf_clk);
+               ac97conf_clk = NULL;
+       }
+       clk_disable(ac97_clk);
+       clk_put(ac97_clk);
+       ac97_clk = NULL;
+}
+EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel/Marvell PXA sound library");
+MODULE_LICENSE("GPL");
+
index 199cca3366df244b4fd05c5125ac096a0ade0f73..cba71d867542ef43d4c43c27db3dd44f17b95a61 100644 (file)
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
+#include <sound/pxa2xx-lib.h>
 
-#include <asm/irq.h>
-#include <linux/mutex.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
 
-
-static DEFINE_MUTEX(car_mutex);
-static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
-static volatile long gsr_bits;
-static struct clk *ac97_clk;
-#ifdef CONFIG_PXA27x
-static struct clk *ac97conf_clk;
-#endif
-
-/*
- * Beware PXA27x bugs:
- *
- *   o Slot 12 read from modem space will hang controller.
- *   o CDONE, SDONE interrupt fails after any slot 12 IO.
- *
- * We therefore have an hybrid approach for waiting on SDONE (interrupt or
- * 1 jiffy timeout if interrupt never comes).
- */ 
-
-static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
-{
-       unsigned short val = -1;
-       volatile u32 *reg_addr;
-
-       mutex_lock(&car_mutex);
-
-       /* set up primary or secondary codec space */
-       reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
-       reg_addr += (reg >> 1);
-
-       /* start read access across the ac97 link */
-       GSR = GSR_CDONE | GSR_SDONE;
-       gsr_bits = 0;
-       val = *reg_addr;
-       if (reg == AC97_GPIO_STATUS)
-               goto out;
-       if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
-           !((GSR | gsr_bits) & GSR_SDONE)) {
-               printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
-                               __func__, reg, GSR | gsr_bits);
-               val = -1;
-               goto out;
-       }
-
-       /* valid data now */
-       GSR = GSR_CDONE | GSR_SDONE;
-       gsr_bits = 0;
-       val = *reg_addr;                        
-       /* but we've just started another cycle... */
-       wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
-
-out:   mutex_unlock(&car_mutex);
-       return val;
-}
-
-static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
-{
-       volatile u32 *reg_addr;
-
-       mutex_lock(&car_mutex);
-
-       /* set up primary or secondary codec space */
-       reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
-       reg_addr += (reg >> 1);
-
-       GSR = GSR_CDONE | GSR_SDONE;
-       gsr_bits = 0;
-       *reg_addr = val;
-       if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
-           !((GSR | gsr_bits) & GSR_CDONE))
-               printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
-                               __func__, reg, GSR | gsr_bits);
-
-       mutex_unlock(&car_mutex);
-}
-
 static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
 {
-       /* First, try cold reset */
-#ifdef CONFIG_PXA3xx
-       int timeout;
-
-       /* Hold CLKBPB for 100us */
-       GCR = 0;
-       GCR = GCR_CLKBPB;
-       udelay(100);
-       GCR = 0;
-#endif
-
-       GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
-       GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
-
-       gsr_bits = 0;
-#ifdef CONFIG_PXA27x
-       /* PXA27x Developers Manual section 13.5.2.2.1 */
-       clk_enable(ac97conf_clk);
-       udelay(5);
-       clk_disable(ac97conf_clk);
-       GCR = GCR_COLD_RST;
-       udelay(50);
-#elif defined(CONFIG_PXA3xx)
-       timeout = 1000;
-       /* Can't use interrupts on PXA3xx */
-       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-
-       GCR = GCR_WARM_RST | GCR_COLD_RST;
-       while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
-               mdelay(10);
-#else
-       GCR = GCR_COLD_RST;
-       GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
-       wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif
-
-       if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
-               printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
-                                __func__, gsr_bits);
-
-               /* let's try warm reset */
-               gsr_bits = 0;
-#ifdef CONFIG_PXA27x
-               /* warm reset broken on Bulverde,
-                  so manually keep AC97 reset high */
-               pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); 
-               udelay(10);
-               GCR |= GCR_WARM_RST;
-               pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-               udelay(500);
-#elif defined(CONFIG_PXA3xx)
-               timeout = 100;
-               /* Can't use interrupts */
-               GCR |= GCR_WARM_RST;
-               while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
-                       mdelay(1);
-#else
-               GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
-               wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif                 
-
-               if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
-                       printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
-                                        __func__, gsr_bits);
-       }
-
-       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-       GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
-}
-
-static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
-{
-       long status;
-
-       status = GSR;
-       if (status) {
-               GSR = status;
-               gsr_bits |= status;
-               wake_up(&gsr_wq);
-
-#ifdef CONFIG_PXA27x
-               /* Although we don't use those we still need to clear them
-                  since they tend to spuriously trigger when MMC is used
-                  (hardware bug? go figure)... */
-               MISR = MISR_EOC;
-               PISR = PISR_EOC;
-               MCSR = MCSR_EOC;
-#endif
-
-               return IRQ_HANDLED;
+       if (!pxa2xx_ac97_try_cold_reset(ac97)) {
+               pxa2xx_ac97_try_warm_reset(ac97);
        }
 
-       return IRQ_NONE;
+       pxa2xx_ac97_finish_reset(ac97);
 }
 
 static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
@@ -288,17 +117,19 @@ static int pxa2xx_ac97_do_suspend(struct snd_card *card, pm_message_t state)
        snd_ac97_suspend(pxa2xx_ac97_ac97);
        if (platform_ops && platform_ops->suspend)
                platform_ops->suspend(platform_ops->priv);
-       GCR |= GCR_ACLINK_OFF;
-       clk_disable(ac97_clk);
 
-       return 0;
+       return pxa2xx_ac97_hw_suspend();
 }
 
 static int pxa2xx_ac97_do_resume(struct snd_card *card)
 {
        pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
+       int rc;
+
+       rc = pxa2xx_ac97_hw_resume();
+       if (rc)
+               return rc;
 
-       clk_enable(ac97_clk);
        if (platform_ops && platform_ops->resume)
                platform_ops->resume(platform_ops->priv);
        snd_ac97_resume(pxa2xx_ac97_ac97);
@@ -354,40 +185,17 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
        if (ret)
                goto err;
 
-       ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
-       if (ret < 0)
-               goto err;
-
-       pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
-       pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
-       pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
-       pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
-#ifdef CONFIG_PXA27x
-       /* Use GPIO 113 as AC97 Reset on Bulverde */
-       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-       ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
-       if (IS_ERR(ac97conf_clk)) {
-               ret = PTR_ERR(ac97conf_clk);
-               ac97conf_clk = NULL;
-               goto err;
-       }
-#endif
-
-       ac97_clk = clk_get(&dev->dev, "AC97CLK");
-       if (IS_ERR(ac97_clk)) {
-               ret = PTR_ERR(ac97_clk);
-               ac97_clk = NULL;
+       ret = pxa2xx_ac97_hw_probe(dev);
+       if (ret)
                goto err;
-       }
-       clk_enable(ac97_clk);
 
        ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
        if (ret)
-               goto err;
+               goto err_remove;
        memset(&ac97_template, 0, sizeof(ac97_template));
        ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
        if (ret)
-               goto err;
+               goto err_remove;
 
        snprintf(card->shortname, sizeof(card->shortname),
                 "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
@@ -401,22 +209,11 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
                return 0;
        }
 
- err:
+err_remove:
+       pxa2xx_ac97_hw_remove(dev);
+err:
        if (card)
                snd_card_free(card);
-       if (ac97_clk) {
-               GCR |= GCR_ACLINK_OFF;
-               free_irq(IRQ_AC97, NULL);
-               clk_disable(ac97_clk);
-               clk_put(ac97_clk);
-               ac97_clk = NULL;
-       }
-#ifdef CONFIG_PXA27x
-       if (ac97conf_clk) {
-               clk_put(ac97conf_clk);
-               ac97conf_clk = NULL;
-       }
-#endif
        return ret;
 }
 
@@ -427,15 +224,7 @@ static int __devexit pxa2xx_ac97_remove(struct platform_device *dev)
        if (card) {
                snd_card_free(card);
                platform_set_drvdata(dev, NULL);
-               GCR |= GCR_ACLINK_OFF;
-               free_irq(IRQ_AC97, NULL);
-               clk_disable(ac97_clk);
-               clk_put(ac97_clk);
-               ac97_clk = NULL;
-#ifdef CONFIG_PXA27x
-               clk_put(ac97conf_clk);
-               ac97conf_clk = NULL;
-#endif
+               pxa2xx_ac97_hw_remove(dev);
        }
 
        return 0;
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
new file mode 100644 (file)
index 0000000..1c93eb7
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/pxa2xx-lib.h>
+
+#include <asm/dma.h>
+#include <mach/pxa-regs.h>
+
+#include "pxa2xx-pcm.h"
+
+static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                       SNDRV_PCM_FMTBIT_S24_LE |
+                                       SNDRV_PCM_FMTBIT_S32_LE,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192 - 32,
+       .periods_min            = 1,
+       .periods_max            = PAGE_SIZE/sizeof(pxa_dma_desc),
+       .buffer_bytes_max       = 128 * 1024,
+       .fifo_size              = 32,
+};
+
+int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct pxa2xx_runtime_data *rtd = runtime->private_data;
+       size_t totsize = params_buffer_bytes(params);
+       size_t period = params_period_bytes(params);
+       pxa_dma_desc *dma_desc;
+       dma_addr_t dma_buff_phys, next_desc_phys;
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       runtime->dma_bytes = totsize;
+
+       dma_desc = rtd->dma_desc_array;
+       next_desc_phys = rtd->dma_desc_array_phys;
+       dma_buff_phys = runtime->dma_addr;
+       do {
+               next_desc_phys += sizeof(pxa_dma_desc);
+               dma_desc->ddadr = next_desc_phys;
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dma_desc->dsadr = dma_buff_phys;
+                       dma_desc->dtadr = rtd->params->dev_addr;
+               } else {
+                       dma_desc->dsadr = rtd->params->dev_addr;
+                       dma_desc->dtadr = dma_buff_phys;
+               }
+               if (period > totsize)
+                       period = totsize;
+               dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
+               dma_desc++;
+               dma_buff_phys += period;
+       } while (totsize -= period);
+       dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
+
+       return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
+
+int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+
+       if (rtd && rtd->params)
+               *rtd->params->drcmr = 0;
+
+       snd_pcm_set_runtime_buffer(substream, NULL);
+       return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
+
+int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+               DCSR(prtd->dma_ch) = DCSR_RUN;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+               break;
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+               DCSR(prtd->dma_ch) |= DCSR_RUN;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+               DCSR(prtd->dma_ch) |= DCSR_RUN;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(pxa2xx_pcm_trigger);
+
+snd_pcm_uframes_t
+pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct pxa2xx_runtime_data *prtd = runtime->private_data;
+
+       dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                        DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
+       snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+
+       if (x == runtime->buffer_size)
+               x = 0;
+       return x;
+}
+EXPORT_SYMBOL(pxa2xx_pcm_pointer);
+
+int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+
+       DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+       DCSR(prtd->dma_ch) = 0;
+       DCMD(prtd->dma_ch) = 0;
+       *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
+
+       return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
+
+void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
+{
+       struct snd_pcm_substream *substream = dev_id;
+       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+       int dcsr;
+
+       dcsr = DCSR(dma_ch);
+       DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
+
+       if (dcsr & DCSR_ENDINTR) {
+               snd_pcm_period_elapsed(substream);
+       } else {
+               printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+                       rtd->params->name, dma_ch, dcsr);
+               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+       }
+}
+EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
+
+int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct pxa2xx_runtime_data *rtd;
+       int ret;
+
+       runtime->hw = pxa2xx_pcm_hardware;
+
+       /*
+        * For mysterious reasons (and despite what the manual says)
+        * playback samples are lost if the DMA count is not a multiple
+        * of the DMA burst size.  Let's add a rule to enforce that.
+        */
+       ret = snd_pcm_hw_constraint_step(runtime, 0,
+               SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+       if (ret)
+               goto out;
+
+       ret = snd_pcm_hw_constraint_step(runtime, 0,
+               SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+       if (ret)
+               goto out;
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               goto out;
+
+       ret = -ENOMEM;
+       rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+       if (!rtd)
+               goto out;
+       rtd->dma_desc_array =
+               dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+                                      &rtd->dma_desc_array_phys, GFP_KERNEL);
+       if (!rtd->dma_desc_array)
+               goto err1;
+
+       runtime->private_data = rtd;
+       return 0;
+
+ err1:
+       kfree(rtd);
+ out:
+       return ret;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_open);
+
+int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct pxa2xx_runtime_data *rtd = runtime->private_data;
+
+       dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+                             rtd->dma_desc_array, rtd->dma_desc_array_phys);
+       kfree(rtd);
+       return 0;
+}
+EXPORT_SYMBOL(__pxa2xx_pcm_close);
+
+int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+                                    runtime->dma_area,
+                                    runtime->dma_addr,
+                                    runtime->dma_bytes);
+}
+EXPORT_SYMBOL(pxa2xx_pcm_mmap);
+
+int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+                                          &buf->addr, GFP_KERNEL);
+       if (!buf->area)
+               return -ENOMEM;
+       buf->bytes = size;
+       return 0;
+}
+EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
+
+void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+               dma_free_writecombine(pcm->card->dev, buf->bytes,
+                                     buf->area, buf->addr);
+               buf->area = NULL;
+       }
+}
+EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx sound library");
+MODULE_LICENSE("GPL");
index 381094aab2355e854914ad3f7c677f93f3e6b6e8..535704f77496040976f9696d18639b9dc4f77606 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
 #include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
+#include <sound/pxa2xx-lib.h>
 
 #include "pxa2xx-pcm.h"
 
-
-static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_PAUSE,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192 - 32,
-       .periods_min            = 1,
-       .periods_max            = PAGE_SIZE/sizeof(pxa_dma_desc),
-       .buffer_bytes_max       = 128 * 1024,
-       .fifo_size              = 32,
-};
-
-struct pxa2xx_runtime_data {
-       int dma_ch;
-       struct pxa2xx_pcm_dma_params *params;
-       pxa_dma_desc *dma_desc_array;
-       dma_addr_t dma_desc_array_phys;
-};
-
-static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
-       size_t totsize = params_buffer_bytes(params);
-       size_t period = params_period_bytes(params);
-       pxa_dma_desc *dma_desc;
-       dma_addr_t dma_buff_phys, next_desc_phys;
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = totsize;
-
-       dma_desc = rtd->dma_desc_array;
-       next_desc_phys = rtd->dma_desc_array_phys;
-       dma_buff_phys = runtime->dma_addr;
-       do {
-               next_desc_phys += sizeof(pxa_dma_desc);
-               dma_desc->ddadr = next_desc_phys;
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       dma_desc->dsadr = dma_buff_phys;
-                       dma_desc->dtadr = rtd->params->dev_addr;
-               } else {
-                       dma_desc->dsadr = rtd->params->dev_addr;
-                       dma_desc->dtadr = dma_buff_phys;
-               }
-               if (period > totsize)
-                       period = totsize;
-               dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
-               dma_desc++;
-               dma_buff_phys += period;
-       } while (totsize -= period);
-       dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
-
-       return 0;
-}
-
-static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-
-       *rtd->params->drcmr = 0;
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       return 0;
-}
-
 static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_pcm_client *client = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
 
-       DCSR(rtd->dma_ch) &= ~DCSR_RUN;
-       DCSR(rtd->dma_ch) = 0;
-       DCMD(rtd->dma_ch) = 0;
-       *rtd->params->drcmr = rtd->dma_ch | DRCMR_MAPVLD;
+       __pxa2xx_pcm_prepare(substream);
 
        return client->prepare(substream);
 }
 
-static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               DDADR(rtd->dma_ch) = rtd->dma_desc_array_phys;
-               DCSR(rtd->dma_ch) = DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               DCSR(rtd->dma_ch) &= ~DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               DCSR(rtd->dma_ch) |= DCSR_RUN;
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
-{
-       struct snd_pcm_substream *substream = dev_id;
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-       int dcsr;
-
-       dcsr = DCSR(dma_ch);
-       DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
-
-       if (dcsr & DCSR_ENDINTR) {
-               snd_pcm_period_elapsed(substream);
-       } else {
-               printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-                       rtd->params->name, dma_ch, dcsr );
-               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-       }
-}
-
-static snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
-       dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                        DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch);
-       snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-       if (x == runtime->buffer_size)
-               x = 0;
-       return x;
-}
-
-static int
-pxa2xx_pcm_hw_rule_mult32(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
-{
-       struct snd_interval *i = hw_param_interval(params, rule->var);
-       int changed = 0;
-
-       if (i->min & 31) {
-               i->min = (i->min & ~31) + 32;
-               i->openmin = 0;
-               changed = 1;
-       }
-
-       if (i->max & 31) {
-               i->max &= ~31;
-               i->openmax = 0;
-               changed = 1;
-       }
-
-       return changed;
-}
-
 static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_pcm_client *client = substream->private_data;
@@ -194,33 +31,11 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
        struct pxa2xx_runtime_data *rtd;
        int ret;
 
-       runtime->hw = pxa2xx_pcm_hardware;
-
-       /*
-        * For mysterious reasons (and despite what the manual says)
-        * playback samples are lost if the DMA count is not a multiple
-        * of the DMA burst size.  Let's add a rule to enforce that.
-        */
-       ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-                                 pxa2xx_pcm_hw_rule_mult32, NULL,
-                                 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
-       if (ret)
-               goto out;
-       ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-                                 pxa2xx_pcm_hw_rule_mult32, NULL,
-                                 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
+       ret = __pxa2xx_pcm_open(substream);
        if (ret)
                goto out;
 
-       ret = -ENOMEM;
-       rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
-       if (!rtd)
-               goto out;
-       rtd->dma_desc_array =
-               dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                                      &rtd->dma_desc_array_phys, GFP_KERNEL);
-       if (!rtd->dma_desc_array)
-               goto err1;
+       rtd = runtime->private_data;
 
        rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                      client->playback_params : client->capture_params;
@@ -230,17 +45,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
                goto err2;
        rtd->dma_ch = ret;
 
-       runtime->private_data = rtd;
        ret = client->startup(substream);
        if (!ret)
                goto out;
 
        pxa_free_dma(rtd->dma_ch);
  err2:
-       dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                             rtd->dma_desc_array, rtd->dma_desc_array_phys);
- err1:
-       kfree(rtd);
+       __pxa2xx_pcm_close(substream);
  out:
        return ret;
 }
@@ -252,69 +63,22 @@ static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 
        pxa_free_dma(rtd->dma_ch);
        client->shutdown(substream);
-       dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                             rtd->dma_desc_array, rtd->dma_desc_array_phys);
-       kfree(rtd);
-       return 0;
-}
 
-static int
-pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
+       return __pxa2xx_pcm_close(substream);
 }
 
 static struct snd_pcm_ops pxa2xx_pcm_ops = {
        .open           = pxa2xx_pcm_open,
        .close          = pxa2xx_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pxa2xx_pcm_hw_params,
-       .hw_free        = pxa2xx_pcm_hw_free,
+       .hw_params      = __pxa2xx_pcm_hw_params,
+       .hw_free        = __pxa2xx_pcm_hw_free,
        .prepare        = pxa2xx_pcm_prepare,
        .trigger        = pxa2xx_pcm_trigger,
        .pointer        = pxa2xx_pcm_pointer,
        .mmap           = pxa2xx_pcm_mmap,
 };
 
-static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-       buf->bytes = size;
-       return 0;
-}
-
-static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
 static u64 pxa2xx_pcm_dmamask = 0xffffffff;
 
 int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
index b79f1e80378035929339b09d2d35eada2f70687e..5c4a4d38a08399c1df3a60ea3bf02e78c70998cf 100644 (file)
@@ -9,14 +9,15 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <asm/dma.h>
 
-struct pxa2xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-       u32 dcmd;                       /* DMA descriptor dcmd field */
-       volatile u32 *drcmr;            /* the DMA request channel to use */
-       u32 dev_addr;                   /* device physical address for DMA */
+struct pxa2xx_runtime_data {
+       int dma_ch;
+       struct pxa2xx_pcm_dma_params *params;
+       pxa_dma_desc *dma_desc_array;
+       dma_addr_t dma_desc_array_phys;
 };
-       
+
 struct pxa2xx_pcm_client {
        struct pxa2xx_pcm_dma_params *playback_params;
        struct pxa2xx_pcm_dma_params *capture_params;
index b9c51bf8cd71a3c09af66dbc705c560d1a3cfe71..1dcd51d81d102c1adcd5ea5282933b9ba9f947f5 100644 (file)
@@ -442,7 +442,8 @@ static void audio_process_dma(struct audio_stream *s)
                 
        /* we are requested to process synchronization DMA transfer */
        if (s->tx_spin) {
-               snd_assert(s->stream_id == SNDRV_PCM_STREAM_PLAYBACK, return);
+               if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK))
+                       return;
                /* fill the xmit dma buffers and return */
 #ifdef HH_VERSION
                sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
@@ -472,7 +473,7 @@ static void audio_process_dma(struct audio_stream *s)
                                continue;               /* special case */
                } else {
                        offset = dma_size * s->period;
-                       snd_assert(dma_size <= DMA_BUF_SIZE, );
+                       snd_BUG_ON(dma_size > DMA_BUF_SIZE);
                }
 #ifdef HH_VERSION
                ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);
@@ -879,7 +880,7 @@ void snd_sa11xx_uda1341_free(struct snd_card *card)
        audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
 }
 
-static int __init sa11xx_uda1341_probe(struct platform_device *devptr)
+static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr)
 {
        int err;
        struct snd_card *card;
index 335d45ecde6a19bc0d3f12a68363c669ea405a17..66348c92f88dcd96453c5eb1b673aaced6259fb5 100644 (file)
@@ -12,6 +12,12 @@ config SND_HWDEP
 config SND_RAWMIDI
        tristate
 
+# To be effective this also requires INPUT - users should say:
+#    select SND_JACK if INPUT=y || INPUT=SND
+# to avoid having to force INPUT on.
+config SND_JACK
+       bool
+
 config SND_SEQUENCER
        tristate "Sequencer support"
        select SND_TIMER
@@ -38,6 +44,7 @@ config SND_SEQ_DUMMY
          will be called snd-seq-dummy.
 
 config SND_OSSEMUL
+       select SOUND_OSS_CORE
        bool
 
 config SND_MIXER_OSS
@@ -101,6 +108,9 @@ config SND_RTCTIMER
          To compile this driver as a module, choose M here: the module
          will be called snd-rtctimer.
 
+         Note that this option is exclusive with the new RTC drivers
+         (CONFIG_RTC_CLASS) since this requires the old API.
+
 config SND_SEQ_RTCTIMER_DEFAULT
        bool "Use RTC as default sequencer timer"
        depends on SND_RTCTIMER && SND_SEQUENCER
index da8e685eef9c38b1af620acb1c25d403223fd0aa..d57125a5687d1b28ed86cc1fe65d657ea94356eb 100644 (file)
@@ -7,6 +7,7 @@ snd-y     := sound.o init.o memory.o info.o control.o misc.o device.o
 snd-$(CONFIG_ISA_DMA_API) += isadma.o
 snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
 snd-$(CONFIG_SND_VMASTER) += vmaster.o
+snd-$(CONFIG_SND_JACK)   += jack.o
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
                pcm_memory.o
index 281b2e2ef0eac0bb4b87c4a475433a466459a98d..6d71f9a7ccbb9a063324d1bc381edc2e113f4e84 100644 (file)
@@ -139,7 +139,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
        struct snd_ctl_file *ctl;
        struct snd_kctl_event *ev;
        
-       snd_assert(card != NULL && id != NULL, return);
+       if (snd_BUG_ON(!card || !id))
+               return;
        read_lock(&card->ctl_files_rwlock);
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
        card->mixer_oss_change_count++;
@@ -188,8 +189,8 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
        struct snd_kcontrol *kctl;
        unsigned int idx;
        
-       snd_assert(control != NULL, return NULL);
-       snd_assert(control->count > 0, return NULL);
+       if (snd_BUG_ON(!control || !control->count))
+               return NULL;
        kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
        if (kctl == NULL) {
                snd_printk(KERN_ERR "Cannot allocate control instance\n");
@@ -218,8 +219,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
        struct snd_kcontrol kctl;
        unsigned int access;
        
-       snd_assert(ncontrol != NULL, return NULL);
-       snd_assert(ncontrol->info != NULL, return NULL);
+       if (snd_BUG_ON(!ncontrol || !ncontrol->info))
+               return NULL;
        memset(&kctl, 0, sizeof(kctl));
        kctl.id.iface = ncontrol->iface;
        kctl.id.device = ncontrol->device;
@@ -315,8 +316,8 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 
        if (! kcontrol)
                return err;
-       snd_assert(card != NULL, goto error);
-       snd_assert(kcontrol->info != NULL, goto error);
+       if (snd_BUG_ON(!card || !kcontrol->info))
+               goto error;
        id = kcontrol->id;
        down_write(&card->controls_rwsem);
        if (snd_ctl_find_id(card, &id)) {
@@ -367,7 +368,8 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
        struct snd_ctl_elem_id id;
        unsigned int idx;
 
-       snd_assert(card != NULL && kcontrol != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card || !kcontrol))
+               return -EINVAL;
        list_del(&kcontrol->list);
        card->controls_count -= kcontrol->count;
        id = kcontrol->id;
@@ -487,7 +489,8 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi
 {
        struct snd_kcontrol *kctl;
 
-       snd_assert(card != NULL && numid != 0, return NULL);
+       if (snd_BUG_ON(!card || !numid))
+               return NULL;
        list_for_each_entry(kctl, &card->controls, list) {
                if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
                        return kctl;
@@ -514,7 +517,8 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
 {
        struct snd_kcontrol *kctl;
 
-       snd_assert(card != NULL && id != NULL, return NULL);
+       if (snd_BUG_ON(!card || !id))
+               return NULL;
        if (id->numid != 0)
                return snd_ctl_find_numid(card, id->numid);
        list_for_each_entry(kctl, &card->controls, list) {
@@ -647,7 +651,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
 #endif
        result = kctl->info(kctl, info);
        if (result >= 0) {
-               snd_assert(info->access == 0, );
+               snd_BUG_ON(info->access);
                index_offset = snd_ctl_get_ioff(kctl, &info->id);
                vd = &kctl->vd[index_offset];
                snd_ctl_build_ioff(&info->id, kctl, index_offset);
@@ -1160,7 +1164,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 
        ctl = file->private_data;
        card = ctl->card;
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        switch (cmd) {
        case SNDRV_CTL_IOCTL_PVERSION:
                return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
@@ -1222,7 +1227,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
        ssize_t result = 0;
 
        ctl = file->private_data;
-       snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!ctl || !ctl->card))
+               return -ENXIO;
        if (!ctl->subscribed)
                return -EBADFD;
        if (count < sizeof(struct snd_ctl_event))
@@ -1328,7 +1334,8 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
 {
        struct snd_kctl_ioctl *p;
 
-       snd_assert(fcn != NULL, return -EINVAL);
+       if (snd_BUG_ON(!fcn))
+               return -EINVAL;
        down_write(&snd_ioctl_rwsem);
        list_for_each_entry(p, lists, list) {
                if (p->fioctl == fcn) {
@@ -1404,9 +1411,11 @@ static int snd_ctl_dev_register(struct snd_device *device)
        int err, cardnum;
        char name[16];
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        cardnum = card->number;
-       snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+       if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
+               return -ENXIO;
        sprintf(name, "controlC%i", cardnum);
        if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
                                       &snd_ctl_f_ops, card, name)) < 0)
@@ -1423,16 +1432,18 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
        struct snd_ctl_file *ctl;
        int err, cardnum;
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        cardnum = card->number;
-       snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+       if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
+               return -ENXIO;
 
-       down_read(&card->controls_rwsem);
+       read_lock(&card->ctl_files_rwlock);
        list_for_each_entry(ctl, &card->ctl_files, list) {
                wake_up(&ctl->change_sleep);
                kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
        }
-       up_read(&card->controls_rwsem);
+       read_unlock(&card->ctl_files_rwlock);
 
        if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
                                         card, -1)) < 0)
@@ -1469,7 +1480,8 @@ int snd_ctl_create(struct snd_card *card)
                .dev_disconnect = snd_ctl_dev_disconnect,
        };
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
 }
 
index 6101259ad860e1b05260f36faa42758944ebc088..368dc9c4aef8d905eff9eb4fb780abedf53fca04 100644 (file)
@@ -398,7 +398,8 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
        int err;
 
        ctl = file->private_data;
-       snd_assert(ctl && ctl->card, return -ENXIO);
+       if (snd_BUG_ON(!ctl || !ctl->card))
+               return -ENXIO;
 
        switch (cmd) {
        case SNDRV_CTL_IOCTL_PVERSION:
index 202dac0e4d895b51f1fde72486b393a32c3ceed7..c58d8227254c8ff77d1a8ab210c1bbbedb769787 100644 (file)
@@ -45,9 +45,8 @@ int snd_device_new(struct snd_card *card, snd_device_type_t type,
 {
        struct snd_device *dev;
 
-       snd_assert(card != NULL, return -ENXIO);
-       snd_assert(device_data != NULL, return -ENXIO);
-       snd_assert(ops != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card || !device_data || !ops))
+               return -ENXIO;
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                snd_printk(KERN_ERR "Cannot allocate device\n");
@@ -80,8 +79,8 @@ int snd_device_free(struct snd_card *card, void *device_data)
 {
        struct snd_device *dev;
        
-       snd_assert(card != NULL, return -ENXIO);
-       snd_assert(device_data != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card || !device_data))
+               return -ENXIO;
        list_for_each_entry(dev, &card->devices, list) {
                if (dev->device_data != device_data)
                        continue;
@@ -123,8 +122,8 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
 {
        struct snd_device *dev;
 
-       snd_assert(card != NULL, return -ENXIO);
-       snd_assert(device_data != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card || !device_data))
+               return -ENXIO;
        list_for_each_entry(dev, &card->devices, list) {
                if (dev->device_data != device_data)
                        continue;
@@ -159,8 +158,8 @@ int snd_device_register(struct snd_card *card, void *device_data)
        struct snd_device *dev;
        int err;
 
-       snd_assert(card != NULL, return -ENXIO);
-       snd_assert(device_data != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card || !device_data))
+               return -ENXIO;
        list_for_each_entry(dev, &card->devices, list) {
                if (dev->device_data != device_data)
                        continue;
@@ -188,7 +187,8 @@ int snd_device_register_all(struct snd_card *card)
        struct snd_device *dev;
        int err;
        
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        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)
@@ -208,7 +208,8 @@ int snd_device_disconnect_all(struct snd_card *card)
        struct snd_device *dev;
        int err = 0;
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        list_for_each_entry(dev, &card->devices, list) {
                if (snd_device_disconnect(card, dev->device_data) < 0)
                        err = -ENXIO;
@@ -226,7 +227,8 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
        int err;
        unsigned int range_low, range_high;
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
        range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
       __again:
index 6d6589f93899035587570807bd46bc5325425962..195cafc5a55342df53e01a4ecb361a37db178dbd 100644 (file)
@@ -353,9 +353,10 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
                .dev_disconnect = snd_hwdep_dev_disconnect,
        };
 
-       snd_assert(rhwdep != NULL, return -EINVAL);
-       *rhwdep = NULL;
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
+       if (rhwdep)
+               *rhwdep = NULL;
        hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
        if (hwdep == NULL) {
                snd_printk(KERN_ERR "hwdep: cannot allocate\n");
@@ -374,13 +375,15 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
        }
        init_waitqueue_head(&hwdep->open_wait);
        mutex_init(&hwdep->open_mutex);
-       *rhwdep = hwdep;
+       if (rhwdep)
+               *rhwdep = hwdep;
        return 0;
 }
 
 static int snd_hwdep_free(struct snd_hwdep *hwdep)
 {
-       snd_assert(hwdep != NULL, return -ENXIO);
+       if (!hwdep)
+               return 0;
        if (hwdep->private_free)
                hwdep->private_free(hwdep);
        kfree(hwdep);
@@ -440,7 +443,8 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
 {
        struct snd_hwdep *hwdep = device->device_data;
 
-       snd_assert(hwdep != NULL, return -ENXIO);
+       if (snd_BUG_ON(!hwdep))
+               return -ENXIO;
        mutex_lock(&register_mutex);
        if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
                mutex_unlock(&register_mutex);
index c67773ad9298076e701ea161b5f7c9ce3560da1e..527b207462b0849809f7843b5d6beace67966b66 100644 (file)
@@ -217,7 +217,8 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
        loff_t pos;
 
        data = file->private_data;
-       snd_assert(data != NULL, return -ENXIO);
+       if (snd_BUG_ON(!data))
+               return -ENXIO;
        pos = *offset;
        if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
                return -EIO;
@@ -258,7 +259,8 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
        loff_t pos;
 
        data = file->private_data;
-       snd_assert(data != NULL, return -ENXIO);
+       if (snd_BUG_ON(!data))
+               return -ENXIO;
        entry = data->entry;
        pos = *offset;
        if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
@@ -614,7 +616,8 @@ int snd_info_card_create(struct snd_card *card)
        char str[8];
        struct snd_info_entry *entry;
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
 
        sprintf(str, "card%i", card->number);
        if ((entry = snd_info_create_module_entry(card->module, str, NULL)) == NULL)
@@ -636,7 +639,8 @@ int snd_info_card_register(struct snd_card *card)
 {
        struct proc_dir_entry *p;
 
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
 
        if (!strcmp(card->id, card->proc_root->name))
                return 0;
@@ -654,7 +658,8 @@ int snd_info_card_register(struct snd_card *card)
  */
 void snd_info_card_disconnect(struct snd_card *card)
 {
-       snd_assert(card != NULL, return);
+       if (!card)
+               return;
        mutex_lock(&info_mutex);
        if (card->proc_root_link) {
                snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
@@ -671,7 +676,8 @@ void snd_info_card_disconnect(struct snd_card *card)
  */
 int snd_info_card_free(struct snd_card *card)
 {
-       snd_assert(card != NULL, return -ENXIO);
+       if (!card)
+               return 0;
        snd_info_free_entry(card->proc_root);
        card->proc_root = NULL;
        return 0;
@@ -849,7 +855,7 @@ static void snd_info_disconnect(struct snd_info_entry *entry)
                return;
        list_del_init(&entry->list);
        root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
-       snd_assert(root, return);
+       snd_BUG_ON(!root);
        snd_remove_proc_entry(root, entry->p);
        entry->p = NULL;
 }
@@ -947,7 +953,8 @@ int snd_info_register(struct snd_info_entry * entry)
 {
        struct proc_dir_entry *root, *p = NULL;
 
-       snd_assert(entry != NULL, return -ENXIO);
+       if (snd_BUG_ON(!entry))
+               return -ENXIO;
        root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
        mutex_lock(&info_mutex);
        p = snd_create_proc_entry(entry->name, entry->mode, root);
index e35789a92752da3b48cf034b8e058b8fc9bfbfeb..e4af138d651af950488a40d5c9ad4f1435b602b8 100644 (file)
@@ -43,8 +43,10 @@ int snd_oss_info_register(int dev, int num, char *string)
 {
        char *x;
 
-       snd_assert(dev >= 0 && dev < SNDRV_OSS_INFO_DEV_COUNT, return -ENXIO);
-       snd_assert(num >= 0 && num < SNDRV_CARDS, return -ENXIO);
+       if (snd_BUG_ON(dev < 0 || dev >= SNDRV_OSS_INFO_DEV_COUNT))
+               return -ENXIO;
+       if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
+               return -ENXIO;
        mutex_lock(&strings);
        if (string == NULL) {
                if ((x = snd_sndstat_strings[num][dev]) != NULL) {
index df46bbc25dc2da7dccf2872abbae76837693e3ba..8af467df9245823a2ea5c96981e161d42ed63734 100644 (file)
@@ -545,7 +545,8 @@ int snd_card_register(struct snd_card *card)
 {
        int err;
 
-       snd_assert(card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card))
+               return -EINVAL;
 #ifndef CONFIG_SYSFS_DEPRECATED
        if (!card->card_dev) {
                card->card_dev = device_create_drvdata(sound_class, card->dev,
diff --git a/sound/core/jack.c b/sound/core/jack.c
new file mode 100644 (file)
index 0000000..8133a2b
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *  Jack abstraction layer
+ *
+ *  Copyright 2008 Wolfson Microelectronics
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/input.h>
+#include <sound/jack.h>
+#include <sound/core.h>
+
+static int snd_jack_dev_free(struct snd_device *device)
+{
+       struct snd_jack *jack = device->device_data;
+
+       /* If the input device is registered with the input subsystem
+        * then we need to use a different deallocator. */
+       if (jack->registered)
+               input_unregister_device(jack->input_dev);
+       else
+               input_free_device(jack->input_dev);
+
+       kfree(jack);
+
+       return 0;
+}
+
+static int snd_jack_dev_register(struct snd_device *device)
+{
+       struct snd_jack *jack = device->device_data;
+       struct snd_card *card = device->card;
+       int err;
+
+       snprintf(jack->name, sizeof(jack->name), "%s %s",
+                card->longname, jack->id);
+       jack->input_dev->name = jack->name;
+
+       /* Default to the sound card device. */
+       if (!jack->input_dev->dev.parent)
+               jack->input_dev->dev.parent = card->dev;
+
+       err = input_register_device(jack->input_dev);
+       if (err == 0)
+               jack->registered = 1;
+
+       return err;
+}
+
+/**
+ * snd_jack_new - Create a new jack
+ * @card:  the card instance
+ * @id:    an identifying string for this jack
+ * @type:  a bitmask of enum snd_jack_type values that can be detected by
+ *         this jack
+ * @jjack: Used to provide the allocated jack object to the caller.
+ *
+ * Creates a new jack object.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ * On success jjack will be initialised.
+ */
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+                struct snd_jack **jjack)
+{
+       struct snd_jack *jack;
+       int err;
+       static struct snd_device_ops ops = {
+               .dev_free = snd_jack_dev_free,
+               .dev_register = snd_jack_dev_register,
+       };
+
+       jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
+       if (jack == NULL)
+               return -ENOMEM;
+
+       jack->id = id;
+
+       jack->input_dev = input_allocate_device();
+       if (jack->input_dev == NULL) {
+               err = -ENOMEM;
+               goto fail_input;
+       }
+
+       jack->input_dev->phys = "ALSA";
+
+       jack->type = type;
+
+       if (type & SND_JACK_HEADPHONE)
+               input_set_capability(jack->input_dev, EV_SW,
+                                    SW_HEADPHONE_INSERT);
+       if (type & SND_JACK_MICROPHONE)
+               input_set_capability(jack->input_dev, EV_SW,
+                                    SW_MICROPHONE_INSERT);
+
+       err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
+       if (err < 0)
+               goto fail_input;
+
+       *jjack = jack;
+
+       return 0;
+
+fail_input:
+       input_free_device(jack->input_dev);
+       kfree(jack);
+       return err;
+}
+EXPORT_SYMBOL(snd_jack_new);
+
+/**
+ * snd_jack_set_parent - Set the parent device for a jack
+ *
+ * @jack:   The jack to configure
+ * @parent: The device to set as parent for the jack.
+ *
+ * Set the parent for the jack input device in the device tree.  This
+ * function is only valid prior to registration of the jack.  If no
+ * parent is configured then the parent device will be the sound card.
+ */
+void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
+{
+       WARN_ON(jack->registered);
+
+       jack->input_dev->dev.parent = parent;
+}
+EXPORT_SYMBOL(snd_jack_set_parent);
+
+/**
+ * snd_jack_report - Report the current status of a jack
+ *
+ * @jack:   The jack to report status for
+ * @status: The current status of the jack
+ */
+void snd_jack_report(struct snd_jack *jack, int status)
+{
+       if (jack->type & SND_JACK_HEADPHONE)
+               input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
+                                   status & SND_JACK_HEADPHONE);
+       if (jack->type & SND_JACK_MICROPHONE)
+               input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
+                                   status & SND_JACK_MICROPHONE);
+
+       input_sync(jack->input_dev);
+}
+EXPORT_SYMBOL(snd_jack_report);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Jack detection support for ALSA");
+MODULE_LICENSE("GPL");
index f5d6d8d129790d8729b82c1f7221616a7ea19f63..a7b46ec72f3231191cb6f81d7c816f6b011bc696 100644 (file)
@@ -43,14 +43,6 @@ MODULE_DESCRIPTION("Memory allocator for ALSA system.");
 MODULE_LICENSE("GPL");
 
 
-/*
- */
-
-void *snd_malloc_sgbuf_pages(struct device *device,
-                             size_t size, struct snd_dma_buffer *dmab,
-                            size_t *res_size);
-int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
-
 /*
  */
 
@@ -67,18 +59,6 @@ struct snd_mem_list {
 /* id for pre-allocated buffers */
 #define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
 
-#ifdef CONFIG_SND_DEBUG
-#define __ASTRING__(x) #x
-#define snd_assert(expr, args...) do {\
-       if (!(expr)) {\
-               printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
-               args;\
-       }\
-} while (0)
-#else
-#define snd_assert(expr, args...) /**/
-#endif
-
 /*
  *
  *  Generic memory allocators
@@ -111,8 +91,10 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
        int pg;
        void *res;
 
-       snd_assert(size > 0, return NULL);
-       snd_assert(gfp_flags != 0, return NULL);
+       if (WARN_ON(!size))
+               return NULL;
+       if (WARN_ON(!gfp_flags))
+               return NULL;
        gfp_flags |= __GFP_COMP;        /* compound page lets parts be mapped */
        pg = get_order(size);
        if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
@@ -152,8 +134,8 @@ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *d
        void *res;
        gfp_t gfp_flags;
 
-       snd_assert(size > 0, return NULL);
-       snd_assert(dma != NULL, return NULL);
+       if (WARN_ON(!dma))
+               return NULL;
        pg = get_order(size);
        gfp_flags = GFP_KERNEL
                | __GFP_COMP    /* compound page lets parts be mapped */
@@ -189,8 +171,8 @@ static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
        int pg;
        void *res;
 
-       snd_assert(size > 0, return NULL);
-       snd_assert(dma_addr != NULL, return NULL);
+       if (WARN_ON(!dma_addr))
+               return NULL;
        pg = get_order(size);
        res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
        if (res != NULL)
@@ -236,8 +218,10 @@ static void snd_free_sbus_pages(struct device *dev, size_t size,
 int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                        struct snd_dma_buffer *dmab)
 {
-       snd_assert(size > 0, return -ENXIO);
-       snd_assert(dmab != NULL, return -ENXIO);
+       if (WARN_ON(!size))
+               return -ENXIO;
+       if (WARN_ON(!dmab))
+               return -ENXIO;
 
        dmab->dev.type = type;
        dmab->dev.dev = device;
@@ -292,15 +276,17 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
 {
        int err;
 
-       snd_assert(size > 0, return -ENXIO);
-       snd_assert(dmab != NULL, return -ENXIO);
-
        while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
+               size_t aligned_size;
                if (err != -ENOMEM)
                        return err;
-               size >>= 1;
                if (size <= PAGE_SIZE)
                        return -ENOMEM;
+               aligned_size = PAGE_SIZE << get_order(size);
+               if (size != aligned_size)
+                       size = aligned_size;
+               else
+                       size >>= 1;
        }
        if (! dmab->area)
                return -ENOMEM;
@@ -353,7 +339,8 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
        struct snd_mem_list *mem;
 
-       snd_assert(dmab, return 0);
+       if (WARN_ON(!dmab))
+               return 0;
 
        mutex_lock(&list_mutex);
        list_for_each_entry(mem, &mem_list_head, list) {
@@ -387,7 +374,8 @@ int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
        struct snd_mem_list *mem;
 
-       snd_assert(dmab, return -EINVAL);
+       if (WARN_ON(!dmab))
+               return -EINVAL;
        mem = kmalloc(sizeof(*mem), GFP_KERNEL);
        if (! mem)
                return -ENOMEM;
index 9ded30d0e97da413c1ec244ec8aa205d0b010254..05b58d4fc2b72d6e2197171520567b9bf7dc16dc 100644 (file)
@@ -32,17 +32,18 @@ static snd_pcm_sframes_t copy_transfer(struct snd_pcm_plugin *plugin,
        unsigned int channel;
        unsigned int nchannels;
 
-       snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+               return -ENXIO;
        if (frames == 0)
                return 0;
        nchannels = plugin->src_format.channels;
        for (channel = 0; channel < nchannels; channel++) {
-               snd_assert(src_channels->area.first % 8 == 0 &&
-                          src_channels->area.step % 8 == 0,
-                          return -ENXIO);
-               snd_assert(dst_channels->area.first % 8 == 0 &&
-                          dst_channels->area.step % 8 == 0,
-                          return -ENXIO);
+               if (snd_BUG_ON(src_channels->area.first % 8 ||
+                              src_channels->area.step % 8))
+                       return -ENXIO;
+               if (snd_BUG_ON(dst_channels->area.first % 8 ||
+                              dst_channels->area.step % 8))
+                       return -ENXIO;
                if (!src_channels->enabled) {
                        if (dst_channels->wanted)
                                snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
@@ -66,15 +67,20 @@ int snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug,
        struct snd_pcm_plugin *plugin;
        int width;
 
-       snd_assert(r_plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!r_plugin))
+               return -ENXIO;
        *r_plugin = NULL;
 
-       snd_assert(src_format->format == dst_format->format, return -ENXIO);
-       snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-       snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+       if (snd_BUG_ON(src_format->format != dst_format->format))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->rate != dst_format->rate))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->channels != dst_format->channels))
+               return -ENXIO;
 
        width = snd_pcm_format_physical_width(src_format->format);
-       snd_assert(width > 0, return -ENXIO);
+       if (snd_BUG_ON(width <= 0))
+               return -ENXIO;
 
        err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
                                   0, &plugin);
index f874f6ca3657037121e1084858c9d002bbef3b44..6faa1d719206ffee96de25f563a0a70ec5de18c6 100644 (file)
@@ -39,14 +39,17 @@ static snd_pcm_sframes_t io_playback_transfer(struct snd_pcm_plugin *plugin,
                                    struct snd_pcm_plugin_channel *dst_channels,
                                    snd_pcm_uframes_t frames)
 {
-       snd_assert(plugin != NULL, return -ENXIO);
-       snd_assert(src_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin))
+               return -ENXIO;
+       if (snd_BUG_ON(!src_channels))
+               return -ENXIO;
        if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
                return pcm_write(plugin->plug, src_channels->area.addr, frames);
        } else {
                int channel, channels = plugin->dst_format.channels;
                void **bufs = (void**)plugin->extra_data;
-               snd_assert(bufs != NULL, return -ENXIO);
+               if (snd_BUG_ON(!bufs))
+                       return -ENXIO;
                for (channel = 0; channel < channels; channel++) {
                        if (src_channels[channel].enabled)
                                bufs[channel] = src_channels[channel].area.addr;
@@ -62,14 +65,17 @@ static snd_pcm_sframes_t io_capture_transfer(struct snd_pcm_plugin *plugin,
                                   struct snd_pcm_plugin_channel *dst_channels,
                                   snd_pcm_uframes_t frames)
 {
-       snd_assert(plugin != NULL, return -ENXIO);
-       snd_assert(dst_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin))
+               return -ENXIO;
+       if (snd_BUG_ON(!dst_channels))
+               return -ENXIO;
        if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
                return pcm_read(plugin->plug, dst_channels->area.addr, frames);
        } else {
                int channel, channels = plugin->dst_format.channels;
                void **bufs = (void**)plugin->extra_data;
-               snd_assert(bufs != NULL, return -ENXIO);
+               if (snd_BUG_ON(!bufs))
+                       return -ENXIO;
                for (channel = 0; channel < channels; channel++) {
                        if (dst_channels[channel].enabled)
                                bufs[channel] = dst_channels[channel].area.addr;
@@ -107,9 +113,11 @@ int snd_pcm_plugin_build_io(struct snd_pcm_substream *plug,
        struct snd_pcm_plugin_format format;
        struct snd_pcm_plugin *plugin;
 
-       snd_assert(r_plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!r_plugin))
+               return -ENXIO;
        *r_plugin = NULL;
-       snd_assert(plug != NULL && params != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plug || !params))
+               return -ENXIO;
        format.format = params_format(params);
        format.rate = params_rate(params);
        format.channels = params_channels(params);
index da3dbd41669eb9556699cfe3e7d1c9cbb20896b3..4c1d168271990a7a76bc70c921fe31ca4b5968f9 100644 (file)
@@ -92,7 +92,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
 {
        struct linear_priv *data;
 
-       snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+               return -ENXIO;
        data = (struct linear_priv *)plugin->extra_data;
        if (frames == 0)
                return 0;
@@ -100,12 +101,12 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
        {
                unsigned int channel;
                for (channel = 0; channel < plugin->src_format.channels; channel++) {
-                       snd_assert(src_channels[channel].area.first % 8 == 0 &&
-                                  src_channels[channel].area.step % 8 == 0,
-                                  return -ENXIO);
-                       snd_assert(dst_channels[channel].area.first % 8 == 0 &&
-                                  dst_channels[channel].area.step % 8 == 0,
-                                  return -ENXIO);
+                       if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+                                      src_channels[channel].area.step % 8))
+                               return -ENXIO;
+                       if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+                                      dst_channels[channel].area.step % 8))
+                               return -ENXIO;
                }
        }
 #endif
@@ -154,13 +155,17 @@ int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug,
        struct linear_priv *data;
        struct snd_pcm_plugin *plugin;
 
-       snd_assert(r_plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!r_plugin))
+               return -ENXIO;
        *r_plugin = NULL;
 
-       snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-       snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
-       snd_assert(snd_pcm_format_linear(src_format->format) &&
-                  snd_pcm_format_linear(dst_format->format), return -ENXIO);
+       if (snd_BUG_ON(src_format->rate != dst_format->rate))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->channels != dst_format->channels))
+               return -ENXIO;
+       if (snd_BUG_ON(!snd_pcm_format_linear(src_format->format) ||
+                      !snd_pcm_format_linear(dst_format->format)))
+               return -ENXIO;
 
        err = snd_pcm_plugin_build(plug, "linear format conversion",
                                   src_format, dst_format,
index 581aa2c60e6529fab85d27a3250151383e58f49f..4690b8b5681fee9b788e01318de01b63f39f22af 100644 (file)
@@ -257,8 +257,10 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
                result = pslot->get_volume(fmixer, pslot, &left, &right);
        if (!pslot->stereo)
                right = left;
-       snd_assert(left >= 0 && left <= 100, return -EIO);
-       snd_assert(right >= 0 && right <= 100, return -EIO);
+       if (snd_BUG_ON(left < 0 || left > 100))
+               return -EIO;
+       if (snd_BUG_ON(right < 0 || right > 100))
+               return -EIO;
        if (result >= 0) {
                pslot->volume[0] = left;
                pslot->volume[1] = right;
@@ -298,7 +300,8 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
        int __user *p = argp;
        int tmp;
 
-       snd_assert(fmixer != NULL, return -ENXIO);
+       if (snd_BUG_ON(!fmixer))
+               return -ENXIO;
        if (((cmd >> 8) & 0xff) == 'M') {
                switch (cmd) {
                case SOUND_MIXER_INFO:
@@ -368,7 +371,8 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l
 {
        struct snd_mixer_oss_file fmixer;
        
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        if (card->mixer_oss == NULL)
                return -ENXIO;
        memset(&fmixer, 0, sizeof(fmixer));
@@ -1284,9 +1288,11 @@ static int snd_mixer_oss_free1(void *private)
        struct snd_card *card;
        int idx;
  
-       snd_assert(mixer != NULL, return -ENXIO);
+       if (!mixer)
+               return 0;
        card = mixer->card;
-       snd_assert(mixer == card->mixer_oss, return -ENXIO);
+       if (snd_BUG_ON(mixer != card->mixer_oss))
+               return -ENXIO;
        card->mixer_oss = NULL;
        for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
                struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
index 77f96194a0eda5eff6ed2cb3e66ae32d5207f88f..f7649d4d950bcdd2555a3633019428536a87fbbd 100644 (file)
@@ -252,19 +252,20 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
 {
        struct mulaw_priv *data;
 
-       snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+               return -ENXIO;
        if (frames == 0)
                return 0;
 #ifdef CONFIG_SND_DEBUG
        {
                unsigned int channel;
                for (channel = 0; channel < plugin->src_format.channels; channel++) {
-                       snd_assert(src_channels[channel].area.first % 8 == 0 &&
-                                  src_channels[channel].area.step % 8 == 0,
-                                  return -ENXIO);
-                       snd_assert(dst_channels[channel].area.first % 8 == 0 &&
-                                  dst_channels[channel].area.step % 8 == 0,
-                                  return -ENXIO);
+                       if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+                                      src_channels[channel].area.step % 8))
+                               return -ENXIO;
+                       if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+                                      dst_channels[channel].area.step % 8))
+                               return -ENXIO;
                }
        }
 #endif
@@ -305,11 +306,14 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
        struct snd_pcm_plugin_format *format;
        mulaw_f func;
 
-       snd_assert(r_plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!r_plugin))
+               return -ENXIO;
        *r_plugin = NULL;
 
-       snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-       snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+       if (snd_BUG_ON(src_format->rate != dst_format->rate))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->channels != dst_format->channels))
+               return -ENXIO;
 
        if (dst_format->format == SNDRV_PCM_FORMAT_MU_LAW) {
                format = src_format;
@@ -323,7 +327,8 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
                snd_BUG();
                return -EINVAL;
        }
-       snd_assert(snd_pcm_format_linear(format->format) != 0, return -ENXIO);
+       if (snd_BUG_ON(!snd_pcm_format_linear(format->format)))
+               return -ENXIO;
 
        err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
                                   src_format, dst_format,
index 4c601b192ddf3feb4117186d230a73f4538f1723..1af62b8b86c6366321a2a707b76f6bcf6ae3e545 100644 (file)
@@ -452,7 +452,8 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
        } else {
                *params = *save;
                max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-               snd_assert(max >= 0, return -EINVAL);
+               if (max < 0)
+                       return max;
                last = 1;
        }
  _end:
@@ -461,7 +462,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
                v = snd_pcm_hw_param_last(pcm, params, var, dir);
        else
                v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       snd_assert(v >= 0, return -EINVAL);
+       snd_BUG_ON(v < 0);
        return v;
 }
 
@@ -778,7 +779,8 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
        while (oss_period_size * oss_periods > oss_buffer_size)
                oss_period_size /= 2;
 
-       snd_assert(oss_period_size >= 16, return -EINVAL);
+       if (oss_period_size < 16)
+               return -EINVAL;
        runtime->oss.period_bytes = oss_period_size;
        runtime->oss.period_frames = 1;
        runtime->oss.periods = oss_periods;
@@ -895,7 +897,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                }
        }
        err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
-       snd_assert(err >= 0, goto failure);
+       if (err < 0)
+               goto failure;
 
        if (direct) {
                memcpy(params, sparams, sizeof(*params));
@@ -958,11 +961,13 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
 
        n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
        err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
-       snd_assert(err >= 0, goto failure);
+       if (err < 0)
+               goto failure;
 
        err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
                                     runtime->oss.periods, NULL);
-       snd_assert(err >= 0, goto failure);
+       if (err < 0)
+               goto failure;
 
        snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
 
@@ -1006,7 +1011,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
 
        runtime->oss.periods = params_periods(sparams);
        oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
-       snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
+       if (oss_period_size < 0) {
+               err = -EINVAL;
+               goto failure;
+       }
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
        if (runtime->oss.plugin_first) {
                err = snd_pcm_plug_alloc(substream, oss_period_size);
@@ -1017,7 +1025,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        oss_period_size *= oss_frame_size;
 
        oss_buffer_size = oss_period_size * runtime->oss.periods;
-       snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
+       if (oss_buffer_size < 0) {
+               err = -EINVAL;
+               goto failure;
+       }
 
        runtime->oss.period_bytes = oss_period_size;
        runtime->oss.buffer_bytes = oss_buffer_size;
@@ -1069,7 +1080,8 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
                                return err;
                }
        }
-       snd_assert(asubstream != NULL, return -EIO);
+       if (!asubstream)
+               return -EIO;
        if (r_substream)
                *r_substream = asubstream;
        return 0;
@@ -1764,7 +1776,8 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
        err = snd_pcm_hw_refine(substream, params);
        format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 
        kfree(params);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        for (fmt = 0; fmt < 32; ++fmt) {
                if (snd_mask_test(&format_mask, fmt)) {
                        int f = snd_pcm_oss_format_to(fmt);
@@ -2250,7 +2263,8 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
 {
        int cidx;
-       snd_assert(pcm_oss_file != NULL, return -ENXIO);
+       if (!pcm_oss_file)
+               return 0;
        for (cidx = 0; cidx < 2; ++cidx) {
                struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
                if (substream)
@@ -2271,8 +2285,8 @@ static int snd_pcm_oss_open_file(struct file *file,
        struct snd_pcm_substream *substream;
        unsigned int f_mode = file->f_mode;
 
-       snd_assert(rpcm_oss_file != NULL, return -EINVAL);
-       *rpcm_oss_file = NULL;
+       if (rpcm_oss_file)
+               *rpcm_oss_file = NULL;
 
        pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
        if (pcm_oss_file == NULL)
@@ -2312,7 +2326,8 @@ static int snd_pcm_oss_open_file(struct file *file,
        }
 
        file->private_data = pcm_oss_file;
-       *rpcm_oss_file = pcm_oss_file;
+       if (rpcm_oss_file)
+               *rpcm_oss_file = pcm_oss_file;
        return 0;
 }
 
@@ -2321,7 +2336,8 @@ static int snd_task_name(struct task_struct *task, char *name, size_t size)
 {
        unsigned int idx;
 
-       snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
+       if (snd_BUG_ON(!task || !name || size < 2))
+               return -EINVAL;
        for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
                name[idx] = task->comm[idx];
        name[idx] = '\0';
@@ -2415,7 +2431,8 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream == NULL)
                substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
-       snd_assert(substream != NULL, return -ENXIO);
+       if (snd_BUG_ON(!substream))
+               return -ENXIO;
        pcm = substream->pcm;
        if (!pcm->card->shutdown)
                snd_pcm_oss_sync(pcm_oss_file);
@@ -2448,7 +2465,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
                        if (substream != NULL)
                                break;
                }
-               snd_assert(substream != NULL, return -ENXIO);
+               if (snd_BUG_ON(idx >= 2))
+                       return -ENXIO;
                return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
        }
 #endif
index bec94138205edf3aad8266d7239100a5aef3d8a3..6751daa3bb507fe9dd3007e2013dff63a4a701ee 100644 (file)
@@ -62,7 +62,8 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t
        if ((width = snd_pcm_format_physical_width(format->format)) < 0)
                return width;
        size = frames * format->channels * width;
-       snd_assert((size % 8) == 0, return -ENXIO);
+       if (snd_BUG_ON(size % 8))
+               return -ENXIO;
        size /= 8;
        if (plugin->buf_frames < frames) {
                vfree(plugin->buf);
@@ -84,7 +85,8 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t
                        c->area.step = format->channels * width;
                }
        } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
-               snd_assert((size % format->channels) == 0,);
+               if (snd_BUG_ON(size % format->channels))
+                       return -EINVAL;
                size /= format->channels;
                for (channel = 0; channel < format->channels; channel++, c++) {
                        c->frames = frames;
@@ -102,13 +104,15 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t
 int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
 {
        int err;
-       snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO);
+       if (snd_BUG_ON(!snd_pcm_plug_first(plug)))
+               return -ENXIO;
        if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
                struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
                while (plugin->next) {
                        if (plugin->dst_frames)
                                frames = plugin->dst_frames(plugin, frames);
-                       snd_assert(frames > 0, return -ENXIO);
+                       if (snd_BUG_ON(frames <= 0))
+                               return -ENXIO;
                        plugin = plugin->next;
                        err = snd_pcm_plugin_alloc(plugin, frames);
                        if (err < 0)
@@ -119,7 +123,8 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
                while (plugin->prev) {
                        if (plugin->src_frames)
                                frames = plugin->src_frames(plugin, frames);
-                       snd_assert(frames > 0, return -ENXIO);
+                       if (snd_BUG_ON(frames <= 0))
+                               return -ENXIO;
                        plugin = plugin->prev;
                        err = snd_pcm_plugin_alloc(plugin, frames);
                        if (err < 0)
@@ -148,8 +153,10 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
        struct snd_pcm_plugin *plugin;
        unsigned int channels;
        
-       snd_assert(plug != NULL, return -ENXIO);
-       snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plug))
+               return -ENXIO;
+       if (snd_BUG_ON(!src_format || !dst_format))
+               return -ENXIO;
        plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
        if (plugin == NULL)
                return -ENOMEM;
@@ -159,10 +166,10 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
        plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
        plugin->src_format = *src_format;
        plugin->src_width = snd_pcm_format_physical_width(src_format->format);
-       snd_assert(plugin->src_width > 0, );
+       snd_BUG_ON(plugin->src_width <= 0);
        plugin->dst_format = *dst_format;
        plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
-       snd_assert(plugin->dst_width > 0, );
+       snd_BUG_ON(plugin->dst_width <= 0);
        if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
                channels = src_format->channels;
        else
@@ -194,7 +201,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p
        struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
        int stream = snd_pcm_plug_stream(plug);
 
-       snd_assert(plug != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plug))
+               return -ENXIO;
        if (drv_frames == 0)
                return 0;
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -224,7 +232,8 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
        snd_pcm_sframes_t frames;
        int stream = snd_pcm_plug_stream(plug);
        
-       snd_assert(plug != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plug))
+               return -ENXIO;
        if (clt_frames == 0)
                return 0;
        frames = clt_frames;
@@ -540,7 +549,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu
        int width, nchannels, channel;
        int stream = snd_pcm_plug_stream(plug);
 
-       snd_assert(buf != NULL, return -ENXIO);
+       if (snd_BUG_ON(!buf))
+               return -ENXIO;
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                plugin = snd_pcm_plug_first(plug);
                format = &plugin->src_format;
@@ -553,7 +563,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu
        if ((width = snd_pcm_format_physical_width(format->format)) < 0)
                return width;
        nchannels = format->channels;
-       snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO);
+       if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
+                      format->channels > 1))
+               return -ENXIO;
        for (channel = 0; channel < nchannels; channel++, v++) {
                v->frames = count;
                v->enabled = 1;
index 14dfb3175d84548f9ef1ccdcde84517cb137a635..a466443c4a2649b819147e70d9f041bc1f25b38b 100644 (file)
@@ -185,7 +185,8 @@ static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_
        struct rate_priv *data;
        snd_pcm_sframes_t res;
 
-       snd_assert(plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin))
+               return -ENXIO;
        if (frames == 0)
                return 0;
        data = (struct rate_priv *)plugin->extra_data;
@@ -217,7 +218,8 @@ static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_
        struct rate_priv *data;
        snd_pcm_sframes_t res;
 
-       snd_assert(plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin))
+               return -ENXIO;
        if (frames == 0)
                return 0;
        data = (struct rate_priv *)plugin->extra_data;
@@ -252,19 +254,20 @@ static snd_pcm_sframes_t rate_transfer(struct snd_pcm_plugin *plugin,
        snd_pcm_uframes_t dst_frames;
        struct rate_priv *data;
 
-       snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+               return -ENXIO;
        if (frames == 0)
                return 0;
 #ifdef CONFIG_SND_DEBUG
        {
                unsigned int channel;
                for (channel = 0; channel < plugin->src_format.channels; channel++) {
-                       snd_assert(src_channels[channel].area.first % 8 == 0 &&
-                                  src_channels[channel].area.step % 8 == 0,
-                                  return -ENXIO);
-                       snd_assert(dst_channels[channel].area.first % 8 == 0 &&
-                                  dst_channels[channel].area.step % 8 == 0,
-                                  return -ENXIO);
+                       if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+                                      src_channels[channel].area.step % 8))
+                               return -ENXIO;
+                       if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+                                      dst_channels[channel].area.step % 8))
+                               return -ENXIO;
                }
        }
 #endif
@@ -281,7 +284,8 @@ static int rate_action(struct snd_pcm_plugin *plugin,
                       enum snd_pcm_plugin_action action,
                       unsigned long udata)
 {
-       snd_assert(plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin))
+               return -ENXIO;
        switch (action) {
        case INIT:
        case PREPARE:
@@ -302,14 +306,20 @@ int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
        struct rate_priv *data;
        struct snd_pcm_plugin *plugin;
 
-       snd_assert(r_plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!r_plugin))
+               return -ENXIO;
        *r_plugin = NULL;
 
-       snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
-       snd_assert(src_format->channels > 0, return -ENXIO);
-       snd_assert(src_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
-       snd_assert(dst_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
-       snd_assert(src_format->rate != dst_format->rate, return -ENXIO);
+       if (snd_BUG_ON(src_format->channels != dst_format->channels))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->channels <= 0))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->format != SNDRV_PCM_FORMAT_S16))
+               return -ENXIO;
+       if (snd_BUG_ON(dst_format->format != SNDRV_PCM_FORMAT_S16))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->rate == dst_format->rate))
+               return -ENXIO;
 
        err = snd_pcm_plugin_build(plug, "rate conversion",
                                   src_format, dst_format,
index da7ab7a3e82cdd51d51a11cc3e2bf935bbc464c9..0dcc2870d537752c98de1014df65330f051e9dfe 100644 (file)
@@ -54,7 +54,8 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
        struct snd_pcm_plugin_channel *dvp;
        int format;
 
-       snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+       if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+               return -ENXIO;
        if (frames == 0)
                return 0;
 
@@ -90,10 +91,13 @@ int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug,
        struct snd_pcm_plugin *plugin;
        int err;
 
-       snd_assert(r_plugin != NULL, return -ENXIO);
+       if (snd_BUG_ON(!r_plugin))
+               return -ENXIO;
        *r_plugin = NULL;
-       snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-       snd_assert(src_format->format == dst_format->format, return -ENXIO);
+       if (snd_BUG_ON(src_format->rate != dst_format->rate))
+               return -ENXIO;
+       if (snd_BUG_ON(src_format->format != dst_format->format))
+               return -ENXIO;
 
        err = snd_pcm_plugin_build(plug, "route conversion",
                                   src_format, dst_format, 0, &plugin);
index ece25c718e95e8f78c5a71b01df6e01e80519908..192a433a240309bd1ce4e977cfa3c6f34d646a85 100644 (file)
@@ -42,7 +42,7 @@ static int snd_pcm_dev_free(struct snd_device *device);
 static int snd_pcm_dev_register(struct snd_device *device);
 static int snd_pcm_dev_disconnect(struct snd_device *device);
 
-static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
+static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
 {
        struct snd_pcm *pcm;
 
@@ -53,6 +53,37 @@ static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
        return NULL;
 }
 
+static int snd_pcm_next(struct snd_card *card, int device)
+{
+       struct snd_pcm *pcm;
+
+       list_for_each_entry(pcm, &snd_pcm_devices, list) {
+               if (pcm->card == card && pcm->device > device)
+                       return pcm->device;
+               else if (pcm->card->number > card->number)
+                       return -1;
+       }
+       return -1;
+}
+
+static int snd_pcm_add(struct snd_pcm *newpcm)
+{
+       struct snd_pcm *pcm;
+
+       list_for_each_entry(pcm, &snd_pcm_devices, list) {
+               if (pcm->card == newpcm->card && pcm->device == newpcm->device)
+                       return -EBUSY;
+               if (pcm->card->number > newpcm->card->number ||
+                               (pcm->card == newpcm->card &&
+                               pcm->device > newpcm->device)) {
+                       list_add(&newpcm->list, pcm->list.prev);
+                       return 0;
+               }
+       }
+       list_add_tail(&newpcm->list, &snd_pcm_devices);
+       return 0;
+}
+
 static int snd_pcm_control_ioctl(struct snd_card *card,
                                 struct snd_ctl_file *control,
                                 unsigned int cmd, unsigned long arg)
@@ -65,14 +96,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        if (get_user(device, (int __user *)arg))
                                return -EFAULT;
                        mutex_lock(&register_mutex);
-                       device = device < 0 ? 0 : device + 1;
-                       while (device < SNDRV_PCM_DEVICES) {
-                               if (snd_pcm_search(card, device))
-                                       break;
-                               device++;
-                       }
-                       if (device == SNDRV_PCM_DEVICES)
-                               device = -1;
+                       device = snd_pcm_next(card, device);
                        mutex_unlock(&register_mutex);
                        if (put_user(device, (int __user *)arg))
                                return -EFAULT;
@@ -98,7 +122,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        if (get_user(subdevice, &info->subdevice))
                                return -EFAULT;
                        mutex_lock(&register_mutex);
-                       pcm = snd_pcm_search(card, device);
+                       pcm = snd_pcm_get(card, device);
                        if (pcm == NULL) {
                                err = -ENXIO;
                                goto _error;
@@ -232,7 +256,6 @@ static char *snd_pcm_tstamp_mode_names[] = {
 
 static const char *snd_pcm_stream_name(int stream)
 {
-       snd_assert(stream <= SNDRV_PCM_STREAM_LAST, return NULL);
        return snd_pcm_stream_names[stream];
 }
 
@@ -248,7 +271,6 @@ static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
 
 static const char *snd_pcm_tstamp_mode_name(int mode)
 {
-       snd_assert(mode <= SNDRV_PCM_TSTAMP_LAST, return NULL);
        return snd_pcm_tstamp_mode_names[mode];
 }
 
@@ -682,9 +704,10 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
                .dev_disconnect = snd_pcm_dev_disconnect,
        };
 
-       snd_assert(rpcm != NULL, return -EINVAL);
-       *rpcm = NULL;
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
+       if (rpcm)
+               *rpcm = NULL;
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
        if (pcm == NULL) {
                snd_printk(KERN_ERR "Cannot allocate PCM\n");
@@ -708,7 +731,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
                snd_pcm_free(pcm);
                return err;
        }
-       *rpcm = pcm;
+       if (rpcm)
+               *rpcm = pcm;
        return 0;
 }
 
@@ -742,7 +766,8 @@ static int snd_pcm_free(struct snd_pcm *pcm)
 {
        struct snd_pcm_notify *notify;
 
-       snd_assert(pcm != NULL, return -ENXIO);
+       if (!pcm)
+               return 0;
        list_for_each_entry(notify, &snd_pcm_notify_list, list) {
                notify->n_unregister(pcm);
        }
@@ -773,9 +798,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        int prefer_subdevice = -1;
        size_t size;
 
-       snd_assert(rsubstream != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pcm || !rsubstream))
+               return -ENXIO;
        *rsubstream = NULL;
-       snd_assert(pcm != NULL, return -ENXIO);
        pstr = &pcm->streams[stream];
        if (pstr->substream == NULL || pstr->substream_count == 0)
                return -ENODEV;
@@ -883,8 +908,9 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
 
+       if (PCM_RUNTIME_CHECK(substream))
+               return;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return);
        if (runtime->private_free != NULL)
                runtime->private_free(runtime);
        snd_free_pages((void*)runtime->status,
@@ -929,13 +955,14 @@ static int snd_pcm_dev_register(struct snd_device *device)
        struct snd_pcm *pcm = device->device_data;
        struct device *dev;
 
-       snd_assert(pcm != NULL && device != NULL, return -ENXIO);
+       if (snd_BUG_ON(!pcm || !device))
+               return -ENXIO;
        mutex_lock(&register_mutex);
-       if (snd_pcm_search(pcm->card, pcm->device)) {
+       err = snd_pcm_add(pcm);
+       if (err) {
                mutex_unlock(&register_mutex);
-               return -EBUSY;
+               return err;
        }
-       list_add_tail(&pcm->list, &snd_pcm_devices);
        for (cidx = 0; cidx < 2; cidx++) {
                int devtype = -1;
                if (pcm->streams[cidx].substream == NULL)
@@ -1019,10 +1046,11 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 {
        struct snd_pcm *pcm;
 
-       snd_assert(notify != NULL &&
-                  notify->n_register != NULL &&
-                  notify->n_unregister != NULL &&
-                  notify->n_disconnect, return -EINVAL);
+       if (snd_BUG_ON(!notify ||
+                      !notify->n_register ||
+                      !notify->n_unregister ||
+                      !notify->n_disconnect))
+               return -EINVAL;
        mutex_lock(&register_mutex);
        if (nfree) {
                list_del(&notify->list);
index 49aa693fba8adb8507d892a3fdc8081960d8c4ce..36d7a5998234f472bec63b603bc5e7366f07f90d 100644 (file)
@@ -397,7 +397,8 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
        snd_pcm_uframes_t boundary;
        int err;
 
-       snd_assert(runtime, return -EINVAL);
+       if (snd_BUG_ON(!runtime))
+               return -EINVAL;
 
        if (get_user(sflags, &src->flags) ||
            get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
index 1533f0379e9d57abe850c0e636952afa5ccc397c..6ea5cfb83998ad04fa0678ab522b4e734a737180 100644 (file)
@@ -85,7 +85,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                }
                frames = runtime->buffer_size - runtime->silence_filled;
        }
-       snd_assert(frames <= runtime->buffer_size, return);
+       if (snd_BUG_ON(frames > runtime->buffer_size))
+               return;
        if (frames == 0)
                return;
        ofs = runtime->silence_start % runtime->buffer_size;
@@ -96,7 +97,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                        if (substream->ops->silence) {
                                int err;
                                err = substream->ops->silence(substream, -1, ofs, transfer);
-                               snd_assert(err >= 0, );
+                               snd_BUG_ON(err < 0);
                        } else {
                                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
                                snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
@@ -108,7 +109,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                                for (c = 0; c < channels; ++c) {
                                        int err;
                                        err = substream->ops->silence(substream, c, ofs, transfer);
-                                       snd_assert(err >= 0, );
+                                       snd_BUG_ON(err < 0);
                                }
                        } else {
                                size_t dma_csize = runtime->dma_bytes / channels;
@@ -354,7 +355,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
 {
        u_int64_t n = (u_int64_t) a * b;
        if (c == 0) {
-               snd_assert(n > 0, );
+               snd_BUG_ON(!n);
                *r = 0;
                return UINT_MAX;
        }
@@ -380,7 +381,8 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 {
        int changed = 0;
-       snd_assert(!snd_interval_empty(i), return -EINVAL);
+       if (snd_BUG_ON(snd_interval_empty(i)))
+               return -EINVAL;
        if (i->min < v->min) {
                i->min = v->min;
                i->openmin = v->openmin;
@@ -423,7 +425,8 @@ EXPORT_SYMBOL(snd_interval_refine);
 
 static int snd_interval_refine_first(struct snd_interval *i)
 {
-       snd_assert(!snd_interval_empty(i), return -EINVAL);
+       if (snd_BUG_ON(snd_interval_empty(i)))
+               return -EINVAL;
        if (snd_interval_single(i))
                return 0;
        i->max = i->min;
@@ -435,7 +438,8 @@ static int snd_interval_refine_first(struct snd_interval *i)
 
 static int snd_interval_refine_last(struct snd_interval *i)
 {
-       snd_assert(!snd_interval_empty(i), return -EINVAL);
+       if (snd_BUG_ON(snd_interval_empty(i)))
+               return -EINVAL;
        if (snd_interval_single(i))
                return 0;
        i->min = i->max;
@@ -889,7 +893,8 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
        c->private = private;
        k = 0;
        while (1) {
-               snd_assert(k < ARRAY_SIZE(c->deps), return -EINVAL);
+               if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps)))
+                       return -EINVAL;
                c->deps[k++] = dep;
                if (dep < 0)
                        break;
@@ -1285,7 +1290,8 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               snd_assert(err >= 0, return err);
+               if (snd_BUG_ON(err < 0))
+                       return err;
        }
        return snd_pcm_hw_param_value(params, var, dir);
 }
@@ -1330,7 +1336,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               snd_assert(err >= 0, return err);
+               if (snd_BUG_ON(err < 0))
+                       return err;
        }
        return snd_pcm_hw_param_value(params, var, dir);
 }
@@ -1368,7 +1375,8 @@ int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
                        err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
                else
                        err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
-               snd_assert(err >= 0, return err);
+               if (snd_BUG_ON(err < 0))
+                       return err;
        }
        return 0;
 }
@@ -1466,9 +1474,9 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime;
        unsigned long flags;
 
-       snd_assert(substream != NULL, return);
+       if (PCM_RUNTIME_CHECK(substream))
+               return;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return);
 
        if (runtime->transfer_ack_begin)
                runtime->transfer_ack_begin(substream);
@@ -1567,7 +1575,6 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
                        return err;
        } else {
                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-               snd_assert(runtime->dma_area, return -EFAULT);
                if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
                        return -EFAULT;
        }
@@ -1629,7 +1636,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
                if (frames > cont)
                        frames = cont;
-               snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+               if (snd_BUG_ON(!frames)) {
+                       snd_pcm_stream_unlock_irq(substream);
+                       return -EINVAL;
+               }
                appl_ptr = runtime->control->appl_ptr;
                appl_ofs = appl_ptr % runtime->buffer_size;
                snd_pcm_stream_unlock_irq(substream);
@@ -1669,18 +1679,30 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
-snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
+/* sanity-check for read/write methods */
+static int pcm_sanity_check(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
-       int nonblock;
-
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
+       if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
+               return -EINVAL;
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
+       return 0;
+}
+
+snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
+{
+       struct snd_pcm_runtime *runtime;
+       int nonblock;
+       int err;
 
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
+       runtime = substream->runtime;
        nonblock = !!(substream->f_flags & O_NONBLOCK);
 
        if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
@@ -1703,7 +1725,8 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
        int channels = runtime->channels;
        int c;
        if (substream->ops->copy) {
-               snd_assert(substream->ops->silence != NULL, return -EINVAL);
+               if (snd_BUG_ON(!substream->ops->silence))
+                       return -EINVAL;
                for (c = 0; c < channels; ++c, ++bufs) {
                        if (*bufs == NULL) {
                                if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
@@ -1717,7 +1740,6 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
        } else {
                /* default transfer behaviour */
                size_t dma_csize = runtime->dma_bytes / channels;
-               snd_assert(runtime->dma_area, return -EFAULT);
                for (c = 0; c < channels; ++c, ++bufs) {
                        char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
                        if (*bufs == NULL) {
@@ -1738,14 +1760,12 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime;
        int nonblock;
+       int err;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-       if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-               return -EBADFD;
-
        nonblock = !!(substream->f_flags & O_NONBLOCK);
 
        if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
@@ -1769,7 +1789,6 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
                        return err;
        } else {
                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-               snd_assert(runtime->dma_area, return -EFAULT);
                if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
                        return -EFAULT;
        }
@@ -1841,7 +1860,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
                if (frames > cont)
                        frames = cont;
-               snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+               if (snd_BUG_ON(!frames)) {
+                       snd_pcm_stream_unlock_irq(substream);
+                       return -EINVAL;
+               }
                appl_ptr = runtime->control->appl_ptr;
                appl_ofs = appl_ptr % runtime->buffer_size;
                snd_pcm_stream_unlock_irq(substream);
@@ -1879,14 +1901,12 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
 {
        struct snd_pcm_runtime *runtime;
        int nonblock;
+       int err;
        
-       snd_assert(substream != NULL, return -ENXIO);
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-       if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-               return -EBADFD;
-
        nonblock = !!(substream->f_flags & O_NONBLOCK);
        if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
                return -EINVAL;
@@ -1916,7 +1936,6 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
                }
        } else {
                snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
-               snd_assert(runtime->dma_area, return -EFAULT);
                for (c = 0; c < channels; ++c, ++bufs) {
                        char *hwbuf;
                        char __user *buf;
@@ -1938,11 +1957,12 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime;
        int nonblock;
+       int err;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
 
index ff07b4a9992e80e4ad65bb3c1dac6a353020ad68..a6d42808828c7d87d233f61782e753c7e99ba646 100644 (file)
@@ -50,8 +50,6 @@ static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t siz
        struct snd_dma_buffer *dmab = &substream->dma_buffer;
        int err;
 
-       snd_assert(size > 0, return -EINVAL);
-
        /* already reserved? */
        if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) {
                if (dmab->bytes >= size)
@@ -326,6 +324,32 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
 
 EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 
+/*
+ * compute the max chunk size with continuous pages on sg-buffer
+ */
+unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
+                                         unsigned int ofs, unsigned int size)
+{
+       struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
+       unsigned int start, end, pg;
+
+       start = ofs >> PAGE_SHIFT;
+       end = (ofs + size - 1) >> PAGE_SHIFT;
+       /* check page continuity */
+       pg = sg->table[start].addr >> PAGE_SHIFT;
+       for (;;) {
+               start++;
+               if (start > end)
+                       break;
+               pg++;
+               if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
+                       return (start << PAGE_SHIFT) - ofs;
+       }
+       /* ok, all on continuous pages */
+       return size;
+}
+EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);
+
 /**
  * snd_pcm_lib_malloc_pages - allocate the DMA buffer
  * @substream: the substream to allocate the DMA buffer to
@@ -342,10 +366,12 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
        struct snd_pcm_runtime *runtime;
        struct snd_dma_buffer *dmab = NULL;
 
-       snd_assert(substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_UNKNOWN, return -EINVAL);
-       snd_assert(substream != NULL, return -EINVAL);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -EINVAL;
+       if (snd_BUG_ON(substream->dma_buffer.dev.type ==
+                      SNDRV_DMA_TYPE_UNKNOWN))
+               return -EINVAL;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -EINVAL);
 
        if (runtime->dma_buffer_p) {
                /* perphaps, we might free the large DMA memory region
@@ -391,9 +417,9 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
 
-       snd_assert(substream != NULL, return -EINVAL);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -EINVAL;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -EINVAL);
        if (runtime->dma_area == NULL)
                return 0;
        if (runtime->dma_buffer_p != &substream->dma_buffer) {
index c487025d345777d56ba228918bbc95eb9564cd05..e61e12506ded711b6a1f06583210e90e3e5d76a8 100644 (file)
@@ -95,7 +95,6 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
        struct snd_pcm *pcm = substream->pcm;
        struct snd_pcm_str *pstr = substream->pstr;
 
-       snd_assert(substream != NULL, return -ENXIO);
        memset(info, 0, sizeof(*info));
        info->card = pcm->card->number;
        info->device = pcm->device;
@@ -370,9 +369,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        unsigned int bits;
        snd_pcm_uframes_t frames;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
        snd_pcm_stream_lock_irq(substream);
        switch (runtime->status->state) {
        case SNDRV_PCM_STATE_OPEN:
@@ -490,9 +489,9 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime;
        int result = 0;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
        snd_pcm_stream_lock_irq(substream);
        switch (runtime->status->state) {
        case SNDRV_PCM_STATE_SETUP:
@@ -518,9 +517,9 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
        snd_pcm_stream_lock_irq(substream);
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                snd_pcm_stream_unlock_irq(substream);
@@ -622,11 +621,8 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
                               struct snd_pcm_status __user * _status)
 {
        struct snd_pcm_status status;
-       struct snd_pcm_runtime *runtime;
        int res;
        
-       snd_assert(substream != NULL, return -ENXIO);
-       runtime = substream->runtime;
        memset(&status, 0, sizeof(status));
        res = snd_pcm_status(substream, &status);
        if (res < 0)
@@ -642,7 +638,6 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime;
        unsigned int channel;
        
-       snd_assert(substream != NULL, return -ENXIO);
        channel = info->channel;
        runtime = substream->runtime;
        snd_pcm_stream_lock_irq(substream);
@@ -1250,7 +1245,6 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
        int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
        if (err < 0)
                return err;
-       // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, );
        runtime->hw_ptr_base = 0;
        runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
                runtime->status->hw_ptr % runtime->period_size;
@@ -1421,7 +1415,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
        int i, num_drecs;
        struct drain_rec *drec, drec_tmp, *d;
 
-       snd_assert(substream != NULL, return -ENXIO);
        card = substream->pcm->card;
        runtime = substream->runtime;
 
@@ -1541,7 +1534,8 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
        struct snd_card *card;
        int result = 0;
        
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
        card = substream->pcm->card;
 
@@ -1934,33 +1928,41 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
                        mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX;
        }
        err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);
-       snd_assert(err >= 0, return -EINVAL);
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
-       snd_assert(err >= 0, return -EINVAL);
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
-       snd_assert(err >= 0, return -EINVAL);
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
                                           hw->channels_min, hw->channels_max);
-       snd_assert(err >= 0, return -EINVAL);
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
                                           hw->rate_min, hw->rate_max);
-       snd_assert(err >= 0, return -EINVAL);
+        if (err < 0)
+                return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
                                           hw->period_bytes_min, hw->period_bytes_max);
-       snd_assert(err >= 0, return -EINVAL);
+        if (err < 0)
+                return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
                                           hw->periods_min, hw->periods_max);
-       snd_assert(err >= 0, return -EINVAL);
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
                                           hw->period_bytes_min, hw->buffer_bytes_max);
-       snd_assert(err >= 0, return -EINVAL);
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 
                                  snd_pcm_hw_rule_buffer_bytes_max, substream,
@@ -1971,7 +1973,8 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
        /* FIXME: remove */
        if (runtime->dma_bytes) {
                err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
-               snd_assert(err >= 0, return -EINVAL);
+               if (err < 0)
+                       return -EINVAL;
        }
 
        if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
@@ -2067,8 +2070,8 @@ static int snd_pcm_open_file(struct file *file,
        struct snd_pcm_str *str;
        int err;
 
-       snd_assert(rpcm_file != NULL, return -EINVAL);
-       *rpcm_file = NULL;
+       if (rpcm_file)
+               *rpcm_file = NULL;
 
        err = snd_pcm_open_substream(pcm, stream, file, &substream);
        if (err < 0)
@@ -2086,7 +2089,8 @@ static int snd_pcm_open_file(struct file *file,
                substream->pcm_release = pcm_release_private;
        }
        file->private_data = pcm_file;
-       *rpcm_file = pcm_file;
+       if (rpcm_file)
+               *rpcm_file = pcm_file;
        return 0;
 }
 
@@ -2170,7 +2174,8 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
 
        pcm_file = file->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
+       if (snd_BUG_ON(!substream))
+               return -ENXIO;
        pcm = substream->pcm;
        fasync_helper(-1, file, 0, &substream->runtime->fasync);
        mutex_lock(&pcm->open_mutex);
@@ -2493,8 +2498,6 @@ static int snd_pcm_common_ioctl1(struct file *file,
                                 struct snd_pcm_substream *substream,
                                 unsigned int cmd, void __user *arg)
 {
-       snd_assert(substream != NULL, return -ENXIO);
-
        switch (cmd) {
        case SNDRV_PCM_IOCTL_PVERSION:
                return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
@@ -2563,8 +2566,10 @@ static int snd_pcm_playback_ioctl1(struct file *file,
                                   struct snd_pcm_substream *substream,
                                   unsigned int cmd, void __user *arg)
 {
-       snd_assert(substream != NULL, return -ENXIO);
-       snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL);
+       if (snd_BUG_ON(!substream))
+               return -ENXIO;
+       if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
+               return -EINVAL;
        switch (cmd) {
        case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
        {
@@ -2643,8 +2648,10 @@ static int snd_pcm_capture_ioctl1(struct file *file,
                                  struct snd_pcm_substream *substream,
                                  unsigned int cmd, void __user *arg)
 {
-       snd_assert(substream != NULL, return -ENXIO);
-       snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL);
+       if (snd_BUG_ON(!substream))
+               return -ENXIO;
+       if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
+               return -EINVAL;
        switch (cmd) {
        case SNDRV_PCM_IOCTL_READI_FRAMES:
        {
@@ -2783,7 +2790,8 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
 
        pcm_file = file->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
@@ -2806,21 +2814,17 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
 
        pcm_file = file->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, result = -ENXIO; goto end);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               result = -EBADFD;
-               goto end;
-       }
-       if (!frame_aligned(runtime, count)) {
-               result = -EINVAL;
-               goto end;
-       }
+       if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+               return -EBADFD;
+       if (!frame_aligned(runtime, count))
+               return -EINVAL;
        count = bytes_to_frames(runtime, count);
        result = snd_pcm_lib_write(substream, buf, count);
        if (result > 0)
                result = frames_to_bytes(runtime, result);
- end:
        return result;
 }
 
@@ -2838,7 +2842,8 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
 
        pcm_file = iocb->ki_filp->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
@@ -2872,17 +2877,14 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
 
        pcm_file = iocb->ki_filp->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, result = -ENXIO; goto end);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-               result = -EBADFD;
-               goto end;
-       }
+       if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+               return -EBADFD;
        if (nr_segs > 128 || nr_segs != runtime->channels ||
-           !frame_aligned(runtime, iov->iov_len)) {
-               result = -EINVAL;
-               goto end;
-       }
+           !frame_aligned(runtime, iov->iov_len))
+               return -EINVAL;
        frames = bytes_to_samples(runtime, iov->iov_len);
        bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
        if (bufs == NULL)
@@ -2893,7 +2895,6 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (result > 0)
                result = frames_to_bytes(runtime, result);
        kfree(bufs);
- end:
        return result;
 }
 
@@ -2908,7 +2909,8 @@ static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait)
        pcm_file = file->private_data;
 
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
 
        poll_wait(file, &runtime->sleep, wait);
@@ -2946,7 +2948,8 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
        pcm_file = file->private_data;
 
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
 
        poll_wait(file, &runtime->sleep, wait);
@@ -3016,7 +3019,6 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
        if (!(area->vm_flags & VM_READ))
                return -EINVAL;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -EAGAIN);
        size = area->vm_end - area->vm_start;
        if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
                return -EINVAL;
@@ -3056,7 +3058,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
        if (!(area->vm_flags & VM_READ))
                return -EINVAL;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -EAGAIN);
        size = area->vm_end - area->vm_start;
        if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
                return -EINVAL;
@@ -3188,7 +3189,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
                        return -EINVAL;
        }
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -EAGAIN);
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
        if (!(runtime->info & SNDRV_PCM_INFO_MMAP))
@@ -3220,7 +3220,8 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
        
        pcm_file = file->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
 
        offset = area->vm_pgoff << PAGE_SHIFT;
        switch (offset) {
@@ -3248,9 +3249,9 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
        lock_kernel();
        pcm_file = file->private_data;
        substream = pcm_file->substream;
-       snd_assert(substream != NULL, goto out);
+       if (PCM_RUNTIME_CHECK(substream))
+               goto out;
        runtime = substream->runtime;
-
        err = fasync_helper(fd, file, on, &runtime->fasync);
 out:
        unlock_kernel();
@@ -3384,6 +3385,17 @@ out:
 }
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 
+#ifndef CONFIG_MMU
+unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr,
+                                     unsigned long len, unsigned long pgoff,
+                                     unsigned long flags)
+{
+       return 0;
+}
+#else
+# define dummy_get_unmapped_area NULL
+#endif
+
 /*
  *  Register section
  */
@@ -3400,6 +3412,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
                .compat_ioctl =         snd_pcm_ioctl_compat,
                .mmap =                 snd_pcm_mmap,
                .fasync =               snd_pcm_fasync,
+               .get_unmapped_area =    dummy_get_unmapped_area,
        },
        {
                .owner =                THIS_MODULE,
@@ -3412,5 +3425,6 @@ const struct file_operations snd_pcm_f_ops[2] = {
                .compat_ioctl =         snd_pcm_ioctl_compat,
                .mmap =                 snd_pcm_mmap,
                .fasync =               snd_pcm_fasync,
+               .get_unmapped_area =    dummy_get_unmapped_area,
        }
 };
index 033a024d153a846ff315d1f275bf049c52dce655..2c89c04f29163766dde1c6b9f6f7a296310343f3 100644 (file)
@@ -51,12 +51,14 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
        
         mult = 1000000000;
        rate = runtime->rate;
-       snd_assert(rate != 0, return);
+       if (snd_BUG_ON(!rate))
+               return;
        l = gcd(mult, rate);
        mult /= l;
        rate /= l;
        fsize = runtime->period_size;
-       snd_assert(fsize != 0, return);
+       if (snd_BUG_ON(!fsize))
+               return;
        l = gcd(rate, fsize);
        rate /= l;
        fsize /= l;
index b917a9f981c7a276b3fbff94deece3f4ab8aa2f4..c4995c9f57303e0590ce5706676c2dc5918bf000 100644 (file)
@@ -470,8 +470,8 @@ int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile)
        struct snd_rawmidi_substream *substream;
        struct snd_rawmidi_runtime *runtime;
 
-       snd_assert(rfile != NULL, return -ENXIO);
-       snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);
+       if (snd_BUG_ON(!rfile))
+               return -ENXIO;
        rmidi = rfile->rmidi;
        mutex_lock(&rmidi->open_mutex);
        if (rfile->input != NULL) {
@@ -1100,7 +1100,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
                return -EINVAL;
        }
        spin_lock_irqsave(&runtime->lock, flags);
-       snd_assert(runtime->avail + count <= runtime->buffer_size, );
+       snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
        runtime->hw_ptr += count;
        runtime->hw_ptr %= runtime->buffer_size;
        runtime->avail += count;
@@ -1141,8 +1141,10 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
        long count1, result;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
-       snd_assert(kernelbuf != NULL || userbuf != NULL, return -EINVAL);
-       snd_assert(runtime->buffer != NULL, return -EINVAL);
+       if (snd_BUG_ON(!kernelbuf && !userbuf))
+               return -EINVAL;
+       if (snd_BUG_ON(!runtime->buffer))
+               return -EINVAL;
 
        result = 0;
        spin_lock_irqsave(&runtime->lock, flags);
@@ -1420,9 +1422,10 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
                .dev_disconnect = snd_rawmidi_dev_disconnect,
        };
 
-       snd_assert(rrawmidi != NULL, return -EINVAL);
-       *rrawmidi = NULL;
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
+       if (rrawmidi)
+               *rrawmidi = NULL;
        rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
        if (rmidi == NULL) {
                snd_printk(KERN_ERR "rawmidi: cannot allocate\n");
@@ -1455,7 +1458,8 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
                snd_rawmidi_free(rmidi);
                return err;
        }
-       *rrawmidi = rmidi;
+       if (rrawmidi)
+               *rrawmidi = rmidi;
        return 0;
 }
 
@@ -1472,7 +1476,8 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
 
 static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
 {
-       snd_assert(rmidi != NULL, return -ENXIO);       
+       if (!rmidi)
+               return 0;
 
        snd_info_free_entry(rmidi->proc_entry);
        rmidi->proc_entry = NULL;
index 97b30fb4c361193b1ef65821a46dea9f67736d9b..51e64e30dd3b6eea52b9d79908e3e50e333e7979 100644 (file)
@@ -91,7 +91,8 @@ static int
 rtctimer_start(struct snd_timer *timer)
 {
        rtc_task_t *rtc = timer->private_data;
-       snd_assert(rtc != NULL, return -EINVAL);
+       if (snd_BUG_ON(!rtc))
+               return -EINVAL;
        rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
        rtc_control(rtc, RTC_PIE_ON, 0);
        return 0;
@@ -101,7 +102,8 @@ static int
 rtctimer_stop(struct snd_timer *timer)
 {
        rtc_task_t *rtc = timer->private_data;
-       snd_assert(rtc != NULL, return -EINVAL);
+       if (snd_BUG_ON(!rtc))
+               return -EINVAL;
        rtc_control(rtc, RTC_PIE_OFF, 0);
        return 0;
 }
index 777796e9449047c2ec2b0ec851638cac9733fd7e..f25e3cc7ddfa53b4aa9244abe3fdf776146d7958 100644 (file)
@@ -164,7 +164,8 @@ odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
        struct seq_oss_devinfo *dp;
        dp = file->private_data;
-       snd_assert(dp != NULL, return -EIO);
+       if (snd_BUG_ON(!dp))
+               return -ENXIO;
        return snd_seq_oss_read(dp, buf, count);
 }
 
@@ -174,7 +175,8 @@ odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offs
 {
        struct seq_oss_devinfo *dp;
        dp = file->private_data;
-       snd_assert(dp != NULL, return -EIO);
+       if (snd_BUG_ON(!dp))
+               return -ENXIO;
        return snd_seq_oss_write(dp, buf, count, file);
 }
 
@@ -183,7 +185,8 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct seq_oss_devinfo *dp;
        dp = file->private_data;
-       snd_assert(dp != NULL, return -EIO);
+       if (snd_BUG_ON(!dp))
+               return -ENXIO;
        return snd_seq_oss_ioctl(dp, cmd, arg);
 }
 
@@ -198,7 +201,8 @@ odev_poll(struct file *file, poll_table * wait)
 {
        struct seq_oss_devinfo *dp;
        dp = file->private_data;
-       snd_assert(dp != NULL, return 0);
+       if (snd_BUG_ON(!dp))
+               return -ENXIO;
        return snd_seq_oss_poll(dp, file, wait);
 }
 
index e024e4588b829280b8871420c7d32a616352e7ef..945a27c34a9d1b2e5a9ed993930c26357fca2c60 100644 (file)
@@ -308,7 +308,8 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
        struct seq_oss_synth *rec;
        struct seq_oss_synthinfo *info;
 
-       snd_assert(dp->max_synthdev <= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS, return);
+       if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
+               return;
        for (i = 0; i < dp->max_synthdev; i++) {
                info = &dp->synths[i];
                if (! info->opened)
@@ -402,7 +403,8 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
        struct seq_oss_synth *rec;
        struct seq_oss_synthinfo *info;
 
-       snd_assert(dev >= 0 && dev < dp->max_synthdev, return);
+       if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev))
+               return;
        info = &dp->synths[dev];
        if (! info->opened)
                return;
index 7a1545d2d9533f4ad53b6e1693969e34cb067965..8ca2be339f3bacb230c584472f5a371f6098073b 100644 (file)
@@ -266,7 +266,8 @@ static int seq_free_client1(struct snd_seq_client *client)
 {
        unsigned long flags;
 
-       snd_assert(client != NULL, return -EINVAL);
+       if (!client)
+               return 0;
        snd_seq_delete_all_ports(client);
        snd_seq_queue_client_leave(client->number);
        spin_lock_irqsave(&clients_lock, flags);
@@ -403,7 +404,8 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
                return -EFAULT;
 
        /* check client structures are in place */
-       snd_assert(client != NULL, return -ENXIO);
+       if (snd_BUG_ON(!client))
+               return -ENXIO;
 
        if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
                return -ENXIO;
@@ -825,7 +827,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
        struct snd_seq_client *client;
        int result;
 
-       snd_assert(cell != NULL, return -EINVAL);
+       if (snd_BUG_ON(!cell))
+               return -EINVAL;
 
        client = snd_seq_client_use_ptr(cell->event.source.client);
        if (client == NULL) {
@@ -994,7 +997,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                return -ENXIO;
 
        /* check client structures are in place */
-       snd_assert(client != NULL, return -ENXIO);
+       if (snd_BUG_ON(!client))
+               return -ENXIO;
                
        if (!client->accept_output || client->pool == NULL)
                return -ENXIO;
@@ -1076,7 +1080,8 @@ static unsigned int snd_seq_poll(struct file *file, poll_table * wait)
        unsigned int mask = 0;
 
        /* check client structures are in place */
-       snd_assert(client != NULL, return -ENXIO);
+       if (snd_BUG_ON(!client))
+               return -ENXIO;
 
        if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) &&
            client->data.user.fifo) {
@@ -2195,7 +2200,8 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 {
        struct snd_seq_client *client = file->private_data;
 
-       snd_assert(client != NULL, return -ENXIO);
+       if (snd_BUG_ON(!client))
+               return -ENXIO;
                
        return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
 }
@@ -2216,7 +2222,8 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
        struct snd_seq_client *client;
        va_list args;
 
-       snd_assert(! in_interrupt(), return -EBUSY);
+       if (snd_BUG_ON(in_interrupt()))
+               return -EBUSY;
 
        if (card && client_index >= SNDRV_SEQ_CLIENTS_PER_CARD)
                return -EINVAL;
@@ -2265,7 +2272,8 @@ int snd_seq_delete_kernel_client(int client)
 {
        struct snd_seq_client *ptr;
 
-       snd_assert(! in_interrupt(), return -EBUSY);
+       if (snd_BUG_ON(in_interrupt()))
+               return -EBUSY;
 
        ptr = clientptr(client);
        if (ptr == NULL)
@@ -2288,7 +2296,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
        struct snd_seq_client *cptr;
        int result;
 
-       snd_assert(ev != NULL, return -EINVAL);
+       if (snd_BUG_ON(!ev))
+               return -EINVAL;
 
        if (ev->type == SNDRV_SEQ_EVENT_NONE)
                return 0; /* ignore this */
@@ -2354,7 +2363,8 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
        struct snd_seq_client *cptr;
        int result;
 
-       snd_assert(ev != NULL, return -EINVAL);
+       if (snd_BUG_ON(!ev))
+               return -EINVAL;
 
        /* fill in client number */
        ev->queue = SNDRV_SEQ_QUEUE_DIRECT;
index 9628c06e4eab3d000c8926b64621672faaee3611..38693f47c2625b2a5bf271c96b3ae124cc603588 100644 (file)
@@ -92,7 +92,8 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
        struct snd_seq_client *client = file->private_data;
        void __user *argp = compat_ptr(arg);
 
-       snd_assert(client != NULL, return -ENXIO);
+       if (snd_BUG_ON(!client))
+               return -ENXIO;
 
        switch (cmd) {
        case SNDRV_SEQ_IOCTL_PVERSION:
index 05410e536a4f432c75289cdea5c1843a7bad88dd..1f997675c893bbeb50fd01c530007540bc7a86fd 100644 (file)
@@ -187,7 +187,8 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
        if (result)
                *result = NULL;
 
-       snd_assert(id != NULL, return -EINVAL);
+       if (snd_BUG_ON(!id))
+               return -EINVAL;
 
        ops = find_driver(id, 1);
        if (ops == NULL)
@@ -232,7 +233,8 @@ static int snd_seq_device_free(struct snd_seq_device *dev)
 {
        struct ops_list *ops;
 
-       snd_assert(dev != NULL, return -EINVAL);
+       if (snd_BUG_ON(!dev))
+               return -EINVAL;
 
        ops = find_driver(dev->id, 0);
        if (ops == NULL)
index 3a94ed021bd96e0ef177284f8c8a9113dbfbb0c2..0d75afa786bc6ffebe8ffd8dc5bde065397c00a8 100644 (file)
@@ -65,9 +65,11 @@ void snd_seq_fifo_delete(struct snd_seq_fifo **fifo)
 {
        struct snd_seq_fifo *f;
 
-       snd_assert(fifo != NULL, return);
+       if (snd_BUG_ON(!fifo))
+               return;
        f = *fifo;
-       snd_assert(f != NULL, return);
+       if (snd_BUG_ON(!f))
+               return;
        *fifo = NULL;
 
        snd_seq_fifo_clear(f);
@@ -116,7 +118,8 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
        unsigned long flags;
        int err;
 
-       snd_assert(f != NULL, return -EINVAL);
+       if (snd_BUG_ON(!f))
+               return -EINVAL;
 
        snd_use_lock_use(&f->use_lock);
        err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
@@ -174,7 +177,8 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
        unsigned long flags;
        wait_queue_t wait;
 
-       snd_assert(f != NULL, return -EINVAL);
+       if (snd_BUG_ON(!f))
+               return -EINVAL;
 
        *cellp = NULL;
        init_waitqueue_entry(&wait, current);
@@ -233,7 +237,8 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
        struct snd_seq_pool *newpool, *oldpool;
        struct snd_seq_event_cell *cell, *next, *oldhead;
 
-       snd_assert(f != NULL && f->pool != NULL, return -EINVAL);
+       if (snd_BUG_ON(!f || !f->pool))
+               return -EINVAL;
 
        /* allocate new pool */
        newpool = snd_seq_pool_new(poolsize);
index 0cf6ac4773187cca81cf511258083f060bd9cfc6..7fb55436287fe7ad807e8e841965610489ca0109 100644 (file)
@@ -187,9 +187,11 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
        unsigned long flags;
        struct snd_seq_pool *pool;
 
-       snd_assert(cell != NULL, return);
+       if (snd_BUG_ON(!cell))
+               return;
        pool = cell->pool;
-       snd_assert(pool != NULL, return);
+       if (snd_BUG_ON(!pool))
+               return;
 
        spin_lock_irqsave(&pool->lock, flags);
        free_cell(pool, cell);
@@ -378,7 +380,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
        struct snd_seq_event_cell *cellptr;
        unsigned long flags;
 
-       snd_assert(pool != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pool))
+               return -EINVAL;
        if (pool->ptr)                  /* should be atomic? */
                return 0;
 
@@ -414,7 +417,8 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
        struct snd_seq_event_cell *ptr;
        int max_count = 5 * HZ;
 
-       snd_assert(pool != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pool))
+               return -EINVAL;
 
        /* wait for closing all threads */
        spin_lock_irqsave(&pool->lock, flags);
index 99b35360c5066df99574c2f2dca0753f9f557609..4d26146a62ccd8fd2fff0c73ea25507ff4a6550f 100644 (file)
@@ -116,7 +116,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
        struct snd_rawmidi_runtime *runtime;
        int tmp;
 
-       snd_assert(substream != NULL || buf != NULL, return -EINVAL);
+       if (snd_BUG_ON(!substream || !buf))
+               return -EINVAL;
        runtime = substream->runtime;
        if ((tmp = runtime->avail) < count) {
                snd_printd("warning, output event was lost (count = %i, available = %i)\n", count, tmp);
@@ -135,7 +136,8 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
        struct snd_rawmidi_substream *substream;
        int len;
 
-       snd_assert(msynth != NULL, return -EINVAL);
+       if (snd_BUG_ON(!msynth))
+               return -EINVAL;
        substream = msynth->output_rfile.output;
        if (substream == NULL)
                return -ENODEV;
@@ -210,7 +212,8 @@ static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscri
        int err;
        struct seq_midisynth *msynth = private_data;
 
-       snd_assert(msynth->input_rfile.input != NULL, return -EINVAL);
+       if (snd_BUG_ON(!msynth->input_rfile.input))
+               return -EINVAL;
        err = snd_rawmidi_kernel_release(&msynth->input_rfile);
        return err;
 }
@@ -247,7 +250,8 @@ static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *in
        struct seq_midisynth *msynth = private_data;
        unsigned char buf = 0xff; /* MIDI reset */
 
-       snd_assert(msynth->output_rfile.output != NULL, return -EINVAL);
+       if (snd_BUG_ON(!msynth->output_rfile.output))
+               return -EINVAL;
        /* sending single MIDI reset message to shut the device up */
        snd_rawmidi_kernel_write(msynth->output_rfile.output, &buf, 1);
        snd_rawmidi_drain_output(msynth->output_rfile.output);
@@ -285,7 +289,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
        int device = dev->device;
        unsigned int input_count = 0, output_count = 0;
 
-       snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL);
+       if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
+               return -EINVAL;
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (! info)
                return -ENOMEM;
index 1c32a53d6bd8d91084fb1a560277199557f40e35..3bf7d73ac52ebbed66858c695050f25cde25156b 100644 (file)
@@ -130,7 +130,8 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        int num = -1;
        
        /* sanity check */
-       snd_assert(client, return NULL);
+       if (snd_BUG_ON(!client))
+               return NULL;
 
        if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
                snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);
@@ -268,8 +269,8 @@ static int port_delete(struct snd_seq_client *client,
        if (port->private_free)
                port->private_free(port->private_data);
 
-       snd_assert(port->c_src.count == 0,);
-       snd_assert(port->c_dest.count == 0,);
+       snd_BUG_ON(port->c_src.count != 0);
+       snd_BUG_ON(port->c_dest.count != 0);
 
        kfree(port);
        return 0;
@@ -336,7 +337,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
 int snd_seq_set_port_info(struct snd_seq_client_port * port,
                          struct snd_seq_port_info * info)
 {
-       snd_assert(port && info, return -EINVAL);
+       if (snd_BUG_ON(!port || !info))
+               return -EINVAL;
 
        /* set port name */
        if (info->name[0])
@@ -365,7 +367,8 @@ int snd_seq_set_port_info(struct snd_seq_client_port * port,
 int snd_seq_get_port_info(struct snd_seq_client_port * port,
                          struct snd_seq_port_info * info)
 {
-       snd_assert(port && info, return -EINVAL);
+       if (snd_BUG_ON(!port || !info))
+               return -EINVAL;
 
        /* get port name */
        strlcpy(info->name, port->name, sizeof(info->name));
index 85969db576c905514974d478e2c1495c8848ff05..0101a8b99b7325650b7b4ccb758aac26366815aa 100644 (file)
@@ -153,8 +153,8 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
        int count;
        int prior;
 
-       snd_assert(f, return -EINVAL);
-       snd_assert(cell, return -EINVAL);
+       if (snd_BUG_ON(!f || !cell))
+               return -EINVAL;
        
        /* check flags */
        prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
index 4a48c6ee8ee835b7b55cc74967ca87beb1ba0812..e7a8e9e4edb2063760607f11afcd6187f94a92b4 100644 (file)
@@ -315,7 +315,8 @@ int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop)
        int dest, err;
        struct snd_seq_queue *q;
 
-       snd_assert(cell != NULL, return -EINVAL);
+       if (snd_BUG_ON(!cell))
+               return -EINVAL;
        dest = cell->event.queue;       /* destination queue */
        q = queueptr(dest);
        if (q == NULL)
@@ -734,7 +735,8 @@ int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop)
 {
        struct snd_seq_queue *q;
 
-       snd_assert(ev != NULL, return -EINVAL);
+       if (snd_BUG_ON(!ev))
+               return -EINVAL;
        q = queueptr(ev->data.queue.queue);
 
        if (q == NULL)
index d8fcd62e400f0ed512b330132e3c603ad4cc7b49..f745c317d6af17e9acb98928eb1332541299b8ec 100644 (file)
@@ -173,7 +173,8 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
 {
        unsigned long flags;
 
-       snd_assert(tmr, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
        if (tempo <= 0)
                return -EINVAL;
        spin_lock_irqsave(&tmr->lock, flags);
@@ -190,7 +191,8 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
 {
        unsigned long flags;
 
-       snd_assert(tmr, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
        if (ppq <= 0)
                return -EINVAL;
        spin_lock_irqsave(&tmr->lock, flags);
@@ -214,7 +216,8 @@ int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
 {
        unsigned long flags;
 
-       snd_assert(tmr, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
 
        spin_lock_irqsave(&tmr->lock, flags);
        tmr->tick.cur_tick = position;
@@ -229,7 +232,8 @@ int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
 {
        unsigned long flags;
 
-       snd_assert(tmr, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
 
        snd_seq_sanity_real_time(&position);
        spin_lock_irqsave(&tmr->lock, flags);
@@ -244,7 +248,8 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
 {
        unsigned long flags;
 
-       snd_assert(tmr, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
 
        /* FIXME */
        if (base != SKEW_BASE) {
@@ -265,7 +270,8 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
        int err;
 
        tmr = q->timer;
-       snd_assert(tmr != NULL, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
        if (tmr->timeri)
                return -EBUSY;
        sprintf(str, "sequencer queue %i", q->queue);
@@ -302,7 +308,8 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
        struct snd_seq_timer *tmr;
        
        tmr = q->timer;
-       snd_assert(tmr != NULL, return -EINVAL);
+       if (snd_BUG_ON(!tmr))
+               return -EINVAL;
        if (tmr->timeri) {
                snd_timer_stop(tmr->timeri);
                snd_timer_close(tmr->timeri);
@@ -328,7 +335,8 @@ static int initialize_timer(struct snd_seq_timer *tmr)
        unsigned long freq;
 
        t = tmr->timeri->timer;
-       snd_assert(t, return -EINVAL);
+       if (snd_BUG_ON(!t))
+               return -EINVAL;
 
        freq = tmr->preferred_resolution;
        if (!freq)
index cefd228cd2aafb964b61150a7a2d9931459a7fe8..d4564edd61d744b19fa98e6cc6a06fcd26d20b68 100644 (file)
@@ -41,9 +41,11 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
        tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
        tmpb.dev.dev = sgbuf->dev;
        for (i = 0; i < sgbuf->pages; i++) {
+               if (!(sgbuf->table[i].addr & ~PAGE_MASK))
+                       continue; /* continuous pages */
                tmpb.area = sgbuf->table[i].buf;
-               tmpb.addr = sgbuf->table[i].addr;
-               tmpb.bytes = PAGE_SIZE;
+               tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
+               tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
                snd_dma_free_pages(&tmpb);
        }
        if (dmab->area)
@@ -58,13 +60,17 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
        return 0;
 }
 
+#define MAX_ALLOC_PAGES                32
+
 void *snd_malloc_sgbuf_pages(struct device *device,
                             size_t size, struct snd_dma_buffer *dmab,
                             size_t *res_size)
 {
        struct snd_sg_buf *sgbuf;
-       unsigned int i, pages;
+       unsigned int i, pages, chunk, maxpages;
        struct snd_dma_buffer tmpb;
+       struct snd_sg_page *table;
+       struct page **pgtable;
 
        dmab->area = NULL;
        dmab->addr = 0;
@@ -74,31 +80,55 @@ void *snd_malloc_sgbuf_pages(struct device *device,
        sgbuf->dev = device;
        pages = snd_sgbuf_aligned_pages(size);
        sgbuf->tblsize = sgbuf_align_table(pages);
-       sgbuf->table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->table), GFP_KERNEL);
-       if (! sgbuf->table)
+       table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
+       if (!table)
                goto _failed;
-       sgbuf->page_table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->page_table), GFP_KERNEL);
-       if (! sgbuf->page_table)
+       sgbuf->table = table;
+       pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
+       if (!pgtable)
                goto _failed;
+       sgbuf->page_table = pgtable;
 
-       /* allocate each page */
-       for (i = 0; i < pages; i++) {
-               if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) {
-                       if (res_size == NULL)
+       /* allocate pages */
+       maxpages = MAX_ALLOC_PAGES;
+       while (pages > 0) {
+               chunk = pages;
+               /* don't be too eager to take a huge chunk */
+               if (chunk > maxpages)
+                       chunk = maxpages;
+               chunk <<= PAGE_SHIFT;
+               if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
+                                                chunk, &tmpb) < 0) {
+                       if (!sgbuf->pages)
+                               return NULL;
+                       if (!res_size)
                                goto _failed;
-                       *res_size = size = sgbuf->pages * PAGE_SIZE;
+                       size = sgbuf->pages * PAGE_SIZE;
                        break;
                }
-               sgbuf->table[i].buf = tmpb.area;
-               sgbuf->table[i].addr = tmpb.addr;
-               sgbuf->page_table[i] = virt_to_page(tmpb.area);
-               sgbuf->pages++;
+               chunk = tmpb.bytes >> PAGE_SHIFT;
+               for (i = 0; i < chunk; i++) {
+                       table->buf = tmpb.area;
+                       table->addr = tmpb.addr;
+                       if (!i)
+                               table->addr |= chunk; /* mark head */
+                       table++;
+                       *pgtable++ = virt_to_page(tmpb.area);
+                       tmpb.area += PAGE_SIZE;
+                       tmpb.addr += PAGE_SIZE;
+               }
+               sgbuf->pages += chunk;
+               pages -= chunk;
+               if (chunk < maxpages)
+                       maxpages = chunk;
        }
 
        sgbuf->size = size;
        dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
        if (! dmab->area)
                goto _failed;
+       if (res_size)
+               *res_size = sgbuf->size;
        return dmab->area;
 
  _failed:
index 1003ae375d478429e128bb7138b751486f069178..c0685e2f0afa1fe39cab14cf86cb733cbaa761e7 100644 (file)
@@ -34,8 +34,6 @@
 #include <linux/kmod.h>
 #include <linux/mutex.h>
 
-#define SNDRV_OS_MINORS 256
-
 static int major = CONFIG_SND_MAJOR;
 int snd_major;
 EXPORT_SYMBOL(snd_major);
@@ -208,20 +206,23 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
                minor = type;
                break;
        case SNDRV_DEVICE_TYPE_CONTROL:
-               snd_assert(card != NULL, return -EINVAL);
+               if (snd_BUG_ON(!card))
+                       return -EINVAL;
                minor = SNDRV_MINOR(card->number, type);
                break;
        case SNDRV_DEVICE_TYPE_HWDEP:
        case SNDRV_DEVICE_TYPE_RAWMIDI:
        case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
        case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
-               snd_assert(card != NULL, return -EINVAL);
+               if (snd_BUG_ON(!card))
+                       return -EINVAL;
                minor = SNDRV_MINOR(card->number, type + dev);
                break;
        default:
                return -EINVAL;
        }
-       snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
+       if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
+               return -EINVAL;
        return minor;
 }
 #endif
@@ -249,7 +250,8 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
        int minor;
        struct snd_minor *preg;
 
-       snd_assert(name, return -EINVAL);
+       if (snd_BUG_ON(!name))
+               return -EINVAL;
        preg = kmalloc(sizeof *preg, GFP_KERNEL);
        if (preg == NULL)
                return -ENOMEM;
index 7be51546eb9e8cd8b26d46e0bb4306377edb2278..7fe12264ff80d60cba667b37804e082dc82d8ef3 100644 (file)
@@ -64,7 +64,8 @@ static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
 
        switch (type) {
        case SNDRV_OSS_DEVICE_TYPE_MIXER:
-               snd_assert(card != NULL && dev <= 1, return -EINVAL);
+               if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+                       return -EINVAL;
                minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIXER1 : SNDRV_MINOR_OSS_MIXER));
                break;
        case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
@@ -74,11 +75,13 @@ static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
                minor = SNDRV_MINOR_OSS_MUSIC;
                break;
        case SNDRV_OSS_DEVICE_TYPE_PCM:
-               snd_assert(card != NULL && dev <= 1, return -EINVAL);
+               if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+                       return -EINVAL;
                minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM));
                break;
        case SNDRV_OSS_DEVICE_TYPE_MIDI:
-               snd_assert(card != NULL && dev <= 1, return -EINVAL);
+               if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+                       return -EINVAL;
                minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIDI1 : SNDRV_MINOR_OSS_MIDI));
                break;
        case SNDRV_OSS_DEVICE_TYPE_DMFM:
@@ -90,7 +93,8 @@ static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
        default:
                return -EINVAL;
        }
-       snd_assert(minor >= 0 && minor < SNDRV_OSS_MINORS, return -EINVAL);
+       if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OSS_MINORS))
+               return -EINVAL;
        return minor;
 }
 
index 0af337efc64e282367727e965bb36c090d0afd37..e582face89d2c463aeb64ed0ee2001d738b54b5c 100644 (file)
@@ -306,7 +306,8 @@ int snd_timer_close(struct snd_timer_instance *timeri)
        struct snd_timer *timer = NULL;
        struct snd_timer_instance *slave, *tmp;
 
-       snd_assert(timeri != NULL, return -ENXIO);
+       if (snd_BUG_ON(!timeri))
+               return -ENXIO;
 
        /* force to stop the timer */
        snd_timer_stop(timeri);
@@ -385,8 +386,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
                do_posix_clock_monotonic_gettime(&tstamp);
        else
                getnstimeofday(&tstamp);
-       snd_assert(event >= SNDRV_TIMER_EVENT_START &&
-                  event <= SNDRV_TIMER_EVENT_PAUSE, return);
+       if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
+                      event > SNDRV_TIMER_EVENT_PAUSE))
+               return;
        if (event == SNDRV_TIMER_EVENT_START ||
            event == SNDRV_TIMER_EVENT_CONTINUE)
                resolution = snd_timer_resolution(ti);
@@ -474,7 +476,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri,
        struct snd_timer *timer;
        unsigned long flags;
 
-       snd_assert(timeri != NULL, return -ENXIO);
+       if (snd_BUG_ON(!timeri))
+               return -ENXIO;
 
        if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
                if (!keep_flag) {
@@ -758,9 +761,10 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
                .dev_disconnect = snd_timer_dev_disconnect,
        };
 
-       snd_assert(tid != NULL, return -EINVAL);
-       snd_assert(rtimer != NULL, return -EINVAL);
-       *rtimer = NULL;
+       if (snd_BUG_ON(!tid))
+               return -EINVAL;
+       if (rtimer)
+               *rtimer = NULL;
        timer = kzalloc(sizeof(*timer), GFP_KERNEL);
        if (timer == NULL) {
                snd_printk(KERN_ERR "timer: cannot allocate\n");
@@ -788,13 +792,15 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
                        return err;
                }
        }
-       *rtimer = timer;
+       if (rtimer)
+               *rtimer = timer;
        return 0;
 }
 
 static int snd_timer_free(struct snd_timer *timer)
 {
-       snd_assert(timer != NULL, return -ENXIO);
+       if (!timer)
+               return 0;
 
        mutex_lock(&register_mutex);
        if (! list_empty(&timer->open_list_head)) {
@@ -827,8 +833,8 @@ static int snd_timer_dev_register(struct snd_device *dev)
        struct snd_timer *timer = dev->device_data;
        struct snd_timer *timer1;
 
-       snd_assert(timer != NULL && timer->hw.start != NULL &&
-                  timer->hw.stop != NULL, return -ENXIO);
+       if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
+               return -ENXIO;
        if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
            !timer->hw.resolution && timer->hw.c_resolution == NULL)
                return -EINVAL;
@@ -879,8 +885,9 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
 
        if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
                return;
-       snd_assert(event >= SNDRV_TIMER_EVENT_MSTART &&
-                  event <= SNDRV_TIMER_EVENT_MRESUME, return);
+       if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
+                      event > SNDRV_TIMER_EVENT_MRESUME))
+               return;
        spin_lock_irqsave(&timer->lock, flags);
        if (event == SNDRV_TIMER_EVENT_MSTART ||
            event == SNDRV_TIMER_EVENT_MCONTINUE ||
index 5512f5373c52ece5ef82f4c54fc81865448ea69a..e05802ae6e1b1e240a187a43c9f5308fcf7145c0 100644 (file)
@@ -40,9 +40,11 @@ static int snd_timer_user_info_compat(struct file *file,
        struct snd_timer *t;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (snd_BUG_ON(!tu->timeri))
+               return -ENXIO;
        t = tu->timeri->timer;
-       snd_assert(t != NULL, return -ENXIO);
+       if (snd_BUG_ON(!t))
+               return -ENXIO;
        memset(&info, 0, sizeof(info));
        info.card = t->card ? t->card->number : -1;
        if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
@@ -71,7 +73,8 @@ static int snd_timer_user_status_compat(struct file *file,
        struct snd_timer_status status;
        
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (snd_BUG_ON(!tu->timeri))
+               return -ENXIO;
        memset(&status, 0, sizeof(status));
        status.tstamp = tu->tstamp;
        status.resolution = snd_timer_resolution(tu->timeri);
index 4e4c69e6cb4c8e850c66c7a2530eab827d793803..e5e749f3e0ef08df9fea76571c6a552a2724e388 100644 (file)
@@ -47,9 +47,11 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
 static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
 {
        int err;
-       if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+       err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
                return err;
-       if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0)
+       err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
+       if (err) < 0)
                return err;
        return 0;
 }
@@ -354,6 +356,7 @@ static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream)
        if ((dpcm = new_pcm_stream(substream)) == NULL)
                return -ENOMEM;
        runtime->private_data = dpcm;
+       /* makes the infrastructure responsible for freeing dpcm */
        runtime->private_free = snd_card_dummy_runtime_free;
        runtime->hw = snd_card_dummy_playback;
        if (substream->pcm->device & 1) {
@@ -362,10 +365,9 @@ static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream)
        }
        if (substream->pcm->device & 2)
                runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
-       if ((err = add_playback_constraints(runtime)) < 0) {
-               kfree(dpcm);
+       err = add_playback_constraints(runtime);
+       if (err < 0)
                return err;
-       }
 
        return 0;
 }
@@ -379,6 +381,7 @@ static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream)
        if ((dpcm = new_pcm_stream(substream)) == NULL)
                return -ENOMEM;
        runtime->private_data = dpcm;
+       /* makes the infrastructure responsible for freeing dpcm */
        runtime->private_free = snd_card_dummy_runtime_free;
        runtime->hw = snd_card_dummy_capture;
        if (substream->pcm->device == 1) {
@@ -387,10 +390,9 @@ static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream)
        }
        if (substream->pcm->device & 2)
                runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
-       if ((err = add_capture_constraints(runtime)) < 0) {
-               kfree(dpcm);
+       err = add_capture_constraints(runtime);
+       if (err < 0)
                return err;
-       }
 
        return 0;
 }
@@ -433,8 +435,9 @@ static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
        struct snd_pcm *pcm;
        int err;
 
-       if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device,
-                              substreams, substreams, &pcm)) < 0)
+       err = snd_pcm_new(dummy->card, "Dummy PCM", device,
+                              substreams, substreams, &pcm);
+       if (err < 0)
                return err;
        dummy->pcm = pcm;
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops);
@@ -565,12 +568,14 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
        unsigned int idx;
        int err;
 
-       snd_assert(dummy != NULL, return -EINVAL);
+       if (snd_BUG_ON(!dummy))
+               return -EINVAL;
        spin_lock_init(&dummy->mixer_lock);
        strcpy(card->mixername, "Dummy Mixer");
 
        for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
-               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0)
+               err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy));
+               if (err < 0)
                        return err;
        }
        return 0;
@@ -594,10 +599,12 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
                        pcm_substreams[dev] = 1;
                if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
                        pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
-               if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0)
+               err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev]);
+               if (err < 0)
                        goto __nodev;
        }
-       if ((err = snd_card_dummy_new_mixer(dummy)) < 0)
+       err = snd_card_dummy_new_mixer(dummy);
+       if (err < 0)
                goto __nodev;
        strcpy(card->driver, "Dummy");
        strcpy(card->shortname, "Dummy");
@@ -605,7 +612,8 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
 
        snd_card_set_dev(card, &devptr->dev);
 
-       if ((err = snd_card_register(card)) == 0) {
+       err = snd_card_register(card);
+       if (err == 0) {
                platform_set_drvdata(devptr, card);
                return 0;
        }
@@ -668,7 +676,8 @@ static int __init alsa_card_dummy_init(void)
 {
        int i, cards, err;
 
-       if ((err = platform_driver_register(&snd_dummy_driver)) < 0)
+       err = platform_driver_register(&snd_dummy_driver);
+       if (err < 0)
                return err;
 
        cards = 0;
index b5e1a71bb64b59857f9a55eb9520d358cd61ed57..5b89c0883d6081b8d5b8b854d72585ef345f6c55 100644 (file)
@@ -715,6 +715,10 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
 
        card->private_free = snd_mtpav_free;
 
+       err = snd_mtpav_get_RAWMIDI(mtp_card);
+       if (err < 0)
+               goto __error;
+
        err = snd_mtpav_get_ISA(mtp_card);
        if (err < 0)
                goto __error;
@@ -724,10 +728,6 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
        snprintf(card->longname, sizeof(card->longname),
                 "MTPAV on parallel port at 0x%lx", port);
 
-       err = snd_mtpav_get_RAWMIDI(mtp_card);
-       if (err < 0)
-               goto __error;
-
        snd_mtpav_portscan(mtp_card);
 
        snd_card_set_dev(card, &dev->dev);
index ebe4359047cb2deb90fdc952ccae21d7ce555c38..780582340fefab73e11930775edc81fcda2ff9f6 100644 (file)
@@ -139,7 +139,8 @@ static int snd_opl3_detect(struct snd_opl3 * opl3)
                 * If we had an OPL4 chip, opl3->hardware would have been set
                 * by the OPL4 driver; so we can assume OPL3 here.
                 */
-               snd_assert(opl3->r_port != 0, return -ENODEV);
+               if (snd_BUG_ON(!opl3->r_port))
+                       return -ENODEV;
                opl3->hardware = OPL3_HW_OPL3;
        }
        return 0;
@@ -324,7 +325,8 @@ EXPORT_SYMBOL(snd_opl3_interrupt);
 
 static int snd_opl3_free(struct snd_opl3 *opl3)
 {
-       snd_assert(opl3 != NULL, return -ENXIO);
+       if (snd_BUG_ON(!opl3))
+               return -ENXIO;
        if (opl3->private_free)
                opl3->private_free(opl3);
        snd_opl3_clear_patches(opl3);
index cebcb8b78acb8af1e1066f919bb5124b83b6c821..16feafa2c51e872cfb6266b3882e76b407c1180e 100644 (file)
@@ -617,7 +617,8 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
 
        struct snd_opl3_voice *vp, *vp2;
 
-       snd_assert(voice < MAX_OPL3_VOICES, return);
+       if (snd_BUG_ON(voice >= MAX_OPL3_VOICES))
+               return;
 
        vp = &opl3->voices[voice];
        if (voice < MAX_OPL2_VOICES) {
@@ -737,7 +738,8 @@ static void snd_opl3_update_pitch(struct snd_opl3 *opl3, int voice)
 
        struct snd_opl3_voice *vp;
 
-       snd_assert(voice < MAX_OPL3_VOICES, return);
+       if (snd_BUG_ON(voice >= MAX_OPL3_VOICES))
+               return;
 
        vp = &opl3->voices[voice];
        if (vp->chan == NULL)
index 239347f26154ba381907874a08a3d6bd2a2da881..9a2271dc046a653e7f80077108bd6c19b2c3e6a7 100644 (file)
@@ -162,7 +162,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
        struct snd_opl3 *opl3 = closure;
        int err;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
 
        if ((err = snd_opl3_synth_setup(opl3)) < 0)
                return err;
@@ -184,7 +185,8 @@ static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg)
 {
        struct snd_opl3 *opl3;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        opl3 = arg->private_data;
 
        snd_opl3_synth_cleanup(opl3);
@@ -206,7 +208,8 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
        char name[32];
        int err, type;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        opl3 = arg->private_data;
 
        if (format == FM_PATCH)
@@ -246,7 +249,8 @@ static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
 {
        struct snd_opl3 *opl3;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        opl3 = arg->private_data;
        switch (cmd) {
                case SNDCTL_FM_LOAD_INSTR:
@@ -271,7 +275,8 @@ static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg)
 {
        struct snd_opl3 *opl3;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        opl3 = arg->private_data;
 
        return 0;
index fb64c890109bdccc743ba7054cfd472027e8b32f..962bb9c8b9c8902b5fd5bcaa111a515b8cc71fe8 100644 (file)
@@ -92,7 +92,8 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
        struct snd_opl3 *opl3 = hw->private_data;
        void __user *argp = (void __user *)arg;
 
-       snd_assert(opl3 != NULL, return -EINVAL);
+       if (snd_BUG_ON(!opl3))
+               return -EINVAL;
 
        switch (cmd) {
                /* get information */
index 74f6e53eae0dd382ce88664a8a297a180207a591..49b9e240915c48d1f236644de16157db03a6f0fb 100644 (file)
@@ -467,7 +467,7 @@ static struct opl4_voice *snd_opl4_get_voice(struct snd_opl4 *opl4)
        if (!list_empty(&opl4->off_voices))
                return list_entry(opl4->off_voices.next, struct opl4_voice, list);
        /* then get the oldest key-on voice */
-       snd_assert(!list_empty(&opl4->on_voices), );
+       snd_BUG_ON(list_empty(&opl4->on_voices));
        return list_entry(opl4->on_voices.next, struct opl4_voice, list);
 }
 
index 9529e3bf2866309f808488e5ba46ac1732c6d684..23f4857f02c888d994292354d1b6b89303bf43c6 100644 (file)
@@ -99,7 +99,8 @@ static struct vx_cmd_info vx_dsp_cmds[] = {
  */
 void vx_init_rmh(struct vx_rmh *rmh, unsigned int cmd)
 {
-       snd_assert(cmd < CMD_LAST_INDEX, return);
+       if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
+               return;
        rmh->LgCmd = vx_dsp_cmds[cmd].length;
        rmh->LgStat = vx_dsp_cmds[cmd].st_length;
        rmh->DspStat = vx_dsp_cmds[cmd].st_type;
index 585af2eb1438945c1418770e37fbe904a8b6093c..473b07f6ae85f09d9760f708468aa7352362c1d1 100644 (file)
@@ -205,7 +205,8 @@ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
 
        if (size < 1)
                return 0;
-       snd_assert(size <= SIZE_MAX_STATUS, return -EINVAL);
+       if (snd_BUG_ON(size > SIZE_MAX_STATUS))
+               return -EINVAL;
 
        for (i = 1; i <= size; i++) {
                /* trigger an irq MESS_WRITE_NEXT */
@@ -425,13 +426,16 @@ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
        int no_fillup = vx_has_new_dsp(chip);
 
        /* check the length of boot image */
-       snd_assert(boot->size > 0, return -EINVAL);
-       snd_assert(boot->size % 3 == 0, return -EINVAL);
+       if (boot->size <= 0)
+               return -EINVAL;
+       if (boot->size % 3)
+               return -EINVAL;
 #if 0
        {
                /* more strict check */
                unsigned int c = ((u32)boot->data[0] << 16) | ((u32)boot->data[1] << 8) | boot->data[2];
-               snd_assert(boot->size == (c + 2) * 3, return -EINVAL);
+               if (boot->size != (c + 2) * 3)
+                       return -EINVAL;
        }
 #endif
 
@@ -554,7 +558,8 @@ EXPORT_SYMBOL(snd_vx_irq_handler);
  */
 static void vx_reset_board(struct vx_core *chip, int cold_reset)
 {
-       snd_assert(chip->ops->reset_board, return);
+       if (snd_BUG_ON(!chip->ops->reset_board))
+               return;
 
        /* current source, later sync'ed with target */
        chip->audio_source = VX_AUDIO_SRC_LINE;
@@ -673,7 +678,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
        unsigned int csum = 0;
        const unsigned char *image, *cptr;
 
-       snd_assert(dsp->size % 3 == 0, return -EINVAL);
+       if (dsp->size % 3)
+               return -EINVAL;
 
        vx_toggle_dac_mute(chip, 1);
 
@@ -775,7 +781,8 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
 {
        struct vx_core *chip;
 
-       snd_assert(card && hw && ops, return NULL);
+       if (snd_BUG_ON(!card || !hw || !ops))
+               return NULL;
 
        chip = kzalloc(sizeof(*chip) + extra_size, GFP_KERNEL);
        if (! chip) {
index efd22e92bcedea68f2a1de780f8e2b919b3d33fe..8d6362e2d4c9ec54f5a0784e6f49baa424990f90 100644 (file)
@@ -141,7 +141,8 @@ static int vx_hwdep_dsp_status(struct snd_hwdep *hw,
        };
        struct vx_core *vx = hw->private_data;
 
-       snd_assert(type_ids[vx->type], return -EINVAL);
+       if (snd_BUG_ON(!type_ids[vx->type]))
+               return -EINVAL;
        strcpy(info->id, type_ids[vx->type]);
        if (vx_is_pcmcia(vx))
                info->num_dsps = 4;
@@ -168,7 +169,8 @@ static int vx_hwdep_dsp_load(struct snd_hwdep *hw,
        int index, err;
        struct firmware *fw;
 
-       snd_assert(vx->ops->load_dsp, return -ENXIO);
+       if (snd_BUG_ON(!vx->ops->load_dsp))
+               return -ENXIO;
 
        fw = kmalloc(sizeof(*fw), GFP_KERNEL);
        if (! fw) {
index 5a347321f8c037a384a310f696674daa06c7b118..c71b8d148d7fa82324a18863da0b98459488582a 100644 (file)
@@ -34,7 +34,8 @@ static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int dat
 {
        unsigned long flags;
 
-       snd_assert(chip->ops->write_codec, return);
+       if (snd_BUG_ON(!chip->ops->write_codec))
+               return;
 
        if (chip->chip_status & VX_STAT_IS_STALE)
                return;
index fdbf86571b1f3f528233b3c13537e78728a2028c..27de574c08f76c5ff5763e1051e6dba353402648 100644 (file)
@@ -587,7 +587,8 @@ static int vx_pcm_playback_open(struct snd_pcm_substream *subs)
                return -EBUSY;
 
        audio = subs->pcm->device * 2;
-       snd_assert(audio < chip->audio_outs, return -EINVAL);
+       if (snd_BUG_ON(audio >= chip->audio_outs))
+               return -EINVAL;
        
        /* playback pipe may have been already allocated for monitoring */
        pipe = chip->playback_pipes[audio];
@@ -996,7 +997,8 @@ static int vx_pcm_capture_open(struct snd_pcm_substream *subs)
                return -EBUSY;
 
        audio = subs->pcm->device * 2;
-       snd_assert(audio < chip->audio_ins, return -EINVAL);
+       if (snd_BUG_ON(audio >= chip->audio_ins))
+               return -EINVAL;
        err = vx_alloc_pipe(chip, 1, audio, 2, &pipe);
        if (err < 0)
                return err;
@@ -1214,7 +1216,8 @@ void vx_pcm_update_intr(struct vx_core *chip, unsigned int events)
                        }
                        if (capture)
                                continue;
-                       snd_assert(p >= 0 && (unsigned int)p < chip->audio_outs,);
+                       if (snd_BUG_ON(p < 0 || p >= chip->audio_outs))
+                               continue;
                        pipe = chip->playback_pipes[p];
                        if (pipe && pipe->substream) {
                                vx_pcm_playback_update(chip, pipe->substream, pipe);
index fb8932af888d6a523fc5c33f489acb61e5b2d82f..0e1ba9b47904aa95de29dfe18f6aa6324aa8a3a7 100644 (file)
@@ -163,13 +163,15 @@ static int vx_calc_clock_from_freq(struct vx_core *chip, int freq)
 {
        int hexfreq;
 
-       snd_assert(freq > 0, return 0);
+       if (snd_BUG_ON(freq <= 0))
+               return 0;
 
        hexfreq = (28224000 * 10) / freq;
        hexfreq = (hexfreq + 5) / 10;
 
        /* max freq = 55125 Hz */
-       snd_assert(hexfreq > 0x00000200, return 0);
+       if (snd_BUG_ON(hexfreq <= 0x00000200))
+               return 0;
 
        if (hexfreq <= 0x03ff)
                return hexfreq - 0x00000201;
index 9c3d361accfb108e71bf2ceea04a42f0b12972dd..020a5d5124721a54ef81b2c5b97943580699a19c 100644 (file)
@@ -314,7 +314,8 @@ static void snd_cs8427_reset(struct snd_i2c_device *cs8427)
        unsigned long end_time;
        int data, aes3input = 0;
 
-       snd_assert(cs8427, return);
+       if (snd_BUG_ON(!cs8427))
+               return;
        chip = cs8427->private_data;
        snd_i2c_lock(cs8427->bus);
        if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) ==
@@ -526,7 +527,8 @@ int snd_cs8427_iec958_build(struct snd_i2c_device *cs8427,
        unsigned int idx;
        int err;
 
-       snd_assert(play_substream && cap_substream, return -EINVAL);
+       if (snd_BUG_ON(!play_substream || !cap_substream))
+               return -EINVAL;
        for (idx = 0; idx < ARRAY_SIZE(snd_cs8427_iec958_controls); idx++) {
                kctl = snd_ctl_new1(&snd_cs8427_iec958_controls[idx], cs8427);
                if (kctl == NULL)
@@ -543,7 +545,8 @@ int snd_cs8427_iec958_build(struct snd_i2c_device *cs8427,
 
        chip->playback.substream = play_substream;
        chip->capture.substream = cap_substream;
-       snd_assert(chip->playback.pcm_ctl, return -EIO);
+       if (snd_BUG_ON(!chip->playback.pcm_ctl))
+               return -EIO;
        return 0;
 }
 
@@ -553,7 +556,8 @@ int snd_cs8427_iec958_active(struct snd_i2c_device *cs8427, int active)
 {
        struct cs8427 *chip;
 
-       snd_assert(cs8427, return -ENXIO);
+       if (snd_BUG_ON(!cs8427))
+               return -ENXIO;
        chip = cs8427->private_data;
        if (active)
                memcpy(chip->playback.pcm_status,
@@ -573,7 +577,8 @@ int snd_cs8427_iec958_pcm(struct snd_i2c_device *cs8427, unsigned int rate)
        char *status;
        int err, reset;
 
-       snd_assert(cs8427, return -ENXIO);
+       if (snd_BUG_ON(!cs8427))
+               return -ENXIO;
        chip = cs8427->private_data;
        status = chip->playback.pcm_status;
        snd_i2c_lock(cs8427->bus);
index b1e74e40cba050656879dbe529a72adb218397c3..5c0c77dd01c30f8a0a584dac38bb13fecd8edc59 100644 (file)
@@ -49,7 +49,8 @@ static int snd_i2c_bus_free(struct snd_i2c_bus *bus)
        struct snd_i2c_bus *slave;
        struct snd_i2c_device *device;
 
-       snd_assert(bus != NULL, return -EINVAL);
+       if (snd_BUG_ON(!bus))
+               return -EINVAL;
        while (!list_empty(&bus->devices)) {
                device = snd_i2c_device(bus->devices.next);
                snd_i2c_device_free(device);
@@ -113,7 +114,8 @@ int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name,
        struct snd_i2c_device *device;
 
        *rdevice = NULL;
-       snd_assert(bus != NULL, return -EINVAL);
+       if (snd_BUG_ON(!bus))
+               return -EINVAL;
        device = kzalloc(sizeof(*device), GFP_KERNEL);
        if (device == NULL)
                return -ENOMEM;
index 1f4942ea141433dfef8569fa3c3f3e478688ffb7..9840eb43648d07e5a05a2a80c8bd3c1406d6aba3 100644 (file)
@@ -771,7 +771,8 @@ int __init snd_chip_uda1341_mixer_new(struct snd_card *card, struct l3_client **
        struct l3_client *clnt;
        int idx, err;
 
-       snd_assert(card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card))
+               return -EINVAL;
 
        clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
        if (clnt == NULL)
index d20d893b3b60c1308694224c56c8838126a6f215..0341451f814c3bfdd3f788776cfe722d833afe54 100644 (file)
@@ -475,7 +475,8 @@ int snd_ak4114_build(struct ak4114 *ak4114,
        unsigned int idx;
        int err;
 
-       snd_assert(cap_substream, return -EINVAL);
+       if (snd_BUG_ON(!cap_substream))
+               return -EINVAL;
        ak4114->playback_substream = ply_substream;
        ak4114->capture_substream = cap_substream;
        for (idx = 0; idx < AK4114_CONTROLS; idx++) {
index f350835ade96cced97ae9815de8d71a09e3cf86b..2cad2d6125186431643dd9a04bcc840f729e67e4 100644 (file)
@@ -431,7 +431,8 @@ int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substr
        unsigned int idx;
        int err;
 
-       snd_assert(cap_substream, return -EINVAL);
+       if (snd_BUG_ON(!cap_substream))
+               return -EINVAL;
        ak4117->substream = cap_substream;
        for (idx = 0; idx < AK4117_CONTROLS; idx++) {
                kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117);
index 288926d2e2054b2706d8749b6be8ff8290bd1911..ee47abab764ed5a90f6e1cc70f941cd353249f29 100644 (file)
@@ -233,8 +233,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
                0x01, 0x02, /* 1: reset and soft-mute */
                0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
                             * disable DZF, sharp roll-off, RSTN#=0 */
-               0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
-               // 0x02, 0x2e, /* quad speed */
+               0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */
+               /* 0x02, 0x6e,*/ /* quad speed */
                0x03, 0x01, /* 3: de-emphasis off */
                0x04, 0x00, /* 4: LOUT1 volume muted */
                0x05, 0x00, /* 5: ROUT1 volume muted */
index 5769a13c1d9577d00dca57cebdcb04b3a1c256f6..660beb41f767f74a42373ba81bf1e0805c33da02 100644 (file)
@@ -1,10 +1,6 @@
 # ALSA ISA drivers
 
-config SND_AD1848_LIB
-        tristate
-        select SND_PCM
-
-config SND_CS4231_LIB
+config SND_WSS_LIB
         tristate
         select SND_PCM
 
@@ -55,7 +51,7 @@ config SND_AD1816A
 
 config SND_AD1848
        tristate "Generic AD1848/CS4248 driver"
-       select SND_AD1848_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for AD1848 (Analog Devices) or
          CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
@@ -86,7 +82,7 @@ config SND_AZT2320
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for soundcards based on the
          Aztech Systems AZT2320 chip.
@@ -96,7 +92,7 @@ config SND_AZT2320
 
 config SND_CMI8330
        tristate "C-Media CMI8330"
-       select SND_AD1848_LIB
+       select SND_WSS_LIB
        select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on the
@@ -108,7 +104,7 @@ config SND_CMI8330
 config SND_CS4231
        tristate "Generic Cirrus Logic CS4231 driver"
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for CS4231 chips from Cirrus
          Logic - Crystal Semiconductors.
@@ -120,7 +116,7 @@ config SND_CS4232
        tristate "Generic Cirrus Logic CS4232 driver"
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for CS4232 chips from Cirrus
          Logic - Crystal Semiconductors.
@@ -132,7 +128,7 @@ config SND_CS4236
        tristate "Generic Cirrus Logic CS4236+ driver"
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
          CS4239 chips from Cirrus Logic - Crystal Semiconductors.
@@ -192,7 +188,7 @@ config SND_ES18XX
 config SND_SC6000
        tristate "Gallant SC-6000, Audio Excel DSP 16"
        depends on HAS_IOPORT
-       select SND_AD1848_LIB
+       select SND_WSS_LIB
        select SND_OPL3_LIB
        select SND_MPU401_UART
        help
@@ -228,7 +224,7 @@ config SND_GUSEXTREME
 config SND_GUSMAX
        tristate "Gravis UltraSound MAX"
        select SND_RAWMIDI
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for Gravis UltraSound MAX
          soundcards.
@@ -240,7 +236,7 @@ config SND_INTERWAVE
        tristate "AMD InterWave, Gravis UltraSound PnP"
        depends on PNP
        select SND_RAWMIDI
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for AMD InterWave based
          soundcards (Gravis UltraSound Plug & Play, STB SoundRage32,
@@ -253,7 +249,7 @@ config SND_INTERWAVE_STB
        tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
        depends on PNP
        select SND_RAWMIDI
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for AMD InterWave based
          soundcards with a TEA6330T bass and treble regulator
@@ -266,7 +262,7 @@ config SND_OPL3SA2
        tristate "Yamaha OPL3-SA2/SA3"
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3
          chips.
@@ -279,7 +275,7 @@ config SND_OPTI92X_AD1848
        select SND_OPL3_LIB
        select SND_OPL4_LIB
        select SND_MPU401_UART
-       select SND_AD1848_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for soundcards based on Opti
          82C92x or OTI-601 chips and using an AD1848 codec.
@@ -292,7 +288,7 @@ config SND_OPTI92X_CS4231
        select SND_OPL3_LIB
        select SND_OPL4_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for soundcards based on Opti
          82C92x chips and using a CS4231 codec.
@@ -304,7 +300,7 @@ config SND_OPTI93X
        tristate "OPTi 82C93x"
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for soundcards based on Opti
          82C93x chips.
@@ -315,7 +311,7 @@ config SND_OPTI93X
 config SND_MIRO
        tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver"
        select SND_OPL4_LIB
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        select SND_MPU401_UART
        select SND_PCM
        help
@@ -364,7 +360,7 @@ config SND_SBAWE
 config SND_SB16_CSP
        bool "Sound Blaster 16/AWE CSP support"
        depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC)
-       select FW_LOADER if !SND_SB16_CSP_FIRMWARE_IN_KERNEL
+       select FW_LOADER
        help
          Say Y here to include support for the CSP core.  This special
          coprocessor can do variable tasks like various compression and
@@ -372,7 +368,7 @@ config SND_SB16_CSP
 
 config SND_SGALAXY
        tristate "Aztech Sound Galaxy"
-       select SND_AD1848_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for Aztech Sound Galaxy
          soundcards.
@@ -384,7 +380,7 @@ config SND_SSCAPE
        tristate "Ensoniq SoundScape PnP driver"
        select SND_HWDEP
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for Ensoniq SoundScape PnP
          soundcards.
@@ -397,7 +393,7 @@ config SND_WAVEFRONT
        select FW_LOADER
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_CS4231_LIB
+       select SND_WSS_LIB
        help
          Say Y here to include support for Turtle Beach Maui, Tropez
          and Tropez+ soundcards based on the Wavefront chip.
index c0ce7db2a1b50f6066a8fd7ae7a3243f4fda8ed3..63af13d901a5f0178c42eb9953495142e895d08b 100644 (file)
@@ -27,4 +27,4 @@ obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 
 obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \
-                    sb/ wavefront/
+                    sb/ wavefront/ wss/
index 68f1260b5602ef119a5844618e5cac9c671673b0..77524244a846458a7f561f7722e39b1e5e17b971 100644 (file)
@@ -83,8 +83,10 @@ static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
        { .id = "MDK1605", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
        /* Shark Predator ISA - added by Ken Arromdee */
        { .id = "SMM7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
-       /* Analog Devices AD1816A - Terratec AudioSystem EWS64S */
+       /* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */
        { .id = "TER1112", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
+       /* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */
+       { .id = "TER1112", .devs = { { .id = "TER1100" }, { .id = "TER1101" } } },
        /* Analog Devices AD1816A - Terratec Base 64 */
        { .id = "TER1411", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
        /* end */
index 4b8dfe2e3dcb69df0767b43df62ef2b9cf0d44a9..3bfca7c59bafe5eaa2e994f44ecc658700e15abd 100644 (file)
@@ -394,7 +394,8 @@ static int snd_ad1816a_timer_open(struct snd_timer *timer)
 
 static unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer)
 {
-       snd_assert(timer != NULL, return 0);
+       if (snd_BUG_ON(!timer))
+               return 0;
 
        return 10000;
 }
@@ -961,7 +962,8 @@ int __devinit snd_ad1816a_mixer(struct snd_ad1816a *chip)
        unsigned int idx;
        int err;
 
-       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip || !chip->card))
+               return -EINVAL;
 
        card = chip->card;
 
index ae23331e9200d40a8e935d5aa668cb1abe4c09b7..3d6dea3ff927c9edfd88b66cb962879835c95bcf 100644 (file)
@@ -3,10 +3,8 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-ad1848-lib-objs := ad1848_lib.o
 snd-ad1848-objs := ad1848.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AD1848) += snd-ad1848.o
-obj-$(CONFIG_SND_AD1848_LIB) += snd-ad1848-lib.o
 
index 5f5271efdc59fe524b2510ba30ed9b4c83091f8a..b68d20edc20f2f1aa3ffb5d0a106b2591c2f77fd 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/initval.h>
 
 #define CRD_NAME "Generic AD1848/AD1847/CS4248"
@@ -87,7 +87,7 @@ static int __devinit snd_ad1848_match(struct device *dev, unsigned int n)
 static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
 {
        struct snd_card *card;
-       struct snd_ad1848 *chip;
+       struct snd_wss *chip;
        struct snd_pcm *pcm;
        int error;
 
@@ -95,18 +95,19 @@ static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
        if (!card)
                return -EINVAL;
 
-       error = snd_ad1848_create(card, port[n], irq[n], dma1[n],
-                       thinkpad[n] ? AD1848_HW_THINKPAD : AD1848_HW_DETECT, &chip);
+       error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1,
+                       thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT,
+                       0, &chip);
        if (error < 0)
                goto out;
 
        card->private_data = chip;
 
-       error = snd_ad1848_pcm(chip, 0, &pcm);
+       error = snd_wss_pcm(chip, 0, &pcm);
        if (error < 0)
                goto out;
 
-       error = snd_ad1848_mixer(chip);
+       error = snd_wss_mixer(chip);
        if (error < 0)
                goto out;
 
@@ -142,7 +143,7 @@ static int __devexit snd_ad1848_remove(struct device *dev, unsigned int n)
 static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t state)
 {
        struct snd_card *card = dev_get_drvdata(dev);
-       struct snd_ad1848 *chip = card->private_data;
+       struct snd_wss *chip = card->private_data;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->suspend(chip);
@@ -152,7 +153,7 @@ static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t s
 static int snd_ad1848_resume(struct device *dev, unsigned int n)
 {
        struct snd_card *card = dev_get_drvdata(dev);
-       struct snd_ad1848 *chip = card->private_data;
+       struct snd_wss *chip = card->private_data;
 
        chip->resume(chip);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
deleted file mode 100644 (file)
index 630c90f..0000000
+++ /dev/null
@@ -1,1267 +0,0 @@
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Routines for control of AD1848/AD1847/CS4248
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#define SNDRV_MAIN_OBJECT_FILE
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <sound/core.h>
-#include <sound/ad1848.h>
-#include <sound/control.h>
-#include <sound/tlv.h>
-#include <sound/pcm_params.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248");
-MODULE_LICENSE("GPL");
-
-#if 0
-#define SNDRV_DEBUG_MCE
-#endif
-
-/*
- *  Some variables
- */
-
-static unsigned char freq_bits[14] = {
-       /* 5510 */      0x00 | AD1848_XTAL2,
-       /* 6620 */      0x0E | AD1848_XTAL2,
-       /* 8000 */      0x00 | AD1848_XTAL1,
-       /* 9600 */      0x0E | AD1848_XTAL1,
-       /* 11025 */     0x02 | AD1848_XTAL2,
-       /* 16000 */     0x02 | AD1848_XTAL1,
-       /* 18900 */     0x04 | AD1848_XTAL2,
-       /* 22050 */     0x06 | AD1848_XTAL2,
-       /* 27042 */     0x04 | AD1848_XTAL1,
-       /* 32000 */     0x06 | AD1848_XTAL1,
-       /* 33075 */     0x0C | AD1848_XTAL2,
-       /* 37800 */     0x08 | AD1848_XTAL2,
-       /* 44100 */     0x0A | AD1848_XTAL2,
-       /* 48000 */     0x0C | AD1848_XTAL1
-};
-
-static unsigned int rates[14] = {
-       5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
-       27042, 32000, 33075, 37800, 44100, 48000
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-       .count = ARRAY_SIZE(rates),
-       .list = rates,
-       .mask = 0,
-};
-
-static unsigned char snd_ad1848_original_image[16] =
-{
-       0x00,                   /* 00 - lic */
-       0x00,                   /* 01 - ric */
-       0x9f,                   /* 02 - la1ic */
-       0x9f,                   /* 03 - ra1ic */
-       0x9f,                   /* 04 - la2ic */
-       0x9f,                   /* 05 - ra2ic */
-       0xbf,                   /* 06 - loc */
-       0xbf,                   /* 07 - roc */
-       0x20,                   /* 08 - dfr */
-       AD1848_AUTOCALIB,       /* 09 - ic */
-       0x00,                   /* 0a - pc */
-       0x00,                   /* 0b - ti */
-       0x00,                   /* 0c - mi */
-       0x00,                   /* 0d - lbc */
-       0x00,                   /* 0e - dru */
-       0x00,                   /* 0f - drl */
-};
-
-/*
- *  Basic I/O functions
- */
-
-static void snd_ad1848_wait(struct snd_ad1848 *chip)
-{
-       int timeout;
-
-       for (timeout = 250; timeout > 0; timeout--) {
-               if ((inb(AD1848P(chip, REGSEL)) & AD1848_INIT) == 0)
-                       break;
-               udelay(100);
-       }
-}
-
-void snd_ad1848_out(struct snd_ad1848 *chip,
-                          unsigned char reg,
-                          unsigned char value)
-{
-       snd_ad1848_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-               snd_printk(KERN_WARNING "auto calibration time out - "
-                          "reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-       outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
-       outb(chip->image[reg] = value, AD1848P(chip, REG));
-       mb();
-       snd_printdd("codec out - reg 0x%x = 0x%x\n",
-                       chip->mce_bit | reg, value);
-}
-
-EXPORT_SYMBOL(snd_ad1848_out);
-
-static void snd_ad1848_dout(struct snd_ad1848 *chip,
-                           unsigned char reg, unsigned char value)
-{
-       snd_ad1848_wait(chip);
-       outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
-       outb(value, AD1848P(chip, REG));
-       mb();
-}
-
-static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg)
-{
-       snd_ad1848_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-               snd_printk(KERN_WARNING "auto calibration time out - "
-                          "reg = 0x%x\n", reg);
-#endif
-       outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
-       mb();
-       return inb(AD1848P(chip, REG));
-}
-
-#if 0
-
-static void snd_ad1848_debug(struct snd_ad1848 *chip)
-{
-       printk("AD1848 REGS:      INDEX = 0x%02x  ", inb(AD1848P(chip, REGSEL)));
-       printk("                 STATUS = 0x%02x\n", inb(AD1848P(chip, STATUS)));
-       printk("  0x00: left input      = 0x%02x  ", snd_ad1848_in(chip, 0x00));
-       printk("  0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08));
-       printk("  0x01: right input     = 0x%02x  ", snd_ad1848_in(chip, 0x01));
-       printk("  0x09: iface (CFIG 1)  = 0x%02x\n", snd_ad1848_in(chip, 0x09));
-       printk("  0x02: AUXA left       = 0x%02x  ", snd_ad1848_in(chip, 0x02));
-       printk("  0x0a: pin control     = 0x%02x\n", snd_ad1848_in(chip, 0x0a));
-       printk("  0x03: AUXA right      = 0x%02x  ", snd_ad1848_in(chip, 0x03));
-       printk("  0x0b: init & status   = 0x%02x\n", snd_ad1848_in(chip, 0x0b));
-       printk("  0x04: AUXB left       = 0x%02x  ", snd_ad1848_in(chip, 0x04));
-       printk("  0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c));
-       printk("  0x05: AUXB right      = 0x%02x  ", snd_ad1848_in(chip, 0x05));
-       printk("  0x0d: loopback        = 0x%02x\n", snd_ad1848_in(chip, 0x0d));
-       printk("  0x06: left output     = 0x%02x  ", snd_ad1848_in(chip, 0x06));
-       printk("  0x0e: data upr count  = 0x%02x\n", snd_ad1848_in(chip, 0x0e));
-       printk("  0x07: right output    = 0x%02x  ", snd_ad1848_in(chip, 0x07));
-       printk("  0x0f: data lwr count  = 0x%02x\n", snd_ad1848_in(chip, 0x0f));
-}
-
-#endif
-
-/*
- *  AD1848 detection / MCE routines
- */
-
-static void snd_ad1848_mce_up(struct snd_ad1848 *chip)
-{
-       unsigned long flags;
-       int timeout;
-
-       snd_ad1848_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-               snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n");
-#endif
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->mce_bit |= AD1848_MCE;
-       timeout = inb(AD1848P(chip, REGSEL));
-       if (timeout == 0x80)
-               snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
-       if (!(timeout & AD1848_MCE))
-               outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
-{
-       unsigned long flags, timeout;
-       int reg;
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       for (timeout = 5; timeout > 0; timeout--)
-               inb(AD1848P(chip, REGSEL));
-       /* end of cleanup sequence */
-       for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
-               udelay(100);
-
-       snd_printdd("(1) timeout = %ld\n", timeout);
-
-#ifdef CONFIG_SND_DEBUG
-       if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-               snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL));
-#endif
-
-       chip->mce_bit &= ~AD1848_MCE;
-       reg = inb(AD1848P(chip, REGSEL));
-       outb(chip->mce_bit | (reg & 0x1f), AD1848P(chip, REGSEL));
-       if (reg == 0x80)
-               snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
-       if ((reg & AD1848_MCE) == 0) {
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               return;
-       }
-
-       /*
-        * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low.
-        * It may take up to 5 sample periods (at most 907 us @ 5.5125 kHz) for
-        * the process to _start_, so it is important to wait at least that long
-        * before checking.  Otherwise we might think AC has finished when it
-        * has in fact not begun.  It could take 128 (no AC) or 384 (AC) cycles
-        * for ACI to drop.  This gives a wait of at most 70 ms with a more
-        * typical value of 3-9 ms.
-        */
-       timeout = jiffies + msecs_to_jiffies(250);
-       do {
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               msleep(1);
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               reg = snd_ad1848_in(chip, AD1848_TEST_INIT) &
-                     AD1848_CALIB_IN_PROGRESS;
-       } while (reg && time_before(jiffies, timeout));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (reg)
-               snd_printk(KERN_ERR
-                          "mce_down - auto calibration time out (2)\n");
-
-       snd_printdd("(4) jiffies = %lu\n", jiffies);
-       snd_printd("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL)));
-}
-
-static unsigned int snd_ad1848_get_count(unsigned char format,
-                                        unsigned int size)
-{
-       switch (format & 0xe0) {
-       case AD1848_LINEAR_16:
-               size >>= 1;
-               break;
-       }
-       if (format & AD1848_STEREO)
-               size >>= 1;
-       return size;
-}
-
-static int snd_ad1848_trigger(struct snd_ad1848 *chip, unsigned char what,
-                             int channel, int cmd)
-{
-       int result = 0;
-
-#if 0
-       printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(AD1848P(card, STATUS)));
-#endif
-       spin_lock(&chip->reg_lock);
-       if (cmd == SNDRV_PCM_TRIGGER_START) {
-               if (chip->image[AD1848_IFACE_CTRL] & what) {
-                       spin_unlock(&chip->reg_lock);
-                       return 0;
-               }
-               snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] |= what);
-               chip->mode |= AD1848_MODE_RUNNING;
-       } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
-               if (!(chip->image[AD1848_IFACE_CTRL] & what)) {
-                       spin_unlock(&chip->reg_lock);
-                       return 0;
-               }
-               snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] &= ~what);
-               chip->mode &= ~AD1848_MODE_RUNNING;
-       } else {
-               result = -EINVAL;
-       }
-       spin_unlock(&chip->reg_lock);
-       return result;
-}
-
-/*
- *  CODEC I/O
- */
-
-static unsigned char snd_ad1848_get_rate(unsigned int rate)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(rates); i++)
-               if (rate == rates[i])
-                       return freq_bits[i];
-       snd_BUG();
-       return freq_bits[ARRAY_SIZE(rates) - 1];
-}
-
-static int snd_ad1848_ioctl(struct snd_pcm_substream *substream,
-                           unsigned int cmd, void *arg)
-{
-       return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-
-static unsigned char snd_ad1848_get_format(int format, int channels)
-{
-       unsigned char rformat;
-
-       rformat = AD1848_LINEAR_8;
-       switch (format) {
-       case SNDRV_PCM_FORMAT_A_LAW:    rformat = AD1848_ALAW_8; break;
-       case SNDRV_PCM_FORMAT_MU_LAW:   rformat = AD1848_ULAW_8; break;
-       case SNDRV_PCM_FORMAT_S16_LE:   rformat = AD1848_LINEAR_16; break;
-       }
-       if (channels > 1)
-               rformat |= AD1848_STEREO;
-#if 0
-       snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
-       return rformat;
-}
-
-static void snd_ad1848_calibrate_mute(struct snd_ad1848 *chip, int mute)
-{
-       unsigned long flags;
-       
-       mute = mute ? 1 : 0;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       if (chip->calibrate_mute == mute) {
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               return;
-       }
-       if (!mute) {
-               snd_ad1848_dout(chip, AD1848_LEFT_INPUT, chip->image[AD1848_LEFT_INPUT]);
-               snd_ad1848_dout(chip, AD1848_RIGHT_INPUT, chip->image[AD1848_RIGHT_INPUT]);
-       }
-       snd_ad1848_dout(chip, AD1848_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_LEFT_INPUT]);
-       snd_ad1848_dout(chip, AD1848_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_RIGHT_INPUT]);
-       snd_ad1848_dout(chip, AD1848_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_LEFT_INPUT]);
-       snd_ad1848_dout(chip, AD1848_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_RIGHT_INPUT]);
-       snd_ad1848_dout(chip, AD1848_LEFT_OUTPUT, mute ? 0x80 : chip->image[AD1848_LEFT_OUTPUT]);
-       snd_ad1848_dout(chip, AD1848_RIGHT_OUTPUT, mute ? 0x80 : chip->image[AD1848_RIGHT_OUTPUT]);
-       chip->calibrate_mute = mute;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_ad1848_set_data_format(struct snd_ad1848 *chip, struct snd_pcm_hw_params *hw_params)
-{
-       if (hw_params == NULL) {
-               chip->image[AD1848_DATA_FORMAT] = 0x20;
-       } else {
-               chip->image[AD1848_DATA_FORMAT] =
-                   snd_ad1848_get_format(params_format(hw_params), params_channels(hw_params)) |
-                   snd_ad1848_get_rate(params_rate(hw_params));
-       }
-       // snd_printk(">>> pmode = 0x%x, dfr = 0x%x\n", pstr->mode, chip->image[AD1848_DATA_FORMAT]);
-}
-
-static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode)
-{
-       unsigned long flags;
-
-       if (chip->mode & AD1848_MODE_OPEN)
-               return -EAGAIN;
-
-       snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("open: (1)\n");
-#endif
-       snd_ad1848_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |
-                            AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO |
-                            AD1848_CALIB_MODE);
-       chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB;
-       snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("open: (2)\n");
-#endif
-
-       snd_ad1848_set_data_format(chip, NULL);
-
-       snd_ad1848_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("open: (3)\n");
-#endif
-
-       /* ok. now enable and ack CODEC IRQ */
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
-       outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
-       chip->image[AD1848_PIN_CTRL] |= AD1848_IRQ_ENABLE;
-       snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       chip->mode = mode;
-
-       return 0;
-}
-
-static void snd_ad1848_close(struct snd_ad1848 *chip)
-{
-       unsigned long flags;
-
-       if (!chip->mode)
-               return;
-       /* disable IRQ */
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
-       outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
-       chip->image[AD1848_PIN_CTRL] &= ~AD1848_IRQ_ENABLE;
-       snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       /* now disable capture & playback */
-
-       snd_ad1848_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |
-                            AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO);
-       snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_ad1848_mce_down(chip);
-
-       /* clear IRQ again */
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
-       outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       chip->mode = 0;
-}
-
-/*
- *  ok.. exported functions..
- */
-
-static int snd_ad1848_playback_trigger(struct snd_pcm_substream *substream,
-                                      int cmd)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       return snd_ad1848_trigger(chip, AD1848_PLAYBACK_ENABLE, SNDRV_PCM_STREAM_PLAYBACK, cmd);
-}
-
-static int snd_ad1848_capture_trigger(struct snd_pcm_substream *substream,
-                                     int cmd)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       return snd_ad1848_trigger(chip, AD1848_CAPTURE_ENABLE, SNDRV_PCM_STREAM_CAPTURE, cmd);
-}
-
-static int snd_ad1848_playback_hw_params(struct snd_pcm_substream *substream,
-                                        struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       unsigned long flags;
-       int err;
-
-       if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-               return err;
-       snd_ad1848_calibrate_mute(chip, 1);
-       snd_ad1848_set_data_format(chip, hw_params);
-       snd_ad1848_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_ad1848_mce_down(chip);
-       snd_ad1848_calibrate_mute(chip, 0);
-       return 0;
-}
-
-static int snd_ad1848_playback_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_ad1848_playback_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-       unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-       chip->dma_size = size;
-       chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO);
-       snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
-       count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count);
-       snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-static int snd_ad1848_capture_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       unsigned long flags;
-       int err;
-
-       if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-               return err;
-       snd_ad1848_calibrate_mute(chip, 1);
-       snd_ad1848_set_data_format(chip, hw_params);
-       snd_ad1848_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_ad1848_mce_down(chip);
-       snd_ad1848_calibrate_mute(chip, 0);
-       return 0;
-}
-
-static int snd_ad1848_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-       unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-       chip->dma_size = size;
-       chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO);
-       snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
-       count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count);
-       snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id)
-{
-       struct snd_ad1848 *chip = dev_id;
-
-       if ((chip->mode & AD1848_MODE_PLAY) && chip->playback_substream &&
-           (chip->mode & AD1848_MODE_RUNNING))
-               snd_pcm_period_elapsed(chip->playback_substream);
-       if ((chip->mode & AD1848_MODE_CAPTURE) && chip->capture_substream &&
-           (chip->mode & AD1848_MODE_RUNNING))
-               snd_pcm_period_elapsed(chip->capture_substream);
-       outb(0, AD1848P(chip, STATUS)); /* clear global interrupt bit */
-       return IRQ_HANDLED;
-}
-
-static snd_pcm_uframes_t snd_ad1848_playback_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       size_t ptr;
-       
-       if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_PLAYBACK_ENABLE))
-               return 0;
-       ptr = snd_dma_pointer(chip->dma, chip->dma_size);
-       return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_ad1848_capture_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       size_t ptr;
-
-       if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_CAPTURE_ENABLE))
-               return 0;
-       ptr = snd_dma_pointer(chip->dma, chip->dma_size);
-       return bytes_to_frames(substream->runtime, ptr);
-}
-
-/*
-
- */
-
-static void snd_ad1848_thinkpad_twiddle(struct snd_ad1848 *chip, int on) {
-
-       int tmp;
-
-       if (!chip->thinkpad_flag) return;
-
-       outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
-       tmp = inb(AD1848_THINKPAD_CTL_PORT2);
-
-       if (on)
-               /* turn it on */
-               tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
-       else
-               /* turn it off */
-               tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
-       
-       outb(tmp, AD1848_THINKPAD_CTL_PORT2);
-
-}
-
-#ifdef CONFIG_PM
-static void snd_ad1848_suspend(struct snd_ad1848 *chip)
-{
-       snd_pcm_suspend_all(chip->pcm);
-       if (chip->thinkpad_flag)
-               snd_ad1848_thinkpad_twiddle(chip, 0);
-}
-
-static void snd_ad1848_resume(struct snd_ad1848 *chip)
-{
-       int i;
-
-       if (chip->thinkpad_flag)
-               snd_ad1848_thinkpad_twiddle(chip, 1);
-
-       /* clear any pendings IRQ */
-       inb(AD1848P(chip, STATUS));
-       outb(0, AD1848P(chip, STATUS));
-       mb();
-
-       snd_ad1848_mce_down(chip);
-       for (i = 0; i < 16; i++)
-               snd_ad1848_out(chip, i, chip->image[i]);
-       snd_ad1848_mce_up(chip);
-       snd_ad1848_mce_down(chip);
-}
-#endif /* CONFIG_PM */
-
-static int snd_ad1848_probe(struct snd_ad1848 * chip)
-{
-       unsigned long flags;
-       int i, id, rev, ad1847;
-       unsigned char *ptr;
-
-#if 0
-       snd_ad1848_debug(chip);
-#endif
-       id = ad1847 = 0;
-       for (i = 0; i < 1000; i++) {
-               mb();
-               if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
-                       udelay(500);
-               else {
-                       spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00);
-                       snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa);
-                       snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45);
-                       rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT);
-                       if (rev == 0x65) {
-                               spin_unlock_irqrestore(&chip->reg_lock, flags);
-                               id = 1;
-                               ad1847 = 1;
-                               break;
-                       }
-                       if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) {
-                               spin_unlock_irqrestore(&chip->reg_lock, flags);
-                               id = 1;
-                               break;
-                       }
-                       spin_unlock_irqrestore(&chip->reg_lock, flags);
-               }
-       }
-       if (id != 1)
-               return -ENODEV; /* no valid device found */
-       if (chip->hardware == AD1848_HW_DETECT) {
-               if (ad1847) {
-                       chip->hardware = AD1848_HW_AD1847;
-               } else {
-                       chip->hardware = AD1848_HW_AD1848;
-                       rev = snd_ad1848_in(chip, AD1848_MISC_INFO);
-                       if (rev & 0x80) {
-                               chip->hardware = AD1848_HW_CS4248;
-                       } else if ((rev & 0x0f) == 0x0a) {
-                               snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40);
-                               for (i = 0; i < 16; ++i) {
-                                       if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) {
-                                               chip->hardware = AD1848_HW_CMI8330;
-                                               break;
-                                       }
-                               }
-                               snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00);
-                       }
-               }
-       }
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       inb(AD1848P(chip, STATUS));     /* clear any pendings IRQ */
-       outb(0, AD1848P(chip, STATUS));
-       mb();
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       chip->image[AD1848_MISC_INFO] = 0x00;
-       chip->image[AD1848_IFACE_CTRL] =
-           (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA;
-       ptr = (unsigned char *) &chip->image;
-       snd_ad1848_mce_down(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       for (i = 0; i < 16; i++)        /* ok.. fill all AD1848 registers */
-               snd_ad1848_out(chip, i, *ptr++);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_ad1848_mce_up(chip);
-       snd_ad1848_mce_down(chip);
-       return 0;               /* all things are ok.. */
-}
-
-/*
-
- */
-
-static struct snd_pcm_hardware snd_ad1848_playback =
-{
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID),
-       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
-                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
-       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-       .rate_min =             5510,
-       .rate_max =             48000,
-       .channels_min =         1,
-       .channels_max =         2,
-       .buffer_bytes_max =     (128*1024),
-       .period_bytes_min =     64,
-       .period_bytes_max =     (128*1024),
-       .periods_min =          1,
-       .periods_max =          1024,
-       .fifo_size =            0,
-};
-
-static struct snd_pcm_hardware snd_ad1848_capture =
-{
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID),
-       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
-                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
-       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-       .rate_min =             5510,
-       .rate_max =             48000,
-       .channels_min =         1,
-       .channels_max =         2,
-       .buffer_bytes_max =     (128*1024),
-       .period_bytes_min =     64,
-       .period_bytes_max =     (128*1024),
-       .periods_min =          1,
-       .periods_max =          1024,
-       .fifo_size =            0,
-};
-
-/*
-
- */
-
-static int snd_ad1848_playback_open(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int err;
-
-       if ((err = snd_ad1848_open(chip, AD1848_MODE_PLAY)) < 0)
-               return err;
-       chip->playback_substream = substream;
-       runtime->hw = snd_ad1848_playback;
-       snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max);
-       snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-       return 0;
-}
-
-static int snd_ad1848_capture_open(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int err;
-
-       if ((err = snd_ad1848_open(chip, AD1848_MODE_CAPTURE)) < 0)
-               return err;
-       chip->capture_substream = substream;
-       runtime->hw = snd_ad1848_capture;
-       snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max);
-       snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-       return 0;
-}
-
-static int snd_ad1848_playback_close(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-
-       chip->mode &= ~AD1848_MODE_PLAY;
-       chip->playback_substream = NULL;
-       snd_ad1848_close(chip);
-       return 0;
-}
-
-static int snd_ad1848_capture_close(struct snd_pcm_substream *substream)
-{
-       struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-
-       chip->mode &= ~AD1848_MODE_CAPTURE;
-       chip->capture_substream = NULL;
-       snd_ad1848_close(chip);
-       return 0;
-}
-
-static int snd_ad1848_free(struct snd_ad1848 *chip)
-{
-       release_and_free_resource(chip->res_port);
-       if (chip->irq >= 0)
-               free_irq(chip->irq, (void *) chip);
-       if (chip->dma >= 0) {
-               snd_dma_disable(chip->dma);
-               free_dma(chip->dma);
-       }
-       kfree(chip);
-       return 0;
-}
-
-static int snd_ad1848_dev_free(struct snd_device *device)
-{
-       struct snd_ad1848 *chip = device->device_data;
-       return snd_ad1848_free(chip);
-}
-
-static const char *snd_ad1848_chip_id(struct snd_ad1848 *chip)
-{
-       switch (chip->hardware) {
-       case AD1848_HW_AD1847:  return "AD1847";
-       case AD1848_HW_AD1848:  return "AD1848";
-       case AD1848_HW_CS4248:  return "CS4248";
-       case AD1848_HW_CMI8330: return "CMI8330/C3D";
-       default:                return "???";
-       }
-}
-
-int snd_ad1848_create(struct snd_card *card,
-                     unsigned long port,
-                     int irq, int dma,
-                     unsigned short hardware,
-                     struct snd_ad1848 ** rchip)
-{
-       static struct snd_device_ops ops = {
-               .dev_free =     snd_ad1848_dev_free,
-       };
-       struct snd_ad1848 *chip;
-       int err;
-
-       *rchip = NULL;
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
-       spin_lock_init(&chip->reg_lock);
-       chip->card = card;
-       chip->port = port;
-       chip->irq = -1;
-       chip->dma = -1;
-       chip->hardware = hardware;
-       memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image));
-       
-       if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) {
-               snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port);
-               snd_ad1848_free(chip);
-               return -EBUSY;
-       }
-       if (request_irq(irq, snd_ad1848_interrupt, IRQF_DISABLED, "AD1848", (void *) chip)) {
-               snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq);
-               snd_ad1848_free(chip);
-               return -EBUSY;
-       }
-       chip->irq = irq;
-       if (request_dma(dma, "AD1848")) {
-               snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma);
-               snd_ad1848_free(chip);
-               return -EBUSY;
-       }
-       chip->dma = dma;
-
-       if (hardware == AD1848_HW_THINKPAD) {
-               chip->thinkpad_flag = 1;
-               chip->hardware = AD1848_HW_DETECT; /* reset */
-               snd_ad1848_thinkpad_twiddle(chip, 1);
-       }
-
-       if (snd_ad1848_probe(chip) < 0) {
-               snd_ad1848_free(chip);
-               return -ENODEV;
-       }
-
-       /* Register device */
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-               snd_ad1848_free(chip);
-               return err;
-       }
-
-#ifdef CONFIG_PM
-       chip->suspend = snd_ad1848_suspend;
-       chip->resume = snd_ad1848_resume;
-#endif
-
-       *rchip = chip;
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_create);
-
-static struct snd_pcm_ops snd_ad1848_playback_ops = {
-       .open =         snd_ad1848_playback_open,
-       .close =        snd_ad1848_playback_close,
-       .ioctl =        snd_ad1848_ioctl,
-       .hw_params =    snd_ad1848_playback_hw_params,
-       .hw_free =      snd_ad1848_playback_hw_free,
-       .prepare =      snd_ad1848_playback_prepare,
-       .trigger =      snd_ad1848_playback_trigger,
-       .pointer =      snd_ad1848_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_ad1848_capture_ops = {
-       .open =         snd_ad1848_capture_open,
-       .close =        snd_ad1848_capture_close,
-       .ioctl =        snd_ad1848_ioctl,
-       .hw_params =    snd_ad1848_capture_hw_params,
-       .hw_free =      snd_ad1848_capture_hw_free,
-       .prepare =      snd_ad1848_capture_prepare,
-       .trigger =      snd_ad1848_capture_trigger,
-       .pointer =      snd_ad1848_capture_pointer,
-};
-
-int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm)
-{
-       struct snd_pcm *pcm;
-       int err;
-
-       if ((err = snd_pcm_new(chip->card, "AD1848", device, 1, 1, &pcm)) < 0)
-               return err;
-
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1848_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ad1848_capture_ops);
-
-       pcm->private_data = chip;
-       pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
-       strcpy(pcm->name, snd_ad1848_chip_id(chip));
-
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-                                             snd_dma_isa_data(),
-                                             64*1024, chip->dma > 3 ? 128*1024 : 64*1024);
-
-       chip->pcm = pcm;
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_pcm);
-
-const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
-{
-       return direction == SNDRV_PCM_STREAM_PLAYBACK ?
-               &snd_ad1848_playback_ops : &snd_ad1848_capture_ops;
-}
-
-EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
-
-/*
- *  MIXER part
- */
-
-static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       static char *texts[4] = {
-               "Line", "Aux", "Mic", "Mix"
-       };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 2;
-       uinfo->value.enumerated.items = 4;
-       if (uinfo->value.enumerated.item > 3)
-               uinfo->value.enumerated.item = 3;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int snd_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6;
-       ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       unsigned short left, right;
-       int change;
-       
-       if (ucontrol->value.enumerated.item[0] > 3 ||
-           ucontrol->value.enumerated.item[1] > 3)
-               return -EINVAL;
-       left = ucontrol->value.enumerated.item[0] << 6;
-       right = ucontrol->value.enumerated.item[1] << 6;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left;
-       right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right;
-       change = left != chip->image[AD1848_LEFT_INPUT] ||
-                right != chip->image[AD1848_RIGHT_INPUT];
-       snd_ad1848_out(chip, AD1848_LEFT_INPUT, left);
-       snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return change;
-}
-
-static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0xff;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
-       
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (invert)
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-       return 0;
-}
-
-static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0xff;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
-       int change;
-       unsigned short val;
-       
-       val = (ucontrol->value.integer.value[0] & mask);
-       if (invert)
-               val = mask - val;
-       val <<= shift;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       val = (chip->image[reg] & ~(mask << shift)) | val;
-       change = val != chip->image[reg];
-       snd_ad1848_out(chip, reg, val);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return change;
-}
-
-static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int left_reg = kcontrol->private_value & 0xff;
-       int right_reg = (kcontrol->private_value >> 8) & 0xff;
-       int shift_left = (kcontrol->private_value >> 16) & 0x07;
-       int shift_right = (kcontrol->private_value >> 19) & 0x07;
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-       int invert = (kcontrol->private_value >> 22) & 1;
-       
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
-       ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (invert) {
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-               ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
-       }
-       return 0;
-}
-
-static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int left_reg = kcontrol->private_value & 0xff;
-       int right_reg = (kcontrol->private_value >> 8) & 0xff;
-       int shift_left = (kcontrol->private_value >> 16) & 0x07;
-       int shift_right = (kcontrol->private_value >> 19) & 0x07;
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-       int invert = (kcontrol->private_value >> 22) & 1;
-       int change;
-       unsigned short val1, val2;
-       
-       val1 = ucontrol->value.integer.value[0] & mask;
-       val2 = ucontrol->value.integer.value[1] & mask;
-       if (invert) {
-               val1 = mask - val1;
-               val2 = mask - val2;
-       }
-       val1 <<= shift_left;
-       val2 <<= shift_right;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       if (left_reg != right_reg) {
-               val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
-               val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
-               change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
-               snd_ad1848_out(chip, left_reg, val1);
-               snd_ad1848_out(chip, right_reg, val2);
-       } else {
-               val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
-               change = val1 != chip->image[left_reg];
-               snd_ad1848_out(chip, left_reg, val1);           
-       }
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return change;
-}
-
-/*
- */
-int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip,
-                           const struct ad1848_mix_elem *c)
-{
-       static struct snd_kcontrol_new newctls[] = {
-               [AD1848_MIX_SINGLE] = {
-                       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                       .info = snd_ad1848_info_single,
-                       .get = snd_ad1848_get_single,
-                       .put = snd_ad1848_put_single,
-               },
-               [AD1848_MIX_DOUBLE] = {
-                       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                       .info = snd_ad1848_info_double,
-                       .get = snd_ad1848_get_double,
-                       .put = snd_ad1848_put_double,
-               },
-               [AD1848_MIX_CAPTURE] = {
-                       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-                       .info = snd_ad1848_info_mux,
-                       .get = snd_ad1848_get_mux,
-                       .put = snd_ad1848_put_mux,
-               },
-       };
-       struct snd_kcontrol *ctl;
-       int err;
-
-       ctl = snd_ctl_new1(&newctls[c->type], chip);
-       if (! ctl)
-               return -ENOMEM;
-       strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name));
-       ctl->id.index = c->index;
-       ctl->private_value = c->private_value;
-       if (c->tlv) {
-               ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-               ctl->tlv.p = c->tlv;
-       }
-       if ((err = snd_ctl_add(chip->card, ctl)) < 0)
-               return err;
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
-
-static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
-
-static struct ad1848_mix_elem snd_ad1848_controls[] = {
-AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
-AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1,
-                 db_scale_6bit),
-AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
-                 db_scale_5bit_12db_max),
-AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
-                 db_scale_5bit_12db_max),
-AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0,
-                 db_scale_rec_gain),
-{
-       .name = "Capture Source",
-       .type = AD1848_MIX_CAPTURE,
-},
-AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
-AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0,
-                 db_scale_6bit),
-};
-                                        
-int snd_ad1848_mixer(struct snd_ad1848 *chip)
-{
-       struct snd_card *card;
-       struct snd_pcm *pcm;
-       unsigned int idx;
-       int err;
-
-       snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
-
-       pcm = chip->pcm;
-       card = chip->card;
-
-       strcpy(card->mixername, pcm->name);
-
-       for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++)
-               if ((err = snd_ad1848_add_ctl_elem(chip, &snd_ad1848_controls[idx])) < 0)
-                       return err;
-
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_mixer);
-
-/*
- *  INIT part
- */
-
-static int __init alsa_ad1848_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_ad1848_exit(void)
-{
-}
-
-module_init(alsa_ad1848_init)
-module_exit(alsa_ad1848_exit)
index 154e728f592d0f7cd8aa523025e01aa5e0d7b7c5..3e74d1a3928e7f8b6067090cb54f13645f6e746b 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/initval.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 
@@ -76,7 +76,7 @@ struct snd_card_azt2320 {
        int dev_no;
        struct pnp_dev *dev;
        struct pnp_dev *devmpu;
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
 };
 
 static struct pnp_card_device_id snd_azt2320_pnpids[] = {
@@ -181,7 +181,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
        int error;
        struct snd_card *card;
        struct snd_card_azt2320 *acard;
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        struct snd_opl3 *opl3;
 
        if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
@@ -200,11 +200,11 @@ static int __devinit snd_card_azt2320_probe(int dev,
                return error;
        }
 
-       if ((error = snd_cs4231_create(card, wss_port[dev], -1,
-                                      irq[dev],
-                                      dma1[dev],
-                                      dma2[dev],
-                                      CS4231_HW_DETECT, 0, &chip)) < 0) {
+       error = snd_wss_create(card, wss_port[dev], -1,
+                              irq[dev],
+                              dma1[dev], dma2[dev],
+                              WSS_HW_DETECT, 0, &chip);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
@@ -214,15 +214,18 @@ static int __devinit snd_card_azt2320_probe(int dev,
        sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
                card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
 
-       if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
+       error = snd_wss_pcm(chip, 0, NULL);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
-       if ((error = snd_cs4231_mixer(chip)) < 0) {
+       error = snd_wss_mixer(chip);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
-       if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
+       error = snd_wss_timer(chip, 0, NULL);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
@@ -293,7 +296,7 @@ static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t sta
 {
        struct snd_card *card = pnp_get_card_drvdata(pcard);
        struct snd_card_azt2320 *acard = card->private_data;
-       struct snd_cs4231 *chip = acard->chip;
+       struct snd_wss *chip = acard->chip;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->suspend(chip);
@@ -304,7 +307,7 @@ static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
 {
        struct snd_card *card = pnp_get_card_drvdata(pcard);
        struct snd_card_azt2320 *acard = card->private_data;
-       struct snd_cs4231 *chip = acard->chip;
+       struct snd_wss *chip = acard->chip;
 
        chip->resume(chip);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
index 4d198ec71e9b410aad2100e189c3293453d3129c..e49aec700a556681ea1e5f05b3e68da7d571852d 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/sb.h>
 #include <sound/initval.h>
 
@@ -151,7 +151,7 @@ struct snd_cmi8330 {
        struct pnp_dev *play;
 #endif
        struct snd_card *card;
-       struct snd_ad1848 *wss;
+       struct snd_wss *wss;
        struct snd_sb *sb;
 
        struct snd_pcm *pcm;
@@ -174,32 +174,57 @@ MODULE_DEVICE_TABLE(pnp_card, snd_cmi8330_pnpids);
 #endif
 
 
-static struct ad1848_mix_elem snd_cmi8330_controls[] __devinitdata = {
-AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
-AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1),
-AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
-AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
-AD1848_DOUBLE("Line Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0),
-AD1848_DOUBLE("Line Playback Volume", 0, CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("Line Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0),
-AD1848_DOUBLE("Line Capture Volume", 0, CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0),
-AD1848_DOUBLE("CD Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
-AD1848_DOUBLE("CD Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
-AD1848_DOUBLE("CD Playback Volume", 0, CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("CD Capture Volume", 0, CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
-AD1848_SINGLE("Mic Playback Switch", 0, CMI8330_MUTEMUX, 0, 1, 0),
-AD1848_SINGLE("Mic Playback Volume", 0, CMI8330_OUTPUTVOL, 0, 7, 0),
-AD1848_SINGLE("Mic Capture Switch", 0, CMI8330_RMUX3D, 0, 1, 0),
-AD1848_SINGLE("Mic Capture Volume", 0, CMI8330_OUTPUTVOL, 5, 7, 0),
-AD1848_DOUBLE("Wavetable Playback Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0),
-AD1848_DOUBLE("Wavetable Playback Volume", 0, CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("Wavetable Capture Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0),
-AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
-AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
-AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
-AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
-AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
-AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
+static struct snd_kcontrol_new snd_cmi8330_controls[] __devinitdata = {
+WSS_DOUBLE("Master Playback Volume", 0,
+               CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
+WSS_SINGLE("Loud Playback Switch", 0,
+               CMI8330_MUTEMUX, 6, 1, 1),
+WSS_DOUBLE("PCM Playback Switch", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+               CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0),
+WSS_DOUBLE("Line Playback Volume", 0,
+               CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0),
+WSS_DOUBLE("Line Capture Switch", 0,
+               CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0),
+WSS_DOUBLE("Line Capture Volume", 0,
+               CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0),
+WSS_DOUBLE("CD Playback Switch", 0,
+               CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
+WSS_DOUBLE("CD Capture Switch", 0,
+               CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
+WSS_DOUBLE("CD Playback Volume", 0,
+               CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
+WSS_DOUBLE("CD Capture Volume", 0,
+               CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
+WSS_SINGLE("Mic Playback Switch", 0,
+               CMI8330_MUTEMUX, 0, 1, 0),
+WSS_SINGLE("Mic Playback Volume", 0,
+               CMI8330_OUTPUTVOL, 0, 7, 0),
+WSS_SINGLE("Mic Capture Switch", 0,
+               CMI8330_RMUX3D, 0, 1, 0),
+WSS_SINGLE("Mic Capture Volume", 0,
+               CMI8330_OUTPUTVOL, 5, 7, 0),
+WSS_DOUBLE("Wavetable Playback Switch", 0,
+               CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0),
+WSS_DOUBLE("Wavetable Playback Volume", 0,
+               CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0),
+WSS_DOUBLE("Wavetable Capture Switch", 0,
+               CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0),
+WSS_DOUBLE("Wavetable Capture Volume", 0,
+               CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
+WSS_SINGLE("3D Control - Switch", 0,
+               CMI8330_RMUX3D, 5, 1, 1),
+WSS_SINGLE("PC Speaker Playback Volume", 0,
+               CMI8330_OUTPUTVOL, 3, 3, 0),
+WSS_SINGLE("FM Playback Switch", 0,
+               CMI8330_RECMUX, 3, 1, 1),
+WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0,
+               CMI8330_RMUX3D, 7, 1, 1),
+WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0,
+               CMI8330_MUTEMUX, 7, 1, 1),
 };
 
 #ifdef ENABLE_SB_MIXER
@@ -268,7 +293,10 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330
        strcpy(card->mixername, "CMI8330/C3D");
 
        for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
-               if ((err = snd_ad1848_add_ctl_elem(acard->wss, &snd_cmi8330_controls[idx])) < 0)
+               err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_cmi8330_controls[idx],
+                                            acard->wss));
+               if (err < 0)
                        return err;
        }
 
@@ -385,7 +413,7 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *
        chip->streams[CMI_SB_STREAM].private_data = chip->sb;
 
        /* AD1848 */
-       ops = snd_ad1848_get_pcm_ops(CMI_AD_STREAM);
+       ops = snd_wss_get_pcm_ops(CMI_AD_STREAM);
        chip->streams[CMI_AD_STREAM].ops = *ops;
        chip->streams[CMI_AD_STREAM].open = ops->open;
        chip->streams[CMI_AD_STREAM].ops.open = cmi_open_callbacks[CMI_AD_STREAM];
@@ -461,16 +489,15 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
        int i, err;
 
        acard = card->private_data;
-       if ((err = snd_ad1848_create(card,
-                                    wssport[dev] + 4,
-                                    wssirq[dev],
-                                    wssdma[dev],
-                                    AD1848_HW_DETECT,
-                                    &acard->wss)) < 0) {
+       err = snd_wss_create(card, wssport[dev] + 4, -1,
+                            wssirq[dev],
+                            wssdma[dev], -1,
+                            WSS_HW_DETECT, 0, &acard->wss);
+       if (err < 0) {
                snd_printk(KERN_ERR PFX "(AD1848) device busy??\n");
                return err;
        }
-       if (acard->wss->hardware != AD1848_HW_CMI8330) {
+       if (acard->wss->hardware != WSS_HW_CMI8330) {
                snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n");
                return -ENODEV;
        }
@@ -489,9 +516,10 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
                return err;
        }
 
-       snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */
+       snd_wss_out(acard->wss, CS4231_MISC_INFO, 0x40); /* switch on MODE2 */
        for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++)
-               snd_ad1848_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]);
+               snd_wss_out(acard->wss, i,
+                           snd_cmi8330_image[i - CMI8330_RMUX3D]);
 
        if ((err = snd_cmi8330_mixer(card, acard)) < 0) {
                snd_printk(KERN_ERR PFX "failed to create mixers\n");
index 5067ee0019333b1d7263bdcfcbc4bd50576f423a..5870ca21ab59c24e135abb500c1d5e1ed4c5b633 100644 (file)
@@ -3,14 +3,12 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-cs4231-lib-objs := cs4231_lib.o
 snd-cs4236-lib-objs := cs4236_lib.o
 snd-cs4231-objs := cs4231.o
 snd-cs4232-objs := cs4232.o
 snd-cs4236-objs := cs4236.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_CS4231_LIB) += snd-cs4231-lib.o
 obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
 obj-$(CONFIG_SND_CS4232) += snd-cs4232.o
 obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o
index e9462b9944be1c8b7ee3e987ca50d01134d056ee..ddd289120aa8e06fc6bc194102f39b1f2e740028 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
@@ -91,7 +91,7 @@ static int __devinit snd_cs4231_match(struct device *dev, unsigned int n)
 static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
 {
        struct snd_card *card;
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        struct snd_pcm *pcm;
        int error;
 
@@ -99,14 +99,14 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
        if (!card)
                return -EINVAL;
 
-       error = snd_cs4231_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
-                       CS4231_HW_DETECT, 0, &chip);
+       error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
+                       WSS_HW_DETECT, 0, &chip);
        if (error < 0)
                goto out;
 
        card->private_data = chip;
 
-       error = snd_cs4231_pcm(chip, 0, &pcm);
+       error = snd_wss_pcm(chip, 0, &pcm);
        if (error < 0)
                goto out;
 
@@ -118,11 +118,11 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
        if (dma2[n] >= 0)
                sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]);
 
-       error = snd_cs4231_mixer(chip);
+       error = snd_wss_mixer(chip);
        if (error < 0)
                goto out;
 
-       error = snd_cs4231_timer(chip, 0, NULL);
+       error = snd_wss_timer(chip, 0, NULL);
        if (error < 0)
                goto out;
 
@@ -160,7 +160,7 @@ static int __devexit snd_cs4231_remove(struct device *dev, unsigned int n)
 static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t state)
 {
        struct snd_card *card = dev_get_drvdata(dev);
-       struct snd_cs4231 *chip = card->private_data;
+       struct snd_wss *chip = card->private_data;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->suspend(chip);
@@ -170,7 +170,7 @@ static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t s
 static int snd_cs4231_resume(struct device *dev, unsigned int n)
 {
        struct snd_card *card = dev_get_drvdata(dev);
-       struct snd_cs4231 *chip = card->private_data;
+       struct snd_wss *chip = card->private_data;
 
        chip->resume(chip);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
deleted file mode 100644 (file)
index 521db70..0000000
+++ /dev/null
@@ -1,1945 +0,0 @@
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *  Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
- *
- *  Bugs:
- *     - sometimes record brokes playback with WSS portion of 
- *       Yamaha OPL3-SA3 chip
- *     - CS4231 (GUS MAX) - still trouble with occasional noises
- *                        - broken initialization?
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <sound/core.h>
-#include <sound/cs4231.h>
-#include <sound/pcm_params.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
-MODULE_LICENSE("GPL");
-
-#if 0
-#define SNDRV_DEBUG_MCE
-#endif
-
-/*
- *  Some variables
- */
-
-static unsigned char freq_bits[14] = {
-       /* 5510 */      0x00 | CS4231_XTAL2,
-       /* 6620 */      0x0E | CS4231_XTAL2,
-       /* 8000 */      0x00 | CS4231_XTAL1,
-       /* 9600 */      0x0E | CS4231_XTAL1,
-       /* 11025 */     0x02 | CS4231_XTAL2,
-       /* 16000 */     0x02 | CS4231_XTAL1,
-       /* 18900 */     0x04 | CS4231_XTAL2,
-       /* 22050 */     0x06 | CS4231_XTAL2,
-       /* 27042 */     0x04 | CS4231_XTAL1,
-       /* 32000 */     0x06 | CS4231_XTAL1,
-       /* 33075 */     0x0C | CS4231_XTAL2,
-       /* 37800 */     0x08 | CS4231_XTAL2,
-       /* 44100 */     0x0A | CS4231_XTAL2,
-       /* 48000 */     0x0C | CS4231_XTAL1
-};
-
-static unsigned int rates[14] = {
-       5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
-       27042, 32000, 33075, 37800, 44100, 48000
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-       .count = ARRAY_SIZE(rates),
-       .list = rates,
-       .mask = 0,
-};
-
-static int snd_cs4231_xrate(struct snd_pcm_runtime *runtime)
-{
-       return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-}
-
-static unsigned char snd_cs4231_original_image[32] =
-{
-       0x00,                   /* 00/00 - lic */
-       0x00,                   /* 01/01 - ric */
-       0x9f,                   /* 02/02 - la1ic */
-       0x9f,                   /* 03/03 - ra1ic */
-       0x9f,                   /* 04/04 - la2ic */
-       0x9f,                   /* 05/05 - ra2ic */
-       0xbf,                   /* 06/06 - loc */
-       0xbf,                   /* 07/07 - roc */
-       0x20,                   /* 08/08 - pdfr */
-       CS4231_AUTOCALIB,       /* 09/09 - ic */
-       0x00,                   /* 0a/10 - pc */
-       0x00,                   /* 0b/11 - ti */
-       CS4231_MODE2,           /* 0c/12 - mi */
-       0xfc,                   /* 0d/13 - lbc */
-       0x00,                   /* 0e/14 - pbru */
-       0x00,                   /* 0f/15 - pbrl */
-       0x80,                   /* 10/16 - afei */
-       0x01,                   /* 11/17 - afeii */
-       0x9f,                   /* 12/18 - llic */
-       0x9f,                   /* 13/19 - rlic */
-       0x00,                   /* 14/20 - tlb */
-       0x00,                   /* 15/21 - thb */
-       0x00,                   /* 16/22 - la3mic/reserved */
-       0x00,                   /* 17/23 - ra3mic/reserved */
-       0x00,                   /* 18/24 - afs */
-       0x00,                   /* 19/25 - lamoc/version */
-       0xcf,                   /* 1a/26 - mioc */
-       0x00,                   /* 1b/27 - ramoc/reserved */
-       0x20,                   /* 1c/28 - cdfr */
-       0x00,                   /* 1d/29 - res4 */
-       0x00,                   /* 1e/30 - cbru */
-       0x00,                   /* 1f/31 - cbrl */
-};
-
-static unsigned char snd_opti93x_original_image[32] =
-{
-       0x00,           /* 00/00 - l_mixout_outctrl */
-       0x00,           /* 01/01 - r_mixout_outctrl */
-       0x88,           /* 02/02 - l_cd_inctrl */
-       0x88,           /* 03/03 - r_cd_inctrl */
-       0x88,           /* 04/04 - l_a1/fm_inctrl */
-       0x88,           /* 05/05 - r_a1/fm_inctrl */
-       0x80,           /* 06/06 - l_dac_inctrl */
-       0x80,           /* 07/07 - r_dac_inctrl */
-       0x00,           /* 08/08 - ply_dataform_reg */
-       0x00,           /* 09/09 - if_conf */
-       0x00,           /* 0a/10 - pin_ctrl */
-       0x00,           /* 0b/11 - err_init_reg */
-       0x0a,           /* 0c/12 - id_reg */
-       0x00,           /* 0d/13 - reserved */
-       0x00,           /* 0e/14 - ply_upcount_reg */
-       0x00,           /* 0f/15 - ply_lowcount_reg */
-       0x88,           /* 10/16 - reserved/l_a1_inctrl */
-       0x88,           /* 11/17 - reserved/r_a1_inctrl */
-       0x88,           /* 12/18 - l_line_inctrl */
-       0x88,           /* 13/19 - r_line_inctrl */
-       0x88,           /* 14/20 - l_mic_inctrl */
-       0x88,           /* 15/21 - r_mic_inctrl */
-       0x80,           /* 16/22 - l_out_outctrl */
-       0x80,           /* 17/23 - r_out_outctrl */
-       0x00,           /* 18/24 - reserved */
-       0x00,           /* 19/25 - reserved */
-       0x00,           /* 1a/26 - reserved */
-       0x00,           /* 1b/27 - reserved */
-       0x00,           /* 1c/28 - cap_dataform_reg */
-       0x00,           /* 1d/29 - reserved */
-       0x00,           /* 1e/30 - cap_upcount_reg */
-       0x00            /* 1f/31 - cap_lowcount_reg */
-};
-
-/*
- *  Basic I/O functions
- */
-
-static inline void cs4231_outb(struct snd_cs4231 *chip, u8 offset, u8 val)
-{
-       outb(val, chip->port + offset);
-}
-
-static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset)
-{
-       return inb(chip->port + offset);
-}
-
-static void snd_cs4231_wait(struct snd_cs4231 *chip)
-{
-       int timeout;
-
-       for (timeout = 250;
-            timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
-            timeout--)
-               udelay(100);
-}
-
-static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg,
-                           unsigned char mask, unsigned char value)
-{
-       unsigned char tmp = (chip->image[reg] & mask) | value;
-
-       snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-       chip->image[reg] = tmp;
-       if (!chip->calibrate_mute) {
-               cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-               wmb();
-               cs4231_outb(chip, CS4231P(REG), tmp);
-               mb();
-       }
-}
-
-static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned char value)
-{
-       int timeout;
-
-       for (timeout = 250;
-            timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
-            timeout--)
-               udelay(10);
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-       cs4231_outb(chip, CS4231P(REG), value);
-       mb();
-}
-
-void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value)
-{
-       snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-       cs4231_outb(chip, CS4231P(REG), value);
-       chip->image[reg] = value;
-       mb();
-       snd_printdd("codec out - reg 0x%x = 0x%x\n",
-                       chip->mce_bit | reg, value);
-}
-
-unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg)
-{
-       snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
-#endif
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-       mb();
-       return cs4231_inb(chip, CS4231P(REG));
-}
-
-void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
-{
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
-       cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
-       cs4231_outb(chip, CS4231P(REG), val);
-       chip->eimage[CS4236_REG(reg)] = val;
-#if 0
-       printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
-#endif
-}
-
-unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg)
-{
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
-       cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
-#if 1
-       return cs4231_inb(chip, CS4231P(REG));
-#else
-       {
-               unsigned char res;
-               res = cs4231_inb(chip, CS4231P(REG));
-               printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
-               return res;
-       }
-#endif
-}
-
-#if 0
-
-static void snd_cs4231_debug(struct snd_cs4231 *chip)
-{
-       printk("CS4231 REGS:      INDEX = 0x%02x  ", cs4231_inb(chip, CS4231P(REGSEL)));
-       printk("                 STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS)));
-       printk("  0x00: left input      = 0x%02x  ", snd_cs4231_in(chip, 0x00));
-       printk("  0x10: alt 1 (CFIG 2)  = 0x%02x\n", snd_cs4231_in(chip, 0x10));
-       printk("  0x01: right input     = 0x%02x  ", snd_cs4231_in(chip, 0x01));
-       printk("  0x11: alt 2 (CFIG 3)  = 0x%02x\n", snd_cs4231_in(chip, 0x11));
-       printk("  0x02: GF1 left input  = 0x%02x  ", snd_cs4231_in(chip, 0x02));
-       printk("  0x12: left line in    = 0x%02x\n", snd_cs4231_in(chip, 0x12));
-       printk("  0x03: GF1 right input = 0x%02x  ", snd_cs4231_in(chip, 0x03));
-       printk("  0x13: right line in   = 0x%02x\n", snd_cs4231_in(chip, 0x13));
-       printk("  0x04: CD left input   = 0x%02x  ", snd_cs4231_in(chip, 0x04));
-       printk("  0x14: timer low       = 0x%02x\n", snd_cs4231_in(chip, 0x14));
-       printk("  0x05: CD right input  = 0x%02x  ", snd_cs4231_in(chip, 0x05));
-       printk("  0x15: timer high      = 0x%02x\n", snd_cs4231_in(chip, 0x15));
-       printk("  0x06: left output     = 0x%02x  ", snd_cs4231_in(chip, 0x06));
-       printk("  0x16: left MIC (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x16));
-       printk("  0x07: right output    = 0x%02x  ", snd_cs4231_in(chip, 0x07));
-       printk("  0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
-       printk("  0x08: playback format = 0x%02x  ", snd_cs4231_in(chip, 0x08));
-       printk("  0x18: IRQ status      = 0x%02x\n", snd_cs4231_in(chip, 0x18));
-       printk("  0x09: iface (CFIG 1)  = 0x%02x  ", snd_cs4231_in(chip, 0x09));
-       printk("  0x19: left line out   = 0x%02x\n", snd_cs4231_in(chip, 0x19));
-       printk("  0x0a: pin control     = 0x%02x  ", snd_cs4231_in(chip, 0x0a));
-       printk("  0x1a: mono control    = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
-       printk("  0x0b: init & status   = 0x%02x  ", snd_cs4231_in(chip, 0x0b));
-       printk("  0x1b: right line out  = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
-       printk("  0x0c: revision & mode = 0x%02x  ", snd_cs4231_in(chip, 0x0c));
-       printk("  0x1c: record format   = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
-       printk("  0x0d: loopback        = 0x%02x  ", snd_cs4231_in(chip, 0x0d));
-       printk("  0x1d: var freq (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
-       printk("  0x0e: ply upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0e));
-       printk("  0x1e: ply lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
-       printk("  0x0f: rec upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0f));
-       printk("  0x1f: rec lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
-}
-
-#endif
-
-/*
- *  CS4231 detection / MCE routines
- */
-
-static void snd_cs4231_busy_wait(struct snd_cs4231 *chip)
-{
-       int timeout;
-
-       /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
-       for (timeout = 5; timeout > 0; timeout--)
-               cs4231_inb(chip, CS4231P(REGSEL));
-       /* end of cleanup sequence */
-       for (timeout = 250;
-            timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
-            timeout--)
-               udelay(10);
-}
-
-void snd_cs4231_mce_up(struct snd_cs4231 *chip)
-{
-       unsigned long flags;
-       int timeout;
-
-       snd_cs4231_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("mce_up - auto calibration time out (0)\n");
-#endif
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->mce_bit |= CS4231_MCE;
-       timeout = cs4231_inb(chip, CS4231P(REGSEL));
-       if (timeout == 0x80)
-               snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
-       if (!(timeout & CS4231_MCE))
-               cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-void snd_cs4231_mce_down(struct snd_cs4231 *chip)
-{
-       unsigned long flags;
-       unsigned long end_time;
-       int timeout;
-
-       snd_cs4231_busy_wait(chip);
-
-#ifdef CONFIG_SND_DEBUG
-       if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
-#endif
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->mce_bit &= ~CS4231_MCE;
-       timeout = cs4231_inb(chip, CS4231P(REGSEL));
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (timeout == 0x80)
-               snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
-       if ((timeout & CS4231_MCE) == 0 ||
-           !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
-               return;
-       }
-
-       /*
-        * Wait for (possible -- during init auto-calibration may not be set)
-        * calibration process to start. Needs upto 5 sample periods on AD1848
-        * which at the slowest possible rate of 5.5125 kHz means 907 us.
-        */
-       msleep(1);
-
-       snd_printdd("(1) jiffies = %lu\n", jiffies);
-
-       /* check condition up to 250 ms */
-       end_time = jiffies + msecs_to_jiffies(250);
-       while (snd_cs4231_in(chip, CS4231_TEST_INIT) &
-               CS4231_CALIB_IN_PROGRESS) {
-
-               if (time_after(jiffies, end_time)) {
-                       snd_printk(KERN_ERR "mce_down - "
-                                       "auto calibration time out (2)\n");
-                       return;
-               }
-               msleep(1);
-       }
-
-       snd_printdd("(2) jiffies = %lu\n", jiffies);
-
-       /* check condition up to 100 ms */
-       end_time = jiffies + msecs_to_jiffies(100);
-       while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
-               if (time_after(jiffies, end_time)) {
-                       snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
-                       return;
-               }
-               msleep(1);
-       }
-
-       snd_printdd("(3) jiffies = %lu\n", jiffies);
-       snd_printd("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL)));
-}
-
-static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
-{
-       switch (format & 0xe0) {
-       case CS4231_LINEAR_16:
-       case CS4231_LINEAR_16_BIG:
-               size >>= 1;
-               break;
-       case CS4231_ADPCM_16:
-               return size >> 2;
-       }
-       if (format & CS4231_STEREO)
-               size >>= 1;
-       return size;
-}
-
-static int snd_cs4231_trigger(struct snd_pcm_substream *substream,
-                             int cmd)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       int result = 0;
-       unsigned int what;
-       struct snd_pcm_substream *s;
-       int do_start;
-
-#if 0
-       printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS)));
-#endif
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               do_start = 1; break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               do_start = 0; break;
-       default:
-               return -EINVAL;
-       }
-
-       what = 0;
-       snd_pcm_group_for_each_entry(s, substream) {
-               if (s == chip->playback_substream) {
-                       what |= CS4231_PLAYBACK_ENABLE;
-                       snd_pcm_trigger_done(s, substream);
-               } else if (s == chip->capture_substream) {
-                       what |= CS4231_RECORD_ENABLE;
-                       snd_pcm_trigger_done(s, substream);
-               }
-       }
-       spin_lock(&chip->reg_lock);
-       if (do_start) {
-               chip->image[CS4231_IFACE_CTRL] |= what;
-               if (chip->trigger)
-                       chip->trigger(chip, what, 1);
-       } else {
-               chip->image[CS4231_IFACE_CTRL] &= ~what;
-               if (chip->trigger)
-                       chip->trigger(chip, what, 0);
-       }
-       snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
-       spin_unlock(&chip->reg_lock);
-#if 0
-       snd_cs4231_debug(chip);
-#endif
-       return result;
-}
-
-/*
- *  CODEC I/O
- */
-
-static unsigned char snd_cs4231_get_rate(unsigned int rate)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(rates); i++)
-               if (rate == rates[i])
-                       return freq_bits[i];
-       // snd_BUG();
-       return freq_bits[ARRAY_SIZE(rates) - 1];
-}
-
-static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip,
-                                          int format,
-                                           int channels)
-{
-       unsigned char rformat;
-
-       rformat = CS4231_LINEAR_8;
-       switch (format) {
-       case SNDRV_PCM_FORMAT_MU_LAW:   rformat = CS4231_ULAW_8; break;
-       case SNDRV_PCM_FORMAT_A_LAW:    rformat = CS4231_ALAW_8; break;
-       case SNDRV_PCM_FORMAT_S16_LE:   rformat = CS4231_LINEAR_16; break;
-       case SNDRV_PCM_FORMAT_S16_BE:   rformat = CS4231_LINEAR_16_BIG; break;
-       case SNDRV_PCM_FORMAT_IMA_ADPCM:        rformat = CS4231_ADPCM_16; break;
-       }
-       if (channels > 1)
-               rformat |= CS4231_STEREO;
-#if 0
-       snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
-       return rformat;
-}
-
-static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute)
-{
-       unsigned long flags;
-
-       mute = mute ? 1 : 0;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       if (chip->calibrate_mute == mute) {
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               return;
-       }
-       if (!mute) {
-               snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]);
-               snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]);
-               snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]);
-       }
-       snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
-       snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
-       snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
-       snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
-       snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
-       snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
-       snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
-       snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
-       snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
-       if (chip->hardware == CS4231_HW_INTERWAVE) {
-               snd_cs4231_dout(chip, CS4231_LEFT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]);
-               snd_cs4231_dout(chip, CS4231_RIGHT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]);               
-               snd_cs4231_dout(chip, CS4231_LINE_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]);
-               snd_cs4231_dout(chip, CS4231_LINE_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]);
-       }
-       chip->calibrate_mute = mute;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_cs4231_playback_format(struct snd_cs4231 *chip,
-                                      struct snd_pcm_hw_params *params,
-                                      unsigned char pdfr)
-{
-       unsigned long flags;
-       int full_calib = 1;
-
-       mutex_lock(&chip->mce_mutex);
-       snd_cs4231_calibrate_mute(chip, 1);
-       if (chip->hardware == CS4231_HW_CS4231A ||
-           (chip->hardware & CS4231_HW_CS4232_MASK)) {
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) {      /* rate is same? */
-                       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
-                       snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
-                       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
-                       udelay(100); /* Fixes audible clicks at least on GUS MAX */
-                       full_calib = 0;
-               }
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-       }
-       if (full_calib) {
-               snd_cs4231_mce_up(chip);
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               if (chip->hardware != CS4231_HW_INTERWAVE && !chip->single_dma) {
-                       snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
-                                       (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
-                                       (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
-                                       pdfr);
-               } else {
-                       snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
-               }
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               if (chip->hardware == CS4231_HW_OPL3SA2)
-                       udelay(100);    /* this seems to help */
-               snd_cs4231_mce_down(chip);
-       }
-       snd_cs4231_calibrate_mute(chip, 0);
-       mutex_unlock(&chip->mce_mutex);
-}
-
-static void snd_cs4231_capture_format(struct snd_cs4231 *chip,
-                                     struct snd_pcm_hw_params *params,
-                                      unsigned char cdfr)
-{
-       unsigned long flags;
-       int full_calib = 1;
-
-       mutex_lock(&chip->mce_mutex);
-       snd_cs4231_calibrate_mute(chip, 1);
-       if (chip->hardware == CS4231_HW_CS4231A ||
-           (chip->hardware & CS4231_HW_CS4232_MASK)) {
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) ||      /* rate is same? */
-                   (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
-                       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
-                       snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT] = cdfr);
-                       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
-                       full_calib = 0;
-               }
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-       }
-       if (full_calib) {
-               snd_cs4231_mce_up(chip);
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               if (chip->hardware != CS4231_HW_INTERWAVE) {
-                       if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
-                               snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
-                                              ((chip->single_dma ? cdfr : chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
-                                              (cdfr & 0x0f));
-                               spin_unlock_irqrestore(&chip->reg_lock, flags);
-                               snd_cs4231_mce_down(chip);
-                               snd_cs4231_mce_up(chip);
-                               spin_lock_irqsave(&chip->reg_lock, flags);
-                       }
-               }
-               snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               snd_cs4231_mce_down(chip);
-       }
-       snd_cs4231_calibrate_mute(chip, 0);
-       mutex_unlock(&chip->mce_mutex);
-}
-
-/*
- *  Timer interface
- */
-
-static unsigned long snd_cs4231_timer_resolution(struct snd_timer * timer)
-{
-       struct snd_cs4231 *chip = snd_timer_chip(timer);
-       if (chip->hardware & CS4231_HW_CS4236B_MASK)
-               return 14467;
-       else
-               return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
-}
-
-static int snd_cs4231_timer_start(struct snd_timer * timer)
-{
-       unsigned long flags;
-       unsigned int ticks;
-       struct snd_cs4231 *chip = snd_timer_chip(timer);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ticks = timer->sticks;
-       if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
-           (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
-           (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
-               snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8));
-               snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks);
-               snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);
-       }
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-static int snd_cs4231_timer_stop(struct snd_timer * timer)
-{
-       unsigned long flags;
-       struct snd_cs4231 *chip = snd_timer_chip(timer);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-static void snd_cs4231_init(struct snd_cs4231 *chip)
-{
-       unsigned long flags;
-
-       snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (1)\n");
-#endif
-       snd_cs4231_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
-                            CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |
-                            CS4231_CALIB_MODE);
-       chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
-       snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (2)\n");
-#endif
-
-       snd_cs4231_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
-#endif
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       snd_cs4231_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (4)\n");
-#endif
-
-       snd_cs4231_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (5)\n");
-#endif
-}
-
-static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode)
-{
-       unsigned long flags;
-
-       mutex_lock(&chip->open_mutex);
-       if ((chip->mode & mode) ||
-           ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {
-               mutex_unlock(&chip->open_mutex);
-               return -EAGAIN;
-       }
-       if (chip->mode & CS4231_MODE_OPEN) {
-               chip->mode |= mode;
-               mutex_unlock(&chip->open_mutex);
-               return 0;
-       }
-       /* ok. now enable and ack CODEC IRQ */
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
-                      CS4231_RECORD_IRQ |
-                      CS4231_TIMER_IRQ);
-       snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-       cs4231_outb(chip, CS4231P(STATUS), 0);  /* clear IRQ */
-       cs4231_outb(chip, CS4231P(STATUS), 0);  /* clear IRQ */
-       chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
-       snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
-       snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
-                      CS4231_RECORD_IRQ |
-                      CS4231_TIMER_IRQ);
-       snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       chip->mode = mode;
-       mutex_unlock(&chip->open_mutex);
-       return 0;
-}
-
-static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode)
-{
-       unsigned long flags;
-
-       mutex_lock(&chip->open_mutex);
-       chip->mode &= ~mode;
-       if (chip->mode & CS4231_MODE_OPEN) {
-               mutex_unlock(&chip->open_mutex);
-               return;
-       }
-       snd_cs4231_calibrate_mute(chip, 1);
-
-       /* disable IRQ */
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-       cs4231_outb(chip, CS4231P(STATUS), 0);  /* clear IRQ */
-       cs4231_outb(chip, CS4231P(STATUS), 0);  /* clear IRQ */
-       chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
-       snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
-
-       /* now disable record & playback */
-
-       if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
-                                              CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               snd_cs4231_mce_up(chip);
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
-                                                    CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
-               snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
-               snd_cs4231_mce_down(chip);
-               spin_lock_irqsave(&chip->reg_lock, flags);
-       }
-
-       /* clear IRQ again */
-       snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-       cs4231_outb(chip, CS4231P(STATUS), 0);  /* clear IRQ */
-       cs4231_outb(chip, CS4231P(STATUS), 0);  /* clear IRQ */
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       snd_cs4231_calibrate_mute(chip, 0);
-
-       chip->mode = 0;
-       mutex_unlock(&chip->open_mutex);
-}
-
-/*
- *  timer open/close
- */
-
-static int snd_cs4231_timer_open(struct snd_timer * timer)
-{
-       struct snd_cs4231 *chip = snd_timer_chip(timer);
-       snd_cs4231_open(chip, CS4231_MODE_TIMER);
-       return 0;
-}
-
-static int snd_cs4231_timer_close(struct snd_timer * timer)
-{
-       struct snd_cs4231 *chip = snd_timer_chip(timer);
-       snd_cs4231_close(chip, CS4231_MODE_TIMER);
-       return 0;
-}
-
-static struct snd_timer_hardware snd_cs4231_timer_table =
-{
-       .flags =        SNDRV_TIMER_HW_AUTO,
-       .resolution =   9945,
-       .ticks =        65535,
-       .open =         snd_cs4231_timer_open,
-       .close =        snd_cs4231_timer_close,
-       .c_resolution = snd_cs4231_timer_resolution,
-       .start =        snd_cs4231_timer_start,
-       .stop =         snd_cs4231_timer_stop,
-};
-
-/*
- *  ok.. exported functions..
- */
-
-static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream,
-                                        struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       unsigned char new_pdfr;
-       int err;
-
-       if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-               return err;
-       new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
-                  snd_cs4231_get_rate(params_rate(hw_params));
-       chip->set_playback_format(chip, hw_params, new_pdfr);
-       return 0;
-}
-
-static int snd_cs4231_playback_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-       unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->p_dma_size = size;
-       chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
-       snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
-       count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
-       snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
-       snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 0
-       snd_cs4231_debug(chip);
-#endif
-       return 0;
-}
-
-static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       unsigned char new_cdfr;
-       int err;
-
-       if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
-               return err;
-       new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
-                  snd_cs4231_get_rate(params_rate(hw_params));
-       chip->set_capture_format(chip, hw_params, new_cdfr);
-       return 0;
-}
-
-static int snd_cs4231_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-       unsigned int count = snd_pcm_lib_period_bytes(substream);
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->c_dma_size = size;
-       chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
-       snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
-       count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;
-       if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
-               snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
-               snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
-       } else {
-               snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
-               snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8));
-       }
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-void snd_cs4231_overrange(struct snd_cs4231 *chip)
-{
-       unsigned long flags;
-       unsigned char res;
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       res = snd_cs4231_in(chip, CS4231_TEST_INIT);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (res & (0x08 | 0x02))        /* detect overrange only above 0dB; may be user selectable? */
-               chip->capture_substream->runtime->overrange++;
-}
-
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id)
-{
-       struct snd_cs4231 *chip = dev_id;
-       unsigned char status;
-
-       status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
-       if (status & CS4231_TIMER_IRQ) {
-               if (chip->timer)
-                       snd_timer_interrupt(chip->timer, chip->timer->sticks);
-       }               
-       if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
-               if (status & CS4231_PLAYBACK_IRQ) {
-                       if (chip->mode & CS4231_MODE_PLAY) {
-                               if (chip->playback_substream)
-                                       snd_pcm_period_elapsed(chip->playback_substream);
-                       }
-                       if (chip->mode & CS4231_MODE_RECORD) {
-                               if (chip->capture_substream) {
-                                       snd_cs4231_overrange(chip);
-                                       snd_pcm_period_elapsed(chip->capture_substream);
-                               }
-                       }
-               }
-       } else {
-               if (status & CS4231_PLAYBACK_IRQ) {
-                       if (chip->playback_substream)
-                               snd_pcm_period_elapsed(chip->playback_substream);
-               }
-               if (status & CS4231_RECORD_IRQ) {
-                       if (chip->capture_substream) {
-                               snd_cs4231_overrange(chip);
-                               snd_pcm_period_elapsed(chip->capture_substream);
-                       }
-               }
-       }
-
-       spin_lock(&chip->reg_lock);
-       snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
-       spin_unlock(&chip->reg_lock);
-       return IRQ_HANDLED;
-}
-
-static snd_pcm_uframes_t snd_cs4231_playback_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       size_t ptr;
-
-       if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
-               return 0;
-       ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
-       return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_cs4231_capture_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       size_t ptr;
-       
-       if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
-               return 0;
-       ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
-       return bytes_to_frames(substream->runtime, ptr);
-}
-
-/*
-
- */
-
-static int snd_cs4231_probe(struct snd_cs4231 *chip)
-{
-       unsigned long flags;
-       int i, id, rev;
-       unsigned char *ptr;
-       unsigned int hw;
-
-#if 0
-       snd_cs4231_debug(chip);
-#endif
-       id = 0;
-       for (i = 0; i < 50; i++) {
-               mb();
-               if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-                       udelay(2000);
-               else {
-                       spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
-                       id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
-                       spin_unlock_irqrestore(&chip->reg_lock, flags);
-                       if (id == 0x0a)
-                               break;  /* this is valid value */
-               }
-       }
-       snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);
-       if (id != 0x0a)
-               return -ENODEV; /* no valid device found */
-
-       if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
-               rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7;
-               snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
-               if (rev == 0x80) {
-                       unsigned char tmp = snd_cs4231_in(chip, 23);
-                       snd_cs4231_out(chip, 23, ~tmp);
-                       if (snd_cs4231_in(chip, 23) != tmp)
-                               chip->hardware = CS4231_HW_AD1845;
-                       else
-                               chip->hardware = CS4231_HW_CS4231;
-               } else if (rev == 0xa0) {
-                       chip->hardware = CS4231_HW_CS4231A;
-               } else if (rev == 0xa2) {
-                       chip->hardware = CS4231_HW_CS4232;
-               } else if (rev == 0xb2) {
-                       chip->hardware = CS4231_HW_CS4232A;
-               } else if (rev == 0x83) {
-                       chip->hardware = CS4231_HW_CS4236;
-               } else if (rev == 0x03) {
-                       chip->hardware = CS4231_HW_CS4236B;
-               } else {
-                       snd_printk("unknown CS chip with version 0x%x\n", rev);
-                       return -ENODEV;         /* unknown CS4231 chip? */
-               }
-       }
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       cs4231_inb(chip, CS4231P(STATUS));      /* clear any pendings IRQ */
-       cs4231_outb(chip, CS4231P(STATUS), 0);
-       mb();
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
-       switch (chip->hardware) {
-       case CS4231_HW_INTERWAVE:
-               chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
-               break;
-       case CS4231_HW_CS4235:
-       case CS4231_HW_CS4236B:
-       case CS4231_HW_CS4237B:
-       case CS4231_HW_CS4238B:
-       case CS4231_HW_CS4239:
-               if (hw == CS4231_HW_DETECT3)
-                       chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
-               else
-                       chip->hardware = CS4231_HW_CS4236;
-               break;
-       }
-
-       chip->image[CS4231_IFACE_CTRL] =
-           (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
-           (chip->single_dma ? CS4231_SINGLE_DMA : 0);
-       if (chip->hardware != CS4231_HW_OPTI93X) {
-               chip->image[CS4231_ALT_FEATURE_1] = 0x80;
-               chip->image[CS4231_ALT_FEATURE_2] =
-                       chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;
-       }
-       ptr = (unsigned char *) &chip->image;
-       snd_cs4231_mce_down(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       for (i = 0; i < 32; i++)        /* ok.. fill all CS4231 registers */
-               snd_cs4231_out(chip, i, *ptr++);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_up(chip);
-       snd_cs4231_mce_down(chip);
-
-       mdelay(2);
-
-       /* ok.. try check hardware version for CS4236+ chips */
-       if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
-               if (chip->hardware == CS4231_HW_CS4236B) {
-                       rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
-                       snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
-                       id = snd_cs4236_ext_in(chip, CS4236_VERSION);
-                       snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
-                       snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
-                       if ((id & 0x1f) == 0x1d) {      /* CS4235 */
-                               chip->hardware = CS4231_HW_CS4235;
-                               switch (id >> 5) {
-                               case 4:
-                               case 5:
-                               case 6:
-                                       break;
-                               default:
-                                       snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
-                               }
-                       } else if ((id & 0x1f) == 0x0b) {       /* CS4236/B */
-                               switch (id >> 5) {
-                               case 4:
-                               case 5:
-                               case 6:
-                               case 7:
-                                       chip->hardware = CS4231_HW_CS4236B;
-                                       break;
-                               default:
-                                       snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
-                               }
-                       } else if ((id & 0x1f) == 0x08) {       /* CS4237B */
-                               chip->hardware = CS4231_HW_CS4237B;
-                               switch (id >> 5) {
-                               case 4:
-                               case 5:
-                               case 6:
-                               case 7:
-                                       break;
-                               default:
-                                       snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
-                               }
-                       } else if ((id & 0x1f) == 0x09) {       /* CS4238B */
-                               chip->hardware = CS4231_HW_CS4238B;
-                               switch (id >> 5) {
-                               case 5:
-                               case 6:
-                               case 7:
-                                       break;
-                               default:
-                                       snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
-                               }
-                       } else if ((id & 0x1f) == 0x1e) {       /* CS4239 */
-                               chip->hardware = CS4231_HW_CS4239;
-                               switch (id >> 5) {
-                               case 4:
-                               case 5:
-                               case 6:
-                                       break;
-                               default:
-                                       snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
-                               }
-                       } else {
-                               snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
-                       }
-               }
-       }
-       return 0;               /* all things are ok.. */
-}
-
-/*
-
- */
-
-static struct snd_pcm_hardware snd_cs4231_playback =
-{
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME |
-                                SNDRV_PCM_INFO_SYNC_START),
-       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
-                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
-       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-       .rate_min =             5510,
-       .rate_max =             48000,
-       .channels_min =         1,
-       .channels_max =         2,
-       .buffer_bytes_max =     (128*1024),
-       .period_bytes_min =     64,
-       .period_bytes_max =     (128*1024),
-       .periods_min =          1,
-       .periods_max =          1024,
-       .fifo_size =            0,
-};
-
-static struct snd_pcm_hardware snd_cs4231_capture =
-{
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME |
-                                SNDRV_PCM_INFO_SYNC_START),
-       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
-                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
-       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-       .rate_min =             5510,
-       .rate_max =             48000,
-       .channels_min =         1,
-       .channels_max =         2,
-       .buffer_bytes_max =     (128*1024),
-       .period_bytes_min =     64,
-       .period_bytes_max =     (128*1024),
-       .periods_min =          1,
-       .periods_max =          1024,
-       .fifo_size =            0,
-};
-
-/*
-
- */
-
-static int snd_cs4231_playback_open(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int err;
-
-       runtime->hw = snd_cs4231_playback;
-
-       /* hardware bug in InterWave chipset */
-       if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3)
-               runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
-       
-       /* hardware limitation of cheap chips */
-       if (chip->hardware == CS4231_HW_CS4235 ||
-           chip->hardware == CS4231_HW_CS4239)
-               runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
-
-       snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
-       snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
-
-       if (chip->claim_dma) {
-               if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
-                       return err;
-       }
-
-       if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
-               if (chip->release_dma)
-                       chip->release_dma(chip, chip->dma_private_data, chip->dma1);
-               snd_free_pages(runtime->dma_area, runtime->dma_bytes);
-               return err;
-       }
-       chip->playback_substream = substream;
-       snd_pcm_set_sync(substream);
-       chip->rate_constraint(runtime);
-       return 0;
-}
-
-static int snd_cs4231_capture_open(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int err;
-
-       runtime->hw = snd_cs4231_capture;
-
-       /* hardware limitation of cheap chips */
-       if (chip->hardware == CS4231_HW_CS4235 ||
-           chip->hardware == CS4231_HW_CS4239)
-               runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
-
-       snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
-       snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
-
-       if (chip->claim_dma) {
-               if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
-                       return err;
-       }
-
-       if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
-               if (chip->release_dma)
-                       chip->release_dma(chip, chip->dma_private_data, chip->dma2);
-               snd_free_pages(runtime->dma_area, runtime->dma_bytes);
-               return err;
-       }
-       chip->capture_substream = substream;
-       snd_pcm_set_sync(substream);
-       chip->rate_constraint(runtime);
-       return 0;
-}
-
-static int snd_cs4231_playback_close(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-
-       chip->playback_substream = NULL;
-       snd_cs4231_close(chip, CS4231_MODE_PLAY);
-       return 0;
-}
-
-static int snd_cs4231_capture_close(struct snd_pcm_substream *substream)
-{
-       struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-
-       chip->capture_substream = NULL;
-       snd_cs4231_close(chip, CS4231_MODE_RECORD);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-/* lowlevel suspend callback for CS4231 */
-static void snd_cs4231_suspend(struct snd_cs4231 *chip)
-{
-       int reg;
-       unsigned long flags;
-       
-       snd_pcm_suspend_all(chip->pcm);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       for (reg = 0; reg < 32; reg++)
-               chip->image[reg] = snd_cs4231_in(chip, reg);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/* lowlevel resume callback for CS4231 */
-static void snd_cs4231_resume(struct snd_cs4231 *chip)
-{
-       int reg;
-       unsigned long flags;
-       /* int timeout; */
-       
-       snd_cs4231_mce_up(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       for (reg = 0; reg < 32; reg++) {
-               switch (reg) {
-               case CS4231_VERSION:
-                       break;
-               default:
-                       snd_cs4231_out(chip, reg, chip->image[reg]);
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 1
-       snd_cs4231_mce_down(chip);
-#else
-       /* The following is a workaround to avoid freeze after resume on TP600E.
-          This is the first half of copy of snd_cs4231_mce_down(), but doesn't
-          include rescheduling.  -- iwai
-          */
-       snd_cs4231_busy_wait(chip);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       chip->mce_bit &= ~CS4231_MCE;
-       timeout = cs4231_inb(chip, CS4231P(REGSEL));
-       cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (timeout == 0x80)
-               snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
-       if ((timeout & CS4231_MCE) == 0 ||
-           !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
-               return;
-       }
-       snd_cs4231_busy_wait(chip);
-#endif
-}
-#endif /* CONFIG_PM */
-
-static int snd_cs4231_free(struct snd_cs4231 *chip)
-{
-       release_and_free_resource(chip->res_port);
-       release_and_free_resource(chip->res_cport);
-       if (chip->irq >= 0) {
-               disable_irq(chip->irq);
-               if (!(chip->hwshare & CS4231_HWSHARE_IRQ))
-                       free_irq(chip->irq, (void *) chip);
-       }
-       if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) {
-               snd_dma_disable(chip->dma1);
-               free_dma(chip->dma1);
-       }
-       if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
-               snd_dma_disable(chip->dma2);
-               free_dma(chip->dma2);
-       }
-       if (chip->timer)
-               snd_device_free(chip->card, chip->timer);
-       kfree(chip);
-       return 0;
-}
-
-static int snd_cs4231_dev_free(struct snd_device *device)
-{
-       struct snd_cs4231 *chip = device->device_data;
-       return snd_cs4231_free(chip);   
-}
-
-const char *snd_cs4231_chip_id(struct snd_cs4231 *chip)
-{
-       switch (chip->hardware) {
-       case CS4231_HW_CS4231:  return "CS4231";
-       case CS4231_HW_CS4231A: return "CS4231A";
-       case CS4231_HW_CS4232:  return "CS4232";
-       case CS4231_HW_CS4232A: return "CS4232A";
-       case CS4231_HW_CS4235:  return "CS4235";
-       case CS4231_HW_CS4236:  return "CS4236";
-       case CS4231_HW_CS4236B: return "CS4236B";
-       case CS4231_HW_CS4237B: return "CS4237B";
-       case CS4231_HW_CS4238B: return "CS4238B";
-       case CS4231_HW_CS4239:  return "CS4239";
-       case CS4231_HW_INTERWAVE: return "AMD InterWave";
-       case CS4231_HW_OPL3SA2: return chip->card->shortname;
-       case CS4231_HW_AD1845: return "AD1845";
-       case CS4231_HW_OPTI93X: return "OPTi 93x";
-       default: return "???";
-       }
-}
-
-static int snd_cs4231_new(struct snd_card *card,
-                         unsigned short hardware,
-                         unsigned short hwshare,
-                         struct snd_cs4231 ** rchip)
-{
-       struct snd_cs4231 *chip;
-
-       *rchip = NULL;
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
-       chip->hardware = hardware;
-       chip->hwshare = hwshare;
-
-       spin_lock_init(&chip->reg_lock);
-       mutex_init(&chip->mce_mutex);
-       mutex_init(&chip->open_mutex);
-       chip->card = card;
-       chip->rate_constraint = snd_cs4231_xrate;
-       chip->set_playback_format = snd_cs4231_playback_format;
-       chip->set_capture_format = snd_cs4231_capture_format;
-       if (chip->hardware == CS4231_HW_OPTI93X)
-               memcpy(&chip->image, &snd_opti93x_original_image,
-                      sizeof(snd_opti93x_original_image));
-       else
-               memcpy(&chip->image, &snd_cs4231_original_image,
-                      sizeof(snd_cs4231_original_image));
-
-        *rchip = chip;
-        return 0;
-}
-
-int snd_cs4231_create(struct snd_card *card,
-                     unsigned long port,
-                     unsigned long cport,
-                     int irq, int dma1, int dma2,
-                     unsigned short hardware,
-                     unsigned short hwshare,
-                     struct snd_cs4231 ** rchip)
-{
-       static struct snd_device_ops ops = {
-               .dev_free =     snd_cs4231_dev_free,
-       };
-       struct snd_cs4231 *chip;
-       int err;
-
-       err = snd_cs4231_new(card, hardware, hwshare, &chip);
-       if (err < 0)
-               return err;
-       
-       chip->irq = -1;
-       chip->dma1 = -1;
-       chip->dma2 = -1;
-
-       if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) {
-               snd_printk(KERN_ERR "cs4231: can't grab port 0x%lx\n", port);
-               snd_cs4231_free(chip);
-               return -EBUSY;
-       }
-       chip->port = port;
-       if ((long)cport >= 0 && (chip->res_cport = request_region(cport, 8, "CS4232 Control")) == NULL) {
-               snd_printk(KERN_ERR "cs4231: can't grab control port 0x%lx\n", cport);
-               snd_cs4231_free(chip);
-               return -ENODEV;
-       }
-       chip->cport = cport;
-       if (!(hwshare & CS4231_HWSHARE_IRQ) && request_irq(irq, snd_cs4231_interrupt, IRQF_DISABLED, "CS4231", (void *) chip)) {
-               snd_printk(KERN_ERR "cs4231: can't grab IRQ %d\n", irq);
-               snd_cs4231_free(chip);
-               return -EBUSY;
-       }
-       chip->irq = irq;
-       if (!(hwshare & CS4231_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) {
-               snd_printk(KERN_ERR "cs4231: can't grab DMA1 %d\n", dma1);
-               snd_cs4231_free(chip);
-               return -EBUSY;
-       }
-       chip->dma1 = dma1;
-       if (!(hwshare & CS4231_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) {
-               snd_printk(KERN_ERR "cs4231: can't grab DMA2 %d\n", dma2);
-               snd_cs4231_free(chip);
-               return -EBUSY;
-       }
-       if (dma1 == dma2 || dma2 < 0) {
-               chip->single_dma = 1;
-               chip->dma2 = chip->dma1;
-       } else
-               chip->dma2 = dma2;
-
-       /* global setup */
-       if (snd_cs4231_probe(chip) < 0) {
-               snd_cs4231_free(chip);
-               return -ENODEV;
-       }
-       snd_cs4231_init(chip);
-
-#if 0
-       if (chip->hardware & CS4231_HW_CS4232_MASK) {
-               if (chip->res_cport == NULL)
-                       snd_printk("CS4232 control port features are not accessible\n");
-       }
-#endif
-
-       /* Register device */
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-               snd_cs4231_free(chip);
-               return err;
-       }
-
-#ifdef CONFIG_PM
-       /* Power Management */
-       chip->suspend = snd_cs4231_suspend;
-       chip->resume = snd_cs4231_resume;
-#endif
-
-       *rchip = chip;
-       return 0;
-}
-
-static struct snd_pcm_ops snd_cs4231_playback_ops = {
-       .open =         snd_cs4231_playback_open,
-       .close =        snd_cs4231_playback_close,
-       .ioctl =        snd_pcm_lib_ioctl,
-       .hw_params =    snd_cs4231_playback_hw_params,
-       .hw_free =      snd_cs4231_playback_hw_free,
-       .prepare =      snd_cs4231_playback_prepare,
-       .trigger =      snd_cs4231_trigger,
-       .pointer =      snd_cs4231_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_cs4231_capture_ops = {
-       .open =         snd_cs4231_capture_open,
-       .close =        snd_cs4231_capture_close,
-       .ioctl =        snd_pcm_lib_ioctl,
-       .hw_params =    snd_cs4231_capture_hw_params,
-       .hw_free =      snd_cs4231_capture_hw_free,
-       .prepare =      snd_cs4231_capture_prepare,
-       .trigger =      snd_cs4231_trigger,
-       .pointer =      snd_cs4231_capture_pointer,
-};
-
-int snd_cs4231_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
-{
-       struct snd_pcm *pcm;
-       int err;
-
-       if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0)
-               return err;
-
-       spin_lock_init(&chip->reg_lock);
-       mutex_init(&chip->mce_mutex);
-       mutex_init(&chip->open_mutex);
-
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
-       
-       /* global setup */
-       pcm->private_data = chip;
-       pcm->info_flags = 0;
-       if (chip->single_dma)
-               pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
-       if (chip->hardware != CS4231_HW_INTERWAVE)
-               pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
-       strcpy(pcm->name, snd_cs4231_chip_id(chip));
-
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-                                             snd_dma_isa_data(),
-                                             64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
-
-       chip->pcm = pcm;
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
-}
-
-static void snd_cs4231_timer_free(struct snd_timer *timer)
-{
-       struct snd_cs4231 *chip = timer->private_data;
-       chip->timer = NULL;
-}
-
-int snd_cs4231_timer(struct snd_cs4231 *chip, int device, struct snd_timer **rtimer)
-{
-       struct snd_timer *timer;
-       struct snd_timer_id tid;
-       int err;
-
-       /* Timer initialization */
-       tid.dev_class = SNDRV_TIMER_CLASS_CARD;
-       tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
-       tid.card = chip->card->number;
-       tid.device = device;
-       tid.subdevice = 0;
-       if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
-               return err;
-       strcpy(timer->name, snd_cs4231_chip_id(chip));
-       timer->private_data = chip;
-       timer->private_free = snd_cs4231_timer_free;
-       timer->hw = snd_cs4231_timer_table;
-       chip->timer = timer;
-       if (rtimer)
-               *rtimer = timer;
-       return 0;
-}
-       
-/*
- *  MIXER part
- */
-
-static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       static char *texts[4] = {
-               "Line", "Aux", "Mic", "Mix"
-       };
-       static char *opl3sa_texts[4] = {
-               "Line", "CD", "Mic", "Mix"
-       };
-       static char *gusmax_texts[4] = {
-               "Line", "Synth", "Mic", "Mix"
-       };
-       char **ptexts = texts;
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-
-       snd_assert(chip->card != NULL, return -EINVAL);
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 2;
-       uinfo->value.enumerated.items = 4;
-       if (uinfo->value.enumerated.item > 3)
-               uinfo->value.enumerated.item = 3;
-       if (!strcmp(chip->card->driver, "GUS MAX"))
-               ptexts = gusmax_texts;
-       switch (chip->hardware) {
-       case CS4231_HW_INTERWAVE: ptexts = gusmax_texts; break;
-       case CS4231_HW_OPL3SA2: ptexts = opl3sa_texts; break;
-       }
-       strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
-       ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return 0;
-}
-
-static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       unsigned short left, right;
-       int change;
-       
-       if (ucontrol->value.enumerated.item[0] > 3 ||
-           ucontrol->value.enumerated.item[1] > 3)
-               return -EINVAL;
-       left = ucontrol->value.enumerated.item[0] << 6;
-       right = ucontrol->value.enumerated.item[1] << 6;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
-       right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
-       change = left != chip->image[CS4231_LEFT_INPUT] ||
-                right != chip->image[CS4231_RIGHT_INPUT];
-       snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
-       snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return change;
-}
-
-int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0xff;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
-       
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (invert)
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-       return 0;
-}
-
-int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0xff;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
-       int change;
-       unsigned short val;
-       
-       val = (ucontrol->value.integer.value[0] & mask);
-       if (invert)
-               val = mask - val;
-       val <<= shift;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       val = (chip->image[reg] & ~(mask << shift)) | val;
-       change = val != chip->image[reg];
-       snd_cs4231_out(chip, reg, val);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return change;
-}
-
-int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int left_reg = kcontrol->private_value & 0xff;
-       int right_reg = (kcontrol->private_value >> 8) & 0xff;
-       int shift_left = (kcontrol->private_value >> 16) & 0x07;
-       int shift_right = (kcontrol->private_value >> 19) & 0x07;
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-       int invert = (kcontrol->private_value >> 22) & 1;
-       
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
-       ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       if (invert) {
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-               ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
-       }
-       return 0;
-}
-
-int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int left_reg = kcontrol->private_value & 0xff;
-       int right_reg = (kcontrol->private_value >> 8) & 0xff;
-       int shift_left = (kcontrol->private_value >> 16) & 0x07;
-       int shift_right = (kcontrol->private_value >> 19) & 0x07;
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-       int invert = (kcontrol->private_value >> 22) & 1;
-       int change;
-       unsigned short val1, val2;
-       
-       val1 = ucontrol->value.integer.value[0] & mask;
-       val2 = ucontrol->value.integer.value[1] & mask;
-       if (invert) {
-               val1 = mask - val1;
-               val2 = mask - val2;
-       }
-       val1 <<= shift_left;
-       val2 <<= shift_right;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
-       val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
-       change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
-       snd_cs4231_out(chip, left_reg, val1);
-       snd_cs4231_out(chip, right_reg, val2);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return change;
-}
-
-static struct snd_kcontrol_new snd_cs4231_controls[] = {
-CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
-CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
-CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
-CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
-CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Source",
-       .info = snd_cs4231_info_mux,
-       .get = snd_cs4231_get_mux,
-       .put = snd_cs4231_put_mux,
-},
-CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1)
-};
-                                        
-static struct snd_kcontrol_new snd_opti93x_controls[] = {
-CS4231_DOUBLE("Master Playback Switch", 0,
-             OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Playback Volume", 0,
-             OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
-CS4231_DOUBLE("PCM Playback Switch", 0,
-             CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0,
-             CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("FM Playback Switch", 0,
-             CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("FM Playback Volume", 0,
-             CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Line Playback Switch", 0,
-             CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Playback Volume", 0,
-             CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1),
-CS4231_DOUBLE("Mic Playback Switch", 0,
-             OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Mic Playback Volume", 0,
-             OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Mic Boost", 0,
-             CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-CS4231_DOUBLE("CD Playback Switch", 0,
-             CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("CD Playback Volume", 0,
-             CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Aux Playback Switch", 0,
-             OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 0,
-             OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
-CS4231_DOUBLE("Capture Volume", 0,
-             CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Source",
-       .info = snd_cs4231_info_mux,
-       .get = snd_cs4231_get_mux,
-       .put = snd_cs4231_put_mux,
-}
-};
-
-int snd_cs4231_mixer(struct snd_cs4231 *chip)
-{
-       struct snd_card *card;
-       unsigned int idx;
-       int err;
-
-       snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
-
-       card = chip->card;
-
-       strcpy(card->mixername, chip->pcm->name);
-
-       if (chip->hardware == CS4231_HW_OPTI93X)
-               for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
-                       err = snd_ctl_add(card,
-                                       snd_ctl_new1(&snd_opti93x_controls[idx],
-                                                    chip));
-                       if (err < 0)
-                               return err;
-               }
-       else
-               for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
-                       err = snd_ctl_add(card,
-                                       snd_ctl_new1(&snd_cs4231_controls[idx],
-                                                    chip));
-                       if (err < 0)
-                               return err;
-               }
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_cs4231_out);
-EXPORT_SYMBOL(snd_cs4231_in);
-EXPORT_SYMBOL(snd_cs4236_ext_out);
-EXPORT_SYMBOL(snd_cs4236_ext_in);
-EXPORT_SYMBOL(snd_cs4231_mce_up);
-EXPORT_SYMBOL(snd_cs4231_mce_down);
-EXPORT_SYMBOL(snd_cs4231_overrange);
-EXPORT_SYMBOL(snd_cs4231_interrupt);
-EXPORT_SYMBOL(snd_cs4231_chip_id);
-EXPORT_SYMBOL(snd_cs4231_create);
-EXPORT_SYMBOL(snd_cs4231_pcm);
-EXPORT_SYMBOL(snd_cs4231_mixer);
-EXPORT_SYMBOL(snd_cs4231_timer);
-EXPORT_SYMBOL(snd_cs4231_info_single);
-EXPORT_SYMBOL(snd_cs4231_get_single);
-EXPORT_SYMBOL(snd_cs4231_put_single);
-EXPORT_SYMBOL(snd_cs4231_info_double);
-EXPORT_SYMBOL(snd_cs4231_get_double);
-EXPORT_SYMBOL(snd_cs4231_put_double);
-
-/*
- *  INIT part
- */
-
-static int __init alsa_cs4231_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_cs4231_exit(void)
-{
-}
-
-module_init(alsa_cs4231_init)
-module_exit(alsa_cs4231_exit)
index 4d4b8ddc26bac1711e51b772212497cdfe0f2ddf..91f9c15d3e30b8dfd29ce2bc5d68a33aa30d38d6 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #include <sound/initval.h>
@@ -134,7 +134,7 @@ static int pnp_registered;
 #endif /* CONFIG_PNP */
 
 struct snd_card_cs4236 {
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        struct resource *res_sb_port;
 #ifdef CONFIG_PNP
        struct pnp_dev *wss;
@@ -239,6 +239,8 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
        { .id = "CSC9836", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
        /* Gallant SC-70P */
        { .id = "CSC9837", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
+       /* Techmakers MF-4236PW */
+       { .id = "CSCa736", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
        /* TerraTec AudioSystem EWS64XL - CS4236B */
        { .id = "CSCa836", .devs = { { "CSCa800" }, { "CSCa810" }, { "CSCa803" } } },
        /* TerraTec AudioSystem EWS64XL - CS4236B */
@@ -396,7 +398,7 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
 {
        struct snd_card_cs4236 *acard;
        struct snd_pcm *pcm;
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        struct snd_opl3 *opl3;
        int err;
 
@@ -408,41 +410,37 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
                }
 
 #ifdef CS4232
-       if ((err = snd_cs4231_create(card,
-                                    port[dev],
-                                    cport[dev],
-                                    irq[dev],
-                                    dma1[dev],
-                                    dma2[dev],
-                                    CS4231_HW_DETECT,
-                                    0,
-                                    &chip)) < 0)
+       err = snd_wss_create(card, port[dev], cport[dev],
+                            irq[dev],
+                            dma1[dev], dma2[dev],
+                            WSS_HW_DETECT, 0, &chip);
+       if (err < 0)
                return err;
        acard->chip = chip;
 
-       if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0)
+       err = snd_wss_pcm(chip, 0, &pcm);
+       if (err < 0)
                return err;
 
-       if ((err = snd_cs4231_mixer(chip)) < 0)
+       err = snd_wss_mixer(chip);
+       if (err < 0)
                return err;
 
 #else /* CS4236 */
-       if ((err = snd_cs4236_create(card,
-                                    port[dev],
-                                    cport[dev],
-                                    irq[dev],
-                                    dma1[dev],
-                                    dma2[dev],
-                                    CS4231_HW_DETECT,
-                                    0,
-                                    &chip)) < 0)
+       err = snd_cs4236_create(card,
+                               port[dev], cport[dev],
+                               irq[dev], dma1[dev], dma2[dev],
+                               WSS_HW_DETECT, 0, &chip);
+       if (err < 0)
                return err;
        acard->chip = chip;
 
-       if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0)
+       err = snd_cs4236_pcm(chip, 0, &pcm);
+       if (err < 0)
                return err;
 
-       if ((err = snd_cs4236_mixer(chip)) < 0)
+       err = snd_cs4236_mixer(chip);
+       if (err < 0)
                return err;
 #endif
        strcpy(card->driver, pcm->name);
@@ -455,7 +453,8 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
        if (dma2[dev] >= 0)
                sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
 
-       if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0)
+       err = snd_wss_timer(chip, 0, NULL);
+       if (err < 0)
                return err;
 
        if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
index de71910401ea531efd514b881fe4a6a2744c3583..6a85fdc53b60a716f248ad1c20210f1148732cd6 100644 (file)
@@ -85,7 +85,7 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/asoundef.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -121,13 +121,14 @@ static unsigned char snd_cs4236_ext_map[18] = {
  *
  */
 
-static void snd_cs4236_ctrl_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
+static void snd_cs4236_ctrl_out(struct snd_wss *chip,
+                               unsigned char reg, unsigned char val)
 {
        outb(reg, chip->cport + 3);
        outb(chip->cimage[reg] = val, chip->cport + 4);
 }
 
-static unsigned char snd_cs4236_ctrl_in(struct snd_cs4231 *chip, unsigned char reg)
+static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
 {
        outb(reg, chip->cport + 3);
        return inb(chip->cport + 4);
@@ -180,44 +181,52 @@ static unsigned char divisor_to_rate_register(unsigned int divisor)
        }
 }
 
-static void snd_cs4236_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr)
+static void snd_cs4236_playback_format(struct snd_wss *chip,
+                                      struct snd_pcm_hw_params *params,
+                                      unsigned char pdfr)
 {
        unsigned long flags;
        unsigned char rate = divisor_to_rate_register(params->rate_den);
        
        spin_lock_irqsave(&chip->reg_lock, flags);
        /* set fast playback format change and clean playback FIFO */
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
-       snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
+       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                   chip->image[CS4231_ALT_FEATURE_1] | 0x10);
+       snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
+       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                   chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
        snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static void snd_cs4236_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char cdfr)
+static void snd_cs4236_capture_format(struct snd_wss *chip,
+                                     struct snd_pcm_hw_params *params,
+                                     unsigned char cdfr)
 {
        unsigned long flags;
        unsigned char rate = divisor_to_rate_register(params->rate_den);
        
        spin_lock_irqsave(&chip->reg_lock, flags);
        /* set fast capture format change and clean capture FIFO */
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
-       snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
+       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                   chip->image[CS4231_ALT_FEATURE_1] | 0x20);
+       snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
+       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                   chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
        snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
 #ifdef CONFIG_PM
 
-static void snd_cs4236_suspend(struct snd_cs4231 *chip)
+static void snd_cs4236_suspend(struct snd_wss *chip)
 {
        int reg;
        unsigned long flags;
        
        spin_lock_irqsave(&chip->reg_lock, flags);
        for (reg = 0; reg < 32; reg++)
-               chip->image[reg] = snd_cs4231_in(chip, reg);
+               chip->image[reg] = snd_wss_in(chip, reg);
        for (reg = 0; reg < 18; reg++)
                chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
        for (reg = 2; reg < 9; reg++)
@@ -225,12 +234,12 @@ static void snd_cs4236_suspend(struct snd_cs4231 *chip)
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static void snd_cs4236_resume(struct snd_cs4231 *chip)
+static void snd_cs4236_resume(struct snd_wss *chip)
 {
        int reg;
        unsigned long flags;
        
-       snd_cs4231_mce_up(chip);
+       snd_wss_mce_up(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
        for (reg = 0; reg < 32; reg++) {
                switch (reg) {
@@ -240,7 +249,7 @@ static void snd_cs4236_resume(struct snd_cs4231 *chip)
                case 29:        /* why? CS4235 - master right */
                        break;
                default:
-                       snd_cs4231_out(chip, reg, chip->image[reg]);
+                       snd_wss_out(chip, reg, chip->image[reg]);
                        break;
                }
        }
@@ -255,7 +264,7 @@ static void snd_cs4236_resume(struct snd_cs4231 *chip)
                }
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_down(chip);
+       snd_wss_mce_down(chip);
 }
 
 #endif /* CONFIG_PM */
@@ -266,24 +275,26 @@ int snd_cs4236_create(struct snd_card *card,
                      int irq, int dma1, int dma2,
                      unsigned short hardware,
                      unsigned short hwshare,
-                     struct snd_cs4231 ** rchip)
+                     struct snd_wss **rchip)
 {
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        unsigned char ver1, ver2;
        unsigned int reg;
        int err;
 
        *rchip = NULL;
-       if (hardware == CS4231_HW_DETECT)
-               hardware = CS4231_HW_DETECT3;
+       if (hardware == WSS_HW_DETECT)
+               hardware = WSS_HW_DETECT3;
        if (cport < 0x100) {
                snd_printk("please, specify control port for CS4236+ chips\n");
                return -ENODEV;
        }
-       if ((err = snd_cs4231_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip)) < 0)
+       err = snd_wss_create(card, port, cport,
+                            irq, dma1, dma2, hardware, hwshare, &chip);
+       if (err < 0)
                return err;
 
-       if (!(chip->hardware & CS4231_HW_CS4236B_MASK)) {
+       if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
                snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
                snd_device_free(card, chip);
                return -ENODEV;
@@ -330,20 +341,20 @@ int snd_cs4236_create(struct snd_card *card,
                snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
 
         /* initialize compatible but more featured registers */
-       snd_cs4231_out(chip, CS4231_LEFT_INPUT, 0x40);
-       snd_cs4231_out(chip, CS4231_RIGHT_INPUT, 0x40);
-       snd_cs4231_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
-       snd_cs4231_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
-       snd_cs4231_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
-       snd_cs4231_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
-       snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
-       snd_cs4231_out(chip, CS4231_LEFT_LINE_IN, 0xff);
-       snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
+       snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
+       snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
+       snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
+       snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
+       snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
+       snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
+       snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
+       snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
+       snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
        switch (chip->hardware) {
-       case CS4231_HW_CS4235:
-       case CS4231_HW_CS4239:
-               snd_cs4231_out(chip, CS4235_LEFT_MASTER, 0xff);
-               snd_cs4231_out(chip, CS4235_RIGHT_MASTER, 0xff);
+       case WSS_HW_CS4235:
+       case WSS_HW_CS4239:
+               snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
+               snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
                break;
        }
 
@@ -351,12 +362,13 @@ int snd_cs4236_create(struct snd_card *card,
        return 0;
 }
 
-int snd_cs4236_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
+int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
 {
        struct snd_pcm *pcm;
        int err;
        
-       if ((err = snd_cs4231_pcm(chip, device, &pcm)) < 0)
+       err = snd_wss_pcm(chip, device, &pcm);
+       if (err < 0)
                return err;
        pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
        if (rpcm)
@@ -387,7 +399,7 @@ static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
 
 static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -404,7 +416,7 @@ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 
 static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -433,7 +445,7 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 
 static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -450,7 +462,7 @@ static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
 
 static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -490,7 +502,7 @@ static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
 
 static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int left_reg = kcontrol->private_value & 0xff;
        int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -512,7 +524,7 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 
 static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int left_reg = kcontrol->private_value & 0xff;
        int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -555,7 +567,7 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 
 static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int left_reg = kcontrol->private_value & 0xff;
        int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -577,7 +589,7 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
 
 static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int left_reg = kcontrol->private_value & 0xff;
        int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -600,7 +612,7 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
        val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
        val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
        change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
-       snd_cs4231_out(chip, left_reg, val1);
+       snd_wss_out(chip, left_reg, val1);
        snd_cs4236_ext_out(chip, right_reg, val2);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        return change;
@@ -619,7 +631,7 @@ static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
 
 static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -631,7 +643,7 @@ static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct s
 
 static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int change;
        unsigned short val1, val2;
@@ -678,7 +690,7 @@ static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
 
 static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -690,7 +702,7 @@ static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_
 
 static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int change;
        unsigned short val1, val2;
@@ -701,108 +713,160 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_
        val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
        val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
        change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
-       snd_cs4231_out(chip, CS4235_LEFT_MASTER, val1);
-       snd_cs4231_out(chip, CS4235_RIGHT_MASTER, val2);
+       snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
+       snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        return change;
 }
 
 static struct snd_kcontrol_new snd_cs4236_controls[] = {
 
-CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+CS4236_DOUBLE("Master Digital Playback Switch", 0,
+               CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
+CS4236_DOUBLE("Master Digital Capture Switch", 0,
+               CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
 CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
 
-CS4236_DOUBLE("Capture Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
-
-CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
-
-CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
-CS4236_DOUBLE("DSP Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
-
-CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
-CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
-
-CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
-CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
-
-CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-CS4231_DOUBLE("Synth Capture Bypass", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
-
-CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
-CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
+CS4236_DOUBLE("Capture Boost Volume", 0,
+               CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+
+WSS_DOUBLE("PCM Playback Switch", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+
+CS4236_DOUBLE("DSP Playback Switch", 0,
+               CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
+CS4236_DOUBLE("DSP Playback Volume", 0,
+               CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
+
+CS4236_DOUBLE("FM Playback Switch", 0,
+               CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
+CS4236_DOUBLE("FM Playback Volume", 0,
+               CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
+
+CS4236_DOUBLE("Wavetable Playback Switch", 0,
+               CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
+CS4236_DOUBLE("Wavetable Playback Volume", 0,
+               CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
+
+WSS_DOUBLE("Synth Playback Switch", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Synth Volume", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE("Synth Capture Switch", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
+WSS_DOUBLE("Synth Capture Bypass", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
+
+CS4236_DOUBLE("Mic Playback Switch", 0,
+               CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
+CS4236_DOUBLE("Mic Capture Switch", 0,
+               CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
 CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
-CS4236_DOUBLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
-
-CS4231_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Line Capture Bypass", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
-
-CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
-
-CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
-CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-CS4231_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
-
-CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-CS4231_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
-
-CS4231_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
+CS4236_DOUBLE("Mic Playback Boost", 0,
+               CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
+
+WSS_DOUBLE("Line Playback Switch", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Line Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Line Capture Switch", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Line Capture Bypass", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
+
+WSS_DOUBLE("CD Playback Switch", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("CD Volume", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("CD Capture Switch", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
+
+CS4236_DOUBLE1("Mono Output Playback Switch", 0,
+               CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
+CS4236_DOUBLE1("Mono Playback Switch", 0,
+               CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
+WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
+
+WSS_DOUBLE("Capture Volume", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+WSS_DOUBLE("Analog Loopback Capture Switch", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+
+WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
+               CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
 };
 
 static struct snd_kcontrol_new snd_cs4235_controls[] = {
 
-CS4231_DOUBLE("Master Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
+WSS_DOUBLE("Master Switch", 0,
+               CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
+WSS_DOUBLE("Master Volume", 0,
+               CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
 
 CS4235_OUTPUT_ACCU("Playback Volume", 0),
 
-CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+CS4236_DOUBLE("Master Digital Playback Switch", 0,
+               CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
+CS4236_DOUBLE("Master Digital Capture Switch", 0,
+               CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
 CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
 
-CS4231_DOUBLE("Master Digital Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Digital Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-CS4231_DOUBLE("Master Digital Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE("Master Digital Playback Switch", 1,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Master Digital Capture Switch", 1,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
+WSS_DOUBLE("Master Digital Volume", 1,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
 
-CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+CS4236_DOUBLE("Capture Volume", 0,
+               CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
 
-CS4231_DOUBLE("PCM Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("PCM Switch", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
 
 CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
 
 CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
 
-CS4236_DOUBLE("Wavetable Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
+CS4236_DOUBLE("Wavetable Switch", 0,
+               CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
 
-CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
-CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
+CS4236_DOUBLE("Mic Capture Switch", 0,
+               CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
+CS4236_DOUBLE("Mic Playback Switch", 0,
+               CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
 CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
 CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
 
-CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Aux Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-
-CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Aux Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-
-CS4236_DOUBLE1("Master Mono Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
-
-CS4236_DOUBLE1("Mono Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-CS4231_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-
-CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+WSS_DOUBLE("Aux Playback Switch", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Capture Switch", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Aux Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+
+WSS_DOUBLE("Aux Playback Switch", 1,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Capture Switch", 1,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Aux Volume", 1,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+
+CS4236_DOUBLE1("Master Mono Switch", 0,
+               CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
+
+CS4236_DOUBLE1("Mono Switch", 0,
+               CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
+WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+
+WSS_DOUBLE("Analog Loopback Switch", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
 };
 
 #define CS4236_IEC958_ENABLE(xname, xindex) \
@@ -813,14 +877,14 @@ CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT
 
 static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        
        spin_lock_irqsave(&chip->reg_lock, flags);
        ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
 #if 0
        printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
-                       snd_cs4231_in(chip, CS4231_ALT_FEATURE_1),
+                       snd_wss_in(chip, CS4231_ALT_FEATURE_1),
                        snd_cs4236_ctrl_in(chip, 3),
                        snd_cs4236_ctrl_in(chip, 4),
                        snd_cs4236_ctrl_in(chip, 5),
@@ -833,7 +897,7 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
 
 static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
        unsigned long flags;
        int change;
        unsigned short enable, val;
@@ -841,23 +905,23 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
        enable = ucontrol->value.integer.value[0] & 1;
 
        mutex_lock(&chip->mce_mutex);
-       snd_cs4231_mce_up(chip);
+       snd_wss_mce_up(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
        val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
        change = val != chip->image[CS4231_ALT_FEATURE_1];
-       snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val);
+       snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
        val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
        snd_cs4236_ctrl_out(chip, 4, val);
        udelay(100);
        val &= ~0x40;
        snd_cs4236_ctrl_out(chip, 4, val);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_cs4231_mce_down(chip);
+       snd_wss_mce_down(chip);
        mutex_unlock(&chip->mce_mutex);
 
 #if 0
        printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
-                       snd_cs4231_in(chip, CS4231_ALT_FEATURE_1),
+                       snd_wss_in(chip, CS4231_ALT_FEATURE_1),
                        snd_cs4236_ctrl_in(chip, 3),
                        snd_cs4236_ctrl_in(chip, 4),
                        snd_cs4236_ctrl_in(chip, 5),
@@ -896,19 +960,20 @@ CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
 };
 
-int snd_cs4236_mixer(struct snd_cs4231 *chip)
+int snd_cs4236_mixer(struct snd_wss *chip)
 {
        struct snd_card *card;
        unsigned int idx, count;
        int err;
        struct snd_kcontrol_new *kcontrol;
 
-       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip || !chip->card))
+               return -EINVAL;
        card = chip->card;
-       strcpy(card->mixername, snd_cs4231_chip_id(chip));
+       strcpy(card->mixername, snd_wss_chip_id(chip));
 
-       if (chip->hardware == CS4231_HW_CS4235 ||
-           chip->hardware == CS4231_HW_CS4239) {
+       if (chip->hardware == WSS_HW_CS4235 ||
+           chip->hardware == WSS_HW_CS4239) {
                for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
                        if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0)
                                return err;
@@ -920,16 +985,16 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip)
                }
        }
        switch (chip->hardware) {
-       case CS4231_HW_CS4235:
-       case CS4231_HW_CS4239:
+       case WSS_HW_CS4235:
+       case WSS_HW_CS4239:
                count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
                kcontrol = snd_cs4236_3d_controls_cs4235;
                break;
-       case CS4231_HW_CS4237B:
+       case WSS_HW_CS4237B:
                count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
                kcontrol = snd_cs4236_3d_controls_cs4237;
                break;
-       case CS4231_HW_CS4238B:
+       case WSS_HW_CS4238B:
                count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
                kcontrol = snd_cs4236_3d_controls_cs4238;
                break;
@@ -941,8 +1006,8 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip)
                if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0)
                        return err;
        }
-       if (chip->hardware == CS4231_HW_CS4237B ||
-           chip->hardware == CS4231_HW_CS4238B) {
+       if (chip->hardware == WSS_HW_CS4237B ||
+           chip->hardware == WSS_HW_CS4238B) {
                for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
                        if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0)
                                return err;
index 1e1e575b1db329f87b289cb4cc57bbb954f1bae0..4fbb508a817f39485406800431c87fc7130c8450 100644 (file)
@@ -1009,7 +1009,8 @@ int snd_es1688_mixer(struct snd_es1688 *chip)
        int err;
        unsigned char reg, val;
 
-       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip || !chip->card))
+               return -EINVAL;
 
        card = chip->card;
 
index cccc16c8113f35a949bc775b56a04b2a4f9f2b38..12eb98f2f931e123c583419134064c1fb7004e33 100644 (file)
@@ -276,9 +276,11 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
        static unsigned char dmas[8] =
                {6, 1, 0, 2, 0, 3, 4, 5};
 
-       snd_assert(gus != NULL, return -EINVAL);
+       if (snd_BUG_ON(!gus))
+               return -EINVAL;
        card = gus->card;
-       snd_assert(card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card))
+               return -EINVAL;
 
        gus->mix_cntrl_reg &= 0xf8;
        gus->mix_cntrl_reg |= 0x01;     /* disable MIC, LINE IN, enable LINE OUT */
index ebdb33469306df356c9a9303c0c8f1dc22c1b802..0dd43414016e8236a968d0af181563288f833ba5 100644 (file)
@@ -161,9 +161,11 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus)
        unsigned int idx, max;
        int err;
 
-       snd_assert(gus != NULL, return -EINVAL);
+       if (snd_BUG_ON(!gus))
+               return -EINVAL;
        card = gus->card;
-       snd_assert(card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card))
+               return -EINVAL;
 
        if (gus->ics_flag)
                snd_component_add(card, "ICS2101");
index 99731dc9732564fa1223becbadff7f2e0b9cb782..38510aeb21c64893a988a900224bd7420b037ff2 100644 (file)
@@ -352,8 +352,10 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,
        
        bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
        len = samples_to_bytes(runtime, count);
-       snd_assert(bpos <= pcmp->dma_size, return -EIO);
-       snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
+       if (snd_BUG_ON(bpos > pcmp->dma_size))
+               return -EIO;
+       if (snd_BUG_ON(bpos + len > pcmp->dma_size))
+               return -EIO;
        if (copy_from_user(runtime->dma_area + bpos, src, len))
                return -EFAULT;
        if (snd_gf1_pcm_use_dma && len > 32) {
@@ -381,8 +383,10 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
        
        bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
        len = samples_to_bytes(runtime, count);
-       snd_assert(bpos <= pcmp->dma_size, return -EIO);
-       snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
+       if (snd_BUG_ON(bpos > pcmp->dma_size))
+               return -EIO;
+       if (snd_BUG_ON(bpos + len > pcmp->dma_size))
+               return -EIO;
        snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count);
        if (snd_gf1_pcm_use_dma && len > 32) {
                return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
index f87c6236661c6ea985134dde22d705d52c7b0860..f94c1976e632c2c55314cd8daee9e0f9aeb0f716 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/gus.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -75,7 +75,7 @@ struct snd_gusmax {
        int irq;
        struct snd_card *card;
        struct snd_gus_card *gus;
-       struct snd_cs4231 *cs4231;
+       struct snd_wss *wss;
        unsigned short gus_status_reg;
        unsigned short pcm_status_reg;
 };
@@ -117,7 +117,7 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id)
                }
                if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
                        handled = 1;
-                       snd_cs4231_interrupt(irq, maxcard->cs4231);
+                       snd_wss_interrupt(irq, maxcard->wss);
                        loop++;
                }
        } while (loop && --max > 0);
@@ -140,10 +140,7 @@ static void __devinit snd_gusmax_init(int dev, struct snd_card *card,
        outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT));
 }
 
-#define CS4231_PRIVATE( left, right, shift, mute ) \
-                       ((left << 24)|(right << 16)|(shift<<8)|mute)
-
-static int __devinit snd_gusmax_mixer(struct snd_cs4231 *chip)
+static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
 {
        struct snd_card *card = chip->card;
        struct snd_ctl_elem_id id1, id2;
@@ -214,7 +211,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
        int xirq, xdma1, xdma2, err;
        struct snd_card *card;
        struct snd_gus_card *gus = NULL;
-       struct snd_cs4231 *cs4231;
+       struct snd_wss *wss;
        struct snd_gusmax *maxcard;
 
        card = snd_card_new(index[dev], id[dev], THIS_MODULE,
@@ -301,33 +298,39 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
        }
        maxcard->irq = xirq;
        
-       if ((err = snd_cs4231_create(card,
-                                    gus->gf1.port + 0x10c, -1, xirq,
-                                    xdma2 < 0 ? xdma1 : xdma2, xdma1,
-                                    CS4231_HW_DETECT,
-                                    CS4231_HWSHARE_IRQ |
-                                    CS4231_HWSHARE_DMA1 |
-                                    CS4231_HWSHARE_DMA2,
-                                    &cs4231)) < 0)
+       err = snd_wss_create(card,
+                            gus->gf1.port + 0x10c, -1, xirq,
+                            xdma2 < 0 ? xdma1 : xdma2, xdma1,
+                            WSS_HW_DETECT,
+                            WSS_HWSHARE_IRQ |
+                            WSS_HWSHARE_DMA1 |
+                            WSS_HWSHARE_DMA2,
+                            &wss);
+       if (err < 0)
                goto _err;
 
-       if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0)
+       err = snd_wss_pcm(wss, 0, NULL);
+       if (err < 0)
                goto _err;
 
-       if ((err = snd_cs4231_mixer(cs4231)) < 0)
+       err = snd_wss_mixer(wss);
+       if (err < 0)
                goto _err;
 
-       if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0)
+       err = snd_wss_timer(wss, 2, NULL);
+       if (err < 0)
                goto _err;
 
        if (pcm_channels[dev] > 0) {
                if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
                        goto _err;
        }
-       if ((err = snd_gusmax_mixer(cs4231)) < 0)
+       err = snd_gusmax_mixer(wss);
+       if (err < 0)
                goto _err;
 
-       if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
+       err = snd_gf1_rawmidi_new(gus, 0, NULL);
+       if (err < 0)
                goto _err;
 
        sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1);
@@ -336,11 +339,12 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
 
        snd_card_set_dev(card, pdev);
 
-       if ((err = snd_card_register(card)) < 0)
+       err = snd_card_register(card);
+       if (err < 0)
                goto _err;
                
        maxcard->gus = gus;
-       maxcard->cs4231 = cs4231;
+       maxcard->wss = wss;
 
        dev_set_drvdata(pdev, card);
        return 0;
index ca0d7ace0c75abec9a6b9006a716e5cddc4b9a37..5faecfb602d3bec1a66235e5c1e5951f2ec2a215 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/gus.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #ifdef SNDRV_STB
 #include <sound/tea6330t.h>
 #endif
@@ -118,7 +118,7 @@ struct snd_interwave {
        int irq;
        struct snd_card *card;
        struct snd_gus_card *gus;
-       struct snd_cs4231 *cs4231;
+       struct snd_wss *wss;
 #ifdef SNDRV_STB
        struct resource *i2c_res;
 #endif
@@ -312,7 +312,7 @@ static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id)
                }
                if (inb(iwcard->pcm_status_reg) & 0x01) {       /* IRQ bit is set? */
                        handled = 1;
-                       snd_cs4231_interrupt(irq, iwcard->cs4231);
+                       snd_wss_interrupt(irq, iwcard->wss);
                        loop++;
                }
        } while (loop && --max > 0);
@@ -498,13 +498,17 @@ static void __devinit snd_interwave_init(int dev, struct snd_gus_card * gus)
 }
 
 static struct snd_kcontrol_new snd_interwave_controls[] = {
-CS4231_DOUBLE("Master Playback Switch", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Playback Volume", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Mic Playback Switch", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
+WSS_DOUBLE("Master Playback Switch", 0,
+               CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Master Playback Volume", 0,
+               CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Mic Playback Switch", 0,
+               CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Mic Playback Volume", 0,
+               CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
 };
 
-static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip)
+static int __devinit snd_interwave_mixer(struct snd_wss *chip)
 {
        struct snd_card *card = chip->card;
        struct snd_ctl_elem_id id1, id2;
@@ -527,10 +531,10 @@ static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip)
        for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++)
                if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0)
                        return err;
-       snd_cs4231_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
-       snd_cs4231_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
-       snd_cs4231_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
-       snd_cs4231_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
+       snd_wss_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
+       snd_wss_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
+       snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
+       snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
        /* reassign AUXA to SYNTHESIZER */
        strcpy(id1.name, "Aux Playback Switch");
        strcpy(id2.name, "Synth Playback Switch");
@@ -642,7 +646,7 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
 {
        int xirq, xdma1, xdma2;
        struct snd_interwave *iwcard = card->private_data;
-       struct snd_cs4231 *cs4231;
+       struct snd_wss *wss;
        struct snd_gus_card *gus;
 #ifdef SNDRV_STB
        struct snd_i2c_bus *i2c_bus;
@@ -684,33 +688,39 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
        }
        iwcard->irq = xirq;
 
-       if ((err = snd_cs4231_create(card,
-                                    gus->gf1.port + 0x10c, -1, xirq,
-                                    xdma2 < 0 ? xdma1 : xdma2, xdma1,
-                                    CS4231_HW_INTERWAVE,
-                                    CS4231_HWSHARE_IRQ |
-                                    CS4231_HWSHARE_DMA1 |
-                                    CS4231_HWSHARE_DMA2,
-                                    &cs4231)) < 0)
+       err = snd_wss_create(card,
+                            gus->gf1.port + 0x10c, -1, xirq,
+                            xdma2 < 0 ? xdma1 : xdma2, xdma1,
+                            WSS_HW_INTERWAVE,
+                            WSS_HWSHARE_IRQ |
+                            WSS_HWSHARE_DMA1 |
+                            WSS_HWSHARE_DMA2,
+                            &wss);
+       if (err < 0)
                return err;
 
-       if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0)
+       err = snd_wss_pcm(wss, 0, &pcm);
+       if (err < 0)
                return err;
 
        sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
        strcat(pcm->name, " (codec)");
 
-       if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0)
+       err = snd_wss_timer(wss, 2, NULL);
+       if (err < 0)
                return err;
 
-       if ((err = snd_cs4231_mixer(cs4231)) < 0)
+       err = snd_wss_mixer(wss);
+       if (err < 0)
                return err;
 
        if (pcm_channels[dev] > 0) {
-               if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+               err = snd_gf1_pcm_new(gus, 1, 1, NULL);
+               if (err < 0)
                        return err;
        }
-       if ((err = snd_interwave_mixer(cs4231)) < 0)
+       err = snd_interwave_mixer(wss);
+       if (err < 0)
                return err;
 
 #ifdef SNDRV_STB
@@ -754,10 +764,11 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
        if (xdma2 >= 0)
                sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
 
-       if ((err = snd_card_register(card)) < 0)
+       err = snd_card_register(card);
+       if (err < 0)
                return err;
        
-       iwcard->cs4231 = cs4231;
+       iwcard->wss = wss;
        iwcard->gus = gus;
        return 0;
 }
index 854a9f74b46665d0fc6b418e49127fe4086ea25a..58c972b2af03821dd1647dba0494cbd15f17a945 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/pnp.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #include <sound/initval.h>
@@ -124,7 +124,6 @@ static int pnpc_registered;
 #define OPL3SA2_PM_D3  (OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX)
 
 struct snd_opl3sa2 {
-       struct snd_card *card;
        int version;            /* 2 or 3 */
        unsigned long port;     /* control port */
        struct resource *res_port; /* control port resource */
@@ -133,7 +132,7 @@ struct snd_opl3sa2 {
        spinlock_t reg_lock;
        struct snd_hwdep *synth;
        struct snd_rawmidi *rmidi;
-       struct snd_cs4231 *cs4231;
+       struct snd_wss *wss;
        unsigned char ctlregs[0x20];
        int ymode;              /* SL added */
        struct snd_kcontrol *master_switch;
@@ -222,14 +221,13 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_detect(struct snd_card *card)
 {
-       struct snd_card *card;
+       struct snd_opl3sa2 *chip = card->private_data;
        unsigned long port;
        unsigned char tmp, tmp1;
        char str[2];
 
-       card = chip->card;
        port = chip->port;
        if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) {
                snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
@@ -298,12 +296,14 @@ static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
 static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
 {
        unsigned short status;
-       struct snd_opl3sa2 *chip = dev_id;
+       struct snd_card *card = dev_id;
+       struct snd_opl3sa2 *chip;
        int handled = 0;
 
-       if (chip == NULL || chip->card == NULL)
+       if (card == NULL)
                return IRQ_NONE;
 
+       chip = card->private_data;
        status = snd_opl3sa2_read(chip, OPL3SA2_IRQ_STATUS);
 
        if (status & 0x20) {
@@ -318,7 +318,7 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
 
        if (status & 0x07) {    /* TI,CI,PI */
                handled = 1;
-               snd_cs4231_interrupt(irq, chip->cs4231);
+               snd_wss_interrupt(irq, chip->wss);
        }
 
        if (status & 0x40) { /* hardware volume change */
@@ -327,8 +327,10 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
                snd_opl3sa2_read(chip, OPL3SA2_MASTER_RIGHT);
                snd_opl3sa2_read(chip, OPL3SA2_MASTER_LEFT);
                if (chip->master_switch && chip->master_volume) {
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->master_switch->id);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &chip->master_volume->id);
                }
        }
        return IRQ_RETVAL(handled);
@@ -336,29 +338,18 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
 
 #define OPL3SA2_SINGLE(xname, xindex, reg, shift, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_single, \
+  .info = snd_wss_info_single, \
   .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
 #define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_single, \
+  .info = snd_wss_info_single, \
   .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
   .tlv = { .p = (xtlv) } }
 
-static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
 static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
@@ -402,29 +393,18 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
 
 #define OPL3SA2_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_double, \
+  .info = snd_wss_info_double, \
   .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
 #define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .name = xname, .index = xindex, \
-  .info = snd_opl3sa2_info_double, \
+  .info = snd_wss_info_double, \
   .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
   .tlv = { .p = (xtlv) } }
 
-static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
 static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
@@ -512,9 +492,9 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol)
        chip->master_volume = NULL;
 }
 
-static int __devinit snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_mixer(struct snd_card *card)
 {
-       struct snd_card *card = chip->card;
+       struct snd_opl3sa2 *chip = card->private_data;
        struct snd_ctl_elem_id id1, id2;
        struct snd_kcontrol *kctl;
        unsigned int idx;
@@ -573,7 +553,7 @@ static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state)
        struct snd_opl3sa2 *chip = card->private_data;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       chip->cs4231->suspend(chip->cs4231);
+       chip->wss->suspend(chip->wss);
        /* power down */
        snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
 
@@ -597,8 +577,8 @@ static int snd_opl3sa2_resume(struct snd_card *card)
                for (i = 0x12; i <= 0x16; i++)
                        snd_opl3sa2_write(chip, i, chip->ctlregs[i]);
        }
-       /* restore cs4231 */
-       chip->cs4231->resume(chip->cs4231);
+       /* restore wss */
+       chip->wss->resume(chip->wss);
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
@@ -650,7 +630,6 @@ static struct snd_card *snd_opl3sa2_card_new(int dev)
        chip = card->private_data;
        spin_lock_init(&chip->reg_lock);
        chip->irq = -1;
-       chip->card = card;
        card->private_free = snd_opl3sa2_free;
        return card;
 }
@@ -659,7 +638,7 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
 {
        int xirq, xdma1, xdma2;
        struct snd_opl3sa2 *chip;
-       struct snd_cs4231 *cs4231;
+       struct snd_wss *wss;
        struct snd_opl3 *opl3;
        int err;
 
@@ -672,30 +651,36 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
        xdma2 = dma2[dev];
        if (xdma2 < 0)
                chip->single_dma = 1;
-       if ((err = snd_opl3sa2_detect(chip)) < 0)
+       err = snd_opl3sa2_detect(card);
+       if (err < 0)
                return err;
-       if (request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED, "OPL3-SA2", chip)) {
+       err = request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED,
+                         "OPL3-SA2", card);
+       if (err) {
                snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq);
                return -ENODEV;
        }
        chip->irq = xirq;
-       if ((err = snd_cs4231_create(card,
-                                    wss_port[dev] + 4, -1,
-                                    xirq, xdma1, xdma2,
-                                    CS4231_HW_OPL3SA2,
-                                    CS4231_HWSHARE_IRQ,
-                                    &cs4231)) < 0) {
+       err = snd_wss_create(card,
+                            wss_port[dev] + 4, -1,
+                            xirq, xdma1, xdma2,
+                            WSS_HW_OPL3SA2, WSS_HWSHARE_IRQ, &wss);
+       if (err < 0) {
                snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4);
                return err;
        }
-       chip->cs4231 = cs4231;
-       if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0)
+       chip->wss = wss;
+       err = snd_wss_pcm(wss, 0, NULL);
+       if (err < 0)
                return err;
-       if ((err = snd_cs4231_mixer(cs4231)) < 0)
+       err = snd_wss_mixer(wss);
+       if (err < 0)
                return err;
-       if ((err = snd_opl3sa2_mixer(chip)) < 0)
+       err = snd_opl3sa2_mixer(card);
+       if (err < 0)
                return err;
-       if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0)
+       err = snd_wss_timer(wss, 0, NULL);
+       if (err < 0)
                return err;
        if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) {
                if ((err = snd_opl3_create(card, fm_port[dev],
index 2a1e2f5d12c2abe78e99192d31c14d39b55b7f13..440755cc00137c663e39c11e258c76ca5d944bed 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl4.h>
 #include <sound/control.h>
@@ -675,7 +675,8 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro)
        unsigned int idx;
        int err;
 
-       snd_assert(miro != NULL && miro->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!miro || !miro->card))
+               return -EINVAL;
 
        card = miro->card;
 
@@ -1221,7 +1222,7 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
 
        int error;
        struct snd_miro *miro;
-       struct snd_cs4231 *codec;
+       struct snd_wss *codec;
        struct snd_timer *timer;
        struct snd_card *card;
        struct snd_pcm *pcm;
@@ -1310,29 +1311,32 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
                }
        }
 
-       if ((error = snd_miro_configure(miro))) {
+       error = snd_miro_configure(miro);
+       if (error) {
                snd_card_free(card);
                return error;
        }
 
-       if ((error = snd_cs4231_create(card, miro->wss_base + 4, -1,
-                                      miro->irq, miro->dma1, miro->dma2,
-                                      CS4231_HW_AD1845,
-                                      0,
-                                      &codec)) < 0) {
+       error = snd_wss_create(card, miro->wss_base + 4, -1,
+                               miro->irq, miro->dma1, miro->dma2,
+                               WSS_HW_AD1845, 0, &codec);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
 
-       if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) {
+       error = snd_wss_pcm(codec, 0, &pcm);
+       if (error < 0)  {
                snd_card_free(card);
                return error;
        }
-       if ((error = snd_cs4231_mixer(codec)) < 0) {
+       error = snd_wss_mixer(codec);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
-       if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) {
+       error = snd_wss_timer(codec, 0, &timer);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
index 0797ca441a372d719de70bad9c7df9b96db458f6..19706b0d84978c5307166826b9aed76a0c40f46e 100644 (file)
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#if defined(CS4231) || defined(OPTi93X)
-#include <sound/cs4231.h>
-#else
-#include <sound/ad1848.h>
-#endif /* CS4231 */
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #ifndef OPTi93X
@@ -139,7 +135,7 @@ struct snd_opti9xx {
        unsigned long mc_base_size;
 #ifdef OPTi93X
        unsigned long mc_indir_index;
-       struct snd_cs4231 *codec;
+       struct snd_wss *codec;
 #endif /* OPTi93X */
        unsigned long pwd_reg;
 
@@ -148,9 +144,7 @@ struct snd_opti9xx {
        long wss_base;
        int irq;
        int dma1;
-#if defined(CS4231) || defined(OPTi93X)
        int dma2;
-#endif /* CS4231 || OPTi93X */
 
        long fm_port;
 
@@ -225,9 +219,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
        chip->wss_base = -1;
        chip->irq = -1;
        chip->dma1 = -1;
-#if defined(CS4231) || defined (OPTi93X)
        chip->dma2 = -1;
-#endif         /* CS4231 || OPTi93X */
        chip->fm_port = -1;
        chip->mpu_port = -1;
        chip->mpu_irq = -1;
@@ -562,7 +554,7 @@ __skip_mpu:
 
 static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
 {
-       struct snd_cs4231 *codec = dev_id;
+       struct snd_wss *codec = dev_id;
        struct snd_opti9xx *chip = codec->card->private_data;
        unsigned char status;
 
@@ -570,7 +562,7 @@ static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
        if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)
                snd_pcm_period_elapsed(codec->playback_substream);
        if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {
-               snd_cs4231_overrange(codec);
+               snd_wss_overrange(codec);
                snd_pcm_period_elapsed(codec->capture_substream);
        }
        outb(0x00, OPTi93X_PORT(codec, STATUS));
@@ -691,7 +683,7 @@ static void snd_card_opti9xx_free(struct snd_card *card)
         
        if (chip) {
 #ifdef OPTi93X
-               struct snd_cs4231 *codec = chip->codec;
+               struct snd_wss *codec = chip->codec;
                if (codec && codec->irq > 0) {
                        disable_irq(codec->irq);
                        free_irq(codec->irq, codec);
@@ -706,13 +698,9 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
        int error;
        struct snd_opti9xx *chip = card->private_data;
-#if defined(CS4231) || defined(OPTi93X)
-       struct snd_cs4231 *codec;
+       struct snd_wss *codec;
 #ifdef CS4231
        struct snd_timer *timer;
-#endif
-#else
-       struct snd_ad1848 *codec;
 #endif
        struct snd_pcm *pcm;
        struct snd_rawmidi *rmidi;
@@ -731,54 +719,52 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        chip->dma1 = dma1;
 #if defined(CS4231) || defined(OPTi93X)
        chip->dma2 = dma2;
+#else
+       chip->dma2 = -1;
 #endif
 
        if (chip->wss_base == SNDRV_AUTO_PORT) {
-               if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) {
+               chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
+               if (chip->wss_base < 0) {
                        snd_printk("unable to find a free WSS port\n");
                        return -EBUSY;
                }
        }
-       if ((error = snd_opti9xx_configure(chip)))
+       error = snd_opti9xx_configure(chip);
+       if (error)
                return error;
 
-#if defined(CS4231) || defined(OPTi93X)
-       if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1,
-                                      chip->irq, chip->dma1, chip->dma2,
-#ifdef CS4231
-                                      CS4231_HW_DETECT, 0,
-#else /* OPTi93x */
-                                      CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ,
+       error = snd_wss_create(card, chip->wss_base + 4, -1,
+                              chip->irq, chip->dma1, chip->dma2,
+#ifdef OPTi93X
+                              WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
+#else
+                              WSS_HW_DETECT, 0,
 #endif
-                                      &codec)) < 0)
+                              &codec);
+       if (error < 0)
                return error;
 #ifdef OPTi93X
        chip->codec = codec;
 #endif
-       if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0)
+       error = snd_wss_pcm(codec, 0, &pcm);
+       if (error < 0)
                return error;
-       if ((error = snd_cs4231_mixer(codec)) < 0)
+       error = snd_wss_mixer(codec);
+       if (error < 0)
                return error;
 #ifdef CS4231
-       if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0)
+       error = snd_wss_timer(codec, 0, &timer);
+       if (error < 0)
                return error;
-#else /* OPTI93X */
+#endif
+#ifdef OPTi93X
        error = request_irq(chip->irq, snd_opti93x_interrupt,
                            IRQF_DISABLED, DEV_NAME" - WSS", codec);
        if (error < 0) {
                snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
                return error;
        }
-#endif
-#else
-       if ((error = snd_ad1848_create(card, chip->wss_base + 4,
-                                      chip->irq, chip->dma1,
-                                      AD1848_HW_DETECT, &codec)) < 0)
-               return error;
-       if ((error = snd_ad1848_pcm(codec, 0, &pcm)) < 0)
-               return error;
-       if ((error = snd_ad1848_mixer(codec)) < 0)
-               return error;
 #endif
        strcpy(card->driver, chip->name);
        sprintf(card->shortname, "OPTi %s", card->driver);
index b35be7d9a9fa8b4a70e1037534c2e8bd0b821d9f..96678d5d3834863fbfe440df54b8170cfa088095 100644 (file)
@@ -1023,7 +1023,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
 {
        int i, err = 0;
 
-       snd_assert(emu != NULL && card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!emu || !card))
+               return -EINVAL;
 
        spin_lock_init(&emu->control_lock);
 
index 1be16c9700f09cd254117f3a0de9b014997de6f6..c99c6078be3376fa792f8b335e31f57a80a7c221 100644 (file)
@@ -156,7 +156,8 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
        struct snd_emu8000 *emu;
 
        emu = rec->hw;
-       snd_assert(sp != NULL, return -EINVAL);
+       if (snd_BUG_ON(!sp))
+               return -EINVAL;
 
        if (sp->v.size == 0)
                return 0;
index 35f3d7b16536ee9dfc528c47fd1365575c3023d7..49037d074c719f8e2ef2160b1d8730af1dec2cf6 100644 (file)
@@ -198,7 +198,8 @@ static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned i
        struct snd_sb_csp_start start_info;
        int err;
 
-       snd_assert(p != NULL, return -EINVAL);
+       if (snd_BUG_ON(!p))
+               return -EINVAL;
 
        if (snd_sb_csp_check_version(p))
                return -ENODEV;
@@ -1046,7 +1047,8 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p)
        struct snd_card *card;
        int err;
 
-       snd_assert(p != NULL, return -EINVAL);
+       if (snd_BUG_ON(!p))
+               return -EINVAL;
 
        card = p->chip->card;
        p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2;
@@ -1071,7 +1073,8 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
        struct snd_card *card;
        unsigned long flags;
 
-       snd_assert(p != NULL, return);
+       if (snd_BUG_ON(!p))
+               return;
 
        card = p->chip->card;   
        
index f7e8192270ae1796a302b1893f3b18136a1f8bee..2a6cc1cfe945a6f731690c06b97026b1e2ef1d65 100644 (file)
@@ -669,7 +669,8 @@ static int snd_sb16_capture_close(struct snd_pcm_substream *substream)
 static int snd_sb16_set_dma_mode(struct snd_sb *chip, int what)
 {
        if (chip->dma8 < 0 || chip->dma16 < 0) {
-               snd_assert(what == 0, return -EINVAL);
+               if (snd_BUG_ON(what))
+                       return -EINVAL;
                return 0;
        }
        if (what == 0) {
index fe03bb820532beed11afd25dbfe8c67959ead1fa..658d55769c9cd5ff44adf13aee830b455b215f5f 100644 (file)
@@ -111,7 +111,9 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
        switch (chip->hardware) {
        case SB_HW_PRO:
                if (runtime->channels > 1) {
-                       snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
+                       if (snd_BUG_ON(rate != SB8_RATE(11025) &&
+                                      rate != SB8_RATE(22050)))
+                               return -EINVAL;
                        chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
                        break;
                }
@@ -237,7 +239,9 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
        switch (chip->hardware) {
        case SB_HW_PRO:
                if (runtime->channels > 1) {
-                       snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
+                       if (snd_BUG_ON(rate != SB8_RATE(11025) &&
+                                      rate != SB8_RATE(22050)))
+                               return -EINVAL;
                        chip->capture_format = SB_DSP_HI_INPUT_AUTO;
                        break;
                }
index b432d9ae874baba6b52d837b8886eff2dd02fc22..27a65150225168a3f7264c4d6c1c6f8667cc7bfa 100644 (file)
@@ -219,7 +219,8 @@ int snd_sbdsp_create(struct snd_card *card,
                .dev_free =     snd_sbdsp_dev_free,
        };
 
-       snd_assert(r_chip != NULL, return -EINVAL);
+       if (snd_BUG_ON(!r_chip))
+               return -EINVAL;
        *r_chip = NULL;
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (chip == NULL)
index 73d4572d136bb893da5435ecc97313a52ccb7ba0..406a431af91ec6880d548b39b0f423c9bb01a56b 100644 (file)
@@ -792,7 +792,8 @@ int snd_sbmixer_new(struct snd_sb *chip)
        struct snd_card *card;
        int err;
 
-       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip || !chip->card))
+               return -EINVAL;
 
        card = chip->card;
 
@@ -925,7 +926,8 @@ static unsigned char als4000_saved_regs[] = {
 static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 {
        unsigned char *val = chip->saved_regs;
-       snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
+       if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
+               return;
        for (; num_regs; num_regs--)
                *val++ = snd_sbmixer_read(chip, *regs++);
 }
@@ -933,7 +935,8 @@ static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 {
        unsigned char *val = chip->saved_regs;
-       snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
+       if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
+               return;
        for (; num_regs; num_regs--)
                snd_sbmixer_write(chip, *regs++, *val++);
 }
index da3d152bcad4d0b5bd7d29b2c1ee1cb5104eaf7a..ca35924dc3b3d05efa49db7051048c5d7b0d4e36 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/opl3.h>
 #include <sound/mpu401.h>
 #include <sound/control.h>
@@ -397,7 +397,7 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
        return 0;
 }
 
-static int __devinit snd_sc6000_mixer(struct snd_ad1848 *chip)
+static int __devinit snd_sc6000_mixer(struct snd_wss *chip)
 {
        struct snd_card *card = chip->card;
        struct snd_ctl_elem_id id1, id2;
@@ -483,7 +483,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
        int xirq = irq[dev];
        int xdma = dma[dev];
        struct snd_card *card;
-       struct snd_ad1848 *chip;
+       struct snd_wss *chip;
        struct snd_opl3 *opl3;
        char __iomem *vport;
        char __iomem *vmss_port;
@@ -548,21 +548,21 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
        if (err < 0)
                goto err_unmap2;
 
-       err = snd_ad1848_create(card, mss_port[dev] + 4, xirq, xdma,
-                               AD1848_HW_DETECT, &chip);
+       err = snd_wss_create(card, mss_port[dev] + 4,  -1, xirq, xdma, -1,
+                            WSS_HW_DETECT, 0, &chip);
        if (err < 0)
                goto err_unmap2;
        card->private_data = chip;
 
-       err = snd_ad1848_pcm(chip, 0, NULL);
+       err = snd_wss_pcm(chip, 0, NULL);
        if (err < 0) {
                snd_printk(KERN_ERR PFX
-                          "error creating new ad1848 PCM device\n");
+                          "error creating new WSS PCM device\n");
                goto err_unmap2;
        }
-       err = snd_ad1848_mixer(chip);
+       err = snd_wss_mixer(chip);
        if (err < 0) {
-               snd_printk(KERN_ERR PFX "error creating new ad1848 mixer\n");
+               snd_printk(KERN_ERR PFX "error creating new WSS mixer\n");
                goto err_unmap2;
        }
        err = snd_sc6000_mixer(chip);
index a07274ecb1494b0b6948533edb15faac3e926dea..2c7503bf12714ade916d128576e7a2edc6c8300e 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/sb.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
 #include <sound/control.h>
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
@@ -175,12 +175,14 @@ static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
        return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
 }
 
-static struct ad1848_mix_elem snd_sgalaxy_controls[] = {
-AD1848_DOUBLE("Aux Playback Switch", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-AD1848_DOUBLE("Aux Playback Volume", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
+static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
+WSS_DOUBLE("Aux Playback Switch", 0,
+               SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 0,
+               SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
 };
 
-static int __devinit snd_sgalaxy_mixer(struct snd_ad1848 *chip)
+static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
 {
        struct snd_card *card = chip->card;
        struct snd_ctl_elem_id id1, id2;
@@ -210,7 +212,9 @@ static int __devinit snd_sgalaxy_mixer(struct snd_ad1848 *chip)
                return err;
        /* build AUX2 input */
        for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
-               if ((err = snd_ad1848_add_ctl_elem(chip, &snd_sgalaxy_controls[idx])) < 0)
+               err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
+               if (err < 0)
                        return err;
        }
        return 0;
@@ -237,7 +241,7 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
        static int possible_dmas[] = {1, 3, 0, -1};
        int err, xirq, xdma1;
        struct snd_card *card;
-       struct snd_ad1848 *chip;
+       struct snd_wss *chip;
 
        card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
        if (card == NULL)
@@ -263,18 +267,21 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
        if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
                goto _err;
 
-       if ((err = snd_ad1848_create(card, wssport[dev] + 4,
-                                    xirq, xdma1,
-                                    AD1848_HW_DETECT, &chip)) < 0)
+       err = snd_wss_create(card, wssport[dev] + 4, -1,
+                            xirq, xdma1, -1,
+                            WSS_HW_DETECT, 0, &chip);
+       if (err < 0)
                goto _err;
        card->private_data = chip;
 
-       if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) {
-               snd_printdd(PFX "error creating new ad1848 PCM device\n");
+       err = snd_wss_pcm(chip, 0, NULL);
+       if (err < 0) {
+               snd_printdd(PFX "error creating new WSS PCM device\n");
                goto _err;
        }
-       if ((err = snd_ad1848_mixer(chip)) < 0) {
-               snd_printdd(PFX "error creating new ad1848 mixer\n");
+       err = snd_wss_mixer(chip);
+       if (err < 0) {
+               snd_printdd(PFX "error creating new WSS mixer\n");
                goto _err;
        }
        if ((err = snd_sgalaxy_mixer(chip)) < 0) {
@@ -312,7 +319,7 @@ static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
                               pm_message_t state)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
-       struct snd_ad1848 *chip = card->private_data;
+       struct snd_wss *chip = card->private_data;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->suspend(chip);
@@ -322,11 +329,11 @@ static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
 static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
-       struct snd_ad1848 *chip = card->private_data;
+       struct snd_wss *chip = card->private_data;
 
        chip->resume(chip);
-       snd_ad1848_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
-       snd_ad1848_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
+       snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
+       snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
index 06ad7863dff577362c0af9dacafbc5fd6f964f8b..48a16d865834b023704eea64b0c27d062bc6dc94 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
@@ -147,7 +147,7 @@ struct soundscape {
        enum card_type type;
        struct resource *io_res;
        struct resource *wss_res;
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        struct snd_mpu401 *mpu;
        struct snd_hwdep *hw;
 
@@ -726,7 +726,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl,
 static int sscape_midi_get(struct snd_kcontrol *kctl,
                            struct snd_ctl_elem_value *uctl)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kctl);
+       struct snd_wss *chip = snd_kcontrol_chip(kctl);
        struct snd_card *card = chip->card;
        register struct soundscape *s = get_card_soundscape(card);
        unsigned long flags;
@@ -746,7 +746,7 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
 static int sscape_midi_put(struct snd_kcontrol *kctl,
                            struct snd_ctl_elem_value *uctl)
 {
-       struct snd_cs4231 *chip = snd_kcontrol_chip(kctl);
+       struct snd_wss *chip = snd_kcontrol_chip(kctl);
        struct snd_card *card = chip->card;
        register struct soundscape *s = get_card_soundscape(card);
        unsigned long flags;
@@ -958,7 +958,9 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
  * Override for the CS4231 playback format function.
  * The AD1845 has much simpler format and rate selection.
  */
-static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format)
+static void ad1845_playback_format(struct snd_wss *chip,
+                                  struct snd_pcm_hw_params *params,
+                                  unsigned char format)
 {
        unsigned long flags;
        unsigned rate = params_rate(params);
@@ -983,9 +985,9 @@ static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_p
         * NOTE: We seem to need to write to the MSB before the LSB
         *       to get the correct sample frequency.
         */
-       snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
-       snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-       snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
+       snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
+       snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
+       snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
 
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
@@ -994,7 +996,9 @@ static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_p
  * Override for the CS4231 capture format function. 
  * The AD1845 has much simpler format and rate selection.
  */
-static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format)
+static void ad1845_capture_format(struct snd_wss *chip,
+                                 struct snd_pcm_hw_params *params,
+                                 unsigned char format)
 {
        unsigned long flags;
        unsigned rate = params_rate(params);
@@ -1019,9 +1023,9 @@ static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_pa
         * NOTE: We seem to need to write to the MSB before the LSB
         *       to get the correct sample frequency.
         */
-       snd_cs4231_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
-       snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-       snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
+       snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
+       snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
+       snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
 
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
@@ -1036,7 +1040,7 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                                   int irq, int dma1, int dma2)
 {
        register struct soundscape *sscape = get_card_soundscape(card);
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        int err;
 
        if (sscape->type == SSCAPE_VIVO)
@@ -1045,9 +1049,8 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
        if (dma1 == dma2)
                dma2 = -1;
 
-       err = snd_cs4231_create(card,
-                               port, -1, irq, dma1, dma2,
-                               CS4231_HW_DETECT, CS4231_HWSHARE_DMA1, &chip);
+       err = snd_wss_create(card, port, -1, irq, dma1, dma2,
+                            WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
        if (!err) {
                unsigned long flags;
                struct snd_pcm *pcm;
@@ -1063,11 +1066,11 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
  *
 #define AD1845_IFACE_CONFIG  \
            (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
-    snd_cs4231_mce_up(chip);
+    snd_wss_mce_up(chip);
     spin_lock_irqsave(&chip->reg_lock, flags);
-    snd_cs4231_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
+    snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
     spin_unlock_irqrestore(&chip->reg_lock, flags);
-    snd_cs4231_mce_down(chip);
+    snd_wss_mce_down(chip);
  */
 
                if (sscape->type != SSCAPE_VIVO) {
@@ -1077,11 +1080,11 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                         * be 14.31818 MHz, because we must set this register
                         * to get the playback to sound correct ...
                         */
-                       snd_cs4231_mce_up(chip);
+                       snd_wss_mce_up(chip);
                        spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
+                       snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
                        spin_unlock_irqrestore(&chip->reg_lock, flags);
-                       snd_cs4231_mce_down(chip);
+                       snd_wss_mce_down(chip);
 
                        /*
                         * More custom configuration:
@@ -1089,28 +1092,28 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                         * b) enable frequency selection (for capture/playback)
                         */
                        spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_cs4231_out(chip, CS4231_MISC_INFO,
-                                       CS4231_MODE2 | 0x10);
-                       val = snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL);
-                       snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL,
-                                       val | AD1845_FREQ_SEL_ENABLE);
+                       snd_wss_out(chip, CS4231_MISC_INFO,
+                                   CS4231_MODE2 | 0x10);
+                       val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
+                       snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
+                                   val | AD1845_FREQ_SEL_ENABLE);
                        spin_unlock_irqrestore(&chip->reg_lock, flags);
                }
 
-               err = snd_cs4231_pcm(chip, 0, &pcm);
+               err = snd_wss_pcm(chip, 0, &pcm);
                if (err < 0) {
                        snd_printk(KERN_ERR "sscape: No PCM device "
                                            "for AD1845 chip\n");
                        goto _error;
                }
 
-               err = snd_cs4231_mixer(chip);
+               err = snd_wss_mixer(chip);
                if (err < 0) {
                        snd_printk(KERN_ERR "sscape: No mixer device "
                                            "for AD1845 chip\n");
                        goto _error;
                }
-               err = snd_cs4231_timer(chip, 0, NULL);
+               err = snd_wss_timer(chip, 0, NULL);
                if (err < 0) {
                        snd_printk(KERN_ERR "sscape: No timer device "
                                            "for AD1845 chip\n");
index 3a6c6fe1ec4d08bed3ff505e84e7a6a5aa8909c3..4c095bc7c7291165c91163293b2390ce14d60f46 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ALSA card-level driver for Turtle Beach Wavefront cards 
- *                                              (Maui,Tropez,Tropez+)
+ *                                             (Maui,Tropez,Tropez+)
  *
  *  Copyright (c) 1997-1999 by Paul Barton-Davis <pbd@op.net>
  *
@@ -29,6 +29,7 @@
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/opl3.h>
+#include <sound/wss.h>
 #include <sound/snd_wavefront.h>
 
 MODULE_AUTHOR("Paul Barton-Davis <pbd@op.net>");
@@ -319,8 +320,8 @@ snd_wavefront_new_midi (struct snd_card *card,
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_wavefront_midi_input);
 
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
-                            SNDRV_RAWMIDI_INFO_INPUT |
-                            SNDRV_RAWMIDI_INFO_DUPLEX;
+                            SNDRV_RAWMIDI_INFO_INPUT |
+                            SNDRV_RAWMIDI_INFO_DUPLEX;
 
        return rmidi;
 }
@@ -363,7 +364,7 @@ static int __devinit
 snd_wavefront_probe (struct snd_card *card, int dev)
 {
        snd_wavefront_card_t *acard = card->private_data;
-       struct snd_cs4231 *chip;
+       struct snd_wss *chip;
        struct snd_hwdep *wavefront_synth;
        struct snd_rawmidi *ics2115_internal_rmidi = NULL;
        struct snd_rawmidi *ics2115_external_rmidi = NULL;
@@ -372,21 +373,20 @@ snd_wavefront_probe (struct snd_card *card, int dev)
 
        /* --------- PCM --------------- */
 
-       if ((err = snd_cs4231_create (card,
-                                     cs4232_pcm_port[dev],
-                                     -1,
-                                     cs4232_pcm_irq[dev],
-                                     dma1[dev],
-                                     dma2[dev],
-                                     CS4231_HW_DETECT, 0, &chip)) < 0) {
-               snd_printk (KERN_ERR "can't allocate CS4231 device\n");
+       err = snd_wss_create(card, cs4232_pcm_port[dev], -1,
+                            cs4232_pcm_irq[dev], dma1[dev], dma2[dev],
+                            WSS_HW_DETECT, 0, &chip);
+       if (err < 0) {
+               snd_printk(KERN_ERR "can't allocate WSS device\n");
                return err;
        }
 
-       if ((err = snd_cs4231_pcm (chip, 0, NULL)) < 0)
+       err = snd_wss_pcm(chip, 0, NULL);
+       if (err < 0)
                return err;
 
-       if ((err = snd_cs4231_timer (chip, 0, NULL)) < 0)
+       err = snd_wss_timer(chip, 0, NULL);
+       if (err < 0)
                return err;
 
        /* ---------- OPL3 synth --------- */
@@ -394,24 +394,24 @@ snd_wavefront_probe (struct snd_card *card, int dev)
        if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
                struct snd_opl3 *opl3;
 
-               if ((err = snd_opl3_create(card,
-                                          fm_port[dev],
-                                          fm_port[dev] + 2,
-                                          OPL3_HW_OPL3_CS,
-                                          0, &opl3)) < 0) {
+               err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
+                                     OPL3_HW_OPL3_CS, 0, &opl3);
+               if (err < 0) {
                        snd_printk (KERN_ERR "can't allocate or detect OPL3 synth\n");
                        return err;
                }
 
-               if ((err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL)) < 0)
+               err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL);
+               if (err < 0)
                        return err;
                hw_dev++;
        }
 
        /* ------- ICS2115 Wavetable synth ------- */
 
-       if ((acard->wavefront.res_base = request_region(ics2115_port[dev], 16,
-                                                       "ICS2115")) == NULL) {
+       acard->wavefront.res_base = request_region(ics2115_port[dev], 16,
+                                                  "ICS2115");
+       if (acard->wavefront.res_base == NULL) {
                snd_printk(KERN_ERR "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n",
                           ics2115_port[dev], ics2115_port[dev] + 16 - 1);
                return -EBUSY;
@@ -425,7 +425,8 @@ snd_wavefront_probe (struct snd_card *card, int dev)
        acard->wavefront.irq = ics2115_irq[dev];
        acard->wavefront.base = ics2115_port[dev];
 
-       if ((wavefront_synth = snd_wavefront_new_synth (card, hw_dev, acard)) == NULL) {
+       wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard);
+       if (wavefront_synth == NULL) {
                snd_printk (KERN_ERR "can't create WaveFront synth device\n");
                return -ENOMEM;
        }
@@ -436,7 +437,8 @@ snd_wavefront_probe (struct snd_card *card, int dev)
 
        /* --------- Mixer ------------ */
 
-       if ((err = snd_cs4231_mixer(chip)) < 0) {
+       err = snd_wss_mixer(chip);
+       if (err < 0) {
                snd_printk (KERN_ERR "can't allocate mixer device\n");
                return err;
        }
@@ -444,11 +446,11 @@ snd_wavefront_probe (struct snd_card *card, int dev)
        /* -------- CS4232 MPU-401 interface -------- */
 
        if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) {
-               if ((err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
-                                              cs4232_mpu_port[dev], 0,
-                                              cs4232_mpu_irq[dev],
-                                              IRQF_DISABLED,
-                                              NULL)) < 0) {
+               err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
+                                         cs4232_mpu_port[dev], 0,
+                                         cs4232_mpu_irq[dev], IRQF_DISABLED,
+                                         NULL);
+               if (err < 0) {
                        snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n");
                        return err;
                }
@@ -601,7 +603,7 @@ static struct isa_driver snd_wavefront_driver = {
 
 #ifdef CONFIG_PNP
 static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
-                                              const struct pnp_card_device_id *pid)
+                                       const struct pnp_card_device_id *pid)
 {
        static int dev;
        struct snd_card *card;
index 2efaa7f205aa617f56c64db3e26f3e279db25246..dfc449a2194e9795cb07cec10edf84af66b529ac 100644 (file)
@@ -180,11 +180,11 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
        unsigned short *pd;
        int err = 0;
 
-       snd_assert(sdev->card != NULL, return -ENODEV);
-       
        card = sdev->card;
-
-       snd_assert(card->private_data != NULL, return -ENODEV);
+       if (snd_BUG_ON(!card))
+               return -ENODEV;
+       if (snd_BUG_ON(!card->private_data))
+               return -ENODEV;
 
        acard = card->private_data;
        dev = &acard->wavefront;
index a33384a55b0f6576d1a71320d8f68b33a1c622c4..f14a7c0b69981ea607236b756588f0919bd3e4fe 100644 (file)
@@ -235,8 +235,10 @@ static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream
        snd_wavefront_midi_t *midi;
        snd_wavefront_mpu_id mpu;
 
-       snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-       snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+       if (snd_BUG_ON(!substream || !substream->rmidi))
+               return -ENXIO;
+       if (snd_BUG_ON(!substream->rmidi->private_data))
+               return -ENXIO;
 
        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
@@ -257,8 +259,10 @@ static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substrea
        snd_wavefront_midi_t *midi;
        snd_wavefront_mpu_id mpu;
 
-       snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-       snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+       if (snd_BUG_ON(!substream || !substream->rmidi))
+               return -ENXIO;
+       if (snd_BUG_ON(!substream->rmidi->private_data))
+               return -ENXIO;
 
        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
@@ -279,8 +283,10 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea
        snd_wavefront_midi_t *midi;
        snd_wavefront_mpu_id mpu;
 
-       snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-       snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+       if (snd_BUG_ON(!substream || !substream->rmidi))
+               return -ENXIO;
+       if (snd_BUG_ON(!substream->rmidi->private_data))
+               return -ENXIO;
 
        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
@@ -300,8 +306,10 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre
        snd_wavefront_midi_t *midi;
        snd_wavefront_mpu_id mpu;
 
-       snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
-       snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+       if (snd_BUG_ON(!substream || !substream->rmidi))
+               return -ENXIO;
+       if (snd_BUG_ON(!substream->rmidi->private_data))
+               return -ENXIO;
 
        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 
index 0bb9b92566010875f148106c8423bf04a5b3cff8..4c410820a994affcdc5f3ed448b8ad4e96343e06 100644 (file)
@@ -1648,9 +1648,10 @@ snd_wavefront_synth_ioctl (struct snd_hwdep *hw, struct file *file,
 
        card = (struct snd_card *) hw->card;
 
-       snd_assert(card != NULL, return -ENODEV);
-
-       snd_assert(card->private_data != NULL, return -ENODEV);
+       if (snd_BUG_ON(!card))
+               return -ENODEV;
+       if (snd_BUG_ON(!card->private_data))
+               return -ENODEV;
 
        acard = card->private_data;
        dev = &acard->wavefront;
diff --git a/sound/isa/wss/Makefile b/sound/isa/wss/Makefile
new file mode 100644 (file)
index 0000000..454fee7
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2008 by Jaroslav Kysela <perex@perex.cz>
+#
+
+snd-wss-lib-objs := wss_lib.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_WSS_LIB) += snd-wss-lib.o
+
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
new file mode 100644 (file)
index 0000000..3d6c5f2
--- /dev/null
@@ -0,0 +1,2322 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
+ *
+ *  Bugs:
+ *     - sometimes record brokes playback with WSS portion of
+ *       Yamaha OPL3-SA3 chip
+ *     - CS4231 (GUS MAX) - still trouble with occasional noises
+ *                       - broken initialization?
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
+MODULE_LICENSE("GPL");
+
+#if 0
+#define SNDRV_DEBUG_MCE
+#endif
+
+/*
+ *  Some variables
+ */
+
+static unsigned char freq_bits[14] = {
+       /* 5510 */      0x00 | CS4231_XTAL2,
+       /* 6620 */      0x0E | CS4231_XTAL2,
+       /* 8000 */      0x00 | CS4231_XTAL1,
+       /* 9600 */      0x0E | CS4231_XTAL1,
+       /* 11025 */     0x02 | CS4231_XTAL2,
+       /* 16000 */     0x02 | CS4231_XTAL1,
+       /* 18900 */     0x04 | CS4231_XTAL2,
+       /* 22050 */     0x06 | CS4231_XTAL2,
+       /* 27042 */     0x04 | CS4231_XTAL1,
+       /* 32000 */     0x06 | CS4231_XTAL1,
+       /* 33075 */     0x0C | CS4231_XTAL2,
+       /* 37800 */     0x08 | CS4231_XTAL2,
+       /* 44100 */     0x0A | CS4231_XTAL2,
+       /* 48000 */     0x0C | CS4231_XTAL1
+};
+
+static unsigned int rates[14] = {
+       5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
+       27042, 32000, 33075, 37800, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static int snd_wss_xrate(struct snd_pcm_runtime *runtime)
+{
+       return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                         &hw_constraints_rates);
+}
+
+static unsigned char snd_wss_original_image[32] =
+{
+       0x00,                   /* 00/00 - lic */
+       0x00,                   /* 01/01 - ric */
+       0x9f,                   /* 02/02 - la1ic */
+       0x9f,                   /* 03/03 - ra1ic */
+       0x9f,                   /* 04/04 - la2ic */
+       0x9f,                   /* 05/05 - ra2ic */
+       0xbf,                   /* 06/06 - loc */
+       0xbf,                   /* 07/07 - roc */
+       0x20,                   /* 08/08 - pdfr */
+       CS4231_AUTOCALIB,       /* 09/09 - ic */
+       0x00,                   /* 0a/10 - pc */
+       0x00,                   /* 0b/11 - ti */
+       CS4231_MODE2,           /* 0c/12 - mi */
+       0xfc,                   /* 0d/13 - lbc */
+       0x00,                   /* 0e/14 - pbru */
+       0x00,                   /* 0f/15 - pbrl */
+       0x80,                   /* 10/16 - afei */
+       0x01,                   /* 11/17 - afeii */
+       0x9f,                   /* 12/18 - llic */
+       0x9f,                   /* 13/19 - rlic */
+       0x00,                   /* 14/20 - tlb */
+       0x00,                   /* 15/21 - thb */
+       0x00,                   /* 16/22 - la3mic/reserved */
+       0x00,                   /* 17/23 - ra3mic/reserved */
+       0x00,                   /* 18/24 - afs */
+       0x00,                   /* 19/25 - lamoc/version */
+       0xcf,                   /* 1a/26 - mioc */
+       0x00,                   /* 1b/27 - ramoc/reserved */
+       0x20,                   /* 1c/28 - cdfr */
+       0x00,                   /* 1d/29 - res4 */
+       0x00,                   /* 1e/30 - cbru */
+       0x00,                   /* 1f/31 - cbrl */
+};
+
+static unsigned char snd_opti93x_original_image[32] =
+{
+       0x00,           /* 00/00 - l_mixout_outctrl */
+       0x00,           /* 01/01 - r_mixout_outctrl */
+       0x88,           /* 02/02 - l_cd_inctrl */
+       0x88,           /* 03/03 - r_cd_inctrl */
+       0x88,           /* 04/04 - l_a1/fm_inctrl */
+       0x88,           /* 05/05 - r_a1/fm_inctrl */
+       0x80,           /* 06/06 - l_dac_inctrl */
+       0x80,           /* 07/07 - r_dac_inctrl */
+       0x00,           /* 08/08 - ply_dataform_reg */
+       0x00,           /* 09/09 - if_conf */
+       0x00,           /* 0a/10 - pin_ctrl */
+       0x00,           /* 0b/11 - err_init_reg */
+       0x0a,           /* 0c/12 - id_reg */
+       0x00,           /* 0d/13 - reserved */
+       0x00,           /* 0e/14 - ply_upcount_reg */
+       0x00,           /* 0f/15 - ply_lowcount_reg */
+       0x88,           /* 10/16 - reserved/l_a1_inctrl */
+       0x88,           /* 11/17 - reserved/r_a1_inctrl */
+       0x88,           /* 12/18 - l_line_inctrl */
+       0x88,           /* 13/19 - r_line_inctrl */
+       0x88,           /* 14/20 - l_mic_inctrl */
+       0x88,           /* 15/21 - r_mic_inctrl */
+       0x80,           /* 16/22 - l_out_outctrl */
+       0x80,           /* 17/23 - r_out_outctrl */
+       0x00,           /* 18/24 - reserved */
+       0x00,           /* 19/25 - reserved */
+       0x00,           /* 1a/26 - reserved */
+       0x00,           /* 1b/27 - reserved */
+       0x00,           /* 1c/28 - cap_dataform_reg */
+       0x00,           /* 1d/29 - reserved */
+       0x00,           /* 1e/30 - cap_upcount_reg */
+       0x00            /* 1f/31 - cap_lowcount_reg */
+};
+
+/*
+ *  Basic I/O functions
+ */
+
+static inline void wss_outb(struct snd_wss *chip, u8 offset, u8 val)
+{
+       outb(val, chip->port + offset);
+}
+
+static inline u8 wss_inb(struct snd_wss *chip, u8 offset)
+{
+       return inb(chip->port + offset);
+}
+
+static void snd_wss_wait(struct snd_wss *chip)
+{
+       int timeout;
+
+       for (timeout = 250;
+            timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+            timeout--)
+               udelay(100);
+}
+
+static void snd_wss_outm(struct snd_wss *chip, unsigned char reg,
+                           unsigned char mask, unsigned char value)
+{
+       unsigned char tmp = (chip->image[reg] & mask) | value;
+
+       snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+               snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+       chip->image[reg] = tmp;
+       if (!chip->calibrate_mute) {
+               wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+               wmb();
+               wss_outb(chip, CS4231P(REG), tmp);
+               mb();
+       }
+}
+
+static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
+                        unsigned char value)
+{
+       int timeout;
+
+       for (timeout = 250;
+            timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+            timeout--)
+               udelay(10);
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+       wss_outb(chip, CS4231P(REG), value);
+       mb();
+}
+
+void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
+{
+       snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+               snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+       wss_outb(chip, CS4231P(REG), value);
+       chip->image[reg] = value;
+       mb();
+       snd_printdd("codec out - reg 0x%x = 0x%x\n",
+                       chip->mce_bit | reg, value);
+}
+EXPORT_SYMBOL(snd_wss_out);
+
+unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
+{
+       snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+               snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+#endif
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+       mb();
+       return wss_inb(chip, CS4231P(REG));
+}
+EXPORT_SYMBOL(snd_wss_in);
+
+void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
+                       unsigned char val)
+{
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+       wss_outb(chip, CS4231P(REG),
+                reg | (chip->image[CS4236_EXT_REG] & 0x01));
+       wss_outb(chip, CS4231P(REG), val);
+       chip->eimage[CS4236_REG(reg)] = val;
+#if 0
+       printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+#endif
+}
+EXPORT_SYMBOL(snd_cs4236_ext_out);
+
+unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
+{
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+       wss_outb(chip, CS4231P(REG),
+                reg | (chip->image[CS4236_EXT_REG] & 0x01));
+#if 1
+       return wss_inb(chip, CS4231P(REG));
+#else
+       {
+               unsigned char res;
+               res = wss_inb(chip, CS4231P(REG));
+               printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
+               return res;
+       }
+#endif
+}
+EXPORT_SYMBOL(snd_cs4236_ext_in);
+
+#if 0
+
+static void snd_wss_debug(struct snd_wss *chip)
+{
+       printk(KERN_DEBUG
+               "CS4231 REGS:      INDEX = 0x%02x  "
+               "                 STATUS = 0x%02x\n",
+                                       wss_inb(chip, CS4231P(REGSEL)),
+                                       wss_inb(chip, CS4231P(STATUS)));
+       printk(KERN_DEBUG
+               "  0x00: left input      = 0x%02x  "
+               "  0x10: alt 1 (CFIG 2)  = 0x%02x\n",
+                                       snd_wss_in(chip, 0x00),
+                                       snd_wss_in(chip, 0x10));
+       printk(KERN_DEBUG
+               "  0x01: right input     = 0x%02x  "
+               "  0x11: alt 2 (CFIG 3)  = 0x%02x\n",
+                                       snd_wss_in(chip, 0x01),
+                                       snd_wss_in(chip, 0x11));
+       printk(KERN_DEBUG
+               "  0x02: GF1 left input  = 0x%02x  "
+               "  0x12: left line in    = 0x%02x\n",
+                                       snd_wss_in(chip, 0x02),
+                                       snd_wss_in(chip, 0x12));
+       printk(KERN_DEBUG
+               "  0x03: GF1 right input = 0x%02x  "
+               "  0x13: right line in   = 0x%02x\n",
+                                       snd_wss_in(chip, 0x03),
+                                       snd_wss_in(chip, 0x13));
+       printk(KERN_DEBUG
+               "  0x04: CD left input   = 0x%02x  "
+               "  0x14: timer low       = 0x%02x\n",
+                                       snd_wss_in(chip, 0x04),
+                                       snd_wss_in(chip, 0x14));
+       printk(KERN_DEBUG
+               "  0x05: CD right input  = 0x%02x  "
+               "  0x15: timer high      = 0x%02x\n",
+                                       snd_wss_in(chip, 0x05),
+                                       snd_wss_in(chip, 0x15));
+       printk(KERN_DEBUG
+               "  0x06: left output     = 0x%02x  "
+               "  0x16: left MIC (PnP)  = 0x%02x\n",
+                                       snd_wss_in(chip, 0x06),
+                                       snd_wss_in(chip, 0x16));
+       printk(KERN_DEBUG
+               "  0x07: right output    = 0x%02x  "
+               "  0x17: right MIC (PnP) = 0x%02x\n",
+                                       snd_wss_in(chip, 0x07),
+                                       snd_wss_in(chip, 0x17));
+       printk(KERN_DEBUG
+               "  0x08: playback format = 0x%02x  "
+               "  0x18: IRQ status      = 0x%02x\n",
+                                       snd_wss_in(chip, 0x08),
+                                       snd_wss_in(chip, 0x18));
+       printk(KERN_DEBUG
+               "  0x09: iface (CFIG 1)  = 0x%02x  "
+               "  0x19: left line out   = 0x%02x\n",
+                                       snd_wss_in(chip, 0x09),
+                                       snd_wss_in(chip, 0x19));
+       printk(KERN_DEBUG
+               "  0x0a: pin control     = 0x%02x  "
+               "  0x1a: mono control    = 0x%02x\n",
+                                       snd_wss_in(chip, 0x0a),
+                                       snd_wss_in(chip, 0x1a));
+       printk(KERN_DEBUG
+               "  0x0b: init & status   = 0x%02x  "
+               "  0x1b: right line out  = 0x%02x\n",
+                                       snd_wss_in(chip, 0x0b),
+                                       snd_wss_in(chip, 0x1b));
+       printk(KERN_DEBUG
+               "  0x0c: revision & mode = 0x%02x  "
+               "  0x1c: record format   = 0x%02x\n",
+                                       snd_wss_in(chip, 0x0c),
+                                       snd_wss_in(chip, 0x1c));
+       printk(KERN_DEBUG
+               "  0x0d: loopback        = 0x%02x  "
+               "  0x1d: var freq (PnP)  = 0x%02x\n",
+                                       snd_wss_in(chip, 0x0d),
+                                       snd_wss_in(chip, 0x1d));
+       printk(KERN_DEBUG
+               "  0x0e: ply upr count   = 0x%02x  "
+               "  0x1e: ply lwr count   = 0x%02x\n",
+                                       snd_wss_in(chip, 0x0e),
+                                       snd_wss_in(chip, 0x1e));
+       printk(KERN_DEBUG
+               "  0x0f: rec upr count   = 0x%02x  "
+               "  0x1f: rec lwr count   = 0x%02x\n",
+                                       snd_wss_in(chip, 0x0f),
+                                       snd_wss_in(chip, 0x1f));
+}
+
+#endif
+
+/*
+ *  CS4231 detection / MCE routines
+ */
+
+static void snd_wss_busy_wait(struct snd_wss *chip)
+{
+       int timeout;
+
+       /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
+       for (timeout = 5; timeout > 0; timeout--)
+               wss_inb(chip, CS4231P(REGSEL));
+       /* end of cleanup sequence */
+       for (timeout = 25000;
+            timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+            timeout--)
+               udelay(10);
+}
+
+void snd_wss_mce_up(struct snd_wss *chip)
+{
+       unsigned long flags;
+       int timeout;
+
+       snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+               snd_printk("mce_up - auto calibration time out (0)\n");
+#endif
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->mce_bit |= CS4231_MCE;
+       timeout = wss_inb(chip, CS4231P(REGSEL));
+       if (timeout == 0x80)
+               snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
+       if (!(timeout & CS4231_MCE))
+               wss_outb(chip, CS4231P(REGSEL),
+                        chip->mce_bit | (timeout & 0x1f));
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+EXPORT_SYMBOL(snd_wss_mce_up);
+
+void snd_wss_mce_down(struct snd_wss *chip)
+{
+       unsigned long flags;
+       unsigned long end_time;
+       int timeout;
+       int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848;
+
+       snd_wss_busy_wait(chip);
+
+#ifdef CONFIG_SND_DEBUG
+       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+               snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
+#endif
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->mce_bit &= ~CS4231_MCE;
+       timeout = wss_inb(chip, CS4231P(REGSEL));
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       if (timeout == 0x80)
+               snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+       if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
+               return;
+
+       /*
+        * Wait for (possible -- during init auto-calibration may not be set)
+        * calibration process to start. Needs upto 5 sample periods on AD1848
+        * which at the slowest possible rate of 5.5125 kHz means 907 us.
+        */
+       msleep(1);
+
+       snd_printdd("(1) jiffies = %lu\n", jiffies);
+
+       /* check condition up to 250 ms */
+       end_time = jiffies + msecs_to_jiffies(250);
+       while (snd_wss_in(chip, CS4231_TEST_INIT) &
+               CS4231_CALIB_IN_PROGRESS) {
+
+               if (time_after(jiffies, end_time)) {
+                       snd_printk(KERN_ERR "mce_down - "
+                                       "auto calibration time out (2)\n");
+                       return;
+               }
+               msleep(1);
+       }
+
+       snd_printdd("(2) jiffies = %lu\n", jiffies);
+
+       /* check condition up to 100 ms */
+       end_time = jiffies + msecs_to_jiffies(100);
+       while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+               if (time_after(jiffies, end_time)) {
+                       snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
+                       return;
+               }
+               msleep(1);
+       }
+
+       snd_printdd("(3) jiffies = %lu\n", jiffies);
+       snd_printd("mce_down - exit = 0x%x\n", wss_inb(chip, CS4231P(REGSEL)));
+}
+EXPORT_SYMBOL(snd_wss_mce_down);
+
+static unsigned int snd_wss_get_count(unsigned char format, unsigned int size)
+{
+       switch (format & 0xe0) {
+       case CS4231_LINEAR_16:
+       case CS4231_LINEAR_16_BIG:
+               size >>= 1;
+               break;
+       case CS4231_ADPCM_16:
+               return size >> 2;
+       }
+       if (format & CS4231_STEREO)
+               size >>= 1;
+       return size;
+}
+
+static int snd_wss_trigger(struct snd_pcm_substream *substream,
+                          int cmd)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       int result = 0;
+       unsigned int what;
+       struct snd_pcm_substream *s;
+       int do_start;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               do_start = 1; break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               do_start = 0; break;
+       default:
+               return -EINVAL;
+       }
+
+       what = 0;
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s == chip->playback_substream) {
+                       what |= CS4231_PLAYBACK_ENABLE;
+                       snd_pcm_trigger_done(s, substream);
+               } else if (s == chip->capture_substream) {
+                       what |= CS4231_RECORD_ENABLE;
+                       snd_pcm_trigger_done(s, substream);
+               }
+       }
+       spin_lock(&chip->reg_lock);
+       if (do_start) {
+               chip->image[CS4231_IFACE_CTRL] |= what;
+               if (chip->trigger)
+                       chip->trigger(chip, what, 1);
+       } else {
+               chip->image[CS4231_IFACE_CTRL] &= ~what;
+               if (chip->trigger)
+                       chip->trigger(chip, what, 0);
+       }
+       snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+       spin_unlock(&chip->reg_lock);
+#if 0
+       snd_wss_debug(chip);
+#endif
+       return result;
+}
+
+/*
+ *  CODEC I/O
+ */
+
+static unsigned char snd_wss_get_rate(unsigned int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rates); i++)
+               if (rate == rates[i])
+                       return freq_bits[i];
+       // snd_BUG();
+       return freq_bits[ARRAY_SIZE(rates) - 1];
+}
+
+static unsigned char snd_wss_get_format(struct snd_wss *chip,
+                                       int format,
+                                       int channels)
+{
+       unsigned char rformat;
+
+       rformat = CS4231_LINEAR_8;
+       switch (format) {
+       case SNDRV_PCM_FORMAT_MU_LAW:   rformat = CS4231_ULAW_8; break;
+       case SNDRV_PCM_FORMAT_A_LAW:    rformat = CS4231_ALAW_8; break;
+       case SNDRV_PCM_FORMAT_S16_LE:   rformat = CS4231_LINEAR_16; break;
+       case SNDRV_PCM_FORMAT_S16_BE:   rformat = CS4231_LINEAR_16_BIG; break;
+       case SNDRV_PCM_FORMAT_IMA_ADPCM:        rformat = CS4231_ADPCM_16; break;
+       }
+       if (channels > 1)
+               rformat |= CS4231_STEREO;
+#if 0
+       snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
+#endif
+       return rformat;
+}
+
+static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
+{
+       unsigned long flags;
+
+       mute = mute ? 0x80 : 0;
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (chip->calibrate_mute == mute) {
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               return;
+       }
+       if (!mute) {
+               snd_wss_dout(chip, CS4231_LEFT_INPUT,
+                            chip->image[CS4231_LEFT_INPUT]);
+               snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+                            chip->image[CS4231_RIGHT_INPUT]);
+               snd_wss_dout(chip, CS4231_LOOPBACK,
+                            chip->image[CS4231_LOOPBACK]);
+       }
+       snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
+                    mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
+       snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
+                    mute | chip->image[CS4231_AUX1_RIGHT_INPUT]);
+       snd_wss_dout(chip, CS4231_AUX2_LEFT_INPUT,
+                    mute | chip->image[CS4231_AUX2_LEFT_INPUT]);
+       snd_wss_dout(chip, CS4231_AUX2_RIGHT_INPUT,
+                    mute | chip->image[CS4231_AUX2_RIGHT_INPUT]);
+       snd_wss_dout(chip, CS4231_LEFT_OUTPUT,
+                    mute | chip->image[CS4231_LEFT_OUTPUT]);
+       snd_wss_dout(chip, CS4231_RIGHT_OUTPUT,
+                    mute | chip->image[CS4231_RIGHT_OUTPUT]);
+       if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+               snd_wss_dout(chip, CS4231_LEFT_LINE_IN,
+                            mute | chip->image[CS4231_LEFT_LINE_IN]);
+               snd_wss_dout(chip, CS4231_RIGHT_LINE_IN,
+                            mute | chip->image[CS4231_RIGHT_LINE_IN]);
+               snd_wss_dout(chip, CS4231_MONO_CTRL,
+                            mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
+       }
+       if (chip->hardware == WSS_HW_INTERWAVE) {
+               snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT,
+                            mute | chip->image[CS4231_LEFT_MIC_INPUT]);
+               snd_wss_dout(chip, CS4231_RIGHT_MIC_INPUT,
+                            mute | chip->image[CS4231_RIGHT_MIC_INPUT]);
+               snd_wss_dout(chip, CS4231_LINE_LEFT_OUTPUT,
+                            mute | chip->image[CS4231_LINE_LEFT_OUTPUT]);
+               snd_wss_dout(chip, CS4231_LINE_RIGHT_OUTPUT,
+                            mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]);
+       }
+       chip->calibrate_mute = mute;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+
+static void snd_wss_playback_format(struct snd_wss *chip,
+                                      struct snd_pcm_hw_params *params,
+                                      unsigned char pdfr)
+{
+       unsigned long flags;
+       int full_calib = 1;
+
+       mutex_lock(&chip->mce_mutex);
+       snd_wss_calibrate_mute(chip, 1);
+       if (chip->hardware == WSS_HW_CS4231A ||
+           (chip->hardware & WSS_HW_CS4232_MASK)) {
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) {      /* rate is same? */
+                       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                                   chip->image[CS4231_ALT_FEATURE_1] | 0x10);
+                       chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+                       snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+                                   chip->image[CS4231_PLAYBK_FORMAT]);
+                       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                                   chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
+                       udelay(100); /* Fixes audible clicks at least on GUS MAX */
+                       full_calib = 0;
+               }
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+       }
+       if (full_calib) {
+               snd_wss_mce_up(chip);
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) {
+                       if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)
+                               pdfr = (pdfr & 0xf0) |
+                                      (chip->image[CS4231_REC_FORMAT] & 0x0f);
+               } else {
+                       chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+               }
+               snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr);
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               if (chip->hardware == WSS_HW_OPL3SA2)
+                       udelay(100);    /* this seems to help */
+               snd_wss_mce_down(chip);
+       }
+       snd_wss_calibrate_mute(chip, 0);
+       mutex_unlock(&chip->mce_mutex);
+}
+
+static void snd_wss_capture_format(struct snd_wss *chip,
+                                  struct snd_pcm_hw_params *params,
+                                  unsigned char cdfr)
+{
+       unsigned long flags;
+       int full_calib = 1;
+
+       mutex_lock(&chip->mce_mutex);
+       snd_wss_calibrate_mute(chip, 1);
+       if (chip->hardware == WSS_HW_CS4231A ||
+           (chip->hardware & WSS_HW_CS4232_MASK)) {
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) ||      /* rate is same? */
+                   (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+                       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                               chip->image[CS4231_ALT_FEATURE_1] | 0x20);
+                       snd_wss_out(chip, CS4231_REC_FORMAT,
+                               chip->image[CS4231_REC_FORMAT] = cdfr);
+                       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                               chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
+                       full_calib = 0;
+               }
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+       }
+       if (full_calib) {
+               snd_wss_mce_up(chip);
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               if (chip->hardware != WSS_HW_INTERWAVE &&
+                   !(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+                       if (chip->single_dma)
+                               snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+                       else
+                               snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+                                  (chip->image[CS4231_PLAYBK_FORMAT] & 0xf0) |
+                                  (cdfr & 0x0f));
+                       spin_unlock_irqrestore(&chip->reg_lock, flags);
+                       snd_wss_mce_down(chip);
+                       snd_wss_mce_up(chip);
+                       spin_lock_irqsave(&chip->reg_lock, flags);
+               }
+               if (chip->hardware & WSS_HW_AD1848_MASK)
+                       snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+               else
+                       snd_wss_out(chip, CS4231_REC_FORMAT, cdfr);
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               snd_wss_mce_down(chip);
+       }
+       snd_wss_calibrate_mute(chip, 0);
+       mutex_unlock(&chip->mce_mutex);
+}
+
+/*
+ *  Timer interface
+ */
+
+static unsigned long snd_wss_timer_resolution(struct snd_timer *timer)
+{
+       struct snd_wss *chip = snd_timer_chip(timer);
+       if (chip->hardware & WSS_HW_CS4236B_MASK)
+               return 14467;
+       else
+               return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
+}
+
+static int snd_wss_timer_start(struct snd_timer *timer)
+{
+       unsigned long flags;
+       unsigned int ticks;
+       struct snd_wss *chip = snd_timer_chip(timer);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       ticks = timer->sticks;
+       if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
+           (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
+           (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
+               chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8);
+               snd_wss_out(chip, CS4231_TIMER_HIGH,
+                           chip->image[CS4231_TIMER_HIGH]);
+               chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks;
+               snd_wss_out(chip, CS4231_TIMER_LOW,
+                           chip->image[CS4231_TIMER_LOW]);
+               snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                           chip->image[CS4231_ALT_FEATURE_1] |
+                           CS4231_TIMER_ENABLE);
+       }
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return 0;
+}
+
+static int snd_wss_timer_stop(struct snd_timer *timer)
+{
+       unsigned long flags;
+       struct snd_wss *chip = snd_timer_chip(timer);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE;
+       snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+                   chip->image[CS4231_ALT_FEATURE_1]);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return 0;
+}
+
+static void snd_wss_init(struct snd_wss *chip)
+{
+       unsigned long flags;
+
+       snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+       snd_printk("init: (1)\n");
+#endif
+       snd_wss_mce_up(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
+                                           CS4231_PLAYBACK_PIO |
+                                           CS4231_RECORD_ENABLE |
+                                           CS4231_RECORD_PIO |
+                                           CS4231_CALIB_MODE);
+       chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
+       snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+       snd_printk("init: (2)\n");
+#endif
+
+       snd_wss_mce_up(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       snd_wss_out(chip,
+                   CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+       snd_printk("init: (3) - afei = 0x%x\n",
+                  chip->image[CS4231_ALT_FEATURE_1]);
+#endif
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       snd_wss_out(chip, CS4231_ALT_FEATURE_2,
+                   chip->image[CS4231_ALT_FEATURE_2]);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       snd_wss_mce_up(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+                   chip->image[CS4231_PLAYBK_FORMAT]);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+       snd_printk("init: (4)\n");
+#endif
+
+       snd_wss_mce_up(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (!(chip->hardware & WSS_HW_AD1848_MASK))
+               snd_wss_out(chip, CS4231_REC_FORMAT,
+                           chip->image[CS4231_REC_FORMAT]);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+       snd_printk("init: (5)\n");
+#endif
+}
+
+static int snd_wss_open(struct snd_wss *chip, unsigned int mode)
+{
+       unsigned long flags;
+
+       mutex_lock(&chip->open_mutex);
+       if ((chip->mode & mode) ||
+           ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) {
+               mutex_unlock(&chip->open_mutex);
+               return -EAGAIN;
+       }
+       if (chip->mode & WSS_MODE_OPEN) {
+               chip->mode |= mode;
+               mutex_unlock(&chip->open_mutex);
+               return 0;
+       }
+       /* ok. now enable and ack CODEC IRQ */
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+               snd_wss_out(chip, CS4231_IRQ_STATUS,
+                           CS4231_PLAYBACK_IRQ |
+                           CS4231_RECORD_IRQ |
+                           CS4231_TIMER_IRQ);
+               snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+       }
+       wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
+       wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
+       chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
+       snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
+       if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+               snd_wss_out(chip, CS4231_IRQ_STATUS,
+                           CS4231_PLAYBACK_IRQ |
+                           CS4231_RECORD_IRQ |
+                           CS4231_TIMER_IRQ);
+               snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+       }
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       chip->mode = mode;
+       mutex_unlock(&chip->open_mutex);
+       return 0;
+}
+
+static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
+{
+       unsigned long flags;
+
+       mutex_lock(&chip->open_mutex);
+       chip->mode &= ~mode;
+       if (chip->mode & WSS_MODE_OPEN) {
+               mutex_unlock(&chip->open_mutex);
+               return;
+       }
+       snd_wss_calibrate_mute(chip, 1);
+
+       /* disable IRQ */
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (!(chip->hardware & WSS_HW_AD1848_MASK))
+               snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+       wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
+       wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
+       chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
+       snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
+
+       /* now disable record & playback */
+
+       if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+                                              CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               snd_wss_mce_up(chip);
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+                                                    CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+               snd_wss_out(chip, CS4231_IFACE_CTRL,
+                           chip->image[CS4231_IFACE_CTRL]);
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               snd_wss_mce_down(chip);
+               spin_lock_irqsave(&chip->reg_lock, flags);
+       }
+
+       /* clear IRQ again */
+       if (!(chip->hardware & WSS_HW_AD1848_MASK))
+               snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+       wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
+       wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       snd_wss_calibrate_mute(chip, 0);
+
+       chip->mode = 0;
+       mutex_unlock(&chip->open_mutex);
+}
+
+/*
+ *  timer open/close
+ */
+
+static int snd_wss_timer_open(struct snd_timer *timer)
+{
+       struct snd_wss *chip = snd_timer_chip(timer);
+       snd_wss_open(chip, WSS_MODE_TIMER);
+       return 0;
+}
+
+static int snd_wss_timer_close(struct snd_timer *timer)
+{
+       struct snd_wss *chip = snd_timer_chip(timer);
+       snd_wss_close(chip, WSS_MODE_TIMER);
+       return 0;
+}
+
+static struct snd_timer_hardware snd_wss_timer_table =
+{
+       .flags =        SNDRV_TIMER_HW_AUTO,
+       .resolution =   9945,
+       .ticks =        65535,
+       .open =         snd_wss_timer_open,
+       .close =        snd_wss_timer_close,
+       .c_resolution = snd_wss_timer_resolution,
+       .start =        snd_wss_timer_start,
+       .stop =         snd_wss_timer_stop,
+};
+
+/*
+ *  ok.. exported functions..
+ */
+
+static int snd_wss_playback_hw_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       unsigned char new_pdfr;
+       int err;
+
+       if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+               return err;
+       new_pdfr = snd_wss_get_format(chip, params_format(hw_params),
+                               params_channels(hw_params)) |
+                               snd_wss_get_rate(params_rate(hw_params));
+       chip->set_playback_format(chip, hw_params, new_pdfr);
+       return 0;
+}
+
+static int snd_wss_playback_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_wss_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long flags;
+       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+       unsigned int count = snd_pcm_lib_period_bytes(substream);
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->p_dma_size = size;
+       chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
+       snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
+       count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
+       snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
+       snd_wss_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+#if 0
+       snd_wss_debug(chip);
+#endif
+       return 0;
+}
+
+static int snd_wss_capture_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       unsigned char new_cdfr;
+       int err;
+
+       if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+               return err;
+       new_cdfr = snd_wss_get_format(chip, params_format(hw_params),
+                          params_channels(hw_params)) |
+                          snd_wss_get_rate(params_rate(hw_params));
+       chip->set_capture_format(chip, hw_params, new_cdfr);
+       return 0;
+}
+
+static int snd_wss_capture_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_wss_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long flags;
+       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+       unsigned int count = snd_pcm_lib_period_bytes(substream);
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->c_dma_size = size;
+       chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+       snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
+       if (chip->hardware & WSS_HW_AD1848_MASK)
+               count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT],
+                                         count);
+       else
+               count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT],
+                                         count);
+       count--;
+       if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
+               snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
+               snd_wss_out(chip, CS4231_PLY_UPR_CNT,
+                           (unsigned char) (count >> 8));
+       } else {
+               snd_wss_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
+               snd_wss_out(chip, CS4231_REC_UPR_CNT,
+                           (unsigned char) (count >> 8));
+       }
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return 0;
+}
+
+void snd_wss_overrange(struct snd_wss *chip)
+{
+       unsigned long flags;
+       unsigned char res;
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       res = snd_wss_in(chip, CS4231_TEST_INIT);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       if (res & (0x08 | 0x02))        /* detect overrange only above 0dB; may be user selectable? */
+               chip->capture_substream->runtime->overrange++;
+}
+EXPORT_SYMBOL(snd_wss_overrange);
+
+irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
+{
+       struct snd_wss *chip = dev_id;
+       unsigned char status;
+
+       if (chip->hardware & WSS_HW_AD1848_MASK)
+               /* pretend it was the only possible irq for AD1848 */
+               status = CS4231_PLAYBACK_IRQ;
+       else
+               status = snd_wss_in(chip, CS4231_IRQ_STATUS);
+       if (status & CS4231_TIMER_IRQ) {
+               if (chip->timer)
+                       snd_timer_interrupt(chip->timer, chip->timer->sticks);
+       }
+       if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
+               if (status & CS4231_PLAYBACK_IRQ) {
+                       if (chip->mode & WSS_MODE_PLAY) {
+                               if (chip->playback_substream)
+                                       snd_pcm_period_elapsed(chip->playback_substream);
+                       }
+                       if (chip->mode & WSS_MODE_RECORD) {
+                               if (chip->capture_substream) {
+                                       snd_wss_overrange(chip);
+                                       snd_pcm_period_elapsed(chip->capture_substream);
+                               }
+                       }
+               }
+       } else {
+               if (status & CS4231_PLAYBACK_IRQ) {
+                       if (chip->playback_substream)
+                               snd_pcm_period_elapsed(chip->playback_substream);
+               }
+               if (status & CS4231_RECORD_IRQ) {
+                       if (chip->capture_substream) {
+                               snd_wss_overrange(chip);
+                               snd_pcm_period_elapsed(chip->capture_substream);
+                       }
+               }
+       }
+
+       spin_lock(&chip->reg_lock);
+       status = ~CS4231_ALL_IRQS | ~status;
+       if (chip->hardware & WSS_HW_AD1848_MASK)
+               wss_outb(chip, CS4231P(STATUS), 0);
+       else
+               snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
+       spin_unlock(&chip->reg_lock);
+       return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(snd_wss_interrupt);
+
+static snd_pcm_uframes_t snd_wss_playback_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       size_t ptr;
+
+       if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
+               return 0;
+       ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
+       return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       size_t ptr;
+
+       if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
+               return 0;
+       ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
+       return bytes_to_frames(substream->runtime, ptr);
+}
+
+/*
+
+ */
+
+static int snd_ad1848_probe(struct snd_wss *chip)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+       unsigned long flags;
+       unsigned char r;
+       unsigned short hardware = 0;
+       int err = 0;
+       int i;
+
+       while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+               if (time_after(jiffies, timeout))
+                       return -ENODEV;
+               cond_resched();
+       }
+       spin_lock_irqsave(&chip->reg_lock, flags);
+
+       /* set CS423x MODE 1 */
+       snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+
+       snd_wss_dout(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */
+       r = snd_wss_in(chip, CS4231_RIGHT_INPUT);
+       if (r != 0x45) {
+               /* RMGE always high on AD1847 */
+               if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) {
+                       err = -ENODEV;
+                       goto out;
+               }
+               hardware = WSS_HW_AD1847;
+       } else {
+               snd_wss_dout(chip, CS4231_LEFT_INPUT,  0xaa);
+               r = snd_wss_in(chip, CS4231_LEFT_INPUT);
+               /* L/RMGE always low on AT2320 */
+               if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) {
+                       err = -ENODEV;
+                       goto out;
+               }
+       }
+
+       /* clear pending IRQ */
+       wss_inb(chip, CS4231P(STATUS));
+       wss_outb(chip, CS4231P(STATUS), 0);
+       mb();
+
+       if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT)
+               goto out;
+
+       if (hardware) {
+               chip->hardware = hardware;
+               goto out;
+       }
+
+       r = snd_wss_in(chip, CS4231_MISC_INFO);
+
+       /* set CS423x MODE 2 */
+       snd_wss_dout(chip, CS4231_MISC_INFO, CS4231_MODE2);
+       for (i = 0; i < 16; i++) {
+               if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) {
+                       /* we have more than 16 registers: check ID */
+                       if ((r & 0xf) != 0xa)
+                               goto out_mode;
+                       /*
+                        * on CMI8330, CS4231_VERSION is volume control and
+                        * can be set to 0
+                        */
+                       snd_wss_dout(chip, CS4231_VERSION, 0);
+                       r = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+                       if (!r)
+                               chip->hardware = WSS_HW_CMI8330;
+                       goto out_mode;
+               }
+       }
+       if (r & 0x80)
+               chip->hardware = WSS_HW_CS4248;
+       else
+               chip->hardware = WSS_HW_AD1848;
+out_mode:
+       snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+out:
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return err;
+}
+
+static int snd_wss_probe(struct snd_wss *chip)
+{
+       unsigned long flags;
+       int i, id, rev, regnum;
+       unsigned char *ptr;
+       unsigned int hw;
+
+       id = snd_ad1848_probe(chip);
+       if (id < 0)
+               return id;
+
+       hw = chip->hardware;
+       if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+               for (i = 0; i < 50; i++) {
+                       mb();
+                       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+                               msleep(2);
+                       else {
+                               spin_lock_irqsave(&chip->reg_lock, flags);
+                               snd_wss_out(chip, CS4231_MISC_INFO,
+                                           CS4231_MODE2);
+                               id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
+                               spin_unlock_irqrestore(&chip->reg_lock, flags);
+                               if (id == 0x0a)
+                                       break;  /* this is valid value */
+                       }
+               }
+               snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
+               if (id != 0x0a)
+                       return -ENODEV; /* no valid device found */
+
+               rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+               snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
+               if (rev == 0x80) {
+                       unsigned char tmp = snd_wss_in(chip, 23);
+                       snd_wss_out(chip, 23, ~tmp);
+                       if (snd_wss_in(chip, 23) != tmp)
+                               chip->hardware = WSS_HW_AD1845;
+                       else
+                               chip->hardware = WSS_HW_CS4231;
+               } else if (rev == 0xa0) {
+                       chip->hardware = WSS_HW_CS4231A;
+               } else if (rev == 0xa2) {
+                       chip->hardware = WSS_HW_CS4232;
+               } else if (rev == 0xb2) {
+                       chip->hardware = WSS_HW_CS4232A;
+               } else if (rev == 0x83) {
+                       chip->hardware = WSS_HW_CS4236;
+               } else if (rev == 0x03) {
+                       chip->hardware = WSS_HW_CS4236B;
+               } else {
+                       snd_printk("unknown CS chip with version 0x%x\n", rev);
+                       return -ENODEV;         /* unknown CS4231 chip? */
+               }
+       }
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */
+       wss_outb(chip, CS4231P(STATUS), 0);
+       mb();
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       if (!(chip->hardware & WSS_HW_AD1848_MASK))
+               chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
+       switch (chip->hardware) {
+       case WSS_HW_INTERWAVE:
+               chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
+               break;
+       case WSS_HW_CS4235:
+       case WSS_HW_CS4236B:
+       case WSS_HW_CS4237B:
+       case WSS_HW_CS4238B:
+       case WSS_HW_CS4239:
+               if (hw == WSS_HW_DETECT3)
+                       chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
+               else
+                       chip->hardware = WSS_HW_CS4236;
+               break;
+       }
+
+       chip->image[CS4231_IFACE_CTRL] =
+           (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
+           (chip->single_dma ? CS4231_SINGLE_DMA : 0);
+       if (chip->hardware != WSS_HW_OPTI93X) {
+               chip->image[CS4231_ALT_FEATURE_1] = 0x80;
+               chip->image[CS4231_ALT_FEATURE_2] =
+                       chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
+       }
+       ptr = (unsigned char *) &chip->image;
+       regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
+       snd_wss_mce_down(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       for (i = 0; i < regnum; i++)    /* ok.. fill all registers */
+               snd_wss_out(chip, i, *ptr++);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       snd_wss_mce_up(chip);
+       snd_wss_mce_down(chip);
+
+       mdelay(2);
+
+       /* ok.. try check hardware version for CS4236+ chips */
+       if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+               if (chip->hardware == WSS_HW_CS4236B) {
+                       rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
+                       snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
+                       id = snd_cs4236_ext_in(chip, CS4236_VERSION);
+                       snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
+                       snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
+                       if ((id & 0x1f) == 0x1d) {      /* CS4235 */
+                               chip->hardware = WSS_HW_CS4235;
+                               switch (id >> 5) {
+                               case 4:
+                               case 5:
+                               case 6:
+                                       break;
+                               default:
+                                       snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
+                               }
+                       } else if ((id & 0x1f) == 0x0b) {       /* CS4236/B */
+                               switch (id >> 5) {
+                               case 4:
+                               case 5:
+                               case 6:
+                               case 7:
+                                       chip->hardware = WSS_HW_CS4236B;
+                                       break;
+                               default:
+                                       snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
+                               }
+                       } else if ((id & 0x1f) == 0x08) {       /* CS4237B */
+                               chip->hardware = WSS_HW_CS4237B;
+                               switch (id >> 5) {
+                               case 4:
+                               case 5:
+                               case 6:
+                               case 7:
+                                       break;
+                               default:
+                                       snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
+                               }
+                       } else if ((id & 0x1f) == 0x09) {       /* CS4238B */
+                               chip->hardware = WSS_HW_CS4238B;
+                               switch (id >> 5) {
+                               case 5:
+                               case 6:
+                               case 7:
+                                       break;
+                               default:
+                                       snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
+                               }
+                       } else if ((id & 0x1f) == 0x1e) {       /* CS4239 */
+                               chip->hardware = WSS_HW_CS4239;
+                               switch (id >> 5) {
+                               case 4:
+                               case 5:
+                               case 6:
+                                       break;
+                               default:
+                                       snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
+                               }
+                       } else {
+                               snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
+                       }
+               }
+       }
+       return 0;               /* all things are ok.. */
+}
+
+/*
+
+ */
+
+static struct snd_pcm_hardware snd_wss_playback =
+{
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_MMAP_VALID |
+                                SNDRV_PCM_INFO_RESUME |
+                                SNDRV_PCM_INFO_SYNC_START),
+       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
+                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
+       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+       .rate_min =             5510,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     (128*1024),
+       .period_bytes_min =     64,
+       .period_bytes_max =     (128*1024),
+       .periods_min =          1,
+       .periods_max =          1024,
+       .fifo_size =            0,
+};
+
+static struct snd_pcm_hardware snd_wss_capture =
+{
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_MMAP_VALID |
+                                SNDRV_PCM_INFO_RESUME |
+                                SNDRV_PCM_INFO_SYNC_START),
+       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
+                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
+       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+       .rate_min =             5510,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     (128*1024),
+       .period_bytes_min =     64,
+       .period_bytes_max =     (128*1024),
+       .periods_min =          1,
+       .periods_max =          1024,
+       .fifo_size =            0,
+};
+
+/*
+
+ */
+
+static int snd_wss_playback_open(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       runtime->hw = snd_wss_playback;
+
+       /* hardware limitation of older chipsets */
+       if (chip->hardware & WSS_HW_AD1848_MASK)
+               runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+                                        SNDRV_PCM_FMTBIT_S16_BE);
+
+       /* hardware bug in InterWave chipset */
+       if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3)
+               runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
+
+       /* hardware limitation of cheap chips */
+       if (chip->hardware == WSS_HW_CS4235 ||
+           chip->hardware == WSS_HW_CS4239)
+               runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
+
+       snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
+       snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
+
+       if (chip->claim_dma) {
+               if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
+                       return err;
+       }
+
+       err = snd_wss_open(chip, WSS_MODE_PLAY);
+       if (err < 0) {
+               if (chip->release_dma)
+                       chip->release_dma(chip, chip->dma_private_data, chip->dma1);
+               snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+               return err;
+       }
+       chip->playback_substream = substream;
+       snd_pcm_set_sync(substream);
+       chip->rate_constraint(runtime);
+       return 0;
+}
+
+static int snd_wss_capture_open(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       runtime->hw = snd_wss_capture;
+
+       /* hardware limitation of older chipsets */
+       if (chip->hardware & WSS_HW_AD1848_MASK)
+               runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+                                        SNDRV_PCM_FMTBIT_S16_BE);
+
+       /* hardware limitation of cheap chips */
+       if (chip->hardware == WSS_HW_CS4235 ||
+           chip->hardware == WSS_HW_CS4239 ||
+           chip->hardware == WSS_HW_OPTI93X)
+               runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 |
+                                     SNDRV_PCM_FMTBIT_S16_LE;
+
+       snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
+       snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
+
+       if (chip->claim_dma) {
+               if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
+                       return err;
+       }
+
+       err = snd_wss_open(chip, WSS_MODE_RECORD);
+       if (err < 0) {
+               if (chip->release_dma)
+                       chip->release_dma(chip, chip->dma_private_data, chip->dma2);
+               snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+               return err;
+       }
+       chip->capture_substream = substream;
+       snd_pcm_set_sync(substream);
+       chip->rate_constraint(runtime);
+       return 0;
+}
+
+static int snd_wss_playback_close(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+
+       chip->playback_substream = NULL;
+       snd_wss_close(chip, WSS_MODE_PLAY);
+       return 0;
+}
+
+static int snd_wss_capture_close(struct snd_pcm_substream *substream)
+{
+       struct snd_wss *chip = snd_pcm_substream_chip(substream);
+
+       chip->capture_substream = NULL;
+       snd_wss_close(chip, WSS_MODE_RECORD);
+       return 0;
+}
+
+static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on)
+{
+       int tmp;
+
+       if (!chip->thinkpad_flag)
+               return;
+
+       outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
+       tmp = inb(AD1848_THINKPAD_CTL_PORT2);
+
+       if (on)
+               /* turn it on */
+               tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
+       else
+               /* turn it off */
+               tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
+
+       outb(tmp, AD1848_THINKPAD_CTL_PORT2);
+}
+
+#ifdef CONFIG_PM
+
+/* lowlevel suspend callback for CS4231 */
+static void snd_wss_suspend(struct snd_wss *chip)
+{
+       int reg;
+       unsigned long flags;
+
+       snd_pcm_suspend_all(chip->pcm);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       for (reg = 0; reg < 32; reg++)
+               chip->image[reg] = snd_wss_in(chip, reg);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       if (chip->thinkpad_flag)
+               snd_wss_thinkpad_twiddle(chip, 0);
+}
+
+/* lowlevel resume callback for CS4231 */
+static void snd_wss_resume(struct snd_wss *chip)
+{
+       int reg;
+       unsigned long flags;
+       /* int timeout; */
+
+       if (chip->thinkpad_flag)
+               snd_wss_thinkpad_twiddle(chip, 1);
+       snd_wss_mce_up(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       for (reg = 0; reg < 32; reg++) {
+               switch (reg) {
+               case CS4231_VERSION:
+                       break;
+               default:
+                       snd_wss_out(chip, reg, chip->image[reg]);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+#if 1
+       snd_wss_mce_down(chip);
+#else
+       /* The following is a workaround to avoid freeze after resume on TP600E.
+          This is the first half of copy of snd_wss_mce_down(), but doesn't
+          include rescheduling.  -- iwai
+          */
+       snd_wss_busy_wait(chip);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->mce_bit &= ~CS4231_MCE;
+       timeout = wss_inb(chip, CS4231P(REGSEL));
+       wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       if (timeout == 0x80)
+               snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+       if ((timeout & CS4231_MCE) == 0 ||
+           !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
+               return;
+       }
+       snd_wss_busy_wait(chip);
+#endif
+}
+#endif /* CONFIG_PM */
+
+static int snd_wss_free(struct snd_wss *chip)
+{
+       release_and_free_resource(chip->res_port);
+       release_and_free_resource(chip->res_cport);
+       if (chip->irq >= 0) {
+               disable_irq(chip->irq);
+               if (!(chip->hwshare & WSS_HWSHARE_IRQ))
+                       free_irq(chip->irq, (void *) chip);
+       }
+       if (!(chip->hwshare & WSS_HWSHARE_DMA1) && chip->dma1 >= 0) {
+               snd_dma_disable(chip->dma1);
+               free_dma(chip->dma1);
+       }
+       if (!(chip->hwshare & WSS_HWSHARE_DMA2) &&
+           chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
+               snd_dma_disable(chip->dma2);
+               free_dma(chip->dma2);
+       }
+       if (chip->timer)
+               snd_device_free(chip->card, chip->timer);
+       kfree(chip);
+       return 0;
+}
+
+static int snd_wss_dev_free(struct snd_device *device)
+{
+       struct snd_wss *chip = device->device_data;
+       return snd_wss_free(chip);
+}
+
+const char *snd_wss_chip_id(struct snd_wss *chip)
+{
+       switch (chip->hardware) {
+       case WSS_HW_CS4231:
+               return "CS4231";
+       case WSS_HW_CS4231A:
+               return "CS4231A";
+       case WSS_HW_CS4232:
+               return "CS4232";
+       case WSS_HW_CS4232A:
+               return "CS4232A";
+       case WSS_HW_CS4235:
+               return "CS4235";
+       case WSS_HW_CS4236:
+               return "CS4236";
+       case WSS_HW_CS4236B:
+               return "CS4236B";
+       case WSS_HW_CS4237B:
+               return "CS4237B";
+       case WSS_HW_CS4238B:
+               return "CS4238B";
+       case WSS_HW_CS4239:
+               return "CS4239";
+       case WSS_HW_INTERWAVE:
+               return "AMD InterWave";
+       case WSS_HW_OPL3SA2:
+               return chip->card->shortname;
+       case WSS_HW_AD1845:
+               return "AD1845";
+       case WSS_HW_OPTI93X:
+               return "OPTi 93x";
+       case WSS_HW_AD1847:
+               return "AD1847";
+       case WSS_HW_AD1848:
+               return "AD1848";
+       case WSS_HW_CS4248:
+               return "CS4248";
+       case WSS_HW_CMI8330:
+               return "CMI8330/C3D";
+       default:
+               return "???";
+       }
+}
+EXPORT_SYMBOL(snd_wss_chip_id);
+
+static int snd_wss_new(struct snd_card *card,
+                         unsigned short hardware,
+                         unsigned short hwshare,
+                         struct snd_wss **rchip)
+{
+       struct snd_wss *chip;
+
+       *rchip = NULL;
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+       chip->hardware = hardware;
+       chip->hwshare = hwshare;
+
+       spin_lock_init(&chip->reg_lock);
+       mutex_init(&chip->mce_mutex);
+       mutex_init(&chip->open_mutex);
+       chip->card = card;
+       chip->rate_constraint = snd_wss_xrate;
+       chip->set_playback_format = snd_wss_playback_format;
+       chip->set_capture_format = snd_wss_capture_format;
+       if (chip->hardware == WSS_HW_OPTI93X)
+               memcpy(&chip->image, &snd_opti93x_original_image,
+                      sizeof(snd_opti93x_original_image));
+       else
+               memcpy(&chip->image, &snd_wss_original_image,
+                      sizeof(snd_wss_original_image));
+       if (chip->hardware & WSS_HW_AD1848_MASK) {
+               chip->image[CS4231_PIN_CTRL] = 0;
+               chip->image[CS4231_TEST_INIT] = 0;
+       }
+
+       *rchip = chip;
+       return 0;
+}
+
+int snd_wss_create(struct snd_card *card,
+                     unsigned long port,
+                     unsigned long cport,
+                     int irq, int dma1, int dma2,
+                     unsigned short hardware,
+                     unsigned short hwshare,
+                     struct snd_wss **rchip)
+{
+       static struct snd_device_ops ops = {
+               .dev_free =     snd_wss_dev_free,
+       };
+       struct snd_wss *chip;
+       int err;
+
+       err = snd_wss_new(card, hardware, hwshare, &chip);
+       if (err < 0)
+               return err;
+
+       chip->irq = -1;
+       chip->dma1 = -1;
+       chip->dma2 = -1;
+
+       chip->res_port = request_region(port, 4, "WSS");
+       if (!chip->res_port) {
+               snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port);
+               snd_wss_free(chip);
+               return -EBUSY;
+       }
+       chip->port = port;
+       if ((long)cport >= 0) {
+               chip->res_cport = request_region(cport, 8, "CS4232 Control");
+               if (!chip->res_cport) {
+                       snd_printk(KERN_ERR
+                               "wss: can't grab control port 0x%lx\n", cport);
+                       snd_wss_free(chip);
+                       return -ENODEV;
+               }
+       }
+       chip->cport = cport;
+       if (!(hwshare & WSS_HWSHARE_IRQ))
+               if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED,
+                               "WSS", (void *) chip)) {
+                       snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
+                       snd_wss_free(chip);
+                       return -EBUSY;
+               }
+       chip->irq = irq;
+       if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) {
+               snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1);
+               snd_wss_free(chip);
+               return -EBUSY;
+       }
+       chip->dma1 = dma1;
+       if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 &&
+             dma2 >= 0 && request_dma(dma2, "WSS - 2")) {
+               snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2);
+               snd_wss_free(chip);
+               return -EBUSY;
+       }
+       if (dma1 == dma2 || dma2 < 0) {
+               chip->single_dma = 1;
+               chip->dma2 = chip->dma1;
+       } else
+               chip->dma2 = dma2;
+
+       if (hardware == WSS_HW_THINKPAD) {
+               chip->thinkpad_flag = 1;
+               chip->hardware = WSS_HW_DETECT; /* reset */
+               snd_wss_thinkpad_twiddle(chip, 1);
+       }
+
+       /* global setup */
+       if (snd_wss_probe(chip) < 0) {
+               snd_wss_free(chip);
+               return -ENODEV;
+       }
+       snd_wss_init(chip);
+
+#if 0
+       if (chip->hardware & WSS_HW_CS4232_MASK) {
+               if (chip->res_cport == NULL)
+                       snd_printk("CS4232 control port features are not accessible\n");
+       }
+#endif
+
+       /* Register device */
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_wss_free(chip);
+               return err;
+       }
+
+#ifdef CONFIG_PM
+       /* Power Management */
+       chip->suspend = snd_wss_suspend;
+       chip->resume = snd_wss_resume;
+#endif
+
+       *rchip = chip;
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_create);
+
+static struct snd_pcm_ops snd_wss_playback_ops = {
+       .open =         snd_wss_playback_open,
+       .close =        snd_wss_playback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_wss_playback_hw_params,
+       .hw_free =      snd_wss_playback_hw_free,
+       .prepare =      snd_wss_playback_prepare,
+       .trigger =      snd_wss_trigger,
+       .pointer =      snd_wss_playback_pointer,
+};
+
+static struct snd_pcm_ops snd_wss_capture_ops = {
+       .open =         snd_wss_capture_open,
+       .close =        snd_wss_capture_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_wss_capture_hw_params,
+       .hw_free =      snd_wss_capture_hw_free,
+       .prepare =      snd_wss_capture_prepare,
+       .trigger =      snd_wss_trigger,
+       .pointer =      snd_wss_capture_pointer,
+};
+
+int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(chip->card, "WSS", device, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops);
+
+       /* global setup */
+       pcm->private_data = chip;
+       pcm->info_flags = 0;
+       if (chip->single_dma)
+               pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
+       if (chip->hardware != WSS_HW_INTERWAVE)
+               pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+       strcpy(pcm->name, snd_wss_chip_id(chip));
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                             snd_dma_isa_data(),
+                                             64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+
+       chip->pcm = pcm;
+       if (rpcm)
+               *rpcm = pcm;
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_pcm);
+
+static void snd_wss_timer_free(struct snd_timer *timer)
+{
+       struct snd_wss *chip = timer->private_data;
+       chip->timer = NULL;
+}
+
+int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
+{
+       struct snd_timer *timer;
+       struct snd_timer_id tid;
+       int err;
+
+       /* Timer initialization */
+       tid.dev_class = SNDRV_TIMER_CLASS_CARD;
+       tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
+       tid.card = chip->card->number;
+       tid.device = device;
+       tid.subdevice = 0;
+       if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
+               return err;
+       strcpy(timer->name, snd_wss_chip_id(chip));
+       timer->private_data = chip;
+       timer->private_free = snd_wss_timer_free;
+       timer->hw = snd_wss_timer_table;
+       chip->timer = timer;
+       if (rtimer)
+               *rtimer = timer;
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_timer);
+
+/*
+ *  MIXER part
+ */
+
+static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[4] = {
+               "Line", "Aux", "Mic", "Mix"
+       };
+       static char *opl3sa_texts[4] = {
+               "Line", "CD", "Mic", "Mix"
+       };
+       static char *gusmax_texts[4] = {
+               "Line", "Synth", "Mic", "Mix"
+       };
+       char **ptexts = texts;
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+
+       if (snd_BUG_ON(!chip->card))
+               return -EINVAL;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 2;
+       uinfo->value.enumerated.items = 4;
+       if (uinfo->value.enumerated.item > 3)
+               uinfo->value.enumerated.item = 3;
+       if (!strcmp(chip->card->driver, "GUS MAX"))
+               ptexts = gusmax_texts;
+       switch (chip->hardware) {
+       case WSS_HW_INTERWAVE:
+               ptexts = gusmax_texts;
+               break;
+       case WSS_HW_OPL3SA2:
+               ptexts = opl3sa_texts;
+               break;
+       }
+       strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int snd_wss_get_mux(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
+       ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return 0;
+}
+
+static int snd_wss_put_mux(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       unsigned short left, right;
+       int change;
+
+       if (ucontrol->value.enumerated.item[0] > 3 ||
+           ucontrol->value.enumerated.item[1] > 3)
+               return -EINVAL;
+       left = ucontrol->value.enumerated.item[0] << 6;
+       right = ucontrol->value.enumerated.item[1] << 6;
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
+       right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
+       change = left != chip->image[CS4231_LEFT_INPUT] ||
+                right != chip->image[CS4231_RIGHT_INPUT];
+       snd_wss_out(chip, CS4231_LEFT_INPUT, left);
+       snd_wss_out(chip, CS4231_RIGHT_INPUT, right);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return change;
+}
+
+int snd_wss_info_single(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       int mask = (kcontrol->private_value >> 16) & 0xff;
+
+       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = mask;
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_info_single);
+
+int snd_wss_get_single(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int reg = kcontrol->private_value & 0xff;
+       int shift = (kcontrol->private_value >> 8) & 0xff;
+       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int invert = (kcontrol->private_value >> 24) & 0xff;
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       if (invert)
+               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_get_single);
+
+int snd_wss_put_single(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int reg = kcontrol->private_value & 0xff;
+       int shift = (kcontrol->private_value >> 8) & 0xff;
+       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int invert = (kcontrol->private_value >> 24) & 0xff;
+       int change;
+       unsigned short val;
+
+       val = (ucontrol->value.integer.value[0] & mask);
+       if (invert)
+               val = mask - val;
+       val <<= shift;
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       val = (chip->image[reg] & ~(mask << shift)) | val;
+       change = val != chip->image[reg];
+       snd_wss_out(chip, reg, val);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return change;
+}
+EXPORT_SYMBOL(snd_wss_put_single);
+
+int snd_wss_info_double(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       int mask = (kcontrol->private_value >> 24) & 0xff;
+
+       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = mask;
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_info_double);
+
+int snd_wss_get_double(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int left_reg = kcontrol->private_value & 0xff;
+       int right_reg = (kcontrol->private_value >> 8) & 0xff;
+       int shift_left = (kcontrol->private_value >> 16) & 0x07;
+       int shift_right = (kcontrol->private_value >> 19) & 0x07;
+       int mask = (kcontrol->private_value >> 24) & 0xff;
+       int invert = (kcontrol->private_value >> 22) & 1;
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
+       ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       if (invert) {
+               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+               ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
+       }
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_get_double);
+
+int snd_wss_put_double(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int left_reg = kcontrol->private_value & 0xff;
+       int right_reg = (kcontrol->private_value >> 8) & 0xff;
+       int shift_left = (kcontrol->private_value >> 16) & 0x07;
+       int shift_right = (kcontrol->private_value >> 19) & 0x07;
+       int mask = (kcontrol->private_value >> 24) & 0xff;
+       int invert = (kcontrol->private_value >> 22) & 1;
+       int change;
+       unsigned short val1, val2;
+
+       val1 = ucontrol->value.integer.value[0] & mask;
+       val2 = ucontrol->value.integer.value[1] & mask;
+       if (invert) {
+               val1 = mask - val1;
+               val2 = mask - val2;
+       }
+       val1 <<= shift_left;
+       val2 <<= shift_right;
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (left_reg != right_reg) {
+               val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
+               val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
+               change = val1 != chip->image[left_reg] ||
+                        val2 != chip->image[right_reg];
+               snd_wss_out(chip, left_reg, val1);
+               snd_wss_out(chip, right_reg, val2);
+       } else {
+               mask = (mask << shift_left) | (mask << shift_right);
+               val1 = (chip->image[left_reg] & ~mask) | val1 | val2;
+               change = val1 != chip->image[left_reg];
+               snd_wss_out(chip, left_reg, val1);
+       }
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return change;
+}
+EXPORT_SYMBOL(snd_wss_put_double);
+
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+
+static struct snd_kcontrol_new snd_ad1848_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
+          7, 7, 1, 1),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+              CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+              db_scale_6bit),
+WSS_DOUBLE("Aux Playback Switch", 0,
+          CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 0,
+              CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+              db_scale_5bit_12db_max),
+WSS_DOUBLE("Aux Playback Switch", 1,
+          CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 1,
+              CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+              db_scale_5bit_12db_max),
+WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
+               0, 0, 15, 0, db_scale_rec_gain),
+{
+       .name = "Capture Source",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_wss_info_mux,
+       .get = snd_wss_get_mux,
+       .put = snd_wss_put_mux,
+},
+WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
+              db_scale_6bit),
+};
+
+static struct snd_kcontrol_new snd_wss_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Line Playback Volume", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+WSS_DOUBLE("Aux Playback Switch", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Aux Playback Switch", 1,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 1,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_SINGLE("Mono Playback Switch", 0,
+               CS4231_MONO_CTRL, 7, 1, 1),
+WSS_SINGLE("Mono Playback Volume", 0,
+               CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE("Mono Output Playback Switch", 0,
+               CS4231_MONO_CTRL, 6, 1, 1),
+WSS_SINGLE("Mono Output Playback Bypass", 0,
+               CS4231_MONO_CTRL, 5, 1, 0),
+WSS_DOUBLE("Capture Volume", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+{
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Source",
+       .info = snd_wss_info_mux,
+       .get = snd_wss_get_mux,
+       .put = snd_wss_put_mux,
+},
+WSS_DOUBLE("Mic Boost", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_SINGLE("Loopback Capture Switch", 0,
+               CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE("Loopback Capture Volume", 0,
+               CS4231_LOOPBACK, 2, 63, 1)
+};
+
+static struct snd_kcontrol_new snd_opti93x_controls[] = {
+WSS_DOUBLE("Master Playback Switch", 0,
+               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
+WSS_DOUBLE("Master Playback Volume", 0,
+               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
+WSS_DOUBLE("PCM Playback Switch", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
+WSS_DOUBLE("FM Playback Switch", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("FM Playback Volume", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Line Playback Volume", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1),
+WSS_DOUBLE("Mic Playback Switch", 0,
+               OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Mic Playback Volume", 0,
+               OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Mic Boost", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_DOUBLE("CD Playback Switch", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("CD Playback Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Aux Playback Switch", 0,
+               OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Aux Playback Volume", 0,
+               OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
+WSS_DOUBLE("Capture Volume", 0,
+               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+{
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Source",
+       .info = snd_wss_info_mux,
+       .get = snd_wss_get_mux,
+       .put = snd_wss_put_mux,
+}
+};
+
+int snd_wss_mixer(struct snd_wss *chip)
+{
+       struct snd_card *card;
+       unsigned int idx;
+       int err;
+
+       if (snd_BUG_ON(!chip || !chip->pcm))
+               return -EINVAL;
+
+       card = chip->card;
+
+       strcpy(card->mixername, chip->pcm->name);
+
+       if (chip->hardware == WSS_HW_OPTI93X)
+               for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
+                       err = snd_ctl_add(card,
+                                       snd_ctl_new1(&snd_opti93x_controls[idx],
+                                                    chip));
+                       if (err < 0)
+                               return err;
+               }
+       else if (chip->hardware & WSS_HW_AD1848_MASK)
+               for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
+                       err = snd_ctl_add(card,
+                                       snd_ctl_new1(&snd_ad1848_controls[idx],
+                                                    chip));
+                       if (err < 0)
+                               return err;
+               }
+       else
+               for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
+                       err = snd_ctl_add(card,
+                                       snd_ctl_new1(&snd_wss_controls[idx],
+                                                    chip));
+                       if (err < 0)
+                               return err;
+               }
+       return 0;
+}
+EXPORT_SYMBOL(snd_wss_mixer);
+
+const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction)
+{
+       return direction == SNDRV_PCM_STREAM_PLAYBACK ?
+               &snd_wss_playback_ops : &snd_wss_capture_ops;
+}
+EXPORT_SYMBOL(snd_wss_get_pcm_ops);
+
+/*
+ *  INIT part
+ */
+
+static int __init alsa_wss_init(void)
+{
+       return 0;
+}
+
+static void __exit alsa_wss_exit(void)
+{
+}
+
+module_init(alsa_wss_init);
+module_exit(alsa_wss_exit);
index fbef38a9604ae31e775cfdaaeac3a5efef922dc9..1881cec11e78d221b55f4132219ec48c0cc9c147 100644 (file)
@@ -190,14 +190,16 @@ au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes,
 static void
 au1000_dma_stop(struct audio_stream *stream)
 {
-       snd_assert(stream->buffer, return);
+       if (snd_BUG_ON(!stream->buffer))
+               return;
        disable_dma(stream->dma);
 }
 
 static void
 au1000_dma_start(struct audio_stream *stream)
 {
-       snd_assert(stream->buffer, return);
+       if (snd_BUG_ON(!stream->buffer))
+               return;
 
        init_dma(stream->dma);
        if (get_dma_active_buffer(stream->dma) == 0) {
index d4fafb6eec6caec2286999a541221d715b1f81db..1ca7427c4b6d869d48a19382c60949620ab178d1 100644 (file)
@@ -24,13 +24,6 @@ config SOUND_VWSND
          <file:Documentation/sound/oss/vwsnd> for more info on this driver's
          capabilities.
 
-config SOUND_HAL2
-       tristate "SGI HAL2 sound (EXPERIMENTAL)"
-       depends on SGI_IP22 && EXPERIMENTAL
-       help
-         Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to
-         use its on-board A2 audio system.
-
 config SOUND_AU1550_AC97
        tristate "Au1550/Au1200 AC97 Sound"
        depends on SOC_AU1550 || SOC_AU1200
@@ -546,34 +539,6 @@ config SC6600_CDROMBASE
          Base I/O port address for the CD-ROM interface of the Audio Excel
          DSP 16 card.
 
-choice
-       prompt "Audio Excel DSP 16"
-       optional
-       depends on SOUND_AEDSP16
-
-config AEDSP16_MSS
-       bool "MSS emulation"
-       depends on SOUND_MSS
-       help
-         Answer Y if you want your audio card to emulate Microsoft Sound
-         System. You should then say Y to "Microsoft Sound System support"
-         and say N to "Audio Excel DSP 16 (SBPro emulation)".
-
-config AEDSP16_SBPRO
-       bool "SBPro emulation"
-       depends on SOUND_SB
-       help
-         Answer Y if you want your audio card to emulate Sound Blaster Pro.
-         You should then say Y to "100% Sound Blaster compatibles
-         (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
-         emulation)".
-
-         If you compile the driver into the kernel, you have to add
-         "aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
-         command line.
-
-endchoice
-
 config SOUND_VIDC
        tristate "VIDC 16-bit sound"
        depends on ARM && (ARCH_ACORN || ARCH_CLPS7500)
index c611514f7ff104ec3289d960d9108d5391fc91c9..e0ae4d4d6a5ceff3b5b78eaf742a13cd0043060f 100644 (file)
@@ -10,7 +10,6 @@ obj-$(CONFIG_SOUND_OSS)               += sound.o
 # Please leave it as is, cause the link order is significant !
 
 obj-$(CONFIG_SOUND_SH_DAC_AUDIO)       += sh_dac_audio.o
-obj-$(CONFIG_SOUND_HAL2)       += hal2.o
 obj-$(CONFIG_SOUND_AEDSP16)    += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
index 51e1fde62e8d5685bed6fc44ef0fdd9bd0dc896a..a0274f3dac08874f6f3092cfb946bb04381973e7 100644 (file)
 #include <linux/init.h>
 #include "sound_config.h"
 
-/*
- * Sanity checks
- */
-
-#if defined(CONFIG_SOUND_AEDSP16_SBPRO) && defined(CONFIG_SOUND_AEDSP16_MSS)
-#error You have to enable only one of the MSS and SBPRO emulations.
-#endif
-
 /*
 
    READ THIS
index 3eb782720e58e3a00ffbabb11fb63bfbd38bf5ae..f456574a964dc22639eb3dcf1a426c85288a1480 100644 (file)
@@ -42,3 +42,4 @@ config DMASOUND_Q40
 
 config DMASOUND
        tristate
+       select SOUND_OSS_CORE
diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
deleted file mode 100644 (file)
index a94b9df..0000000
+++ /dev/null
@@ -1,1558 +0,0 @@
-/*
- *  Driver for A2 audio system used in SGI machines
- *  Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
- *  
- *  Based on Ulf Carlsson's code.
- *
- *  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.
- *
- *  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.
- *
- *  Supported devices:
- *  /dev/dsp    standard dsp device, (mostly) OSS compatible
- *  /dev/mixer standard mixer device, (mostly) OSS compatible
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/sgi/hpc3.h>
-#include <asm/sgi/ip22.h>
-
-#include "hal2.h"
-
-#if 0
-#define DEBUG(args...)         printk(args)
-#else
-#define DEBUG(args...)
-#endif
-
-#if 0 
-#define DEBUG_MIX(args...)     printk(args)
-#else
-#define DEBUG_MIX(args...)
-#endif
-
-/*
- * Before touching these look how it works. It is a bit unusual I know,
- * but it helps to keep things simple. This driver is considered complete
- * and I won't add any new features although hardware has many cool
- * capabilities.
- * (Historical note: HAL2 driver was first written by Ulf Carlsson - ALSA
- * 0.3 running with 2.2.x kernel. Then ALSA changed completely and it
- * seemed easier to me to write OSS driver from scratch - this one. Now
- * when ALSA is official part of 2.6 kernel it's time to write ALSA driver
- * using (hopefully) final version of ALSA interface)
- */
-#define H2_BLOCK_SIZE  1024
-#define H2_ADC_BUFSIZE 8192
-#define H2_DAC_BUFSIZE 16834
-
-struct hal2_pbus {
-       struct hpc3_pbus_dmacregs *pbus;
-       int pbusnr;
-       unsigned int ctrl;              /* Current state of pbus->pbdma_ctrl */
-};
-
-struct hal2_desc {
-       struct hpc_dma_desc desc;
-       u32 cnt;                        /* don't touch, it is also padding */
-};
-
-struct hal2_codec {
-       unsigned char *buffer;
-       struct hal2_desc *desc;
-       int desc_count;
-       int tail, head;                 /* tail index, head index */
-       struct hal2_pbus pbus;
-       unsigned int format;            /* Audio data format */
-       int voices;                     /* mono/stereo */
-       unsigned int sample_rate;
-       unsigned int master;            /* Master frequency */
-       unsigned short mod;             /* MOD value */
-       unsigned short inc;             /* INC value */
-
-       wait_queue_head_t dma_wait;
-       spinlock_t lock;
-       struct mutex sem;
-
-       int usecount;                   /* recording and playback are
-                                        * independent */
-};
-
-#define H2_MIX_OUTPUT_ATT      0
-#define H2_MIX_INPUT_GAIN      1
-#define H2_MIXERS              2
-struct hal2_mixer {
-       int modcnt;
-       unsigned int master;
-       unsigned int volume[H2_MIXERS];
-};
-
-struct hal2_card {
-       int dev_dsp;                    /* audio device */
-       int dev_mixer;                  /* mixer device */
-       int dev_midi;                   /* midi device */
-
-       struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */
-       struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */
-       struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */
-       struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */
-
-       struct hal2_codec dac;
-       struct hal2_codec adc;
-       struct hal2_mixer mixer;
-};
-
-#define H2_INDIRECT_WAIT(regs) while (regs->isr & H2_ISR_TSTATUS);
-
-#define H2_READ_ADDR(addr)     (addr | (1<<7))
-#define H2_WRITE_ADDR(addr)    (addr)
-
-static char *hal2str = "HAL2";
-
-/*
- * I doubt anyone has a machine with two HAL2 cards. It's possible to
- * have two HPC's, so it is probably possible to have two HAL2 cards.
- * Try to deal with it, but note that it is not tested.
- */
-#define MAXCARDS       2
-static struct hal2_card* hal2_card[MAXCARDS];
-
-static const struct {
-       unsigned char idx:4, avail:1;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
-       [SOUND_MIXER_PCM]       = { H2_MIX_OUTPUT_ATT, 1 },     /* voice */
-       [SOUND_MIXER_MIC]       = { H2_MIX_INPUT_GAIN, 1 },     /* mic */
-};
-
-#define H2_SUPPORTED_FORMATS   (AFMT_S16_LE | AFMT_S16_BE)
-
-static inline void hal2_isr_write(struct hal2_card *hal2, u16 val)
-{
-       hal2->ctl_regs->isr = val;
-}
-
-static inline u16 hal2_isr_look(struct hal2_card *hal2)
-{
-       return hal2->ctl_regs->isr;
-}
-
-static inline u16 hal2_rev_look(struct hal2_card *hal2)
-{
-       return hal2->ctl_regs->rev;
-}
-
-#ifdef HAL2_DUMP_REGS
-static u16 hal2_i_look16(struct hal2_card *hal2, u16 addr)
-{
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->iar = H2_READ_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-       return regs->idr0;
-}
-#endif
-
-static u32 hal2_i_look32(struct hal2_card *hal2, u16 addr)
-{
-       u32 ret;
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->iar = H2_READ_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-       ret = regs->idr0 & 0xffff;
-       regs->iar = H2_READ_ADDR(addr | 0x1);
-       H2_INDIRECT_WAIT(regs);
-       ret |= (regs->idr0 & 0xffff) << 16;
-       return ret;
-}
-
-static void hal2_i_write16(struct hal2_card *hal2, u16 addr, u16 val)
-{
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->idr0 = val;
-       regs->idr1 = 0;
-       regs->idr2 = 0;
-       regs->idr3 = 0;
-       regs->iar = H2_WRITE_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_write32(struct hal2_card *hal2, u16 addr, u32 val)
-{
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->idr0 = val & 0xffff;
-       regs->idr1 = val >> 16;
-       regs->idr2 = 0;
-       regs->idr3 = 0;
-       regs->iar = H2_WRITE_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_setbit16(struct hal2_card *hal2, u16 addr, u16 bit)
-{
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->iar = H2_READ_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-       regs->idr0 = (regs->idr0 & 0xffff) | bit;
-       regs->idr1 = 0;
-       regs->idr2 = 0;
-       regs->idr3 = 0;
-       regs->iar = H2_WRITE_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_setbit32(struct hal2_card *hal2, u16 addr, u32 bit)
-{
-       u32 tmp;
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->iar = H2_READ_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-       tmp = (regs->idr0 & 0xffff) | (regs->idr1 << 16) | bit;
-       regs->idr0 = tmp & 0xffff;
-       regs->idr1 = tmp >> 16;
-       regs->idr2 = 0;
-       regs->idr3 = 0;
-       regs->iar = H2_WRITE_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_clearbit16(struct hal2_card *hal2, u16 addr, u16 bit)
-{
-       struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
-       regs->iar = H2_READ_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-       regs->idr0 = (regs->idr0 & 0xffff) & ~bit;
-       regs->idr1 = 0;
-       regs->idr2 = 0;
-       regs->idr3 = 0;
-       regs->iar = H2_WRITE_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-}
-
-#if 0
-static void hal2_i_clearbit32(struct hal2_card *hal2, u16 addr, u32 bit)
-{
-       u32 tmp;
-       hal2_ctl_regs_t *regs = hal2->ctl_regs;
-
-       regs->iar = H2_READ_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-       tmp = ((regs->idr0 & 0xffff) | (regs->idr1 << 16)) & ~bit;
-       regs->idr0 = tmp & 0xffff;
-       regs->idr1 = tmp >> 16;
-       regs->idr2 = 0;
-       regs->idr3 = 0;
-       regs->iar = H2_WRITE_ADDR(addr);
-       H2_INDIRECT_WAIT(regs);
-}
-#endif
-
-#ifdef HAL2_DUMP_REGS
-static void hal2_dump_regs(struct hal2_card *hal2)
-{
-       DEBUG("isr: %08hx ", hal2_isr_look(hal2));
-       DEBUG("rev: %08hx\n", hal2_rev_look(hal2));
-       DEBUG("relay: %04hx\n", hal2_i_look16(hal2, H2I_RELAY_C));
-       DEBUG("port en: %04hx ", hal2_i_look16(hal2, H2I_DMA_PORT_EN));
-       DEBUG("dma end: %04hx ", hal2_i_look16(hal2, H2I_DMA_END));
-       DEBUG("dma drv: %04hx\n", hal2_i_look16(hal2, H2I_DMA_DRV));
-       DEBUG("syn ctl: %04hx ", hal2_i_look16(hal2, H2I_SYNTH_C));
-       DEBUG("aesrx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESRX_C));
-       DEBUG("aestx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESTX_C));
-       DEBUG("dac ctl1: %04hx ", hal2_i_look16(hal2, H2I_ADC_C1));
-       DEBUG("dac ctl2: %08x ", hal2_i_look32(hal2, H2I_ADC_C2));
-       DEBUG("adc ctl1: %04hx ", hal2_i_look16(hal2, H2I_DAC_C1));
-       DEBUG("adc ctl2: %08x ", hal2_i_look32(hal2, H2I_DAC_C2));
-       DEBUG("syn map: %04hx\n", hal2_i_look16(hal2, H2I_SYNTH_MAP_C));
-       DEBUG("bres1 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES1_C1));
-       DEBUG("bres1 ctl2: %04x ", hal2_i_look32(hal2, H2I_BRES1_C2));
-       DEBUG("bres2 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES2_C1));
-       DEBUG("bres2 ctl2: %04x ", hal2_i_look32(hal2, H2I_BRES2_C2));
-       DEBUG("bres3 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES3_C1));
-       DEBUG("bres3 ctl2: %04x\n", hal2_i_look32(hal2, H2I_BRES3_C2));
-}
-#endif
-
-static struct hal2_card* hal2_dsp_find_card(int minor)
-{
-       int i;
-
-       for (i = 0; i < MAXCARDS; i++)
-               if (hal2_card[i] != NULL && hal2_card[i]->dev_dsp == minor)
-                       return hal2_card[i];
-       return NULL;
-}
-
-static struct hal2_card* hal2_mixer_find_card(int minor)
-{
-       int i;
-
-       for (i = 0; i < MAXCARDS; i++)
-               if (hal2_card[i] != NULL && hal2_card[i]->dev_mixer == minor)
-                       return hal2_card[i];
-       return NULL;
-}
-
-static void hal2_inc_head(struct hal2_codec *codec)
-{
-       codec->head++;
-       if (codec->head == codec->desc_count)
-               codec->head = 0;
-}
-
-static void hal2_inc_tail(struct hal2_codec *codec)
-{
-       codec->tail++;
-       if (codec->tail == codec->desc_count)
-               codec->tail = 0;
-}
-
-static void hal2_dac_interrupt(struct hal2_codec *dac)
-{
-       int running;
-
-       spin_lock(&dac->lock);
-       /* if tail buffer contains zero samples DMA stream was already
-        * stopped */
-       running = dac->desc[dac->tail].cnt;
-       dac->desc[dac->tail].cnt = 0;
-       dac->desc[dac->tail].desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX;
-       /* we just proccessed empty buffer, don't update tail pointer */
-       if (running)
-               hal2_inc_tail(dac);
-       spin_unlock(&dac->lock);
-
-       wake_up(&dac->dma_wait);
-}
-
-static void hal2_adc_interrupt(struct hal2_codec *adc)
-{
-       int running;
-
-       spin_lock(&adc->lock);
-       /* if head buffer contains nonzero samples DMA stream was already
-        * stopped */
-       running = !adc->desc[adc->head].cnt;
-       adc->desc[adc->head].cnt = H2_BLOCK_SIZE;
-       adc->desc[adc->head].desc.cntinfo = HPCDMA_XIE | HPCDMA_EOR;
-       /* we just proccessed empty buffer, don't update head pointer */
-       if (running)
-               hal2_inc_head(adc);
-       spin_unlock(&adc->lock);
-
-       wake_up(&adc->dma_wait);
-}
-
-static irqreturn_t hal2_interrupt(int irq, void *dev_id)
-{
-       struct hal2_card *hal2 = dev_id;
-       irqreturn_t ret = IRQ_NONE;
-
-       /* decide what caused this interrupt */
-       if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
-               hal2_dac_interrupt(&hal2->dac);
-               ret = IRQ_HANDLED;
-       }
-       if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
-               hal2_adc_interrupt(&hal2->adc);
-               ret = IRQ_HANDLED;
-       }
-       return ret;
-}
-
-static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate)
-{
-       unsigned short mod;
-       
-       DEBUG("rate: %d\n", rate);
-       
-       if (rate < 4000) rate = 4000;
-       else if (rate > 48000) rate = 48000;
-
-       if (44100 % rate < 48000 % rate) {
-               mod = 4 * 44100 / rate;
-               codec->master = 44100;
-       } else {
-               mod = 4 * 48000 / rate;
-               codec->master = 48000;
-       }
-
-       codec->inc = 4;
-       codec->mod = mod;
-       rate = 4 * codec->master / mod;
-
-       DEBUG("real_rate: %d\n", rate);
-
-       return rate;
-}
-
-static void hal2_set_dac_rate(struct hal2_card *hal2)
-{
-       unsigned int master = hal2->dac.master;
-       int inc = hal2->dac.inc;
-       int mod = hal2->dac.mod;
-
-       DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
-       
-       hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0);
-       hal2_i_write32(hal2, H2I_BRES1_C2, ((0xffff & (inc - mod - 1)) << 16) | inc);
-}
-
-static void hal2_set_adc_rate(struct hal2_card *hal2)
-{
-       unsigned int master = hal2->adc.master;
-       int inc = hal2->adc.inc;
-       int mod = hal2->adc.mod;
-
-       DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
-       
-       hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0);
-       hal2_i_write32(hal2, H2I_BRES2_C2, ((0xffff & (inc - mod - 1)) << 16) | inc);
-}
-
-static void hal2_setup_dac(struct hal2_card *hal2)
-{
-       unsigned int fifobeg, fifoend, highwater, sample_size;
-       struct hal2_pbus *pbus = &hal2->dac.pbus;
-
-       DEBUG("hal2_setup_dac\n");
-       
-       /* Now we set up some PBUS information. The PBUS needs information about
-        * what portion of the fifo it will use. If it's receiving or
-        * transmitting, and finally whether the stream is little endian or big
-        * endian. The information is written later, on the start call.
-        */
-       sample_size = 2 * hal2->dac.voices;
-       /* Fifo should be set to hold exactly four samples. Highwater mark
-        * should be set to two samples. */
-       highwater = (sample_size * 2) >> 1;     /* halfwords */
-       fifobeg = 0;                            /* playback is first */
-       fifoend = (sample_size * 4) >> 3;       /* doublewords */
-       pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD |
-                    (highwater << 8) | (fifobeg << 16) | (fifoend << 24) |
-                    (hal2->dac.format & AFMT_S16_LE ? HPC3_PDMACTRL_SEL : 0);
-       /* We disable everything before we do anything at all */
-       pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-       hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
-       /* Setup the HAL2 for playback */
-       hal2_set_dac_rate(hal2);
-       /* Set endianess */
-       if (hal2->dac.format & AFMT_S16_LE)
-               hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
-       else
-               hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
-       /* Set DMA bus */
-       hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
-       /* We are using 1st Bresenham clock generator for playback */
-       hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
-                       | (1 << H2I_C1_CLKID_SHIFT)
-                       | (hal2->dac.voices << H2I_C1_DATAT_SHIFT));
-}
-
-static void hal2_setup_adc(struct hal2_card *hal2)
-{
-       unsigned int fifobeg, fifoend, highwater, sample_size;
-       struct hal2_pbus *pbus = &hal2->adc.pbus;
-
-       DEBUG("hal2_setup_adc\n");
-
-       sample_size = 2 * hal2->adc.voices;
-       highwater = (sample_size * 2) >> 1;             /* halfwords */
-       fifobeg = (4 * 4) >> 3;                         /* record is second */
-       fifoend = (4 * 4 + sample_size * 4) >> 3;       /* doublewords */
-       pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD | 
-                    (highwater << 8) | (fifobeg << 16) | (fifoend << 24) |
-                    (hal2->adc.format & AFMT_S16_LE ? HPC3_PDMACTRL_SEL : 0);
-       pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-       hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
-       /* Setup the HAL2 for record */
-       hal2_set_adc_rate(hal2);
-       /* Set endianess */
-       if (hal2->adc.format & AFMT_S16_LE)
-               hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
-       else
-               hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
-       /* Set DMA bus */
-       hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
-       /* We are using 2nd Bresenham clock generator for record */
-       hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
-                       | (2 << H2I_C1_CLKID_SHIFT)
-                       | (hal2->adc.voices << H2I_C1_DATAT_SHIFT));
-}
-
-static dma_addr_t hal2_desc_addr(struct hal2_codec *codec, int i)
-{
-       if (--i < 0)
-               i = codec->desc_count - 1;
-       return codec->desc[i].desc.pnext;
-}
-
-static void hal2_start_dac(struct hal2_card *hal2)
-{
-       struct hal2_codec *dac = &hal2->dac;
-       struct hal2_pbus *pbus = &dac->pbus;
-
-       pbus->pbus->pbdma_dptr = hal2_desc_addr(dac, dac->tail);
-       pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
-       /* enable DAC */
-       hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
-}
-
-static void hal2_start_adc(struct hal2_card *hal2)
-{
-       struct hal2_codec *adc = &hal2->adc;
-       struct hal2_pbus *pbus = &adc->pbus;
-
-       pbus->pbus->pbdma_dptr = hal2_desc_addr(adc, adc->head);
-       pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
-       /* enable ADC */
-       hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
-}
-
-static inline void hal2_stop_dac(struct hal2_card *hal2)
-{
-       hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-       /* The HAL2 itself may remain enabled safely */
-}
-
-static inline void hal2_stop_adc(struct hal2_card *hal2)
-{
-       hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-}
-
-static int hal2_alloc_dmabuf(struct hal2_codec *codec, int size,
-                            int count, int cntinfo, int dir)
-{
-       struct hal2_desc *desc, *dma_addr;
-       int i;
-
-       DEBUG("allocating %dk DMA buffer.\n", size / 1024);
-
-       codec->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL | GFP_DMA,
-                                                         get_order(size));
-       if (!codec->buffer)
-               return -ENOMEM;
-       desc = dma_alloc_coherent(NULL, count * sizeof(struct hal2_desc),
-                                 (dma_addr_t *)&dma_addr, GFP_KERNEL);
-       if (!desc) {
-               free_pages((unsigned long)codec->buffer, get_order(size));
-               return -ENOMEM;
-       }
-       codec->desc = desc;
-       for (i = 0; i < count; i++) {
-               desc->desc.pbuf = dma_map_single(NULL,
-                       (void *)(codec->buffer + i * H2_BLOCK_SIZE),
-                       H2_BLOCK_SIZE, dir);
-               desc->desc.cntinfo = cntinfo;
-               desc->desc.pnext = (i == count - 1) ?
-                                  (u32)dma_addr : (u32)(dma_addr + i + 1);
-               desc->cnt = 0;
-               desc++;
-       }
-       codec->desc_count = count;
-       codec->head = codec->tail = 0;
-       return 0;
-}
-
-static int hal2_alloc_dac_dmabuf(struct hal2_codec *codec)
-{
-       return hal2_alloc_dmabuf(codec, H2_DAC_BUFSIZE,
-                                H2_DAC_BUFSIZE / H2_BLOCK_SIZE,
-                                HPCDMA_XIE | HPCDMA_EOX,
-                                DMA_TO_DEVICE);
-}
-
-static int hal2_alloc_adc_dmabuf(struct hal2_codec *codec)
-{
-       return hal2_alloc_dmabuf(codec, H2_ADC_BUFSIZE,
-                                H2_ADC_BUFSIZE / H2_BLOCK_SIZE,
-                                HPCDMA_XIE | H2_BLOCK_SIZE,
-                                DMA_TO_DEVICE);
-}
-
-static void hal2_free_dmabuf(struct hal2_codec *codec, int size, int dir)
-{
-       dma_addr_t dma_addr;
-       int i;
-
-       dma_addr = codec->desc[codec->desc_count - 1].desc.pnext;
-       for (i = 0; i < codec->desc_count; i++)
-               dma_unmap_single(NULL, codec->desc[i].desc.pbuf,
-                                H2_BLOCK_SIZE, dir);
-       dma_free_coherent(NULL, codec->desc_count * sizeof(struct hal2_desc),
-                         (void *)codec->desc, dma_addr);
-       free_pages((unsigned long)codec->buffer, get_order(size));
-}
-
-static void hal2_free_dac_dmabuf(struct hal2_codec *codec)
-{
-       return hal2_free_dmabuf(codec, H2_DAC_BUFSIZE, DMA_TO_DEVICE);
-}
-
-static void hal2_free_adc_dmabuf(struct hal2_codec *codec)
-{
-       return hal2_free_dmabuf(codec, H2_ADC_BUFSIZE, DMA_FROM_DEVICE);
-}
-
-/* 
- * Add 'count' bytes to 'buffer' from DMA ring buffers. Return number of
- * bytes added or -EFAULT if copy_from_user failed.
- */
-static int hal2_get_buffer(struct hal2_card *hal2, char *buffer, int count)
-{
-       unsigned long flags;
-       int size, ret = 0;
-       unsigned char *buf;
-       struct hal2_desc *tail;
-       struct hal2_codec *adc = &hal2->adc;
-
-       DEBUG("getting %d bytes ", count);
-
-       spin_lock_irqsave(&adc->lock, flags);
-       tail = &adc->desc[adc->tail];
-       /* enable DMA stream if there are no data */
-       if (!tail->cnt && !(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
-               hal2_start_adc(hal2);
-       while (tail->cnt > 0 && count > 0) {
-               size = min((int)tail->cnt, count);
-               buf = &adc->buffer[(adc->tail + 1) * H2_BLOCK_SIZE - tail->cnt];
-               spin_unlock_irqrestore(&adc->lock, flags);
-               dma_sync_single(NULL, tail->desc.pbuf, size, DMA_FROM_DEVICE);
-               if (copy_to_user(buffer, buf, size)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               spin_lock_irqsave(&adc->lock, flags);
-               tail->cnt -= size;
-               /* buffer is empty, update tail pointer */
-               if (tail->cnt == 0) {
-                       tail->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE;
-                       hal2_inc_tail(adc);
-                       tail = &adc->desc[adc->tail];
-                       /* enable DMA stream again if needed */
-                       if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
-                               hal2_start_adc(hal2);
-               }
-               buffer += size;
-               ret += size;
-               count -= size;
-
-               DEBUG("(%d) ", size);
-       }
-       spin_unlock_irqrestore(&adc->lock, flags);
-out:
-       DEBUG("\n");
-
-       return ret;
-} 
-
-/* 
- * Add 'count' bytes from 'buffer' to DMA ring buffers. Return number of
- * bytes added or -EFAULT if copy_from_user failed.
- */
-static int hal2_add_buffer(struct hal2_card *hal2, char *buffer, int count)
-{
-       unsigned long flags;
-       unsigned char *buf;
-       int size, ret = 0;
-       struct hal2_desc *head;
-       struct hal2_codec *dac = &hal2->dac;
-
-       DEBUG("adding %d bytes ", count);
-
-       spin_lock_irqsave(&dac->lock, flags);
-       head = &dac->desc[dac->head];
-       while (head->cnt == 0 && count > 0) {
-               size = min((int)H2_BLOCK_SIZE, count);
-               buf = &dac->buffer[dac->head * H2_BLOCK_SIZE];
-               spin_unlock_irqrestore(&dac->lock, flags);
-               if (copy_from_user(buf, buffer, size)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               dma_sync_single(NULL, head->desc.pbuf, size, DMA_TO_DEVICE);
-               spin_lock_irqsave(&dac->lock, flags);
-               head->desc.cntinfo = size | HPCDMA_XIE;
-               head->cnt = size;
-               buffer += size;
-               ret += size;
-               count -= size;
-               hal2_inc_head(dac);
-               head = &dac->desc[dac->head];
-
-               DEBUG("(%d) ", size);
-       }
-       if (!(dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) && ret > 0)
-               hal2_start_dac(hal2);
-       spin_unlock_irqrestore(&dac->lock, flags);
-out:
-       DEBUG("\n");
-
-       return ret;
-}
-
-#define hal2_reset_dac_pointer(hal2)   hal2_reset_pointer(hal2, 1)
-#define hal2_reset_adc_pointer(hal2)   hal2_reset_pointer(hal2, 0)
-static void hal2_reset_pointer(struct hal2_card *hal2, int is_dac)
-{
-       int i;
-       struct hal2_codec *codec = (is_dac) ? &hal2->dac : &hal2->adc;
-
-       DEBUG("hal2_reset_pointer\n");
-
-       for (i = 0; i < codec->desc_count; i++) {
-               codec->desc[i].cnt = 0;
-               codec->desc[i].desc.cntinfo = HPCDMA_XIE | (is_dac) ?
-                                             HPCDMA_EOX : H2_BLOCK_SIZE;
-       }
-       codec->head = codec->tail = 0;
-}
-
-static int hal2_sync_dac(struct hal2_card *hal2)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       struct hal2_codec *dac = &hal2->dac;
-       int ret = 0;
-       unsigned long flags;
-       signed long timeout = 1000 * H2_BLOCK_SIZE * 2 * dac->voices *
-                             HZ / dac->sample_rate / 900;
-
-       while (dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) {
-               add_wait_queue(&dac->dma_wait, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(timeout);
-               spin_lock_irqsave(&dac->lock, flags);
-               if (dac->desc[dac->tail].cnt)
-                       ret = -ETIME;
-               spin_unlock_irqrestore(&dac->lock, flags);
-               if (signal_pending(current))
-                       ret = -ERESTARTSYS;
-               if (ret) {
-                       hal2_stop_dac(hal2);
-                       hal2_reset_dac_pointer(hal2);
-               }
-               remove_wait_queue(&dac->dma_wait, &wait);
-       }
-
-       return ret;
-}
-
-static int hal2_write_mixer(struct hal2_card *hal2, int index, int vol)
-{
-       unsigned int l, r, tmp;
-
-       DEBUG_MIX("mixer %d write\n", index);
-
-       if (index >= SOUND_MIXER_NRDEVICES || !mixtable[index].avail)
-               return -EINVAL;
-
-       r = (vol >> 8) & 0xff;
-       if (r > 100)
-               r = 100;
-       l = vol & 0xff;
-       if (l > 100)
-               l = 100;
-
-       hal2->mixer.volume[mixtable[index].idx] = l | (r << 8);
-
-       switch (mixtable[index].idx) {
-       case H2_MIX_OUTPUT_ATT:
-
-               DEBUG_MIX("output attenuator %d,%d\n", l, r);
-
-               if (r | l) {
-                       tmp = hal2_i_look32(hal2, H2I_DAC_C2);
-                       tmp &= ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
-
-                       /* Attenuator has five bits */
-                       l = 31 * (100 - l) / 99;
-                       r = 31 * (100 - r) / 99;
-
-                       DEBUG_MIX("left: %d, right %d\n", l, r);
-
-                       tmp |= (l << H2I_C2_L_ATT_SHIFT) & H2I_C2_L_ATT_M;
-                       tmp |= (r << H2I_C2_R_ATT_SHIFT) & H2I_C2_R_ATT_M;
-                       hal2_i_write32(hal2, H2I_DAC_C2, tmp);
-               } else 
-                       hal2_i_setbit32(hal2, H2I_DAC_C2, H2I_C2_MUTE);
-               break;
-       case H2_MIX_INPUT_GAIN:
-
-               DEBUG_MIX("input gain %d,%d\n", l, r);
-
-               tmp = hal2_i_look32(hal2, H2I_ADC_C2);
-               tmp &= ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M);
-
-               /* Gain control has four bits */
-               l = 16 * l / 100;
-               r = 16 * r / 100;
-
-               DEBUG_MIX("left: %d, right %d\n", l, r);
-
-               tmp |= (l << H2I_C2_L_GAIN_SHIFT) & H2I_C2_L_GAIN_M;
-               tmp |= (r << H2I_C2_R_GAIN_SHIFT) & H2I_C2_R_GAIN_M;
-               hal2_i_write32(hal2, H2I_ADC_C2, tmp);
-
-               break;
-       }
-
-       return 0;
-}
-
-static void hal2_init_mixer(struct hal2_card *hal2)
-{
-       int i;
-
-       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-               if (mixtable[i].avail)
-                       hal2->mixer.volume[mixtable[i].idx] = 100 | (100 << 8);
-
-       /* disable attenuator */
-       hal2_i_write32(hal2, H2I_DAC_C2, 0);
-       /* set max input gain */
-       hal2_i_write32(hal2, H2I_ADC_C2, H2I_C2_MUTE |
-                       (H2I_C2_L_GAIN_M << H2I_C2_L_GAIN_SHIFT) |
-                       (H2I_C2_R_GAIN_M << H2I_C2_R_GAIN_SHIFT));
-       /* set max volume */
-       hal2->mixer.master = 0xff;
-       hal2->vol_regs->left = 0xff;
-       hal2->vol_regs->right = 0xff;
-}
-
-/*
- * XXX: later i'll implement mixer for main volume which will be disabled
- * by default. enabling it users will be allowed to have master volume level
- * control on panel in their favourite X desktop
- */
-static void hal2_volume_control(int direction)
-{
-       unsigned int master = hal2_card[0]->mixer.master;
-       struct hal2_vol_regs *vol = hal2_card[0]->vol_regs;
-
-       /* volume up */
-       if (direction > 0 && master < 0xff)
-               master++;
-       /* volume down */
-       else if (direction < 0 && master > 0)
-               master--;
-       /* TODO: mute/unmute */
-       vol->left = master;
-       vol->right = master;
-       hal2_card[0]->mixer.master = master;
-}
-
-static int hal2_mixer_ioctl(struct hal2_card *hal2, unsigned int cmd,
-                           unsigned long arg)
-{
-       int val;
-
-        if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-
-               memset(&info, 0, sizeof(info));
-               strlcpy(info.id, hal2str, sizeof(info.id));
-               strlcpy(info.name, hal2str, sizeof(info.name));
-               info.modify_counter = hal2->mixer.modcnt;
-               if (copy_to_user((void *)arg, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-
-               memset(&info, 0, sizeof(info));
-               strlcpy(info.id, hal2str, sizeof(info.id));
-               strlcpy(info.name, hal2str, sizeof(info.name));
-               if (copy_to_user((void *)arg, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, (int *)arg);
-
-       if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-
-        if (_IOC_DIR(cmd) == _IOC_READ) {
-                switch (_IOC_NR(cmd)) {
-               /* Give the current record source */
-               case SOUND_MIXER_RECSRC:
-                       val = 0;        /* FIXME */
-                       break;
-               /* Give the supported mixers, all of them support stereo */
-                case SOUND_MIXER_DEVMASK:
-                case SOUND_MIXER_STEREODEVS: {
-                       int i;
-
-                       for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-                               if (mixtable[i].avail)
-                                       val |= 1 << i;
-                       break;
-                       }
-               /* Arg contains a bit for each supported recording source */
-                case SOUND_MIXER_RECMASK:
-                       val = 0;
-                       break;
-                case SOUND_MIXER_CAPS:
-                       val = 0;
-                       break;
-               /* Read a specific mixer */
-               default: {
-                       int i = _IOC_NR(cmd);
-
-                       if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
-                               return -EINVAL;
-                       val = hal2->mixer.volume[mixtable[i].idx];
-                       break;
-                       }
-               }
-               return put_user(val, (int *)arg);
-       }
-
-        if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
-               return -EINVAL;
-
-       hal2->mixer.modcnt++;
-
-       if (get_user(val, (int *)arg))
-               return -EFAULT;
-
-       switch (_IOC_NR(cmd)) {
-       /* Arg contains a bit for each recording source */
-       case SOUND_MIXER_RECSRC:
-               return 0;       /* FIXME */
-       default:
-               return hal2_write_mixer(hal2, _IOC_NR(cmd), val);
-       }
-
-       return 0;
-}
-
-static int hal2_open_mixdev(struct inode *inode, struct file *file)
-{
-       struct hal2_card *hal2 = hal2_mixer_find_card(iminor(inode));
-
-       if (hal2) {
-               file->private_data = hal2;
-               return nonseekable_open(inode, file);
-       }
-       return -ENODEV;
-}
-
-static int hal2_release_mixdev(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int hal2_ioctl_mixdev(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg)
-{
-       return hal2_mixer_ioctl((struct hal2_card *)file->private_data, cmd, arg);
-}
-
-static int hal2_ioctl(struct inode *inode, struct file *file, 
-                     unsigned int cmd, unsigned long arg)
-{
-       int val;
-       struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, (int *)arg);
-
-       case SNDCTL_DSP_SYNC:
-               if (file->f_mode & FMODE_WRITE)
-                       return hal2_sync_dac(hal2);
-               return 0;
-
-       case SNDCTL_DSP_SETDUPLEX:
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_MULTI, (int *)arg);
-
-       case SNDCTL_DSP_RESET:
-               if (file->f_mode & FMODE_READ) {
-                       hal2_stop_adc(hal2);
-                       hal2_reset_adc_pointer(hal2);
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       hal2_stop_dac(hal2);
-                       hal2_reset_dac_pointer(hal2);
-               }
-               return 0;
-
-       case SNDCTL_DSP_SPEED:
-               if (get_user(val, (int *)arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       hal2_stop_adc(hal2);
-                       val = hal2_compute_rate(&hal2->adc, val);
-                       hal2->adc.sample_rate = val;
-                       hal2_set_adc_rate(hal2);
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       hal2_stop_dac(hal2);
-                       val = hal2_compute_rate(&hal2->dac, val);
-                       hal2->dac.sample_rate = val;
-                       hal2_set_dac_rate(hal2);
-               }
-               return put_user(val, (int *)arg);
-
-       case SNDCTL_DSP_STEREO:
-               if (get_user(val, (int *)arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       hal2_stop_adc(hal2);
-                       hal2->adc.voices = (val) ? 2 : 1;
-                       hal2_setup_adc(hal2);
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       hal2_stop_dac(hal2);
-                       hal2->dac.voices = (val) ? 2 : 1;
-                       hal2_setup_dac(hal2);
-                }
-               return 0;
-
-       case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, (int *)arg))
-                       return -EFAULT;
-               if (val != 0) {
-                       if (file->f_mode & FMODE_READ) {
-                               hal2_stop_adc(hal2);
-                               hal2->adc.voices = (val == 1) ? 1 : 2;
-                               hal2_setup_adc(hal2);
-                       }
-                       if (file->f_mode & FMODE_WRITE) {
-                               hal2_stop_dac(hal2);
-                               hal2->dac.voices = (val == 1) ? 1 : 2;
-                               hal2_setup_dac(hal2);
-                       }
-               }
-               val = -EINVAL;
-               if (file->f_mode & FMODE_READ)
-                       val = hal2->adc.voices;
-               if (file->f_mode & FMODE_WRITE)
-                       val = hal2->dac.voices;
-               return put_user(val, (int *)arg);
-
-       case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(H2_SUPPORTED_FORMATS, (int *)arg);
-
-       case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-               if (get_user(val, (int *)arg))
-                       return -EFAULT;
-               if (val != AFMT_QUERY) {
-                       if (!(val & H2_SUPPORTED_FORMATS))
-                               return -EINVAL;
-                       if (file->f_mode & FMODE_READ) {
-                               hal2_stop_adc(hal2);
-                               hal2->adc.format = val;
-                               hal2_setup_adc(hal2);
-                       }
-                       if (file->f_mode & FMODE_WRITE) {
-                               hal2_stop_dac(hal2);
-                               hal2->dac.format = val;
-                               hal2_setup_dac(hal2);
-                       }
-               } else {
-                       val = -EINVAL;
-                       if (file->f_mode & FMODE_READ)
-                               val = hal2->adc.format;
-                       if (file->f_mode & FMODE_WRITE)
-                               val = hal2->dac.format;
-               }
-               return put_user(val, (int *)arg);
-
-       case SNDCTL_DSP_POST:
-               return 0;
-
-       case SNDCTL_DSP_GETOSPACE: {
-               audio_buf_info info;
-               int i;
-               unsigned long flags;
-               struct hal2_codec *dac = &hal2->dac;
-
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               info.fragments = 0;
-               spin_lock_irqsave(&dac->lock, flags);
-               for (i = 0; i < dac->desc_count; i++)
-                       if (dac->desc[i].cnt == 0)
-                               info.fragments++;
-               spin_unlock_irqrestore(&dac->lock, flags);
-               info.fragstotal = dac->desc_count;
-               info.fragsize = H2_BLOCK_SIZE;
-                info.bytes = info.fragsize * info.fragments;
-
-               return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-       }
-
-       case SNDCTL_DSP_GETISPACE: {
-               audio_buf_info info;
-               int i;
-               unsigned long flags;
-               struct hal2_codec *adc = &hal2->adc;
-
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               info.fragments = 0;
-               info.bytes = 0;
-               spin_lock_irqsave(&adc->lock, flags);
-               for (i = 0; i < adc->desc_count; i++)
-                       if (adc->desc[i].cnt > 0) {
-                               info.fragments++;
-                               info.bytes += adc->desc[i].cnt;
-                       }
-               spin_unlock_irqrestore(&adc->lock, flags);
-               info.fragstotal = adc->desc_count;
-               info.fragsize = H2_BLOCK_SIZE;
-
-               return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-       }
-
-       case SNDCTL_DSP_NONBLOCK:
-               file->f_flags |= O_NONBLOCK;
-               return 0;
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               return put_user(H2_BLOCK_SIZE, (int *)arg);
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               return 0;
-
-       case SOUND_PCM_READ_RATE:
-               val = -EINVAL;
-               if (file->f_mode & FMODE_READ)
-                       val = hal2->adc.sample_rate;
-               if (file->f_mode & FMODE_WRITE)
-                       val = hal2->dac.sample_rate;
-               return put_user(val, (int *)arg);
-
-       case SOUND_PCM_READ_CHANNELS:
-               val = -EINVAL;
-               if (file->f_mode & FMODE_READ)
-                       val = hal2->adc.voices;
-               if (file->f_mode & FMODE_WRITE)
-                       val = hal2->dac.voices;
-               return put_user(val, (int *)arg);
-
-       case SOUND_PCM_READ_BITS:
-               return put_user(16, (int *)arg);
-       }
-
-       return hal2_mixer_ioctl(hal2, cmd, arg);
-}
-
-static ssize_t hal2_read(struct file *file, char *buffer,
-                        size_t count, loff_t *ppos)
-{
-       ssize_t err;
-       struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-       struct hal2_codec *adc = &hal2->adc;
-
-       if (!count)
-               return 0;
-       if (mutex_lock_interruptible(&adc->sem))
-               return -EINTR;
-       if (file->f_flags & O_NONBLOCK) {
-               err = hal2_get_buffer(hal2, buffer, count);
-               err = err == 0 ? -EAGAIN : err;
-       } else {
-               do {
-                       /* ~10% longer */
-                       signed long timeout = 1000 * H2_BLOCK_SIZE *
-                               2 * adc->voices * HZ / adc->sample_rate / 900;
-                       unsigned long flags;
-                       DECLARE_WAITQUEUE(wait, current);
-                       ssize_t cnt = 0;
-
-                       err = hal2_get_buffer(hal2, buffer, count);
-                       if (err > 0) {
-                               count -= err;
-                               cnt += err;
-                               buffer += err;
-                               err = cnt;
-                       }
-                       if (count > 0 && err >= 0) {
-                               add_wait_queue(&adc->dma_wait, &wait);
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               schedule_timeout(timeout);
-                               spin_lock_irqsave(&adc->lock, flags);
-                               if (!adc->desc[adc->tail].cnt)
-                                       err = -EAGAIN;
-                               spin_unlock_irqrestore(&adc->lock, flags);
-                               if (signal_pending(current))
-                                       err = -ERESTARTSYS;
-                               remove_wait_queue(&adc->dma_wait, &wait);
-                               if (err < 0) {
-                                       hal2_stop_adc(hal2);
-                                       hal2_reset_adc_pointer(hal2);
-                               }
-                       }
-               } while (count > 0 && err >= 0);
-       }
-       mutex_unlock(&adc->sem);
-
-       return err;
-}
-
-static ssize_t hal2_write(struct file *file, const char *buffer,
-                         size_t count, loff_t *ppos)
-{
-       ssize_t err;
-       char *buf = (char*) buffer;
-       struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-       struct hal2_codec *dac = &hal2->dac;
-
-       if (!count)
-               return 0;
-       if (mutex_lock_interruptible(&dac->sem))
-               return -EINTR;
-       if (file->f_flags & O_NONBLOCK) {
-               err = hal2_add_buffer(hal2, buf, count);
-               err = err == 0 ? -EAGAIN : err;
-       } else {
-               do {
-                       /* ~10% longer */
-                       signed long timeout = 1000 * H2_BLOCK_SIZE *
-                               2 * dac->voices * HZ / dac->sample_rate / 900;
-                       unsigned long flags;
-                       DECLARE_WAITQUEUE(wait, current);
-                       ssize_t cnt = 0;
-
-                       err = hal2_add_buffer(hal2, buf, count);
-                       if (err > 0) {
-                               count -= err;
-                               cnt += err;
-                               buf += err;
-                               err = cnt;
-                       }
-                       if (count > 0 && err >= 0) {
-                               add_wait_queue(&dac->dma_wait, &wait);
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               schedule_timeout(timeout);
-                               spin_lock_irqsave(&dac->lock, flags);
-                               if (dac->desc[dac->head].cnt)
-                                       err = -EAGAIN;
-                               spin_unlock_irqrestore(&dac->lock, flags);
-                               if (signal_pending(current))
-                                       err = -ERESTARTSYS;
-                               remove_wait_queue(&dac->dma_wait, &wait);
-                               if (err < 0) {
-                                       hal2_stop_dac(hal2);
-                                       hal2_reset_dac_pointer(hal2);
-                               }
-                       }
-               } while (count > 0 && err >= 0);
-       }
-       mutex_unlock(&dac->sem);
-
-       return err;
-}
-
-static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait)
-{
-       unsigned long flags;
-       unsigned int mask = 0;
-       struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
-       if (file->f_mode & FMODE_READ) {
-               struct hal2_codec *adc = &hal2->adc;
-
-               poll_wait(file, &adc->dma_wait, wait);
-               spin_lock_irqsave(&adc->lock, flags);
-               if (adc->desc[adc->tail].cnt > 0)
-                       mask |= POLLIN;
-               spin_unlock_irqrestore(&adc->lock, flags);
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               struct hal2_codec *dac = &hal2->dac;
-
-               poll_wait(file, &dac->dma_wait, wait);
-               spin_lock_irqsave(&dac->lock, flags);
-               if (dac->desc[dac->head].cnt == 0)
-                       mask |= POLLOUT;
-               spin_unlock_irqrestore(&dac->lock, flags);
-       }
-
-       return mask;
-}
-
-static int hal2_open(struct inode *inode, struct file *file)
-{
-       int err;
-       struct hal2_card *hal2 = hal2_dsp_find_card(iminor(inode));
-
-       if (!hal2)
-               return -ENODEV;
-       file->private_data = hal2;
-       if (file->f_mode & FMODE_READ) {
-               struct hal2_codec *adc = &hal2->adc;
-
-               if (adc->usecount)
-                       return -EBUSY;
-               /* OSS spec wanted us to use 8 bit, 8 kHz mono by default,
-                * but HAL2 can't do 8bit audio */
-               adc->format = AFMT_S16_BE;
-               adc->voices = 1;
-               adc->sample_rate = hal2_compute_rate(adc, 8000);
-               hal2_set_adc_rate(hal2);
-               err = hal2_alloc_adc_dmabuf(adc);
-               if (err)
-                       return err;
-               hal2_setup_adc(hal2);
-               adc->usecount++;
-       }
-       if (file->f_mode & FMODE_WRITE) {
-               struct hal2_codec *dac = &hal2->dac;
-
-               if (dac->usecount)
-                       return -EBUSY;
-               dac->format = AFMT_S16_BE;
-               dac->voices = 1;
-               dac->sample_rate = hal2_compute_rate(dac, 8000);
-               hal2_set_dac_rate(hal2);
-               err = hal2_alloc_dac_dmabuf(dac);
-               if (err)
-                       return err;
-               hal2_setup_dac(hal2);
-               dac->usecount++;
-       }
-
-       return nonseekable_open(inode, file);
-}
-
-static int hal2_release(struct inode *inode, struct file *file)
-{
-       struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
-       if (file->f_mode & FMODE_READ) {
-               struct hal2_codec *adc = &hal2->adc;
-
-               mutex_lock(&adc->sem);
-               hal2_stop_adc(hal2);
-               hal2_free_adc_dmabuf(adc);
-               adc->usecount--;
-               mutex_unlock(&adc->sem);
-       }
-       if (file->f_mode & FMODE_WRITE) {
-               struct hal2_codec *dac = &hal2->dac;
-
-               mutex_lock(&dac->sem);
-               hal2_sync_dac(hal2);
-               hal2_free_dac_dmabuf(dac);
-               dac->usecount--;
-               mutex_unlock(&dac->sem);
-       }
-
-       return 0;
-}
-
-static const struct file_operations hal2_audio_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .read           = hal2_read,
-       .write          = hal2_write,
-       .poll           = hal2_poll,
-       .ioctl          = hal2_ioctl,
-       .open           = hal2_open,
-       .release        = hal2_release,
-};
-
-static const struct file_operations hal2_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .ioctl          = hal2_ioctl_mixdev,
-       .open           = hal2_open_mixdev,
-       .release        = hal2_release_mixdev,
-};
-
-static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3,
-                           int index)
-{
-       codec->pbus.pbusnr = index;
-       codec->pbus.pbus = &hpc3->pbdma[index];
-       init_waitqueue_head(&codec->dma_wait);
-       mutex_init(&codec->sem);
-       spin_lock_init(&codec->lock);
-}
-
-static int hal2_detect(struct hal2_card *hal2)
-{
-       unsigned short board, major, minor;
-       unsigned short rev;
-
-       /* reset HAL2 */
-       hal2_isr_write(hal2, 0);
-       /* release reset */
-       hal2_isr_write(hal2, H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N);
-
-       hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); 
-       if ((rev = hal2_rev_look(hal2)) & H2_REV_AUDIO_PRESENT)
-               return -ENODEV;
-
-       board = (rev & H2_REV_BOARD_M) >> 12;
-       major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;
-       minor = (rev & H2_REV_MINOR_CHIP_M);
-
-       printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n",
-              board, major, minor);
-
-       return 0;
-}
-
-static int hal2_init_card(struct hal2_card **phal2, struct hpc3_regs *hpc3)
-{
-       int ret = 0;
-       struct hal2_card *hal2;
-
-       hal2 = kzalloc(sizeof(struct hal2_card), GFP_KERNEL);
-       if (!hal2)
-               return -ENOMEM;
-
-       hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0];
-       hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1];
-       hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2];
-       hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3];
-
-       if (hal2_detect(hal2) < 0) {
-               ret = -ENODEV;
-               goto free_card;
-       }
-
-       hal2_init_codec(&hal2->dac, hpc3, 0);
-       hal2_init_codec(&hal2->adc, hpc3, 1);
-
-       /*
-        * All DMA channel interfaces in HAL2 are designed to operate with
-        * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles
-        * in D5. HAL2 is a 16-bit device which can accept both big and little
-        * endian format. It assumes that even address bytes are on high
-        * portion of PBUS (15:8) and assumes that HPC3 is programmed to
-        * accept a live (unsynchronized) version of P_DREQ_N from HAL2.
-        */
-#define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \
-                         (2 << HPC3_DMACFG_D4R_SHIFT) | \
-                         (2 << HPC3_DMACFG_D5R_SHIFT) | \
-                         (0 << HPC3_DMACFG_D3W_SHIFT) | \
-                         (2 << HPC3_DMACFG_D4W_SHIFT) | \
-                         (2 << HPC3_DMACFG_D5W_SHIFT) | \
-                               HPC3_DMACFG_DS16 | \
-                               HPC3_DMACFG_EVENHI | \
-                               HPC3_DMACFG_RTIME | \
-                         (8 << HPC3_DMACFG_BURST_SHIFT) | \
-                               HPC3_DMACFG_DRQLIVE)
-       /*
-        * Ignore what's mentioned in the specification and write value which
-        * works in The Real World (TM)
-        */
-       hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844;
-       hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844;
-
-       if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED,
-                       hal2str, hal2)) {
-               printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ);
-               ret = -EAGAIN;
-               goto free_card;
-       }
-
-       hal2->dev_dsp = register_sound_dsp(&hal2_audio_fops, -1);
-       if (hal2->dev_dsp < 0) {
-               ret = hal2->dev_dsp;
-               goto free_irq;
-       }
-
-       hal2->dev_mixer = register_sound_mixer(&hal2_mixer_fops, -1);
-       if (hal2->dev_mixer < 0) {
-               ret = hal2->dev_mixer;
-               goto unregister_dsp;
-       }
-
-       hal2_init_mixer(hal2);
-
-       *phal2 = hal2;
-       return 0;
-unregister_dsp:
-       unregister_sound_dsp(hal2->dev_dsp);
-free_irq:
-       free_irq(SGI_HPCDMA_IRQ, hal2);
-free_card:
-       kfree(hal2);
-
-       return ret;
-}
-
-extern void (*indy_volume_button)(int);
-
-/* 
- * Assuming only one HAL2 card. Mail me if you ever meet machine with
- * more than one.
- */
-static int __init init_hal2(void)
-{
-       int i, error;
-
-       for (i = 0; i < MAXCARDS; i++)
-               hal2_card[i] = NULL;
-
-       error = hal2_init_card(&hal2_card[0], hpc3c0);
-
-       /* let Indy's volume buttons work */
-       if (!error && !ip22_is_fullhouse())
-               indy_volume_button = hal2_volume_control;
-
-       return error;
-
-}
-
-static void __exit exit_hal2(void)
-{
-       int i;
-
-       /* unregister volume butons callback function */
-       indy_volume_button = NULL;
-       
-       for (i = 0; i < MAXCARDS; i++)
-               if (hal2_card[i]) {
-                       free_irq(SGI_HPCDMA_IRQ, hal2_card[i]);
-                       unregister_sound_dsp(hal2_card[i]->dev_dsp);
-                       unregister_sound_mixer(hal2_card[i]->dev_mixer);
-                       kfree(hal2_card[i]);
-       }
-}
-
-module_init(init_hal2);
-module_exit(exit_hal2);
-
-MODULE_DESCRIPTION("OSS compatible driver for SGI HAL2 audio");
-MODULE_AUTHOR("Ladislav Michl");
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/hal2.h b/sound/oss/hal2.h
deleted file mode 100644 (file)
index 2bd3b52..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#ifndef __HAL2_H
-#define __HAL2_H
-
-/*
- *  Driver for HAL2 sound processors
- *  Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se>
- *  Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
- *
- *  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.
- *
- *  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.
- *
- */
-
-#include <asm/addrspace.h>
-#include <asm/sgi/hpc3.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/* Indirect status register */
-
-#define H2_ISR_TSTATUS         0x01    /* RO: transaction status 1=busy */
-#define H2_ISR_USTATUS         0x02    /* RO: utime status bit 1=armed */
-#define H2_ISR_QUAD_MODE       0x04    /* codec mode 0=indigo 1=quad */
-#define H2_ISR_GLOBAL_RESET_N  0x08    /* chip global reset 0=reset */
-#define H2_ISR_CODEC_RESET_N   0x10    /* codec/synth reset 0=reset  */
-
-/* Revision register */
-
-#define H2_REV_AUDIO_PRESENT   0x8000  /* RO: audio present 0=present */
-#define H2_REV_BOARD_M         0x7000  /* RO: bits 14:12, board revision */
-#define H2_REV_MAJOR_CHIP_M    0x00F0  /* RO: bits 7:4, major chip revision */
-#define H2_REV_MINOR_CHIP_M    0x000F  /* RO: bits 3:0, minor chip revision */
-
-/* Indirect address register */
-
-/*
- * Address of indirect internal register to be accessed. A write to this
- * register initiates read or write access to the indirect registers in the
- * HAL2. Note that there af four indirect data registers for write access to
- * registers larger than 16 byte.
- */
-
-#define H2_IAR_TYPE_M          0xF000  /* bits 15:12, type of functional */
-                                       /* block the register resides in */
-                                       /* 1=DMA Port */
-                                       /* 9=Global DMA Control */
-                                       /* 2=Bresenham */
-                                       /* 3=Unix Timer */
-#define H2_IAR_NUM_M           0x0F00  /* bits 11:8 instance of the */
-                                       /* blockin which the indirect */
-                                       /* register resides */
-                                       /* If IAR_TYPE_M=DMA Port: */
-                                       /* 1=Synth In */
-                                       /* 2=AES In */
-                                       /* 3=AES Out */
-                                       /* 4=DAC Out */
-                                       /* 5=ADC Out */
-                                       /* 6=Synth Control */
-                                       /* If IAR_TYPE_M=Global DMA Control: */
-                                       /* 1=Control */
-                                       /* If IAR_TYPE_M=Bresenham: */
-                                       /* 1=Bresenham Clock Gen 1 */
-                                       /* 2=Bresenham Clock Gen 2 */
-                                       /* 3=Bresenham Clock Gen 3 */
-                                       /* If IAR_TYPE_M=Unix Timer: */
-                                       /* 1=Unix Timer */
-#define H2_IAR_ACCESS_SELECT   0x0080  /* 1=read 0=write */
-#define H2_IAR_PARAM           0x000C  /* Parameter Select */
-#define H2_IAR_RB_INDEX_M      0x0003  /* Read Back Index */
-                                       /* 00:word0 */
-                                       /* 01:word1 */
-                                       /* 10:word2 */
-                                       /* 11:word3 */
-/*
- * HAL2 internal addressing
- *
- * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
- * Indirect Data registers. Write the address to the Indirect Address register
- * to transfer the data.
- *
- * We define the H2IR_* to the read address and H2IW_* to the write address and
- * H2I_* to be fields in whatever register is referred to.
- *
- * When we write to indirect registers which are larger than one word (16 bit)
- * we have to fill more than one indirect register before writing. When we read
- * back however we have to read several times, each time with different Read
- * Back Indexes (there are defs for doing this easily).
- */
-
-/*
- * Relay Control
- */
-#define H2I_RELAY_C            0x9100
-#define H2I_RELAY_C_STATE      0x01            /* state of RELAY pin signal */
-
-/* DMA port enable */
-
-#define H2I_DMA_PORT_EN                0x9104
-#define H2I_DMA_PORT_EN_SY_IN  0x01            /* Synth_in DMA port */
-#define H2I_DMA_PORT_EN_AESRX  0x02            /* AES receiver DMA port */
-#define H2I_DMA_PORT_EN_AESTX  0x04            /* AES transmitter DMA port */
-#define H2I_DMA_PORT_EN_CODECTX        0x08            /* CODEC transmit DMA port */
-#define H2I_DMA_PORT_EN_CODECR 0x10            /* CODEC receive DMA port */
-
-#define H2I_DMA_END            0x9108          /* global dma endian select */
-#define H2I_DMA_END_SY_IN      0x01            /* Synth_in DMA port */
-#define H2I_DMA_END_AESRX      0x02            /* AES receiver DMA port */
-#define H2I_DMA_END_AESTX      0x04            /* AES transmitter DMA port */
-#define H2I_DMA_END_CODECTX    0x08            /* CODEC transmit DMA port */
-#define H2I_DMA_END_CODECR     0x10            /* CODEC receive DMA port */
-                                               /* 0=b_end 1=l_end */
-
-#define H2I_DMA_DRV            0x910C          /* global PBUS DMA enable */
-
-#define H2I_SYNTH_C            0x1104          /* Synth DMA control */
-
-#define H2I_AESRX_C            0x1204          /* AES RX dma control */
-
-#define H2I_C_TS_EN            0x20            /* Timestamp enable */
-#define H2I_C_TS_FRMT          0x40            /* Timestamp format */
-#define H2I_C_NAUDIO           0x80            /* Sign extend */
-
-/* AESRX CTL, 16 bit */
-
-#define H2I_AESTX_C            0x1304          /* AES TX DMA control */
-#define H2I_AESTX_C_CLKID_SHIFT        3               /* Bresenham Clock Gen 1-3 */
-#define H2I_AESTX_C_CLKID_M    0x18
-#define H2I_AESTX_C_DATAT_SHIFT        8               /* 1=mono 2=stereo (3=quad) */
-#define H2I_AESTX_C_DATAT_M    0x300
-
-/* CODEC registers */
-
-#define H2I_DAC_C1             0x1404          /* DAC DMA control, 16 bit */
-#define H2I_DAC_C2             0x1408          /* DAC DMA control, 32 bit */
-#define H2I_ADC_C1             0x1504          /* ADC DMA control, 16 bit */
-#define H2I_ADC_C2             0x1508          /* ADC DMA control, 32 bit */
-
-/* Bits in CTL1 register */
-
-#define H2I_C1_DMA_SHIFT       0               /* DMA channel */
-#define H2I_C1_DMA_M           0x7
-#define H2I_C1_CLKID_SHIFT     3               /* Bresenham Clock Gen 1-3 */
-#define H2I_C1_CLKID_M         0x18
-#define H2I_C1_DATAT_SHIFT     8               /* 1=mono 2=stereo (3=quad) */
-#define H2I_C1_DATAT_M         0x300
-
-/* Bits in CTL2 register */
-
-#define H2I_C2_R_GAIN_SHIFT    0               /* right a/d input gain */      
-#define H2I_C2_R_GAIN_M                0xf     
-#define H2I_C2_L_GAIN_SHIFT    4               /* left a/d input gain */
-#define H2I_C2_L_GAIN_M                0xf0
-#define H2I_C2_R_SEL           0x100           /* right input select */
-#define H2I_C2_L_SEL           0x200           /* left input select */
-#define H2I_C2_MUTE            0x400           /* mute */
-#define H2I_C2_DO1             0x00010000      /* digital output port bit 0 */
-#define H2I_C2_DO2             0x00020000      /* digital output port bit 1 */
-#define H2I_C2_R_ATT_SHIFT     18              /* right d/a output - */
-#define H2I_C2_R_ATT_M         0x007c0000      /* attenuation */
-#define H2I_C2_L_ATT_SHIFT     23              /* left d/a output - */
-#define H2I_C2_L_ATT_M         0x0f800000      /* attenuation */
-
-#define H2I_SYNTH_MAP_C                0x1104          /* synth dma handshake ctrl */
-
-/* Clock generator CTL 1, 16 bit */
-
-#define H2I_BRES1_C1           0x2104
-#define H2I_BRES2_C1           0x2204
-#define H2I_BRES3_C1           0x2304
-
-#define H2I_BRES_C1_SHIFT      0               /* 0=48.0 1=44.1 2=aes_rx */
-#define H2I_BRES_C1_M          0x03
-                               
-/* Clock generator CTL 2, 32 bit */
-
-#define H2I_BRES1_C2           0x2108
-#define H2I_BRES2_C2           0x2208
-#define H2I_BRES3_C2           0x2308
-
-#define H2I_BRES_C2_INC_SHIFT  0               /* increment value */
-#define H2I_BRES_C2_INC_M      0xffff
-#define H2I_BRES_C2_MOD_SHIFT  16              /* modcontrol value */
-#define H2I_BRES_C2_MOD_M      0xffff0000      /* modctrl=0xffff&(modinc-1) */
-
-/* Unix timer, 64 bit */
-
-#define H2I_UTIME              0x3104
-#define H2I_UTIME_0_LD         0xffff          /* microseconds, LSB's */
-#define H2I_UTIME_1_LD0                0x0f            /* microseconds, MSB's */
-#define H2I_UTIME_1_LD1                0xf0            /* tenths of microseconds */
-#define H2I_UTIME_2_LD         0xffff          /* seconds, LSB's */
-#define H2I_UTIME_3_LD         0xffff          /* seconds, MSB's */
-
-struct hal2_ctl_regs {
-       u32 _unused0[4];
-       volatile u32 isr;               /* 0x10 Status Register */
-       u32 _unused1[3];
-       volatile u32 rev;               /* 0x20 Revision Register */
-       u32 _unused2[3];
-       volatile u32 iar;               /* 0x30 Indirect Address Register */
-       u32 _unused3[3];
-       volatile u32 idr0;              /* 0x40 Indirect Data Register 0 */
-       u32 _unused4[3];
-       volatile u32 idr1;              /* 0x50 Indirect Data Register 1 */
-       u32 _unused5[3];
-       volatile u32 idr2;              /* 0x60 Indirect Data Register 2 */
-       u32 _unused6[3];
-       volatile u32 idr3;              /* 0x70 Indirect Data Register 3 */
-};
-
-struct hal2_aes_regs {
-       volatile u32 rx_stat[2];        /* Status registers */
-       volatile u32 rx_cr[2];          /* Control registers */
-       volatile u32 rx_ud[4];          /* User data window */
-       volatile u32 rx_st[24];         /* Channel status data */
-       
-       volatile u32 tx_stat[1];        /* Status register */
-       volatile u32 tx_cr[3];          /* Control registers */
-       volatile u32 tx_ud[4];          /* User data window */
-       volatile u32 tx_st[24];         /* Channel status data */
-};
-
-struct hal2_vol_regs {
-       volatile u32 right;             /* Right volume */
-       volatile u32 left;              /* Left volume */
-};
-
-struct hal2_syn_regs {
-       u32 _unused0[2];
-       volatile u32 page;              /* DOC Page register */
-       volatile u32 regsel;            /* DOC Register selection */
-       volatile u32 dlow;              /* DOC Data low */
-       volatile u32 dhigh;             /* DOC Data high */
-       volatile u32 irq;               /* IRQ Status */
-       volatile u32 dram;              /* DRAM Access */
-};
-
-#endif /* __HAL2_H */
index a690ca57adb50e349255c321f1d22bbaacd6e40b..6c0a770ed0543d62bdc26203244c1e730a106110 100644 (file)
@@ -1015,7 +1015,7 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
                mpu401_chk_version(m, devc);
                if (devc->version == 0)
                        mpu401_chk_version(m, devc);
-                       spin_unlock_irqrestore(&devc->lock,flags);
+               spin_unlock_irqrestore(&devc->lock, flags);
        }
 
        if (devc->version != 0)
index 99f5483abf2e7efb006a01928edb3b64d0dcf886..41f870f8a11d21390e1caa473326d659274e28fc 100644 (file)
@@ -868,7 +868,8 @@ snd_harmony_mixer_init(struct snd_harmony *h)
        struct snd_card *card = h->card;
        int idx, err;
 
-       snd_assert(h != NULL, return -EINVAL);
+       if (snd_BUG_ON(!h))
+               return -EINVAL;
        strcpy(card->mixername, "Harmony Gain control interface");
 
        for (idx = 0; idx < HARMONY_CONTROLS; idx++) {
index 31f52d3fc21f9bce9793b316b2228ad23414faa3..7003711f4fcc4165d6e5a24f7fb3be2c55ea91cb 100644 (file)
@@ -517,6 +517,14 @@ config SND_HDA_HWDEP
          This interface can be used for out-of-band communication
          with codecs for debugging purposes.
 
+config SND_HDA_INPUT_BEEP
+       bool "Support digital beep via input layer"
+       depends on SND_HDA_INTEL
+       depends on INPUT=y || INPUT=SND_HDA_INTEL
+       help
+         Say Y here to build a digital beep interface for HD-audio
+         driver. This interface is used to generate digital beeps.
+
 config SND_HDA_CODEC_REALTEK
        bool "Build Realtek HD-audio codec support"
        depends on SND_HDA_INTEL
@@ -557,6 +565,14 @@ config SND_HDA_CODEC_ATIHDMI
          Say Y here to include ATI HDMI HD-audio codec support in
          snd-hda-intel driver, such as ATI RS600 HDMI.
 
+config SND_HDA_CODEC_NVHDMI
+       bool "Build NVIDIA HDMI HD-audio codec support"
+       depends on SND_HDA_INTEL
+       default y
+       help
+         Say Y here to include NVIDIA HDMI HD-audio codec support in
+         snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
+
 config SND_HDA_CODEC_CONEXANT
        bool "Build Conexant HD-audio codec support"
        depends on SND_HDA_INTEL
@@ -649,8 +665,9 @@ config SND_ICE1712
 
          Currently supported hardware is: M-Audio Delta 1010(LT),
          DiO 2496, 66, 44, 410, Audiophile 24/96; Digigram VX442;
-         TerraTec EWX 24/96, EWS 88MT, 88D, DMX 6Fire, Phase 88;
-         Hoontech SoundTrack DSP 24/Value/Media7.1; Event EZ8.
+         TerraTec EWX 24/96, EWS 88MT/D, DMX 6Fire, Phase 88;
+         Hoontech SoundTrack DSP 24/Value/Media7.1; Event EZ8;
+         Lionstracs Mediastation, Terrasoniq TS 88.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-ice1712.
@@ -665,9 +682,12 @@ config SND_ICE1724
          ICE/VT1724/1720 (Envy24HT/PT) chips.
 
          Currently supported hardware is: AMP AUDIO2000; M-Audio
-         Revolution 7.1; TerraTec Aureon 5.1 Sky, 7.1 Space/Universe;
-         AudioTrak Prodigy 7.1; Pontis MS300; Albatron K8X800 Pro II;
-         Chaintech ZNF3-150/250.
+         Revolution 5.1, 7.1, Audiophile 192; TerraTec Aureon 5.1 Sky,
+         7.1 Space/Universe, Phase 22/28; Onkyo SE-90PCI, SE-200PCI;
+         AudioTrak Prodigy 192, 7.1 (HIFI/LT/XT), HD2; Hercules
+         Fortissimo IV; ESI Juli@; Pontis MS300; EGO-SYS WaveTerminal
+         192M; Albatron K8X800 Pro II; Chaintech ZNF3-150/250, 9CJS,
+         AV-710; Shuttle SN25P.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-ice1724.
@@ -845,7 +865,8 @@ config SND_VIRTUOSO
        select SND_OXYGEN_LIB
        help
          Say Y here to include support for sound cards based on the
-         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X.
+         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X and
+         HDAV1.3 (Deluxe).
 
          To compile this driver as a module, choose M here: the module
          will be called snd-virtuoso.
index 8c49a00a5e3919d835b3f5d3a6fe0569eafda80d..6704acbca8c08015cd5c67b22d9d9a78f149c072 100644 (file)
@@ -67,8 +67,8 @@ struct ac97_codec_id {
 };
 
 static const struct ac97_codec_id snd_ac97_codec_id_vendors[] = {
-{ 0x414b4d00, 0xffffff00, "Asahi Kasei",       NULL,   NULL },
 { 0x41445300, 0xffffff00, "Analog Devices",    NULL,   NULL },
+{ 0x414b4d00, 0xffffff00, "Asahi Kasei",       NULL,   NULL },
 { 0x414c4300, 0xffffff00, "Realtek",           NULL,   NULL },
 { 0x414c4700, 0xffffff00, "Realtek",           NULL,   NULL },
 { 0x434d4900, 0xffffff00, "C-Media Electronics", NULL, NULL },
@@ -94,11 +94,6 @@ static const struct ac97_codec_id snd_ac97_codec_id_vendors[] = {
 };
 
 static const struct ac97_codec_id snd_ac97_codec_ids[] = {
-{ 0x414b4d00, 0xffffffff, "AK4540",            NULL,           NULL },
-{ 0x414b4d01, 0xffffffff, "AK4542",            NULL,           NULL },
-{ 0x414b4d02, 0xffffffff, "AK4543",            NULL,           NULL },
-{ 0x414b4d06, 0xffffffff, "AK4544A",           NULL,           NULL },
-{ 0x414b4d07, 0xffffffff, "AK4545",            NULL,           NULL },
 { 0x41445303, 0xffffffff, "AD1819",            patch_ad1819,   NULL },
 { 0x41445340, 0xffffffff, "AD1881",            patch_ad1881,   NULL },
 { 0x41445348, 0xffffffff, "AD1881A",           patch_ad1881,   NULL },
@@ -112,20 +107,25 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x41445374, 0xffffffff, "AD1981B",           patch_ad1981b,  NULL },
 { 0x41445375, 0xffffffff, "AD1985",            patch_ad1985,   NULL },
 { 0x41445378, 0xffffffff, "AD1986",            patch_ad1986,   NULL },
+{ 0x414b4d00, 0xffffffff, "AK4540",            NULL,           NULL },
+{ 0x414b4d01, 0xffffffff, "AK4542",            NULL,           NULL },
+{ 0x414b4d02, 0xffffffff, "AK4543",            NULL,           NULL },
+{ 0x414b4d06, 0xffffffff, "AK4544A",           NULL,           NULL },
+{ 0x414b4d07, 0xffffffff, "AK4545",            NULL,           NULL },
 { 0x414c4300, 0xffffff00, "ALC100,100P",       NULL,           NULL },
 { 0x414c4710, 0xfffffff0, "ALC200,200P",       NULL,           NULL },
 { 0x414c4721, 0xffffffff, "ALC650D",           NULL,   NULL }, /* already patched */
 { 0x414c4722, 0xffffffff, "ALC650E",           NULL,   NULL }, /* already patched */
 { 0x414c4723, 0xffffffff, "ALC650F",           NULL,   NULL }, /* already patched */
 { 0x414c4720, 0xfffffff0, "ALC650",            patch_alc650,   NULL },
+{ 0x414c4730, 0xffffffff, "ALC101",            NULL,           NULL },
+{ 0x414c4740, 0xfffffff0, "ALC202",            NULL,           NULL },
+{ 0x414c4750, 0xfffffff0, "ALC250",            NULL,           NULL },
 { 0x414c4760, 0xfffffff0, "ALC655",            patch_alc655,   NULL },
+{ 0x414c4770, 0xfffffff0, "ALC203",            patch_alc203,   NULL },
 { 0x414c4781, 0xffffffff, "ALC658D",           NULL,   NULL }, /* already patched */
 { 0x414c4780, 0xfffffff0, "ALC658",            patch_alc655,   NULL },
 { 0x414c4790, 0xfffffff0, "ALC850",            patch_alc850,   NULL },
-{ 0x414c4730, 0xffffffff, "ALC101",            NULL,           NULL },
-{ 0x414c4740, 0xfffffff0, "ALC202",            NULL,           NULL },
-{ 0x414c4750, 0xfffffff0, "ALC250",            NULL,           NULL },
-{ 0x414c4770, 0xfffffff0, "ALC203",            NULL,           NULL },
 { 0x434d4941, 0xffffffff, "CMI9738",           patch_cm9738,   NULL },
 { 0x434d4961, 0xffffffff, "CMI9739",           patch_cm9739,   NULL },
 { 0x434d4969, 0xffffffff, "CMI9780",           patch_cm9780,   NULL },
@@ -168,7 +168,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
-{ 0x56494182, 0xffffffff, "VIA1618",           NULL,           NULL },
+{ 0x56494182, 0xffffffff, "VIA1618",           patch_vt1618,   NULL },
 { 0x57454301, 0xffffffff, "W83971D",           NULL,           NULL },
 { 0x574d4c00, 0xffffffff, "WM9701,WM9701A",    NULL,           NULL },
 { 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -1890,8 +1890,8 @@ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,
                .dev_free =     snd_ac97_bus_dev_free,
        };
 
-       snd_assert(card != NULL, return -EINVAL);
-       snd_assert(rbus != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card))
+               return -EINVAL;
        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
        if (bus == NULL)
                return -ENOMEM;
@@ -1906,7 +1906,8 @@ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,
                snd_ac97_bus_free(bus);
                return err;
        }
-       *rbus = bus;
+       if (rbus)
+               *rbus = bus;
        return 0;
 }
 
@@ -1991,10 +1992,14 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
                .dev_disconnect =       snd_ac97_dev_disconnect,
        };
 
-       snd_assert(rac97 != NULL, return -EINVAL);
-       *rac97 = NULL;
-       snd_assert(bus != NULL && template != NULL, return -EINVAL);
-       snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL);
+       if (rac97)
+               *rac97 = NULL;
+       if (snd_BUG_ON(!bus || !template))
+               return -EINVAL;
+       if (snd_BUG_ON(template->num >= 4))
+               return -EINVAL;
+       if (bus->codec[template->num])
+               return -EBUSY;
 
        card = bus->card;
        ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL);
index f4fbc795ee8140853305d4297e0818a48e01dd87..6ce3cbe98a6a11d7212cfca404a01a73f6bf26bd 100644 (file)
@@ -2560,6 +2560,14 @@ static int patch_ad1986(struct snd_ac97 * ac97)
        return 0;
 }
 
+/*
+ * realtek ALC203: use mono-out for pin 37
+ */
+static int patch_alc203(struct snd_ac97 *ac97)
+{
+       snd_ac97_update_bits(ac97, 0x7a, 0x400, 0x400);
+       return 0;
+}
 
 /*
  * realtek ALC65x/850 codecs
@@ -3457,7 +3465,7 @@ static int patch_vt1616(struct snd_ac97 * ac97)
 
 /*
  * unfortunately, the vt1617a stashes the twiddlers required for
- * nooding the i/o jacks on 2 different regs. * thameans that we cant
+ * noodling the i/o jacks on 2 different regs. that means that we can't
  * use the easy way provided by AC97_ENUM_DOUBLE() we have to write
  * are own funcs.
  *
@@ -3490,7 +3498,7 @@ static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol,
        
        pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */
 
-       /* grab our desirec bits, then mash them together in a manner
+       /* grab our desired bits, then mash them together in a manner
         * consistent with Table 6 on page 17 in the 1617a docs */
  
        usSM51 = snd_ac97_read(pac97, 0x7a) >> 14;
@@ -3540,7 +3548,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_vt1617a[] = {
        },
 };
 
-int patch_vt1617a(struct snd_ac97 * ac97)
+static int patch_vt1617a(struct snd_ac97 * ac97)
 {
        int err = 0;
        int val;
@@ -3568,6 +3576,200 @@ int patch_vt1617a(struct snd_ac97 * ac97)
        return err;
 }
 
+/* VIA VT1618 8 CHANNEL AC97 CODEC
+ *
+ * VIA implements 'Smart 5.1' completely differently on the 1618 than
+ * it does on the 1617a. awesome! They seem to have sourced this
+ * particular revision of the technology from somebody else, it's
+ * called Universal Audio Jack and it shows up on some other folk's chips
+ * as well.
+ *
+ * ordering in this list reflects vt1618 docs for Reg 60h and
+ * the block diagram, DACs are as follows:
+ *
+ *        OUT_O -> Front,
+ *       OUT_1 -> Surround,
+ *       OUT_2 -> C/LFE
+ *
+ * Unlike the 1617a, each OUT has a consistent set of mappings
+ * for all bitpatterns other than 00:
+ *
+ *        01       Unmixed Output
+ *        10       Line In
+ *        11       Mic  In
+ *
+ * Special Case of 00:
+ *
+ *        OUT_0    Mixed Output
+ *        OUT_1    Reserved
+ *        OUT_2    Reserved
+ *
+ * I have no idea what the hell Reserved does, but on an MSI
+ * CN700T, i have to set it to get 5.1 output - YMMV, bad
+ * shit may happen.
+ *
+ * If other chips use Universal Audio Jack, then this code might be applicable
+ * to them.
+ */
+
+struct vt1618_uaj_item {
+       unsigned short mask;
+       unsigned short shift;
+       const char *items[4];
+};
+
+/* This list reflects the vt1618 docs for Vendor Defined Register 0x60. */
+
+static struct vt1618_uaj_item vt1618_uaj[3] = {
+       {
+               /* speaker jack */
+               .mask  = 0x03,
+               .shift = 0,
+               .items = {
+                       "Speaker Out", "DAC Unmixed Out", "Line In", "Mic In"
+               }
+       },
+       {
+               /* line jack */
+               .mask  = 0x0c,
+               .shift = 2,
+               .items = {
+                       "Surround Out", "DAC Unmixed Out", "Line In", "Mic In"
+               }
+       },
+       {
+               /* mic jack */
+               .mask  = 0x30,
+               .shift = 4,
+               .items = {
+                       "Center LFE Out", "DAC Unmixed Out", "Line In", "Mic In"
+               },
+       },
+};
+
+static int snd_ac97_vt1618_UAJ_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       return ac97_enum_text_info(kcontrol, uinfo,
+                                  vt1618_uaj[kcontrol->private_value].items,
+                                  4);
+}
+
+/* All of the vt1618 Universal Audio Jack twiddlers are on
+ * Vendor Defined Register 0x60, page 0. The bits, and thus
+ * the mask, are the only thing that changes
+ */
+static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       unsigned short datpag, uaj;
+       struct snd_ac97 *pac97 = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&pac97->page_mutex);
+
+       datpag = snd_ac97_read(pac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+       snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, 0);
+
+       uaj = snd_ac97_read(pac97, 0x60) &
+               vt1618_uaj[kcontrol->private_value].mask;
+
+       snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, datpag);
+       mutex_unlock(&pac97->page_mutex);
+
+       ucontrol->value.enumerated.item[0] = uaj >>
+               vt1618_uaj[kcontrol->private_value].shift;
+
+       return 0;
+}
+
+static int snd_ac97_vt1618_UAJ_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       return ac97_update_bits_page(snd_kcontrol_chip(kcontrol), 0x60,
+                                    vt1618_uaj[kcontrol->private_value].mask,
+                                    ucontrol->value.enumerated.item[0]<<
+                                    vt1618_uaj[kcontrol->private_value].shift,
+                                    0);
+}
+
+/* config aux in jack - not found on 3 jack motherboards or soundcards */
+
+static int snd_ac97_vt1618_aux_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       static const char *txt_aux[] = {"Aux In", "Back Surr Out"};
+
+       return ac97_enum_text_info(kcontrol, uinfo, txt_aux, 2);
+}
+
+static int snd_ac97_vt1618_aux_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] =
+               (snd_ac97_read(snd_kcontrol_chip(kcontrol), 0x5c) & 0x0008)>>3;
+       return 0;
+}
+
+static int snd_ac97_vt1618_aux_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       /* toggle surround rear dac power */
+
+       snd_ac97_update_bits(snd_kcontrol_chip(kcontrol), 0x5c, 0x0008,
+                            ucontrol->value.enumerated.item[0] << 3);
+
+       /* toggle aux in surround rear out jack */
+
+       return snd_ac97_update_bits(snd_kcontrol_chip(kcontrol), 0x76, 0x0008,
+                                   ucontrol->value.enumerated.item[0] << 3);
+}
+
+static const struct snd_kcontrol_new snd_ac97_controls_vt1618[] = {
+       AC97_SINGLE("Exchange Center/LFE", 0x5a,  8, 1,     0),
+       AC97_SINGLE("DC Offset",           0x5a, 10, 1,     0),
+       AC97_SINGLE("Soft Mute",           0x5c,  0, 1,     1),
+       AC97_SINGLE("Headphone Amp",       0x5c,  5, 1,     1),
+       AC97_DOUBLE("Back Surr Volume",    0x5e,  8, 0, 31, 1),
+       AC97_SINGLE("Back Surr Switch",    0x5e, 15, 1,     1),
+       {
+               .iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name          = "Speaker Jack Mode",
+               .info          = snd_ac97_vt1618_UAJ_info,
+               .get           = snd_ac97_vt1618_UAJ_get,
+               .put           = snd_ac97_vt1618_UAJ_put,
+               .private_value = 0
+       },
+       {
+               .iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name          = "Line Jack Mode",
+               .info          = snd_ac97_vt1618_UAJ_info,
+               .get           = snd_ac97_vt1618_UAJ_get,
+               .put           = snd_ac97_vt1618_UAJ_put,
+               .private_value = 1
+       },
+       {
+               .iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name          = "Mic Jack Mode",
+               .info          = snd_ac97_vt1618_UAJ_info,
+               .get           = snd_ac97_vt1618_UAJ_get,
+               .put           = snd_ac97_vt1618_UAJ_put,
+               .private_value = 2
+       },
+       {
+               .iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name          = "Aux Jack Mode",
+               .info          = snd_ac97_vt1618_aux_info,
+               .get           = snd_ac97_vt1618_aux_get,
+               .put           = snd_ac97_vt1618_aux_put,
+       }
+};
+
+static int patch_vt1618(struct snd_ac97 *ac97)
+{
+       return patch_build_controls(ac97, snd_ac97_controls_vt1618,
+                                   ARRAY_SIZE(snd_ac97_controls_vt1618));
+}
+
 /*
  */
 static void it2646_update_jacks(struct snd_ac97 *ac97)
index 39ec55b57b1e808ffef72e96cbea23bc9095cabd..92f3a976ef2e719a8d81154d8501dc492deec1dd 100644 (file)
@@ -549,7 +549,8 @@ snd_ad1889_playback_pointer(struct snd_pcm_substream *ss)
        ptr = ad1889_readl(chip, AD_DMA_WAVCA);
        ptr -= chip->wave.addr;
        
-       snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0);
+       if (snd_BUG_ON(ptr >= chip->wave.size))
+               return 0;
        
        return bytes_to_frames(ss->runtime, ptr);
 }
@@ -567,7 +568,8 @@ snd_ad1889_capture_pointer(struct snd_pcm_substream *ss)
        ptr = ad1889_readl(chip, AD_DMA_ADCCA);
        ptr -= chip->ramc.addr;
 
-       snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0);
+       if (snd_BUG_ON(ptr >= chip->ramc.size))
+               return 0;
        
        return bytes_to_frames(ss->runtime, ptr);
 }
index 33d37b1c42fcc4354919615a43747655fcdafe4b..0f819ddb3ebfe0906a45f2166c6a32cbb0f26a88 100644 (file)
@@ -392,9 +392,10 @@ int __devinit snd_ak4531_mixer(struct snd_card *card,
                .dev_free =     snd_ak4531_dev_free,
        };
 
-       snd_assert(rak4531 != NULL, return -EINVAL);
-       *rak4531 = NULL;
-       snd_assert(card != NULL && _ak4531 != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card || !_ak4531))
+               return -EINVAL;
+       if (rak4531)
+               *rak4531 = NULL;
        ak4531 = kzalloc(sizeof(*ak4531), GFP_KERNEL);
        if (ak4531 == NULL)
                return -ENOMEM;
@@ -428,7 +429,8 @@ int __devinit snd_ak4531_mixer(struct snd_card *card,
 #if 0
        snd_ak4531_dump(ak4531);
 #endif
-       *rak4531 = ak4531;
+       if (rak4531)
+               *rak4531 = ak4531;
        return 0;
 }
 
index 27ce6136ab009e66052026fdc038bd449a138b02..ba570053d4d538c74b0c5f8b127ba41c2759acd8 100644 (file)
@@ -2,7 +2,7 @@
  *  card-als4000.c - driver for Avance Logic ALS4000 based soundcards.
  *  Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>,
  *                       Jaroslav Kysela <perex@perex.cz>
- *  Copyright (C) 2002 by Andreas Mohr <hw7oshyuv3001@sneakemail.com>
+ *  Copyright (C) 2002, 2008 by Andreas Mohr <hw7oshyuv3001@sneakemail.com>
  *
  *  Framework borrowed from Massimo Piccioni's card-als100.c.
  *
  *  bought an ALS4000 based soundcard, I was forced to base this driver
  *  on reverse engineering.
  *
- *  Note: this is no longer true. Pretty verbose chip docu (ALS4000a.PDF)
- *  can be found on the ALSA web site.
+ *  Note: this is no longer true (thank you!):
+ *  pretty verbose chip docu (ALS4000a.PDF) can be found on the ALSA web site.
+ *  Page numbers stated anywhere below with the "SPECS_PAGE:" tag
+ *  refer to: ALS4000a.PDF specs Ver 1.0, May 28th, 1998.
  *
  *  The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an
  *  ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport 
@@ -59,7 +61,7 @@
  * - value -> some port 0x0c0d
  *
  * ToDo:
- * - Proper shared IRQ handling?
+ * - by default, don't enable legacy game and use PCI game I/O
  * - power management? (card can do voice wakeup according to datasheet!!)
  */
 
@@ -78,7 +80,7 @@
 #include <sound/sb.h>
 #include <sound/initval.h>
 
-MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>");
+MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>, Andreas Mohr");
 MODULE_DESCRIPTION("Avance Logic ALS4000");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}");
@@ -107,7 +109,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0
 
 struct snd_card_als4000 {
        /* most frequent access first */
-       unsigned long gcr;
+       unsigned long iobase;
        struct pci_dev *pci;
        struct snd_sb *chip;
 #ifdef SUPPORT_JOYSTICK
@@ -122,28 +124,168 @@ static struct pci_device_id snd_als4000_ids[] = {
 
 MODULE_DEVICE_TABLE(pci, snd_als4000_ids);
 
-static inline void snd_als4000_gcr_write_addr(unsigned long port, u32 reg, u32 val)
+enum als4k_iobase_t {
+       /* IOx: B == Byte, W = Word, D = DWord; SPECS_PAGE: 37 */
+       ALS4K_IOD_00_AC97_ACCESS = 0x00,
+       ALS4K_IOW_04_AC97_READ = 0x04,
+       ALS4K_IOB_06_AC97_STATUS = 0x06,
+       ALS4K_IOB_07_IRQSTATUS = 0x07,
+       ALS4K_IOD_08_GCR_DATA = 0x08,
+       ALS4K_IOB_0C_GCR_INDEX = 0x0c,
+       ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU = 0x0e,
+       ALS4K_IOB_10_ADLIB_ADDR0 = 0x10,
+       ALS4K_IOB_11_ADLIB_ADDR1 = 0x11,
+       ALS4K_IOB_12_ADLIB_ADDR2 = 0x12,
+       ALS4K_IOB_13_ADLIB_ADDR3 = 0x13,
+       ALS4K_IOB_14_MIXER_INDEX = 0x14,
+       ALS4K_IOB_15_MIXER_DATA = 0x15,
+       ALS4K_IOB_16_ESP_RESET = 0x16,
+       ALS4K_IOB_16_ACK_FOR_CR1E = 0x16, /* 2nd function */
+       ALS4K_IOB_18_OPL_ADDR0 = 0x18,
+       ALS4K_IOB_19_OPL_ADDR1 = 0x19,
+       ALS4K_IOB_1A_ESP_RD_DATA = 0x1a,
+       ALS4K_IOB_1C_ESP_CMD_DATA = 0x1c,
+       ALS4K_IOB_1C_ESP_WR_STATUS = 0x1c, /* 2nd function */
+       ALS4K_IOB_1E_ESP_RD_STATUS8 = 0x1e,
+       ALS4K_IOB_1F_ESP_RD_STATUS16 = 0x1f,
+       ALS4K_IOB_20_ESP_GAMEPORT_200 = 0x20,
+       ALS4K_IOB_21_ESP_GAMEPORT_201 = 0x21,
+       ALS4K_IOB_30_MIDI_DATA = 0x30,
+       ALS4K_IOB_31_MIDI_STATUS = 0x31,
+       ALS4K_IOB_31_MIDI_COMMAND = 0x31, /* 2nd function */
+};
+
+enum als4k_iobase_0e_t {
+       ALS4K_IOB_0E_MPU_IRQ = 0x10,
+       ALS4K_IOB_0E_CR1E_IRQ = 0x40,
+       ALS4K_IOB_0E_SB_DMA_IRQ = 0x80,
+};
+
+enum als4k_gcr_t { /* all registers 32bit wide; SPECS_PAGE: 38 to 42 */
+       ALS4K_GCR8C_MISC_CTRL = 0x8c,
+       ALS4K_GCR90_TEST_MODE_REG = 0x90,
+       ALS4K_GCR91_DMA0_ADDR = 0x91,
+       ALS4K_GCR92_DMA0_MODE_COUNT = 0x92,
+       ALS4K_GCR93_DMA1_ADDR = 0x93,
+       ALS4K_GCR94_DMA1_MODE_COUNT = 0x94,
+       ALS4K_GCR95_DMA3_ADDR = 0x95,
+       ALS4K_GCR96_DMA3_MODE_COUNT = 0x96,
+       ALS4K_GCR99_DMA_EMULATION_CTRL = 0x99,
+       ALS4K_GCRA0_FIFO1_CURRENT_ADDR = 0xa0,
+       ALS4K_GCRA1_FIFO1_STATUS_BYTECOUNT = 0xa1,
+       ALS4K_GCRA2_FIFO2_PCIADDR = 0xa2,
+       ALS4K_GCRA3_FIFO2_COUNT = 0xa3,
+       ALS4K_GCRA4_FIFO2_CURRENT_ADDR = 0xa4,
+       ALS4K_GCRA5_FIFO1_STATUS_BYTECOUNT = 0xa5,
+       ALS4K_GCRA6_PM_CTRL = 0xa6,
+       ALS4K_GCRA7_PCI_ACCESS_STORAGE = 0xa7,
+       ALS4K_GCRA8_LEGACY_CFG1 = 0xa8,
+       ALS4K_GCRA9_LEGACY_CFG2 = 0xa9,
+       ALS4K_GCRFF_DUMMY_SCRATCH = 0xff,
+};
+
+enum als4k_gcr8c_t {
+       ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE = 0x8000,
+       ALS4K_GCR8C_CHIP_REV_MASK = 0xf0000
+};
+
+static inline void snd_als4k_iobase_writeb(unsigned long iobase,
+                                               enum als4k_iobase_t reg,
+                                               u8 val)
+{
+       outb(val, iobase + reg);
+}
+
+static inline void snd_als4k_iobase_writel(unsigned long iobase,
+                                               enum als4k_iobase_t reg,
+                                               u32 val)
+{
+       outl(val, iobase + reg);
+}
+
+static inline u8 snd_als4k_iobase_readb(unsigned long iobase,
+                                               enum als4k_iobase_t reg)
+{
+       return inb(iobase + reg);
+}
+
+static inline u32 snd_als4k_iobase_readl(unsigned long iobase,
+                                               enum als4k_iobase_t reg)
+{
+       return inl(iobase + reg);
+}
+
+static inline void snd_als4k_gcr_write_addr(unsigned long iobase,
+                                                enum als4k_gcr_t reg,
+                                                u32 val)
 {
-       outb(reg, port+0x0c);
-       outl(val, port+0x08);
+       snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg);
+       snd_als4k_iobase_writel(iobase, ALS4K_IOD_08_GCR_DATA, val);
 }
 
-static inline void snd_als4000_gcr_write(struct snd_sb *sb, u32 reg, u32 val)
+static inline void snd_als4k_gcr_write(struct snd_sb *sb,
+                                        enum als4k_gcr_t reg,
+                                        u32 val)
 {
-       snd_als4000_gcr_write_addr(sb->alt_port, reg, val);
+       snd_als4k_gcr_write_addr(sb->alt_port, reg, val);
 }      
 
-static inline u32 snd_als4000_gcr_read_addr(unsigned long port, u32 reg)
+static inline u32 snd_als4k_gcr_read_addr(unsigned long iobase,
+                                                enum als4k_gcr_t reg)
 {
-       outb(reg, port+0x0c);
-       return inl(port+0x08);
+       /* SPECS_PAGE: 37/38 */
+       snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg);
+       return snd_als4k_iobase_readl(iobase, ALS4K_IOD_08_GCR_DATA);
 }
 
-static inline u32 snd_als4000_gcr_read(struct snd_sb *sb, u32 reg)
+static inline u32 snd_als4k_gcr_read(struct snd_sb *sb, enum als4k_gcr_t reg)
 {
-       return snd_als4000_gcr_read_addr(sb->alt_port, reg);
+       return snd_als4k_gcr_read_addr(sb->alt_port, reg);
 }
 
+enum als4k_cr_t { /* all registers 8bit wide; SPECS_PAGE: 20 to 23 */
+       ALS4K_CR0_SB_CONFIG = 0x00,
+       ALS4K_CR2_MISC_CONTROL = 0x02,
+       ALS4K_CR3_CONFIGURATION = 0x03,
+       ALS4K_CR17_FIFO_STATUS = 0x17,
+       ALS4K_CR18_ESP_MAJOR_VERSION = 0x18,
+       ALS4K_CR19_ESP_MINOR_VERSION = 0x19,
+       ALS4K_CR1A_MPU401_UART_MODE_CONTROL = 0x1a,
+       ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO = 0x1c,
+       ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI = 0x1d,
+       ALS4K_CR1E_FIFO2_CONTROL = 0x1e, /* secondary PCM FIFO (recording) */
+       ALS4K_CR3A_MISC_CONTROL = 0x3a,
+       ALS4K_CR3B_CRC32_BYTE0 = 0x3b, /* for testing, activate via CR3A */
+       ALS4K_CR3C_CRC32_BYTE1 = 0x3c,
+       ALS4K_CR3D_CRC32_BYTE2 = 0x3d,
+       ALS4K_CR3E_CRC32_BYTE3 = 0x3e,
+};
+
+enum als4k_cr0_t {
+       ALS4K_CR0_DMA_CONTIN_MODE_CTRL = 0x02, /* IRQ/FIFO controlled for 0/1 */
+       ALS4K_CR0_DMA_90H_MODE_CTRL = 0x04, /* IRQ/FIFO controlled for 0/1 */
+       ALS4K_CR0_MX80_81_REG_WRITE_ENABLE = 0x80,
+};
+
+static inline void snd_als4_cr_write(struct snd_sb *chip,
+                                       enum als4k_cr_t reg,
+                                       u8 data)
+{
+       /* Control Register is reg | 0xc0 (bit 7, 6 set) on sbmixer_index
+        * NOTE: assumes chip->mixer_lock to be locked externally already!
+        * SPECS_PAGE: 6 */
+       snd_sbmixer_write(chip, reg | 0xc0, data);
+}
+
+static inline u8 snd_als4_cr_read(struct snd_sb *chip,
+                                       enum als4k_cr_t reg)
+{
+       /* NOTE: assumes chip->mixer_lock to be locked externally already! */
+       return snd_sbmixer_read(chip, reg | 0xc0);
+}
+
+
+
 static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate)
 {
        if (!(chip->mode & SB_RATE_LOCK)) {
@@ -156,15 +298,19 @@ static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate)
 static inline void snd_als4000_set_capture_dma(struct snd_sb *chip,
                                               dma_addr_t addr, unsigned size)
 {
-       snd_als4000_gcr_write(chip, 0xa2, addr);
-       snd_als4000_gcr_write(chip, 0xa3, (size-1));
+       /* SPECS_PAGE: 40 */
+       snd_als4k_gcr_write(chip, ALS4K_GCRA2_FIFO2_PCIADDR, addr);
+       snd_als4k_gcr_write(chip, ALS4K_GCRA3_FIFO2_COUNT, (size-1));
 }
 
 static inline void snd_als4000_set_playback_dma(struct snd_sb *chip,
-                                               dma_addr_t addr, unsigned size)
+                                               dma_addr_t addr,
+                                               unsigned size)
 {
-       snd_als4000_gcr_write(chip, 0x91, addr);
-       snd_als4000_gcr_write(chip, 0x92, (size-1)|0x180000);
+       /* SPECS_PAGE: 38 */
+       snd_als4k_gcr_write(chip, ALS4K_GCR91_DMA0_ADDR, addr);
+       snd_als4k_gcr_write(chip, ALS4K_GCR92_DMA0_MODE_COUNT,
+                                                       (size-1)|0x180000);
 }
 
 #define ALS4000_FORMAT_SIGNED  (1<<0)
@@ -248,7 +394,7 @@ static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream)
        count = snd_pcm_lib_period_bytes(substream);
        
        if (chip->capture_format & ALS4000_FORMAT_16BIT)
-               count >>=1;
+               count >>= 1;
        count--;
 
        spin_lock_irq(&chip->reg_lock);
@@ -256,8 +402,8 @@ static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream)
        snd_als4000_set_capture_dma(chip, runtime->dma_addr, size);
        spin_unlock_irq(&chip->reg_lock);
        spin_lock_irq(&chip->mixer_lock);
-       snd_sbmixer_write(chip, 0xdc, count);
-       snd_sbmixer_write(chip, 0xdd, count>>8);
+       snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff);
+       snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8);
        spin_unlock_irq(&chip->mixer_lock);
        return 0;
 }
@@ -275,7 +421,7 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream)
        count = snd_pcm_lib_period_bytes(substream);
        
        if (chip->playback_format & ALS4000_FORMAT_16BIT)
-               count >>=1;
+               count >>= 1;
        count--;
        
        /* FIXME: from second playback on, there's a lot more clicks and pops
@@ -292,8 +438,8 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream)
        /* snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); */
        snd_sbdsp_command(chip, playback_cmd(chip).dsp_cmd);
        snd_sbdsp_command(chip, playback_cmd(chip).format);
-       snd_sbdsp_command(chip, count);
-       snd_sbdsp_command(chip, count>>8);
+       snd_sbdsp_command(chip, count & 0xff);
+       snd_sbdsp_command(chip, count >> 8);
        snd_sbdsp_command(chip, playback_cmd(chip).dma_off);    
        spin_unlock_irq(&chip->reg_lock);
        
@@ -305,17 +451,25 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int
        struct snd_sb *chip = snd_pcm_substream_chip(substream);
        int result = 0;
        
+       /* FIXME race condition in here!!!
+          chip->mode non-atomic update gets consistently protected
+          by reg_lock always, _except_ for this place!!
+          Probably need to take reg_lock as outer (or inner??) lock, too.
+          (or serialize both lock operations? probably not, though... - racy?)
+       */
        spin_lock(&chip->mixer_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
                chip->mode |= SB_RATE_LOCK_CAPTURE;
-               snd_sbmixer_write(chip, 0xde, capture_cmd(chip));
+               snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
+                                                        capture_cmd(chip));
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
                chip->mode &= ~SB_RATE_LOCK_CAPTURE;
-               snd_sbmixer_write(chip, 0xde, 0);
+               snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL,
+                                                        capture_cmd(chip));
                break;
        default:
                result = -EINVAL;
@@ -356,8 +510,9 @@ static snd_pcm_uframes_t snd_als4000_capture_pointer(struct snd_pcm_substream *s
        unsigned int result;
 
        spin_lock(&chip->reg_lock);     
-       result = snd_als4000_gcr_read(chip, 0xa4) & 0xffff;
+       result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR);
        spin_unlock(&chip->reg_lock);
+       result &= 0xffff;
        return bytes_to_frames( substream->runtime, result );
 }
 
@@ -367,8 +522,9 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream *
        unsigned result;
 
        spin_lock(&chip->reg_lock);     
-       result = snd_als4000_gcr_read(chip, 0xa0) & 0xffff;
+       result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR);
        spin_unlock(&chip->reg_lock);
+       result &= 0xffff;
        return bytes_to_frames( substream->runtime, result );
 }
 
@@ -376,45 +532,63 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream *
  * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not).
  * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK
  * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ
- * register (alt_port + 0x0e). Probably something could be optimized here to
- * query/write one register only...
+ * register (alt_port + ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU). Probably something
+ * could be optimized here to query/write one register only...
  * And even if both registers need to be queried, then there's still the
  * question of whether it's actually correct to ACK PCI IRQ before reading
  * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear*
  * SB IRQ status.
+ * (hmm, SPECS_PAGE: 38 mentions it the other way around!)
  * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS??
  * */
 static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
 {
        struct snd_sb *chip = dev_id;
-       unsigned gcr_status;
-       unsigned sb_status;
-
-       /* find out which bit of the ALS4000 produced the interrupt */
-       gcr_status = inb(chip->alt_port + 0xe);
-
-       if ((gcr_status & 0x80) && (chip->playback_substream)) /* playback */
+       unsigned pci_irqstatus;
+       unsigned sb_irqstatus;
+
+       /* find out which bit of the ALS4000 PCI block produced the interrupt,
+          SPECS_PAGE: 38, 5 */
+       pci_irqstatus = snd_als4k_iobase_readb(chip->alt_port,
+                                ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU);
+       if ((pci_irqstatus & ALS4K_IOB_0E_SB_DMA_IRQ)
+        && (chip->playback_substream)) /* playback */
                snd_pcm_period_elapsed(chip->playback_substream);
-       if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */
+       if ((pci_irqstatus & ALS4K_IOB_0E_CR1E_IRQ)
+        && (chip->capture_substream)) /* capturing */
                snd_pcm_period_elapsed(chip->capture_substream);
-       if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */
+       if ((pci_irqstatus & ALS4K_IOB_0E_MPU_IRQ)
+        && (chip->rmidi)) /* MPU401 interrupt */
                snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
-       /* release the gcr */
-       outb(gcr_status, chip->alt_port + 0xe);
+       /* ACK the PCI block IRQ */
+       snd_als4k_iobase_writeb(chip->alt_port,
+                        ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU, pci_irqstatus);
        
        spin_lock(&chip->mixer_lock);
-       sb_status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
+       /* SPECS_PAGE: 20 */
+       sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
        spin_unlock(&chip->mixer_lock);
        
-       if (sb_status & SB_IRQTYPE_8BIT) 
+       if (sb_irqstatus & SB_IRQTYPE_8BIT)
                snd_sb_ack_8bit(chip);
-       if (sb_status & SB_IRQTYPE_16BIT) 
+       if (sb_irqstatus & SB_IRQTYPE_16BIT)
                snd_sb_ack_16bit(chip);
-       if (sb_status & SB_IRQTYPE_MPUIN)
+       if (sb_irqstatus & SB_IRQTYPE_MPUIN)
                inb(chip->mpu_port);
-       if (sb_status & 0x20)
-               inb(SBP(chip, RESET));
-       return IRQ_HANDLED;
+       if (sb_irqstatus & ALS4K_IRQTYPE_CR1E_DMA)
+               snd_als4k_iobase_readb(chip->alt_port,
+                                       ALS4K_IOB_16_ACK_FOR_CR1E);
+
+       /* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x\n",
+                                        pci_irqstatus, sb_irqstatus); */
+
+       /* only ack the things we actually handled above */
+       return IRQ_RETVAL(
+            (pci_irqstatus & (ALS4K_IOB_0E_SB_DMA_IRQ|ALS4K_IOB_0E_CR1E_IRQ|
+                               ALS4K_IOB_0E_MPU_IRQ))
+         || (sb_irqstatus & (SB_IRQTYPE_8BIT|SB_IRQTYPE_16BIT|
+                               SB_IRQTYPE_MPUIN|ALS4K_IRQTYPE_CR1E_DMA))
+       );
 }
 
 /*****************************************************************/
@@ -526,7 +700,8 @@ static int __devinit snd_als4000_pcm(struct snd_sb *chip, int device)
        struct snd_pcm *pcm;
        int err;
 
-       if ((err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm)) < 0)
+       err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm);
+       if (err < 0)
                return err;
        pcm->private_data = chip;
        pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
@@ -543,48 +718,55 @@ static int __devinit snd_als4000_pcm(struct snd_sb *chip, int device)
 
 /******************************************************************/
 
-static void snd_als4000_set_addr(unsigned long gcr,
-                                       unsigned int sb,
-                                       unsigned int mpu,
-                                       unsigned int opl,
-                                       unsigned int game)
+static void snd_als4000_set_addr(unsigned long iobase,
+                                       unsigned int sb_io,
+                                       unsigned int mpu_io,
+                                       unsigned int opl_io,
+                                       unsigned int game_io)
 {
-       u32 confA = 0;
-       u32 confB = 0;
-
-       if (mpu > 0)
-               confB |= (mpu | 1) << 16;
-       if (sb > 0)
-               confB |= (sb | 1);
-       if (game > 0)
-               confA |= (game | 1) << 16;
-       if (opl > 0)    
-               confA |= (opl | 1);
-       snd_als4000_gcr_write_addr(gcr, 0xa8, confA);
-       snd_als4000_gcr_write_addr(gcr, 0xa9, confB);
+       u32 cfg1 = 0;
+       u32 cfg2 = 0;
+
+       if (mpu_io > 0)
+               cfg2 |= (mpu_io | 1) << 16;
+       if (sb_io > 0)
+               cfg2 |= (sb_io | 1);
+       if (game_io > 0)
+               cfg1 |= (game_io | 1) << 16;
+       if (opl_io > 0)
+               cfg1 |= (opl_io | 1);
+       snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA8_LEGACY_CFG1, cfg1);
+       snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA9_LEGACY_CFG2, cfg2);
 }
 
 static void snd_als4000_configure(struct snd_sb *chip)
 {
-       unsigned tmp;
+       u8 tmp;
        int i;
 
        /* do some more configuration */
        spin_lock_irq(&chip->mixer_lock);
-       tmp = snd_sbmixer_read(chip, 0xc0);
-       snd_sbmixer_write(chip, 0xc0, tmp|0x80);
-       /* always select DMA channel 0, since we do not actually use DMA */
+       tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG);
+       snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
+                               tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
+       /* always select DMA channel 0, since we do not actually use DMA
+        * SPECS_PAGE: 19/20 */
        snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0);
-       snd_sbmixer_write(chip, 0xc0, tmp&0x7f);
+       snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
+                                tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
        spin_unlock_irq(&chip->mixer_lock);
        
        spin_lock_irq(&chip->reg_lock);
-       /* magic number. Enables interrupts(?) */
-       snd_als4000_gcr_write(chip, 0x8c, 0x28000);
-       for(i = 0x91; i <= 0x96; ++i)
-               snd_als4000_gcr_write(chip, i, 0);
+       /* enable interrupts */
+       snd_als4k_gcr_write(chip, ALS4K_GCR8C_MISC_CTRL,
+                                       ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE);
+
+       /* SPECS_PAGE: 39 */
+       for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i)
+               snd_als4k_gcr_write(chip, i, 0);
        
-       snd_als4000_gcr_write(chip, 0x99, snd_als4000_gcr_read(chip, 0x99));
+       snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
+               snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL));
        spin_unlock_irq(&chip->reg_lock);
 }
 
@@ -628,7 +810,7 @@ static int __devinit snd_als4000_create_gameport(struct snd_card_als4000 *acard,
        gameport_set_port_data(gp, r);
 
        /* Enable legacy joystick port */
-       snd_als4000_set_addr(acard->gcr, 0, 0, 0, 1);
+       snd_als4000_set_addr(acard->iobase, 0, 0, 0, 1);
 
        gameport_register_port(acard->gameport);
 
@@ -643,7 +825,9 @@ static void snd_als4000_free_gameport(struct snd_card_als4000 *acard)
                gameport_unregister_port(acard->gameport);
                acard->gameport = NULL;
 
-               snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
+               /* disable joystick */
+               snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0);
+
                release_and_free_resource(r);
        }
 }
@@ -654,10 +838,10 @@ static inline void snd_als4000_free_gameport(struct snd_card_als4000 *acard) { }
 
 static void snd_card_als4000_free( struct snd_card *card )
 {
-       struct snd_card_als4000 * acard = (struct snd_card_als4000 *)card->private_data;
+       struct snd_card_als4000 *acard = card->private_data;
 
        /* make sure that interrupts are disabled */
-       snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0);
+       snd_als4k_gcr_write_addr(acard->iobase, ALS4K_GCR8C_MISC_CTRL, 0);
        /* free resources */
        snd_als4000_free_gameport(acard);
        pci_release_regions(acard->pci);
@@ -670,7 +854,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
        static int dev;
        struct snd_card *card;
        struct snd_card_als4000 *acard;
-       unsigned long gcr;
+       unsigned long iobase;
        struct snd_sb *chip;
        struct snd_opl3 *opl3;
        unsigned short word;
@@ -699,31 +883,32 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
                pci_disable_device(pci);
                return err;
        }
-       gcr = pci_resource_start(pci, 0);
+       iobase = pci_resource_start(pci, 0);
 
        pci_read_config_word(pci, PCI_COMMAND, &word);
        pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
        pci_set_master(pci);
        
        card = snd_card_new(index[dev], id[dev], THIS_MODULE, 
-                           sizeof( struct snd_card_als4000 ) );
+                           sizeof(*acard) /* private_data: acard */);
        if (card == NULL) {
                pci_release_regions(pci);
                pci_disable_device(pci);
                return -ENOMEM;
        }
 
-       acard = (struct snd_card_als4000 *)card->private_data;
+       acard = card->private_data;
        acard->pci = pci;
-       acard->gcr = gcr;
+       acard->iobase = iobase;
        card->private_free = snd_card_als4000_free;
 
        /* disable all legacy ISA stuff */
-       snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0);
+       snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0);
 
        if ((err = snd_sbdsp_create(card,
-                                   gcr + 0x10,
+                                   iobase + ALS4K_IOB_10_ADLIB_ADDR0,
                                    pci->irq,
+               /* internally registered as IRQF_SHARED in case of ALS4000 SB */
                                    snd_als4000_interrupt,
                                    -1,
                                    -1,
@@ -734,7 +919,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
        acard->chip = chip;
 
        chip->pci = pci;
-       chip->alt_port = gcr;
+       chip->alt_port = iobase;
        snd_card_set_dev(card, &pci->dev);
 
        snd_als4000_configure(chip);
@@ -745,11 +930,18 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
                card->shortname, chip->alt_port, chip->irq);
 
        if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
-                                       gcr+0x30, MPU401_INFO_INTEGRATED,
+                                       iobase + ALS4K_IOB_30_MIDI_DATA,
+                                       MPU401_INFO_INTEGRATED,
                                        pci->irq, 0, &chip->rmidi)) < 0) {
-               printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30);
+               printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n",
+                               iobase + ALS4K_IOB_30_MIDI_DATA);
                goto out_err;
        }
+       /* FIXME: ALS4000 has interesting MPU401 configuration features
+        * at ALS4K_CR1A_MPU401_UART_MODE_CONTROL
+        * (pass-thru / UART switching, fast MIDI clock, etc.),
+        * however there doesn't seem to be an ALSA API for this...
+        * SPECS_PAGE: 21 */
 
        if ((err = snd_als4000_pcm(chip, 0)) < 0) {
                goto out_err;
@@ -758,10 +950,13 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
                goto out_err;
        }           
 
-       if (snd_opl3_create(card, gcr+0x10, gcr+0x12,
+       if (snd_opl3_create(card,
+                               iobase + ALS4K_IOB_10_ADLIB_ADDR0,
+                               iobase + ALS4K_IOB_12_ADLIB_ADDR2,
                            OPL3_HW_AUTO, 1, &opl3) < 0) {
                printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?\n",
-                          gcr+0x10, gcr+0x12 );
+                          iobase + ALS4K_IOB_10_ADLIB_ADDR0,
+                          iobase + ALS4K_IOB_12_ADLIB_ADDR2);
        } else {
                if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
                        goto out_err;
@@ -831,13 +1026,13 @@ static int snd_als4000_resume(struct pci_dev *pci)
 
 #ifdef SUPPORT_JOYSTICK
        if (acard->gameport)
-               snd_als4000_set_addr(acard->gcr, 0, 0, 0, 1);
+               snd_als4000_set_addr(acard->iobase, 0, 0, 0, 1);
 #endif
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
-#endif
+#endif /* CONFIG_PM */
 
 
 static struct pci_driver driver = {
index 457228fb22aad76dee9fafb9950d85c80acfd73c..085a52b8c80764a0ebcfe42c4d5bcb3e130f446d 100644 (file)
@@ -37,7 +37,7 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ATI IXP AC97 controller");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300/400}}");
+MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300/400/600}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
@@ -290,6 +290,7 @@ static struct pci_device_id snd_atiixp_ids[] = {
        { 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
        { 0x1002, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB300 */
        { 0x1002, 0x4370, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
+       { 0x1002, 0x4382, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB600 */
        { 0, }
 };
 
@@ -722,7 +723,9 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct atiixp_dma *dma = substream->runtime->private_data;
        int err = 0;
 
-       snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
+       if (snd_BUG_ON(!dma->ops->enable_transfer ||
+                      !dma->ops->flush_dma))
+               return -EINVAL;
 
        spin_lock(&chip->reg_lock);
        switch (cmd) {
@@ -1032,7 +1035,8 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
-       snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+       if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+               return -EINVAL;
 
        if (dma->opened)
                return -EBUSY;
@@ -1064,7 +1068,8 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
 {
        struct atiixp *chip = snd_pcm_substream_chip(substream);
        /* disable DMA bits */
-       snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+       if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+               return -EINVAL;
        spin_lock_irq(&chip->reg_lock);
        dma->ops->enable_dma(chip, 0);
        spin_unlock_irq(&chip->reg_lock);
index d457a32a7939fffb7987af0709a3bb353ce647c3..2f106306c7fe6305a3d1f5c5a22f2cf54837b1ff 100644 (file)
@@ -674,7 +674,9 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct atiixp_dma *dma = substream->runtime->private_data;
        int err = 0;
 
-       snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
+       if (snd_BUG_ON(!dma->ops->enable_transfer ||
+                      !dma->ops->flush_dma))
+               return -EINVAL;
 
        spin_lock(&chip->reg_lock);
        switch(cmd) {
@@ -865,7 +867,8 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,
                .mask = 0,
        };
 
-       snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+       if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+               return -EINVAL;
 
        if (dma->opened)
                return -EBUSY;
@@ -895,7 +898,8 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
 {
        struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
        /* disable DMA bits */
-       snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+       if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
+               return -EINVAL;
        spin_lock_irq(&chip->reg_lock);
        dma->ops->enable_dma(chip, 0);
        spin_unlock_irq(&chip->reg_lock);
index 4aad35bba11a7af57679d47da3002223cd0c14ba..cf46bba563cf938ac19803315fd92a5ea51a5c0e 100644 (file)
@@ -125,7 +125,6 @@ typedef struct {
        /* Virtual page extender stuff */
        int nr_periods;
        int period_bytes;
-       struct snd_sg_buf *sgbuf;       /* DMA Scatter Gather struct */
        int period_real;
        int period_virt;
 
@@ -195,16 +194,14 @@ static void vortex_adb_setsrc(vortex_t * vortex, int adbdma,
 
 /* DMA Engines. */
 static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
-                                    struct snd_sg_buf * sgbuf, int size,
-                                    int count);
+                                    int size, int count);
 static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
                                  int dir, int fmt, int d,
                                  u32 offset);
 static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
 #ifndef CHIP_AU8810
 static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
-                                   struct snd_sg_buf * sgbuf, int size,
-                                   int count);
+                                   int size, int count);
 static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, /*int e, */
                                 u32 offset);
 static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
index 333c62de862042f3672b3cf06c87c59c4cd8c707..b070e57145143e6cb0703f338d9bf5db7dd3cffc 100644 (file)
@@ -427,7 +427,7 @@ static void vortex_mixer_init(vortex_t * vortex)
 
        /* Set clipping ceiling (this may be all wrong). */
        /*
-       for (x = 0; x > 0x80; x++) {
+       for (x = 0; x < 0x80; x++) {
                hwwrite(vortex->mmio, VORTEX_MIXER_CLIP + (x << 2), 0x3ffff);
        }
        */
@@ -1097,19 +1097,12 @@ static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb)
 
 static void
 vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
-                        struct snd_sg_buf * sgbuf, int psize, int count)
+                        int psize, int count)
 {
        stream_t *dma = &vortex->dma_adb[adbdma];
 
-       if (sgbuf == NULL) {
-               printk(KERN_INFO "vortex: FATAL: sgbuf is NULL!\n");
-               return;
-       }
-       //printk(KERN_INFO "vortex: page count = %d, tblcount = %d\n", count, sgbuf->tblsize);
-
        dma->period_bytes = psize;
        dma->nr_periods = count;
-       dma->sgbuf = sgbuf;
 
        dma->cfg0 = 0;
        dma->cfg1 = 0;
@@ -1120,26 +1113,26 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
                dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize - 1);
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
-                       snd_sgbuf_get_addr(sgbuf, psize * 3));
+                       snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
                /* 3 pages */
        case 3:
                dma->cfg0 |= 0x12000000;
                dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
-                       snd_sgbuf_get_addr(sgbuf, psize * 2));
+                       snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
                /* 2 pages */
        case 2:
                dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
-                       snd_sgbuf_get_addr(sgbuf, psize));
+                       snd_pcm_sgbuf_get_addr(dma->substream, psize));
                /* 1 page */
        case 1:
                dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
                hwwrite(vortex->mmio,
                        VORTEX_ADBDMA_BUFBASE + (adbdma << 4),
-                       snd_sgbuf_get_addr(sgbuf, 0));
+                       snd_pcm_sgbuf_get_addr(dma->substream, 0));
                break;
        }
        //printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1);
@@ -1205,7 +1198,7 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
                        //hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), dma->table[p].addr);
                        hwwrite(vortex->mmio,
                                VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
-                               snd_sgbuf_get_addr(dma->sgbuf,
+                               snd_pcm_sgbuf_get_addr(dma->substream,
                                dma->period_bytes * p));
                        /* Force write thru cache. */
                        hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE +
@@ -1244,7 +1237,10 @@ static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
                        if (pp >= 4)
                                pp -= 4;
                }
-               hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
+               hwwrite(vortex->mmio,
+                       VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
+                       snd_pcm_sgbuf_get_addr(dma->substream,
+                                              dma->period_bytes * p));
                /* Force write thru cache. */
                hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (((adbdma << 2)+pp) << 2));
        }
@@ -1367,13 +1363,12 @@ static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb)
 
 static void
 vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
-                       struct snd_sg_buf * sgbuf, int psize, int count)
+                       int psize, int count)
 {
        stream_t *dma = &vortex->dma_wt[wtdma];
 
        dma->period_bytes = psize;
        dma->nr_periods = count;
-       dma->sgbuf = sgbuf;
 
        dma->cfg0 = 0;
        dma->cfg1 = 0;
@@ -1383,23 +1378,23 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
        case 4:
                dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
-                       snd_sgbuf_get_addr(sgbuf, psize * 3));
+                       snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
                /* 3 pages */
        case 3:
                dma->cfg0 |= 0x12000000;
                dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4)  + 0x8,
-                       snd_sgbuf_get_addr(sgbuf, psize * 2));
+                       snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
                /* 2 pages */
        case 2:
                dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
-                       snd_sgbuf_get_addr(sgbuf, psize));
+                       snd_pcm_sgbuf_get_addr(dma->substream, psize));
                /* 1 page */
        case 1:
                dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
                hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
-                       snd_sgbuf_get_addr(sgbuf, 0));
+                       snd_pcm_sgbuf_get_addr(dma->substream, 0));
                break;
        }
        hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG0 + (wtdma << 3), dma->cfg0);
@@ -1465,7 +1460,8 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
                        hwwrite(vortex->mmio,
                                VORTEX_WTDMA_BUFBASE +
                                (((wtdma << 2) + pp) << 2),
-                               snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
+                               snd_pcm_sgbuf_get_addr(dma->substream,
+                                                      dma->period_bytes * p));
                        /* Force write thru cache. */
                        hwread(vortex->mmio, VORTEX_WTDMA_BUFBASE +
                               (((wtdma << 2) + pp) << 2));
index f9a58b4a30ebb2f8411c5439db8b6175e619c8ab..b9d2f202cf9b4385db4291d5fb919cf6365525ab 100644 (file)
@@ -189,7 +189,6 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        vortex_t *chip = snd_pcm_substream_chip(substream);
        stream_t *stream = (stream_t *) (substream->runtime->private_data);
-       struct snd_sg_buf *sgbuf;
        int err;
 
        // Alloc buffer memory.
@@ -199,8 +198,6 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
                printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
                return err;
        }
-       //sgbuf = (struct snd_sg_buf *) substream->runtime->dma_private;
-       sgbuf = snd_pcm_substream_sgbuf(substream);
        /*
           printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
           params_period_bytes(hw_params), params_channels(hw_params));
@@ -226,7 +223,7 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
                stream = substream->runtime->private_data = &chip->dma_adb[dma];
                stream->substream = substream;
                /* Setup Buffers. */
-               vortex_adbdma_setbuffers(chip, dma, sgbuf,
+               vortex_adbdma_setbuffers(chip, dma,
                                         params_period_bytes(hw_params),
                                         params_periods(hw_params));
        }
@@ -240,7 +237,7 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
                    &chip->dma_wt[substream->number];
                stream->dma = substream->number;
                stream->substream = substream;
-               vortex_wtdma_setbuffers(chip, substream->number, sgbuf,
+               vortex_wtdma_setbuffers(chip, substream->number,
                                        params_period_bytes(hw_params),
                                        params_periods(hw_params));
        }
@@ -392,13 +389,6 @@ static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substr
        return (bytes_to_frames(substream->runtime, current_ptr));
 }
 
-/* Page callback. */
-/*
-static struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset) {
-       
-       
-}
-*/
 /* operators */
 static struct snd_pcm_ops snd_vortex_playback_ops = {
        .open = snd_vortex_pcm_open,
index 22f18f3cfbc9f45d1b7921aa25ab2399029fe663..333007c523a1f876b2deca492a71c59f93de86e4 100644 (file)
@@ -816,7 +816,8 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
        int err;
 
        snd_azf3328_dbgcallenter();
-       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip || !chip->card))
+               return -EINVAL;
 
        card = chip->card;
 
@@ -1471,7 +1472,8 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
        u8 val;
        unsigned long flags;
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
 
        spin_lock_irqsave(&chip->reg_lock, flags);
        val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE);
index 4ecdd635ed1d34bcf06749aa7dcc4ad7f6b0acb3..3aa8d973540abefb0c55234ec4c84eafe66ece26 100644 (file)
@@ -227,7 +227,6 @@ static inline void snd_bt87x_writel(struct snd_bt87x *chip, u32 reg, u32 value)
 static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substream *substream,
                                 unsigned int periods, unsigned int period_bytes)
 {
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
        unsigned int i, offset;
        u32 *risc;
 
@@ -246,6 +245,7 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea
                rest = period_bytes;
                do {
                        u32 cmd, len;
+                       unsigned int addr;
 
                        len = PAGE_SIZE - (offset % PAGE_SIZE);
                        if (len > rest)
@@ -260,7 +260,8 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea
                        if (len == rest)
                                cmd |= RISC_EOL | RISC_IRQ;
                        *risc++ = cpu_to_le32(cmd);
-                       *risc++ = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, offset));
+                       addr = snd_pcm_sgbuf_get_addr(substream, offset);
+                       *risc++ = cpu_to_le32(addr);
                        offset += len;
                        rest -= len;
                } while (rest > 0);
index 6abe8a3bd365cc703d6d405b579f80f60dc051a9..a7d89662acf66e200c5305ac409fd3bfd7188500 100644 (file)
@@ -254,7 +254,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "MSI K8N Diamond MB",
           .gpio_type = 2,
           .i2c_adc = 1,
-          .spi_dac = 2 },
+          .spi_dac = 2 } ,
         /* Shuttle XPC SD31P which has an onboard Creative Labs
          * Sound Blaster Live! 24-bit EAX
          * high-definition 7.1 audio processor".
index 893ee4f1ea7773f54e90c1824c75fe08a6bdb13f..c7885117da334c3da81b41a582f1126f4e4f7489 100644 (file)
@@ -125,7 +125,8 @@ static int ca_midi_input_open(struct snd_rawmidi_substream *substream)
        struct snd_ca_midi *midi = substream->rmidi->private_data;
        unsigned long flags;
        
-       snd_assert(midi->dev_id, return -ENXIO);
+       if (snd_BUG_ON(!midi->dev_id))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->midi_mode |= CA_MIDI_MODE_INPUT;
        midi->substream_input = substream;
@@ -144,7 +145,8 @@ static int ca_midi_output_open(struct snd_rawmidi_substream *substream)
        struct snd_ca_midi *midi = substream->rmidi->private_data;
        unsigned long flags;
 
-       snd_assert(midi->dev_id, return -ENXIO);
+       if (snd_BUG_ON(!midi->dev_id))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->midi_mode |= CA_MIDI_MODE_OUTPUT;
        midi->substream_output = substream;
@@ -163,7 +165,8 @@ static int ca_midi_input_close(struct snd_rawmidi_substream *substream)
        struct snd_ca_midi *midi = substream->rmidi->private_data;
        unsigned long flags;
 
-       snd_assert(midi->dev_id, return -ENXIO);
+       if (snd_BUG_ON(!midi->dev_id))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->interrupt_disable(midi,midi->rx_enable);
        midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
@@ -181,7 +184,9 @@ static int ca_midi_output_close(struct snd_rawmidi_substream *substream)
 {
        struct snd_ca_midi *midi = substream->rmidi->private_data;
        unsigned long flags;
-       snd_assert(midi->dev_id, return -ENXIO);
+
+       if (snd_BUG_ON(!midi->dev_id))
+               return -ENXIO;
        
        spin_lock_irqsave(&midi->open_lock, flags);
 
@@ -201,7 +206,9 @@ static int ca_midi_output_close(struct snd_rawmidi_substream *substream)
 static void ca_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 {
        struct snd_ca_midi *midi = substream->rmidi->private_data;
-       snd_assert(midi->dev_id, return);
+
+       if (snd_BUG_ON(!midi->dev_id))
+               return;
 
        if (up) {
                midi->interrupt_enable(midi,midi->rx_enable);
@@ -215,7 +222,8 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int
        struct snd_ca_midi *midi = substream->rmidi->private_data;
        unsigned long flags;
 
-       snd_assert(midi->dev_id, return);
+       if (snd_BUG_ON(!midi->dev_id))
+               return;
 
        if (up) {
                int max = 4;
index 9971b5b7735b5620599fb83df460b973355cbb89..1a74ca62c31484a8b8923f324771c43fcd1491a3 100644 (file)
@@ -2357,7 +2357,8 @@ static int snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol,
 {
        struct cmipci_switch_args *args;
        args = (struct cmipci_switch_args *)kcontrol->private_value;
-       snd_assert(args != NULL, return -EINVAL);
+       if (snd_BUG_ON(!args))
+               return -EINVAL;
        return _snd_cmipci_uswitch_get(kcontrol, ucontrol, args);
 }
 
@@ -2401,7 +2402,8 @@ static int snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol,
 {
        struct cmipci_switch_args *args;
        args = (struct cmipci_switch_args *)kcontrol->private_value;
-       snd_assert(args != NULL, return -EINVAL);
+       if (snd_BUG_ON(!args))
+               return -EINVAL;
        return _snd_cmipci_uswitch_put(kcontrol, ucontrol, args);
 }
 
@@ -2662,7 +2664,8 @@ static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_devic
        unsigned int idx;
        int err;
 
-       snd_assert(cm != NULL && cm->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!cm || !cm->card))
+               return -EINVAL;
 
        card = cm->card;
 
index 7556fd90d0eb5c67973ddfa3fba26c597a766844..ef9308f7c45b3e17deb00c3fcf22f9fa96795293 100644 (file)
@@ -766,13 +766,13 @@ static void snd_cs4281_mode(struct cs4281 *chip, struct cs4281_dma *dma,
        if (!capture) {
                if (dma->left_slot == chip->src_left_play_slot) {
                        unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
-                       snd_assert(dma->right_slot == chip->src_right_play_slot, );
+                       snd_BUG_ON(dma->right_slot != chip->src_right_play_slot);
                        snd_cs4281_pokeBA0(chip, BA0_DACSR, val);
                }
        } else {
                if (dma->left_slot == chip->src_left_rec_slot) {
                        unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
-                       snd_assert(dma->right_slot == chip->src_right_rec_slot, );
+                       snd_BUG_ON(dma->right_slot != chip->src_right_rec_slot);
                        snd_cs4281_pokeBA0(chip, BA0_ADCSR, val);
                }
        }
@@ -1209,7 +1209,8 @@ static void snd_cs4281_gameport_trigger(struct gameport *gameport)
 {
        struct cs4281 *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return);
+       if (snd_BUG_ON(!chip))
+               return;
        snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);
 }
 
@@ -1217,7 +1218,8 @@ static unsigned char snd_cs4281_gameport_read(struct gameport *gameport)
 {
        struct cs4281 *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
        return snd_cs4281_peekBA0(chip, BA0_JSPT);
 }
 
@@ -1228,7 +1230,8 @@ static int snd_cs4281_gameport_cooked_read(struct gameport *gameport,
        struct cs4281 *chip = gameport_get_port_data(gameport);
        unsigned js1, js2, jst;
        
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
 
        js1 = snd_cs4281_peekBA0(chip, BA0_JSC1);
        js2 = snd_cs4281_peekBA0(chip, BA0_JSC2);
index e214e567dec894074568b48205d5a6c139ac6224..fb6dc398025753c08fd861ed134677dd675d1117 100644 (file)
@@ -90,9 +90,10 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
        int count;
        unsigned short result,tmp;
        u32 offset = 0;
-       snd_assert ( (codec_index == CS46XX_PRIMARY_CODEC_INDEX) ||
-                    (codec_index == CS46XX_SECONDARY_CODEC_INDEX),
-                    return -EINVAL);
+
+       if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+                      codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+               return -EINVAL;
 
        chip->active_ctrl(chip, 1);
 
@@ -212,9 +213,9 @@ static unsigned short snd_cs46xx_ac97_read(struct snd_ac97 * ac97,
        unsigned short val;
        int codec_index = ac97->num;
 
-       snd_assert(codec_index == CS46XX_PRIMARY_CODEC_INDEX ||
-                  codec_index == CS46XX_SECONDARY_CODEC_INDEX,
-                  return 0xffff);
+       if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+                      codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+               return 0xffff;
 
        val = snd_cs46xx_codec_read(chip, reg, codec_index);
 
@@ -229,9 +230,9 @@ static void snd_cs46xx_codec_write(struct snd_cs46xx *chip,
 {
        int count;
 
-       snd_assert ((codec_index == CS46XX_PRIMARY_CODEC_INDEX) ||
-                   (codec_index == CS46XX_SECONDARY_CODEC_INDEX),
-                   return);
+       if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+                      codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+               return;
 
        chip->active_ctrl(chip, 1);
 
@@ -294,9 +295,9 @@ static void snd_cs46xx_ac97_write(struct snd_ac97 *ac97,
        struct snd_cs46xx *chip = ac97->private_data;
        int codec_index = ac97->num;
 
-       snd_assert(codec_index == CS46XX_PRIMARY_CODEC_INDEX ||
-                  codec_index == CS46XX_SECONDARY_CODEC_INDEX,
-                  return);
+       if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
+                      codec_index != CS46XX_SECONDARY_CODEC_INDEX))
+               return;
 
        snd_cs46xx_codec_write(chip, reg, val, codec_index);
 }
@@ -315,7 +316,8 @@ int snd_cs46xx_download(struct snd_cs46xx *chip,
        unsigned int bank = offset >> 16;
        offset = offset & 0xffff;
 
-       snd_assert(!(offset & 3) && !(len & 3), return -EINVAL);
+       if (snd_BUG_ON((offset & 3) || (len & 3)))
+               return -EINVAL;
        dst = chip->region.idx[bank+1].remap_addr + offset;
        len /= sizeof(u32);
 
@@ -343,7 +345,8 @@ int snd_cs46xx_clear_BA1(struct snd_cs46xx *chip,
        unsigned int bank = offset >> 16;
        offset = offset & 0xffff;
 
-       snd_assert(!(offset & 3) && !(len & 3), return -EINVAL);
+       if (snd_BUG_ON((offset & 3) || (len & 3)))
+               return -EINVAL;
        dst = chip->region.idx[bank+1].remap_addr + offset;
        len /= sizeof(u32);
 
@@ -722,7 +725,9 @@ static snd_pcm_uframes_t snd_cs46xx_playback_direct_pointer(struct snd_pcm_subst
        struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
        size_t ptr;
        struct snd_cs46xx_pcm *cpcm = substream->runtime->private_data;
-       snd_assert (cpcm->pcm_channel,return -ENXIO);
+
+       if (snd_BUG_ON(!cpcm->pcm_channel))
+               return -ENXIO;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);
@@ -740,7 +745,8 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(struct snd_pcm_sub
        struct snd_cs46xx_pcm *cpcm = substream->runtime->private_data;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-       snd_assert (cpcm->pcm_channel,return -ENXIO);
+       if (snd_BUG_ON(!cpcm->pcm_channel))
+               return -ENXIO;
        ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);
 #else
        ptr = snd_cs46xx_peek(chip, BA1_PBA);
@@ -908,7 +914,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
        cpcm = runtime->private_data;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-       snd_assert (sample_rate != 0, return -ENXIO);
+       if (snd_BUG_ON(!sample_rate))
+               return -ENXIO;
 
        mutex_lock(&chip->spos_mutex);
 
@@ -917,7 +924,7 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
                return -ENXIO;
        }
 
-       snd_assert (cpcm->pcm_channel != NULL);
+       snd_BUG_ON(!cpcm->pcm_channel);
        if (!cpcm->pcm_channel) {
                mutex_unlock(&chip->spos_mutex);
                return -ENXIO;
@@ -952,7 +959,7 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
                } else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {
                        substream->ops = &snd_cs46xx_playback_iec958_ops;
                } else {
-                       snd_assert(0);
+                       snd_BUG();
                }
 #else
                substream->ops = &snd_cs46xx_playback_ops;
@@ -981,7 +988,7 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
                } else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {
                        substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;
                } else {
-                       snd_assert(0);
+                       snd_BUG();
                }
 #else
                substream->ops = &snd_cs46xx_playback_indirect_ops;
@@ -1029,7 +1036,8 @@ static int snd_cs46xx_playback_prepare(struct snd_pcm_substream *substream)
        cpcm = runtime->private_data;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-    snd_assert (cpcm->pcm_channel != NULL, return -ENXIO);
+       if (snd_BUG_ON(!cpcm->pcm_channel))
+               return -ENXIO;
 
        pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );
        pfie &= ~0x0000f03f;
@@ -1714,9 +1722,9 @@ static void snd_cs46xx_mixer_free_ac97(struct snd_ac97 *ac97)
 {
        struct snd_cs46xx *chip = ac97->private_data;
 
-       snd_assert ((ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) ||
-                   (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]),
-                   return);
+       if (snd_BUG_ON(ac97 != chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] &&
+                      ac97 != chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]))
+               return;
 
        if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) {
                chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = NULL;
@@ -1864,7 +1872,7 @@ static int snd_cs46xx_iec958_put(struct snd_kcontrol *kcontrol,
                break;
        default:
                res = -EINVAL;
-               snd_assert(0, (void)0);
+               snd_BUG(); /* should never happen ... */
        }
 
        return res;
@@ -2236,7 +2244,7 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
                snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3);
                snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3);
        } else {
-               snd_assert(0); /* should never happen ... */
+               snd_BUG(); /* should never happen ... */
        }
 
        udelay(50);
@@ -2553,7 +2561,8 @@ static void snd_cs46xx_gameport_trigger(struct gameport *gameport)
 {
        struct snd_cs46xx *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return);
+       if (snd_BUG_ON(!chip))
+               return;
        snd_cs46xx_pokeBA0(chip, BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
 }
 
@@ -2561,7 +2570,8 @@ static unsigned char snd_cs46xx_gameport_read(struct gameport *gameport)
 {
        struct snd_cs46xx *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
        return snd_cs46xx_peekBA0(chip, BA0_JSPT); //inb(gameport->io);
 }
 
@@ -2570,7 +2580,8 @@ static int snd_cs46xx_gameport_cooked_read(struct gameport *gameport, int *axes,
        struct snd_cs46xx *chip = gameport_get_port_data(gameport);
        unsigned js1, js2, jst;
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
 
        js1 = snd_cs46xx_peekBA0(chip, BA0_JSC1);
        js2 = snd_cs46xx_peekBA0(chip, BA0_JSC2);
@@ -2754,7 +2765,8 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
 {
        int idx;
 
-       snd_assert(chip != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
 
        if (chip->active_ctrl)
                chip->active_ctrl(chip, 1);
@@ -3489,8 +3501,9 @@ static struct cs_card_type __devinitdata cards[] = {
                .name = "Mitac MI6020/21",
                .amp = amp_voyetra,
        },
+       /* Hercules Game Theatre XP */
        {
-               .vendor = 0x14AF,
+               .vendor = 0x14af, /* Guillemot Corporation */
                .id = 0x0050,
                .name = "Hercules Game Theatre XP",
                .amp = amp_hercules,
@@ -3532,7 +3545,23 @@ static struct cs_card_type __devinitdata cards[] = {
                .amp = amp_hercules,
                .mixer_init = hercules_mixer_init,
        },
+       /* Herculess Fortissimo */
+       {
+               .vendor = 0x1681,
+               .id = 0xa010,
+               .name = "Hercules Gamesurround Fortissimo II",
+       },
+       {
+               .vendor = 0x1681,
+               .id = 0xa011,
+               .name = "Hercules Gamesurround Fortissimo III 7.1",
+       },
        /* Teratec */
+       {
+               .vendor = 0x153b,
+               .id = 0x112e,
+               .name = "Terratec DMX XFire 1024",
+       },
        {
                .vendor = 0x153b,
                .id = 0x1136,
index ccc8bedb5b1a3e6136c913806cf347d60f7f8053..f4f0c8f5dad76ab71cf57eaf835bfda69922c972 100644 (file)
@@ -63,7 +63,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
        u32 mop_operands,mop_type,wide_op;
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert( ((size % 2) == 0), return -EINVAL);
+       if (snd_BUG_ON(size %2))
+               return -EINVAL;
   
        while (i < size) {
                loval = data[i++];
@@ -289,7 +290,8 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
        int i;
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert(ins != NULL, return);
+       if (snd_BUG_ON(!ins))
+               return;
 
        mutex_lock(&chip->spos_mutex);
        for (i = 0; i < ins->nscb; ++i) {
@@ -404,7 +406,8 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
 
                /* if module has a code segment it must have
                   symbol table */
-               snd_assert(module->symbol_table.symbols != NULL ,return -ENOMEM);
+               if (snd_BUG_ON(!module->symbol_table.symbols))
+                       return -ENOMEM;
                if (add_symbols(chip,module)) {
                        snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");
                        return -ENOMEM;
@@ -1369,7 +1372,8 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
 
        valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
 
-       snd_assert (chip->nr_ac97_codecs == 1 || chip->nr_ac97_codecs == 2);
+       if (snd_BUG_ON(chip->nr_ac97_codecs != 1 && chip->nr_ac97_codecs != 2))
+               goto _fail_end;
 
        if (chip->nr_ac97_codecs == 1) {
                /* output on slot 5 and 11 
@@ -1609,11 +1613,14 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
 
                spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
 
-               snd_assert(spdifo_scb_desc, return -EIO);
+               if (snd_BUG_ON(!spdifo_scb_desc))
+                       return -EIO;
                spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
-               snd_assert(spdifi_scb_desc, return -EIO);
+               if (snd_BUG_ON(!spdifi_scb_desc))
+                       return -EIO;
                async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
-               snd_assert(async_codec_scb_desc, return -EIO);
+               if (snd_BUG_ON(!async_codec_scb_desc))
+                       return -EIO;
 
                async_codec_scb_desc->parent_scb_ptr = NULL;
                async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
@@ -1698,8 +1705,10 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
        chip->active_ctrl(chip, 1);
        chip->amplifier_ctrl(chip, 1);
 
-       snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL);
-       snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
+       if (snd_BUG_ON(ins->asynch_rx_scb))
+               return -EINVAL;
+       if (snd_BUG_ON(!ins->spdif_in_src))
+               return -EINVAL;
 
        mutex_lock(&chip->spos_mutex);
 
@@ -1754,8 +1763,10 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL);
-       snd_assert (ins->spdif_in_src != NULL,return -EINVAL);  
+       if (snd_BUG_ON(!ins->asynch_rx_scb))
+               return -EINVAL;
+       if (snd_BUG_ON(!ins->spdif_in_src))
+               return -EINVAL;
 
        mutex_lock(&chip->spos_mutex);
 
@@ -1780,8 +1791,10 @@ int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert (ins->pcm_input == NULL,return -EINVAL);
-       snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL);
+       if (snd_BUG_ON(ins->pcm_input))
+               return -EINVAL;
+       if (snd_BUG_ON(!ins->ref_snoop_scb))
+               return -EINVAL;
 
        mutex_lock(&chip->spos_mutex);
        ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
@@ -1795,7 +1808,8 @@ int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert (ins->pcm_input != NULL,return -EINVAL);
+       if (snd_BUG_ON(!ins->pcm_input))
+               return -EINVAL;
 
        mutex_lock(&chip->spos_mutex);
        cs46xx_dsp_remove_scb (chip,ins->pcm_input);
@@ -1809,8 +1823,10 @@ int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert (ins->adc_input == NULL,return -EINVAL);
-       snd_assert (ins->codec_in_scb != NULL,return -EINVAL);
+       if (snd_BUG_ON(ins->adc_input))
+               return -EINVAL;
+       if (snd_BUG_ON(!ins->codec_in_scb))
+               return -EINVAL;
 
        mutex_lock(&chip->spos_mutex);
        ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
@@ -1824,7 +1840,8 @@ int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert (ins->adc_input != NULL,return -EINVAL);
+       if (snd_BUG_ON(!ins->adc_input))
+               return -EINVAL;
 
        mutex_lock(&chip->spos_mutex);
        cs46xx_dsp_remove_scb (chip,ins->adc_input);
index 2873cfe48c331605f50d23f84350ba4865ce9750..dd7c41b037b45e0700c55db9e32851a04e34ef55 100644 (file)
@@ -46,8 +46,11 @@ static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * s
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
        int symbol_index = (int)(symbol - ins->symbol_table.symbols);
 
-       snd_assert(ins->symbol_table.nsymbols > 0,return);
-       snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return);
+       if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
+               return;
+       if (snd_BUG_ON(symbol_index < 0 ||
+                      symbol_index >= ins->symbol_table.nsymbols))
+               return;
 
        ins->symbol_table.symbols[symbol_index].deleted = 1;
 
@@ -116,8 +119,9 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor
 
        if ( scb->parent_scb_ptr ) {
                /* unlink parent SCB */
-               snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
-                            scb->parent_scb_ptr->next_scb_ptr == scb),return);
+               if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
+                              scb->parent_scb_ptr->next_scb_ptr != scb))
+                       return;
   
                if (scb->parent_scb_ptr->sub_list_ptr == scb) {
 
@@ -140,7 +144,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor
                                scb->next_scb_ptr = ins->the_null_scb;
                        }
                } else {
-                       /* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */
                        scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
 
                        if (scb->next_scb_ptr != ins->the_null_scb) {
@@ -181,16 +184,17 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
        unsigned long flags;
 
        /* check integrety */
-       snd_assert ( (scb->index >= 0 && 
-                     scb->index < ins->nscb && 
-                     (ins->scbs + scb->index) == scb), return );
+       if (snd_BUG_ON(scb->index < 0 ||
+                      scb->index >= ins->nscb ||
+                      (ins->scbs + scb->index) != scb))
+               return;
 
 #if 0
        /* can't remove a SCB with childs before 
           removing childs first  */
-       snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
-                     scb->next_scb_ptr == ins->the_null_scb),
-                    goto _end);
+       if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
+                      scb->next_scb_ptr != ins->the_null_scb))
+               goto _end;
 #endif
 
        spin_lock_irqsave(&scb->lock, flags);
@@ -198,7 +202,8 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
        spin_unlock_irqrestore(&scb->lock, flags);
 
        cs46xx_dsp_proc_free_scb_desc(scb);
-       snd_assert (scb->scb_symbol != NULL, return );
+       if (snd_BUG_ON(!scb->scb_symbol))
+               return;
        remove_symbol (chip,scb->scb_symbol);
 
        ins->scbs[scb->index].deleted = 1;
@@ -234,7 +239,6 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
                snd_info_free_entry(scb->proc_info);
                scb->proc_info = NULL;
 
-               snd_assert (scb_info != NULL, return);
                kfree (scb_info);
        }
 }
@@ -291,7 +295,8 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
   
        unsigned long flags;
 
-       snd_assert (ins->the_null_scb != NULL,return NULL);
+       if (snd_BUG_ON(!ins->the_null_scb))
+               return NULL;
 
        /* fill the data that will be wroten to DSP */
        scb_data[SCBsubListPtr] = 
@@ -321,18 +326,20 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
 #endif
                /* link to  parent SCB */
                if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
-                       snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
-                                    return NULL);
+                       if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
+                                      ins->the_null_scb))
+                               return NULL;
 
                        scb->parent_scb_ptr->next_scb_ptr = scb;
 
                } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
-                       snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
-                                    return NULL);
+                       if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
+                                      ins->the_null_scb))
+                               return NULL;
 
                        scb->parent_scb_ptr->sub_list_ptr = scb;
                } else {
-                       snd_assert (0,return NULL);
+                       snd_BUG();
                }
 
                spin_lock_irqsave(&chip->reg_lock, flags);
@@ -675,7 +682,7 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
                if (pass_through) {
                        /* wont work with any other rate than
                           the native DSP rate */
-                       snd_assert (rate == 48000);
+                       snd_BUG_ON(rate != 48000);
 
                        scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
                                                            dest,"DMAREADER",parent_scb,
@@ -1142,7 +1149,8 @@ find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
        struct dsp_scb_descriptor * scb = from;
 
        while (scb->next_scb_ptr != ins->the_null_scb) {
-               snd_assert (scb->next_scb_ptr != NULL, return NULL);
+               if (snd_BUG_ON(!scb->next_scb_ptr))
+                       return NULL;
 
                scb = scb->next_scb_ptr;
        }
@@ -1246,10 +1254,11 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
                break;
        case DSP_PCM_S71_CHANNEL:
                /* TODO */
-               snd_assert(0);
+               snd_BUG();
                break;
        case DSP_IEC958_CHANNEL:
-               snd_assert (ins->asynch_tx_scb != NULL, return NULL);
+               if (snd_BUG_ON(!ins->asynch_tx_scb))
+                       return NULL;
                mixer_scb = ins->asynch_tx_scb;
 
                /* if sample rate is set to 48khz we pass
@@ -1262,7 +1271,7 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
                }
                break;
        default:
-               snd_assert (0);
+               snd_BUG();
                return NULL;
        }
        /* default sample rate is 44100 */
@@ -1308,7 +1317,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
                                break;
                        }
                }
-               snd_assert (src_index != -1,return NULL);
+               if (snd_BUG_ON(src_index == -1))
+                       return NULL;
 
                /* we need to create a new SRC SCB */
                if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
@@ -1462,9 +1472,10 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
        unsigned long flags;
 
-       snd_assert(pcm_channel->active, return );
-       snd_assert(ins->npcm_channels > 0, return );
-       snd_assert(pcm_channel->src_scb->ref_count > 0, return );
+       if (snd_BUG_ON(!pcm_channel->active ||
+                      ins->npcm_channels <= 0 ||
+                      pcm_channel->src_scb->ref_count <= 0))
+               return;
 
        spin_lock_irqsave(&chip->reg_lock, flags);
        pcm_channel->unlinked = 1;
@@ -1479,8 +1490,9 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
        if (!pcm_channel->src_scb->ref_count) {
                cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
 
-               snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot < DSP_MAX_SRC_NR,
-                           return );
+               if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
+                              pcm_channel->src_slot >= DSP_MAX_SRC_NR))
+                       return;
 
                ins->src_scb_slots[pcm_channel->src_slot] = 0;
                ins->nsrc_scb --;
@@ -1490,11 +1502,11 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
                           struct dsp_pcm_channel_descriptor * pcm_channel)
 {
-       struct dsp_spos_instance * ins = chip->dsp_spos_instance;
        unsigned long flags;
 
-       snd_assert(pcm_channel->active,return -EIO);
-       snd_assert(ins->npcm_channels > 0,return -EIO);
+       if (snd_BUG_ON(!pcm_channel->active ||
+                      chip->dsp_spos_instance->npcm_channels <= 0))
+               return -EIO;
 
        spin_lock(&pcm_channel->src_scb->lock);
 
@@ -1537,7 +1549,7 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
 
        src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
 
-       snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
+       snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
        pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
 
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1564,7 +1576,8 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s
        struct dsp_scb_descriptor * pcm_input;
        int insert_point;
 
-       snd_assert (ins->record_mixer_scb != NULL,return NULL);
+       if (snd_BUG_ON(!ins->record_mixer_scb))
+               return NULL;
 
        if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
                parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
@@ -1583,7 +1596,8 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s
 
 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
 {
-       snd_assert (src->parent_scb_ptr != NULL,  return -EINVAL );
+       if (snd_BUG_ON(!src->parent_scb_ptr))
+               return -EINVAL;
 
        /* mute SCB */
        cs46xx_dsp_scb_set_volume (chip,src,0,0);
@@ -1598,8 +1612,10 @@ int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
        struct dsp_scb_descriptor * parent_scb;
 
-       snd_assert (src->parent_scb_ptr == NULL,   return -EINVAL );
-       snd_assert(ins->master_mix_scb !=NULL,   return -EINVAL );
+       if (snd_BUG_ON(src->parent_scb_ptr))
+               return -EINVAL;
+       if (snd_BUG_ON(!ins->master_mix_scb))
+               return -EINVAL;
 
        if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
                parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
@@ -1635,8 +1651,11 @@ int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
                return -EBUSY;
        }
 
-       snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
-       snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
+       if (snd_BUG_ON(ins->asynch_tx_scb))
+               return -EINVAL;
+       if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
+                      ins->the_null_scb))
+               return -EINVAL;
 
        /* reset output snooper sample buffer pointer */
        snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
@@ -1676,10 +1695,15 @@ int  cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
        }
 
        /* check integrety */
-       snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
-       snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
-       snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
-       snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
+       if (snd_BUG_ON(!ins->asynch_tx_scb))
+               return -EINVAL;
+       if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
+               return -EINVAL;
+       if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
+               return -EINVAL;
+       if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
+                      ins->master_mix_scb))
+               return -EINVAL;
 
        cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
        cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
@@ -1734,7 +1758,8 @@ int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-       snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
+       if (snd_BUG_ON(!ins->asynch_tx_scb))
+               return -EINVAL;
 
        ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
 
index 4159e3bc186f359ab3076dff75ce14c9f02b870b..29043301ebb867aaaf32f0b6221905407e0f5a0f 100644 (file)
@@ -34,7 +34,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Darla20\n"));
-       snd_assert((subdevice_id & 0xfff0) == DARLA20, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
index 79938eed7e9c20cbdaa106123877cb63526a5562..60228731841f84fc2b1bc814242f9e9d06839451 100644 (file)
@@ -34,7 +34,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Darla24\n"));
-       snd_assert((subdevice_id & 0xfff0) == DARLA24, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -148,8 +149,9 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
 
 static int set_input_clock(struct echoaudio *chip, u16 clock)
 {
-       snd_assert(clock == ECHO_CLOCK_INTERNAL ||
-                  clock == ECHO_CLOCK_ESYNC, return -EINVAL);
+       if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
+                      clock != ECHO_CLOCK_ESYNC))
+               return -EINVAL;
        chip->input_clock = clock;
        return set_sample_rate(chip, chip->sample_rate);
 }
index 48eb7c599111b62e5a2af76b3962c1831db14808..417e25add82bccdb120724b837b5d32f52b2f62c 100644 (file)
@@ -47,7 +47,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
 
        local_irq_enable();
        DE_INIT(("init_hw() - Echo3G\n"));
-       snd_assert((subdevice_id & 0xfff0) == ECHO3G, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -104,9 +105,11 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)) < 0)
                return err;
        err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        err = set_phantom_power(chip, 0);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        err = set_professional_spdif(chip, TRUE);
 
        DE_INIT(("init_hw done\n"));
index e16dc92e82fb4359e5ae92b11300fce4dd9e9c9c..8dbc5c4ba421a03dd128050dbd271616efdee3ae 100644 (file)
@@ -490,7 +490,6 @@ static int init_engine(struct snd_pcm_substream *substream,
 {
        struct echoaudio *chip;
        int err, per, rest, page, edge, offs;
-       struct snd_sg_buf *sgbuf;
        struct audiopipe *pipe;
 
        chip = snd_pcm_substream_chip(substream);
@@ -503,7 +502,7 @@ static int init_engine(struct snd_pcm_substream *substream,
        if (pipe->index >= 0) {
                DE_HWP(("hwp_ie free(%d)\n", pipe->index));
                err = free_pipes(chip, pipe);
-               snd_assert(!err);
+               snd_BUG_ON(err);
                chip->substream[pipe->index] = NULL;
        }
 
@@ -531,10 +530,6 @@ static int init_engine(struct snd_pcm_substream *substream,
                return err;
        }
 
-       sgbuf = snd_pcm_substream_sgbuf(substream);
-
-       DE_HWP(("pcm_hw_params table size=%d pages=%d\n",
-               sgbuf->size, sgbuf->pages));
        sglist_init(chip, pipe);
        edge = PAGE_SIZE;
        for (offs = page = per = 0; offs < params_buffer_bytes(hw_params);
@@ -543,16 +538,15 @@ static int init_engine(struct snd_pcm_substream *substream,
                if (offs + rest > params_buffer_bytes(hw_params))
                        rest = params_buffer_bytes(hw_params) - offs;
                while (rest) {
+                       dma_addr_t addr;
+                       addr = snd_pcm_sgbuf_get_addr(substream, offs);
                        if (rest <= edge - offs) {
-                               sglist_add_mapping(chip, pipe,
-                                                  snd_sgbuf_get_addr(sgbuf, offs),
-                                                  rest);
+                               sglist_add_mapping(chip, pipe, addr, rest);
                                sglist_add_irq(chip, pipe);
                                offs += rest;
                                rest = 0;
                        } else {
-                               sglist_add_mapping(chip, pipe,
-                                                  snd_sgbuf_get_addr(sgbuf, offs),
+                               sglist_add_mapping(chip, pipe, addr,
                                                   edge - offs);
                                rest -= edge - offs;
                                offs = edge;
@@ -690,8 +684,10 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
                return -EINVAL;
        }
 
-       snd_assert(pipe_index < px_num(chip), return -EINVAL);
-       snd_assert(is_pipe_allocated(chip, pipe_index), return -EINVAL);
+       if (snd_BUG_ON(pipe_index >= px_num(chip)))
+               return -EINVAL;
+       if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index)))
+               return -EINVAL;
        set_audio_format(chip, pipe_index, &format);
        return 0;
 }
index 52a933189576ad5a2f1060347af38dc5d88786d7..c3736bbd819e31da81312ccf942ff687bfa787d7 100644 (file)
@@ -103,9 +103,11 @@ static int set_digital_mode(struct echoaudio *chip, u8 mode)
        int err, i, o;
 
        /* All audio channels must be closed before changing the digital mode */
-       snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
+       if (snd_BUG_ON(chip->pipe_alloc_mask))
+               return -EAGAIN;
 
-       snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
+       if (snd_BUG_ON(!(chip->digital_modes & (1 << mode))))
+               return -EINVAL;
 
        previous_mode = chip->digital_mode;
        err = dsp_set_digital_mode(chip, mode);
@@ -267,8 +269,9 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
                return 0;
        }
 
-       snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
-                  return -EINVAL);
+       if (snd_BUG_ON(rate >= 50000 &&
+                      chip->digital_mode == DIGITAL_MODE_ADAT))
+               return -EINVAL;
 
        clock = 0;
        control_reg = le32_to_cpu(chip->comm_page->control_register);
index e6c100770392ef20b146903bc142305323a301f8..be0e18192de3ffca06502cbbc23e872df3d0cecb 100644 (file)
@@ -474,7 +474,8 @@ static int load_firmware(struct echoaudio *chip)
        const struct firmware *fw;
        int box_type, err;
 
-       snd_assert(chip->dsp_code_to_load && chip->comm_page, return -EPERM);
+       if (snd_BUG_ON(!chip->dsp_code_to_load || !chip->comm_page))
+               return -EPERM;
 
        /* See if the ASIC is present and working - only if the DSP is already loaded */
        if (chip->dsp_code) {
@@ -512,8 +513,8 @@ static int load_firmware(struct echoaudio *chip)
 /* Set the nominal level for an input or output bus (true = -10dBV, false = +4dBu) */
 static int set_nominal_level(struct echoaudio *chip, u16 index, char consumer)
 {
-       snd_assert(index < num_busses_out(chip) + num_busses_in(chip),
-                  return -EINVAL);
+       if (snd_BUG_ON(index >= num_busses_out(chip) + num_busses_in(chip)))
+               return -EINVAL;
 
        /* Wait for the handshake (OK even if ASIC is not loaded) */
        if (wait_handshake(chip))
@@ -536,7 +537,8 @@ static int set_nominal_level(struct echoaudio *chip, u16 index, char consumer)
 /* Set the gain for a single physical output channel (dB). */
 static int set_output_gain(struct echoaudio *chip, u16 channel, s8 gain)
 {
-       snd_assert(channel < num_busses_out(chip), return -EINVAL);
+       if (snd_BUG_ON(channel >= num_busses_out(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
@@ -554,8 +556,9 @@ static int set_output_gain(struct echoaudio *chip, u16 channel, s8 gain)
 static int set_monitor_gain(struct echoaudio *chip, u16 output, u16 input,
                            s8 gain)
 {
-       snd_assert(output < num_busses_out(chip) &&
-                  input < num_busses_in(chip), return -EINVAL);
+       if (snd_BUG_ON(output >= num_busses_out(chip) ||
+                   input >= num_busses_in(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
@@ -1065,8 +1068,10 @@ static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe)
        int i;
 
        DE_ACT(("free_pipes: Pipe %d\n", pipe->index));
-       snd_assert(is_pipe_allocated(chip, pipe->index), return -EINVAL);
-       snd_assert(pipe->state == PIPE_STATE_STOPPED, return -EINVAL);
+       if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index)))
+               return -EINVAL;
+       if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED))
+               return -EINVAL;
 
        for (channel_mask = i = 0; i < pipe->interleave; i++)
                channel_mask |= 1 << (pipe->index + i);
index 3aa37e76ebab12f3f895d75f128d9eeada3fe209..afa273330e8a744b37327f679b55bda61f1924e4 100644 (file)
@@ -112,9 +112,11 @@ static int set_digital_mode(struct echoaudio *chip, u8 mode)
                return -EIO;
 
        /* All audio channels must be closed before changing the digital mode */
-       snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
+       if (snd_BUG_ON(chip->pipe_alloc_mask))
+               return -EAGAIN;
 
-       snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
+       if (snd_BUG_ON(!(chip->digital_modes & (1 << mode))))
+               return -EINVAL;
 
        previous_mode = chip->digital_mode;
        err = dsp_set_digital_mode(chip, mode);
index 2757c89608434f4a3c48f59d8520c0be39d800fe..db6c952e9d7f12e77a799d0e8edaabd12c8af5a8 100644 (file)
@@ -38,7 +38,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Gina20\n"));
-       snd_assert((subdevice_id & 0xfff0) == GINA20, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -177,7 +178,8 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
 /* Set input bus gain (one unit is 0.5dB !) */
 static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
 {
-       snd_assert(input < num_busses_in(chip), return -EINVAL);
+       if (snd_BUG_ON(input >= num_busses_in(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
index 144fc567becf1ff179ea6fac383c2162b350e19c..2fef37a2a5b96693abc5988fc420a7827d36b8ae 100644 (file)
@@ -43,7 +43,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Gina24\n"));
-       snd_assert((subdevice_id & 0xfff0) == GINA24, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -84,7 +85,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)) < 0)
                return err;
        err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        err = set_professional_spdif(chip, TRUE);
 
        DE_INIT(("init_hw done\n"));
@@ -163,8 +165,9 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
 {
        u32 control_reg, clock;
 
-       snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
-                  return -EINVAL);
+       if (snd_BUG_ON(rate >= 50000 &&
+                      chip->digital_mode == DIGITAL_MODE_ADAT))
+               return -EINVAL;
 
        /* Only set the clock for internal mode. */
        if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
index d6ac7734609e7fcd151856cd22dc05a88d619889..f05e39f7aad943c2e5591cda8aac4b4336d524de 100644 (file)
@@ -39,7 +39,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Indigo\n"));
-       snd_assert((subdevice_id & 0xfff0) == INDIGO, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -143,8 +144,9 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
 {
        int index;
 
-       snd_assert(pipe < num_pipes_out(chip) &&
-                  output < num_busses_out(chip), return -EINVAL);
+       if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+                      output >= num_busses_out(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
index 500e150b49fcaa340f6028300d1de19d62d57798..90730a5ecb422b880c8e36aff0d21adf2d8198aa 100644 (file)
@@ -39,7 +39,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Indigo DJ\n"));
-       snd_assert((subdevice_id & 0xfff0) == INDIGO_DJ, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -143,8 +144,9 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
 {
        int index;
 
-       snd_assert(pipe < num_pipes_out(chip) &&
-                  output < num_busses_out(chip), return -EINVAL);
+       if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+                      output >= num_busses_out(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
index f3ad13d06be0237f42a4fd511943c50fb3aa1ee1..a7e09ec2107908f395319ca8b9cb0ab491b646f9 100644 (file)
@@ -39,7 +39,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Indigo IO\n"));
-       snd_assert((subdevice_id & 0xfff0) == INDIGO_IO, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -114,8 +115,9 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
 {
        int index;
 
-       snd_assert(pipe < num_pipes_out(chip) &&
-                  output < num_busses_out(chip), return -EINVAL);
+       if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+                      output >= num_busses_out(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
index 990c9a60a0a89a81f8acf6c280faa50395d17012..ede75c6ca0fb7520fb8ec8b93049da396618f946 100644 (file)
@@ -42,7 +42,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Layla20\n"));
-       snd_assert((subdevice_id & 0xfff0) == LAYLA20, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -155,7 +156,8 @@ static int load_asic(struct echoaudio *chip)
 
 static int set_sample_rate(struct echoaudio *chip, u32 rate)
 {
-       snd_assert(rate >= 8000 && rate <= 50000, return -EINVAL);
+       if (snd_BUG_ON(rate < 8000 || rate > 50000))
+               return -EINVAL;
 
        /* Only set the clock for internal mode. Do not return failure,
           simply treat it as a non-event. */
@@ -252,7 +254,8 @@ static int set_output_clock(struct echoaudio *chip, u16 clock)
 /* Set input bus gain (one unit is 0.5dB !) */
 static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
 {
-       snd_assert(input < num_busses_in(chip), return -EINVAL);
+       if (snd_BUG_ON(input >= num_busses_in(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
index 97e42e1151476cdafbb40ac83a6d09b2798bd704..d61b5cbcccad4235314d6d0bd05ee93e82ed282f 100644 (file)
@@ -42,7 +42,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Layla24\n"));
-       snd_assert((subdevice_id & 0xfff0) == LAYLA24, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -73,7 +74,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
 
        err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        err = set_professional_spdif(chip, TRUE);
 
        DE_INIT(("init_hw done\n"));
@@ -158,8 +160,9 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
 {
        u32 control_reg, clock, base_rate;
 
-       snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
-                  return -EINVAL);
+       if (snd_BUG_ON(rate >= 50000 &&
+                      chip->digital_mode == DIGITAL_MODE_ADAT))
+               return -EINVAL;
 
        /* Only set the clock for internal mode. */
        if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
index 891c7051909648948566eb0e8c0887ce25d1c899..227386602f9b6a86064f8c92c94acbb980a953f3 100644 (file)
@@ -42,7 +42,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Mia\n"));
-       snd_assert((subdevice_id & 0xfff0) == MIA, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -161,8 +162,9 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
 static int set_input_clock(struct echoaudio *chip, u16 clock)
 {
        DE_ACT(("set_input_clock(%d)\n", clock));
-       snd_assert(clock == ECHO_CLOCK_INTERNAL || clock == ECHO_CLOCK_SPDIF,
-                  return -EINVAL);
+       if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
+                      clock != ECHO_CLOCK_SPDIF))
+               return -EINVAL;
 
        chip->input_clock = clock;
        return set_sample_rate(chip, chip->sample_rate);
@@ -176,8 +178,9 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
 {
        int index;
 
-       snd_assert(pipe < num_pipes_out(chip) &&
-                  output < num_busses_out(chip), return -EINVAL);
+       if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+                      output >= num_busses_out(chip)))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
index 91f5bff66d3f923fa870184bfc3705be62b1f7a9..77bf2a83d9970751c3e26a449c7dfa1d882f89d8 100644 (file)
@@ -59,7 +59,8 @@ static int enable_midi_input(struct echoaudio *chip, char enable)
 Returns how many actually written or < 0 on error */
 static int write_midi(struct echoaudio *chip, u8 *data, int bytes)
 {
-       snd_assert(bytes > 0 && bytes < MIDI_OUT_BUFFER_SIZE, return -EINVAL);
+       if (snd_BUG_ON(bytes <= 0 || bytes >= MIDI_OUT_BUFFER_SIZE))
+               return -EINVAL;
 
        if (wait_handshake(chip))
                return -EIO;
@@ -119,7 +120,8 @@ static int midi_service_irq(struct echoaudio *chip)
        /* The count is at index 0, followed by actual data */
        count = le16_to_cpu(chip->comm_page->midi_input[0]);
 
-       snd_assert(count < MIDI_IN_BUFFER_SIZE, return 0);
+       if (snd_BUG_ON(count >= MIDI_IN_BUFFER_SIZE))
+               return 0;
 
        /* Get the MIDI data from the comm page */
        i = 1;
index c0b4bf0be7d1af6273ef8c8cab9c46e38e0b0c12..eaa619bd2a0343f2d9a5e7a7c7c8b54585a9413c 100644 (file)
@@ -43,7 +43,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        int err;
 
        DE_INIT(("init_hw() - Mona\n"));
-       snd_assert((subdevice_id & 0xfff0) == MONA, return -ENODEV);
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA))
+               return -ENODEV;
 
        if ((err = init_dsp_comm_page(chip))) {
                DE_INIT(("init_hw - could not initialize DSP comm page\n"));
@@ -79,7 +80,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
 
        err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       snd_assert(err >= 0, return err);
+       if (err < 0)
+               return err;
        err = set_professional_spdif(chip, TRUE);
 
        DE_INIT(("init_hw done\n"));
index 45088ebcce5041a9b25e147d41be6add78351f05..0e649dcdbf64bef54d800e8ad7b3384124ca0efe 100644 (file)
@@ -145,7 +145,8 @@ terminate_voice(struct snd_emux_voice *vp)
 {
        struct snd_emu10k1 *hw;
        
-       snd_assert(vp, return);
+       if (snd_BUG_ON(!vp))
+               return;
        hw = vp->hw;
        snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK);
        if (vp->block) {
@@ -325,7 +326,8 @@ start_voice(struct snd_emux_voice *vp)
        
        hw = vp->hw;
        ch = vp->ch;
-       snd_assert(ch >= 0, return -EINVAL);
+       if (snd_BUG_ON(ch < 0))
+               return -EINVAL;
        chan = vp->chan;
 
        emem = (struct snd_emu10k1_memblk *)vp->block;
index 42bae6f7e9a4c61458c96dab0cc89d5c2fa0252c..e10f027bde03a660899e1a440538c2a661d150e9 100644 (file)
@@ -46,8 +46,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
        struct snd_emu10k1 *emu;
 
        emu = rec->hw;
-       snd_assert(sp != NULL, return -EINVAL);
-       snd_assert(hdr != NULL, return -EINVAL);
+       if (snd_BUG_ON(!sp || !hdr))
+               return -EINVAL;
 
        if (sp->v.size == 0) {
                snd_printd("emu: rom font for sample %d\n", sp->v.sample);
@@ -104,7 +104,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
        size = BLANK_HEAD_SIZE;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                size *= 2;
-       snd_assert(offset + size <= blocksize, return -EINVAL);
+       if (offset + size > blocksize)
+               return -EINVAL;
        snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
        offset += size;
 
@@ -112,7 +113,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
        size = loopend;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                size *= 2;
-       snd_assert(offset + size <= blocksize, return -EINVAL);
+       if (offset + size > blocksize)
+               return -EINVAL;
        if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
                snd_emu10k1_synth_free(emu, sp->block);
                sp->block = NULL;
@@ -129,12 +131,14 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
                        int woffset;
                        unsigned short *wblock = (unsigned short*)block;
                        woffset = offset / 2;
-                       snd_assert(offset + loopsize*2 <= blocksize, return -EINVAL);
+                       if (offset + loopsize * 2 > blocksize)
+                               return -EINVAL;
                        for (i = 0; i < loopsize; i++)
                                wblock[woffset + i] = wblock[woffset - i -1];
                        offset += loopsize * 2;
                } else {
-                       snd_assert(offset + loopsize <= blocksize, return -EINVAL);
+                       if (offset + loopsize > blocksize)
+                               return -EINVAL;
                        for (i = 0; i < loopsize; i++)
                                block[offset + i] = block[offset - i -1];
                        offset += loopsize;
@@ -154,7 +158,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 
        /* loopend -> sample end */
        size = sp->v.size - loopend;
-       snd_assert(size >= 0, return -EINVAL);
+       if (size < 0)
+               return -EINVAL;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                size *= 2;
        if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
@@ -212,8 +217,8 @@ snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
        struct snd_emu10k1 *emu;
 
        emu = rec->hw;
-       snd_assert(sp != NULL, return -EINVAL);
-       snd_assert(hdr != NULL, return -EINVAL);
+       if (snd_BUG_ON(!sp || !hdr))
+               return -EINVAL;
 
        if (sp->block) {
                snd_emu10k1_synth_free(emu, sp->block);
index 491a4a50f869c3dca9887bb9347ca6af64eb5d9b..5ff4dbb62dad1412e3f7ca987052427086912944 100644 (file)
@@ -1319,7 +1319,8 @@ static int snd_emu10k1x_midi_input_open(struct snd_rawmidi_substream *substream)
        unsigned long flags;
        
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT;
        midi->substream_input = substream;
@@ -1345,7 +1346,8 @@ static int snd_emu10k1x_midi_output_open(struct snd_rawmidi_substream *substream
        unsigned long flags;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT;
        midi->substream_output = substream;
@@ -1372,7 +1374,8 @@ static int snd_emu10k1x_midi_input_close(struct snd_rawmidi_substream *substream
        int err = 0;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        snd_emu10k1x_intr_disable(emu, midi->rx_enable);
        midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT;
@@ -1394,7 +1397,8 @@ static int snd_emu10k1x_midi_output_close(struct snd_rawmidi_substream *substrea
        int err = 0;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        snd_emu10k1x_intr_disable(emu, midi->tx_enable);
        midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT;
@@ -1413,7 +1417,8 @@ static void snd_emu10k1x_midi_input_trigger(struct snd_rawmidi_substream *substr
        struct emu10k1x *emu;
        struct emu10k1x_midi *midi = substream->rmidi->private_data;
        emu = midi->emu;
-       snd_assert(emu, return);
+       if (snd_BUG_ON(!emu))
+               return;
 
        if (up)
                snd_emu10k1x_intr_enable(emu, midi->rx_enable);
@@ -1428,7 +1433,8 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst
        unsigned long flags;
 
        emu = midi->emu;
-       snd_assert(emu, return);
+       if (snd_BUG_ON(!emu))
+               return;
 
        if (up) {
                int max = 4;
index 71dc4c8865b88323edbe13a811c5171061d26e51..7dba08f0ab8e2c9d9e166fd12f3ed9934ed3cd34 100644 (file)
@@ -487,7 +487,8 @@ static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
                                 u32 op, u32 r, u32 a, u32 x, u32 y)
 {
        u_int32_t *code;
-       snd_assert(*ptr < 512, return);
+       if (snd_BUG_ON(*ptr >= 512))
+               return;
        code = (u_int32_t __force *)icode->code + (*ptr) * 2;
        set_bit(*ptr, icode->code_valid);
        code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
@@ -503,7 +504,8 @@ static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
                                        u32 op, u32 r, u32 a, u32 x, u32 y)
 {
        u_int32_t *code;
-       snd_assert(*ptr < 1024, return);
+       if (snd_BUG_ON(*ptr >= 1024))
+               return;
        code = (u_int32_t __force *)icode->code + (*ptr) * 2;
        set_bit(*ptr, icode->code_valid);
        code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
index c4d76d16661eed2d5af5a49ec51e81cb22cef45c..8578c70c61f2b4ee15a7583c47641bd2405d4e78 100644 (file)
@@ -157,7 +157,8 @@ static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
        unsigned long flags;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
        midi->substream_input = substream;
@@ -183,7 +184,8 @@ static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
        unsigned long flags;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
        midi->substream_output = substream;
@@ -210,7 +212,8 @@ static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
        int err = 0;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        snd_emu10k1_intr_disable(emu, midi->rx_enable);
        midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
@@ -232,7 +235,8 @@ static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream
        int err = 0;
 
        emu = midi->emu;
-       snd_assert(emu, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
        spin_lock_irqsave(&midi->open_lock, flags);
        snd_emu10k1_intr_disable(emu, midi->tx_enable);
        midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
@@ -251,7 +255,8 @@ static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substre
        struct snd_emu10k1 *emu;
        struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
        emu = midi->emu;
-       snd_assert(emu, return);
+       if (snd_BUG_ON(!emu))
+               return;
 
        if (up)
                snd_emu10k1_intr_enable(emu, midi->rx_enable);
@@ -266,7 +271,8 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr
        unsigned long flags;
 
        emu = midi->emu;
-       snd_assert(emu, return);
+       if (snd_BUG_ON(!emu))
+               return;
 
        if (up) {
                int max = 4;
index 7d379f5131fbf61d4ab527a51bac881592c96fff..6a47672f930aedfe67163ce56a0e5a726470e734 100644 (file)
@@ -107,7 +107,8 @@ static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct lis
 
        list_for_each (pos, &emu->mapped_link_head) {
                struct snd_emu10k1_memblk *blk = get_emu10k1_memblk(pos, mapped_link);
-               snd_assert(blk->mapped_page >= 0, continue);
+               if (blk->mapped_page < 0)
+                       continue;
                size = blk->mapped_page - page;
                if (size == npages) {
                        *nextp = pos;
@@ -295,15 +296,18 @@ struct snd_util_memblk *
 snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
        struct snd_util_memhdr *hdr;
        struct snd_emu10k1_memblk *blk;
        int page, err, idx;
 
-       snd_assert(emu, return NULL);
-       snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL);
+       if (snd_BUG_ON(!emu))
+               return NULL;
+       if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
+                      runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE))
+               return NULL;
        hdr = emu->memhdr;
-       snd_assert(hdr, return NULL);
+       if (snd_BUG_ON(!hdr))
+               return NULL;
 
        mutex_lock(&hdr->block_mutex);
        blk = search_empty(emu, runtime->dma_bytes);
@@ -316,16 +320,9 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
         */
        idx = 0;
        for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
+               unsigned long ofs = idx << PAGE_SHIFT;
                dma_addr_t addr;
-#ifdef CONFIG_SND_DEBUG
-               if (idx >= sgbuf->pages) {
-                       printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n",
-                              blk->first_page, blk->last_page, sgbuf->pages);
-                       mutex_unlock(&hdr->block_mutex);
-                       return NULL;
-               }
-#endif
-               addr = sgbuf->table[idx].addr;
+               addr = snd_pcm_sgbuf_get_addr(substream, ofs);
                if (! is_valid_page(emu, addr)) {
                        printk(KERN_ERR "emu: failure page = %d\n", idx);
                        mutex_unlock(&hdr->block_mutex);
@@ -353,7 +350,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
  */
 int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk)
 {
-       snd_assert(emu && blk, return -EINVAL);
+       if (snd_BUG_ON(!emu || !blk))
+               return -EINVAL;
        return snd_emu10k1_synth_free(emu, blk);
 }
 
@@ -498,7 +496,8 @@ static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *
 static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset)
 {
        char *ptr;
-       snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL);
+       if (snd_BUG_ON(page < 0 || page >= emu->max_cache_pages))
+               return NULL;
        ptr = emu->page_ptr_table[page];
        if (! ptr) {
                printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page);
index 958cb2a65a4ec8f79680f1bd8ed2a3570bfd2273..d7300a1aa262b64cc54a9ca060242167b4b90ba5 100644 (file)
@@ -111,8 +111,10 @@ int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number,
        unsigned long flags;
        int result;
 
-       snd_assert(rvoice != NULL, return -EINVAL);
-       snd_assert(number, return -EINVAL);
+       if (snd_BUG_ON(!rvoice))
+               return -EINVAL;
+       if (snd_BUG_ON(!number))
+               return -EINVAL;
 
        spin_lock_irqsave(&emu->voice_lock, flags);
        for (;;) {
@@ -145,7 +147,8 @@ int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
 {
        unsigned long flags;
 
-       snd_assert(pvoice != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pvoice))
+               return -EINVAL;
        spin_lock_irqsave(&emu->voice_lock, flags);
        pvoice->interrupt = NULL;
        pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
index 84fac1fbf10399bf9a3c0008945e78e9ad8c1d0f..4cd9a1faaecc186732b1ad911ebfd74e3c59e77e 100644 (file)
@@ -860,7 +860,8 @@ static int snd_es1938_capture_copy(struct snd_pcm_substream *substream,
        struct es1938 *chip = snd_pcm_substream_chip(substream);
        pos <<= chip->dma1_shift;
        count <<= chip->dma1_shift;
-       snd_assert(pos + count <= chip->dma1_size, return -EINVAL);
+       if (snd_BUG_ON(pos + count > chip->dma1_size))
+               return -EINVAL;
        if (pos + count < chip->dma1_size) {
                if (copy_to_user(dst, runtime->dma_area + pos + 1, count))
                        return -EFAULT;
index 1bf298d214b90462cfe7b5253c7d4d0f6c097fd1..20ee7599600bee87340f264e99842a4efa195465 100644 (file)
@@ -692,7 +692,8 @@ static void apu_data_set(struct es1968 *chip, u16 data)
 /* no spinlock */
 static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
 {
-       snd_assert(channel < NR_APUS, return);
+       if (snd_BUG_ON(channel >= NR_APUS))
+               return;
 #ifdef CONFIG_PM
        chip->apu_map[channel][reg] = data;
 #endif
@@ -711,7 +712,8 @@ static void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
 
 static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
 {
-       snd_assert(channel < NR_APUS, return 0);
+       if (snd_BUG_ON(channel >= NR_APUS))
+               return 0;
        reg |= (channel << 4);
        apu_index_set(chip, reg);
        return __maestro_read(chip, IDR0_DATA_PORT);
index ab0c726d648e77e2ea4477b285407bce37b8a7d3..1980c6d207e7602dce5e8881223a6dff2b194cda 100644 (file)
@@ -5,6 +5,7 @@ snd-hda-intel-y := hda_intel.o
 snd-hda-intel-y += hda_codec.o
 snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
+snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o
@@ -14,5 +15,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
+snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o
 
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
new file mode 100644 (file)
index 0000000..9b77b3e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Digital Beep Input Interface for HD-audio codec
+ *
+ * Author: Matthew Ranostay <mranostay@embeddedalley.com>
+ * Copyright (c) 2008 Embedded Alley Solutions Inc
+ *
+ *  This driver 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 driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/input.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include "hda_beep.h"
+
+enum {
+       DIGBEEP_HZ_STEP = 46875,        /* 46.875 Hz */
+       DIGBEEP_HZ_MIN = 93750,         /* 93.750 Hz */
+       DIGBEEP_HZ_MAX = 12000000,      /* 12 KHz */
+};
+
+static void snd_hda_generate_beep(struct work_struct *work)
+{
+       struct hda_beep *beep =
+               container_of(work, struct hda_beep, beep_work);
+       struct hda_codec *codec = beep->codec;
+
+       /* generate tone */
+       snd_hda_codec_write_cache(codec, beep->nid, 0,
+                       AC_VERB_SET_BEEP_CONTROL, beep->tone);
+}
+
+static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
+                               unsigned int code, int hz)
+{
+       struct hda_beep *beep = input_get_drvdata(dev);
+
+       switch (code) {
+       case SND_BELL:
+               if (hz)
+                       hz = 1000;
+       case SND_TONE:
+               hz *= 1000; /* fixed point */
+               hz = hz - DIGBEEP_HZ_MIN;
+               if (hz < 0)
+                       hz = 0; /* turn off PC beep*/
+               else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
+                       hz = 0xff;
+               else {
+                       hz /= DIGBEEP_HZ_STEP;
+                       hz++;
+               }
+               break;
+       default:
+               return -1;
+       }
+       beep->tone = hz;
+
+       /* schedule beep event */
+       schedule_work(&beep->beep_work);
+       return 0;
+}
+
+int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+{
+       struct input_dev *input_dev;
+       struct hda_beep *beep;
+       int err;
+
+       beep = kzalloc(sizeof(*beep), GFP_KERNEL);
+       if (beep == NULL)
+               return -ENOMEM;
+       snprintf(beep->phys, sizeof(beep->phys),
+               "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
+       input_dev = input_allocate_device();
+
+       /* setup digital beep device */
+       input_dev->name = "HDA Digital PCBeep";
+       input_dev->phys = beep->phys;
+       input_dev->id.bustype = BUS_PCI;
+
+       input_dev->id.vendor = codec->vendor_id >> 16;
+       input_dev->id.product = codec->vendor_id & 0xffff;
+       input_dev->id.version = 0x01;
+
+       input_dev->evbit[0] = BIT_MASK(EV_SND);
+       input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+       input_dev->event = snd_hda_beep_event;
+       input_dev->dev.parent = &codec->bus->pci->dev;
+       input_set_drvdata(input_dev, beep);
+
+       err = input_register_device(input_dev);
+       if (err < 0) {
+               input_free_device(input_dev);
+               kfree(beep);
+               return err;
+       }
+
+       /* enable linear scale */
+       snd_hda_codec_write(codec, nid, 0,
+               AC_VERB_SET_DIGI_CONVERT_2, 0x01);
+
+       beep->nid = nid;
+       beep->dev = input_dev;
+       beep->codec = codec;
+       codec->beep = beep;
+
+       INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
+       return 0;
+}
+
+void snd_hda_detach_beep_device(struct hda_codec *codec)
+{
+       struct hda_beep *beep = codec->beep;
+       if (beep) {
+               cancel_work_sync(&beep->beep_work);
+               flush_scheduled_work();
+
+               input_unregister_device(beep->dev);
+               kfree(beep);
+       }
+}
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
new file mode 100644 (file)
index 0000000..de4036e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Digital Beep Input Interface for HD-audio codec
+ *
+ * Author: Matthew Ranostay <mranostay@embeddedalley.com>
+ * Copyright (c) 2008 Embedded Alley Solutions Inc
+ *
+ *  This driver 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 driver 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_HDA_BEEP_H
+#define __SOUND_HDA_BEEP_H
+
+#include "hda_codec.h"
+
+/* beep information */
+struct hda_beep {
+       struct input_dev *dev;
+       struct hda_codec *codec;
+       char phys[32];
+       int tone;
+       int nid;
+       struct work_struct beep_work; /* scheduled task for beep event */
+};
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
+void snd_hda_detach_beep_device(struct hda_codec *codec);
+#else
+#define snd_hda_attach_beep_device(...)
+#define snd_hda_detach_beep_device(...)
+#endif
+#endif
index d2e1093f8e972306727255a46ffb7ce7d59ccf2e..6447754ae56e3a6ef97af1434325df5d15ac8209 100644 (file)
@@ -93,6 +93,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
 #endif
 #ifdef CONFIG_SND_HDA_CODEC_VIA
        snd_hda_preset_via,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+       snd_hda_preset_nvhdmi,
 #endif
        NULL
 };
@@ -211,7 +214,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
        unsigned int shift, num_elems, mask;
        hda_nid_t prev_nid;
 
-       snd_assert(conn_list && max_conns > 0, return -EINVAL);
+       if (snd_BUG_ON(!conn_list || max_conns <= 0))
+               return -EINVAL;
 
        parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
        if (parm & AC_CLIST_LONG) {
@@ -313,7 +317,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
 }
 
 /*
- * process queueud unsolicited events
+ * process queued unsolicited events
  */
 static void process_unsol_events(struct work_struct *work)
 {
@@ -407,8 +411,10 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
                .dev_free = snd_hda_bus_dev_free,
        };
 
-       snd_assert(temp, return -EINVAL);
-       snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL);
+       if (snd_BUG_ON(!temp))
+               return -EINVAL;
+       if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response))
+               return -EINVAL;
 
        if (busp)
                *busp = NULL;
@@ -585,11 +591,13 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
                                struct hda_codec **codecp)
 {
        struct hda_codec *codec;
-       char component[13];
+       char component[31];
        int err;
 
-       snd_assert(bus, return -EINVAL);
-       snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL);
+       if (snd_BUG_ON(!bus))
+               return -EINVAL;
+       if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
+               return -EINVAL;
 
        if (bus->caddr_tbl[codec_addr]) {
                snd_printk(KERN_ERR "hda_codec: "
@@ -688,7 +696,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
        snd_hda_create_hwdep(codec);
 #endif
 
-       sprintf(component, "HDA:%08x", codec->vendor_id);
+       sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id);
        snd_component_add(codec->bus->card, component);
 
        if (codecp)
@@ -956,15 +964,6 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
 }
 #endif /* SND_HDA_NEEDS_RESUME */
 
-/*
- * AMP control callbacks
- */
-/* retrieve parameters from private_value */
-#define get_amp_nid(kc)                ((kc)->private_value & 0xffff)
-#define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
-#define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
-#define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
-
 /* volume */
 int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
@@ -1430,6 +1429,29 @@ static unsigned int convert_to_spdif_status(unsigned short val)
        return sbits;
 }
 
+/* set digital convert verbs both for the given NID and its slaves */
+static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
+                       int verb, int val)
+{
+       hda_nid_t *d;
+
+       snd_hda_codec_write(codec, nid, 0, verb, val);
+       d = codec->slave_dig_outs;
+       if (!d)
+               return;
+       for (; *d; d++)
+               snd_hda_codec_write(codec, *d, 0, verb, val);
+}
+
+static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
+                                      int dig1, int dig2)
+{
+       if (dig1 != -1)
+               set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
+       if (dig2 != -1)
+               set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
+}
+
 static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
@@ -1448,14 +1470,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
        change = codec->spdif_ctls != val;
        codec->spdif_ctls = val;
 
-       if (change) {
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_DIGI_CONVERT_1,
-                                         val & 0xff);
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_DIGI_CONVERT_2,
-                                         val >> 8);
-       }
+       if (change)
+               set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
 
        mutex_unlock(&codec->spdif_mutex);
        return change;
@@ -1487,9 +1503,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
        change = codec->spdif_ctls != val;
        if (change) {
                codec->spdif_ctls = val;
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_DIGI_CONVERT_1,
-                                         val & 0xff);
+               set_dig_out_convert(codec, nid, val & 0xff, -1);
                /* unmute amp switch (if any) */
                if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
                    (val & AC_DIG1_ENABLE))
@@ -2236,11 +2250,13 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
        if (info->ops.close == NULL)
                info->ops.close = hda_pcm_default_open_close;
        if (info->ops.prepare == NULL) {
-               snd_assert(info->nid, return -EINVAL);
+               if (snd_BUG_ON(!info->nid))
+                       return -EINVAL;
                info->ops.prepare = hda_pcm_default_prepare;
        }
        if (info->ops.cleanup == NULL) {
-               snd_assert(info->nid, return -EINVAL);
+               if (snd_BUG_ON(!info->nid))
+                       return -EINVAL;
                info->ops.cleanup = hda_pcm_default_cleanup;
        }
        return 0;
@@ -2583,14 +2599,31 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
                                 unsigned int stream_tag, unsigned int format)
 {
        /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_ctls & AC_DIG1_ENABLE)
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+               set_dig_out_convert(codec, nid, 
+                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
+                                   -1);
        snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+       if (codec->slave_dig_outs) {
+               hda_nid_t *d;
+               for (d = codec->slave_dig_outs; *d; d++)
+                       snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
+                                                  format);
+       }
        /* turn on again (if needed) */
-       if (codec->spdif_ctls & AC_DIG1_ENABLE)
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                   codec->spdif_ctls & 0xff);
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+               set_dig_out_convert(codec, nid,
+                                   codec->spdif_ctls & 0xff, -1);
+}
+
+static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
+{
+       snd_hda_codec_cleanup_stream(codec, nid);
+       if (codec->slave_dig_outs) {
+               hda_nid_t *d;
+               for (d = codec->slave_dig_outs; *d; d++)
+                       snd_hda_codec_cleanup_stream(codec, *d);
+       }
 }
 
 /*
@@ -2602,7 +2635,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
        mutex_lock(&codec->spdif_mutex);
        if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
                /* already opened as analog dup; reset it once */
-               snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+               cleanup_dig_out_stream(codec, mout->dig_out_nid);
        mout->dig_out_used = HDA_DIG_EXCLUSIVE;
        mutex_unlock(&codec->spdif_mutex);
        return 0;
@@ -2697,7 +2730,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                                             stream_tag, format);
                } else {
                        mout->dig_out_used = 0;
-                       snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+                       cleanup_dig_out_stream(codec, mout->dig_out_nid);
                }
        }
        mutex_unlock(&codec->spdif_mutex);
@@ -2748,7 +2781,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
                                                     mout->extra_out_nid[i]);
        mutex_lock(&codec->spdif_mutex);
        if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
-               snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
+               cleanup_dig_out_stream(codec, mout->dig_out_nid);
                mout->dig_out_used = 0;
        }
        mutex_unlock(&codec->spdif_mutex);
@@ -2756,7 +2789,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 }
 
 /*
- * Helper for automatic ping configuration
+ * Helper for automatic pin configuration
  */
 
 static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
index efc682888b3173242510a0705accba40b09ad1cd..60468f562400b3cea43c290c799a60091957c18b 100644 (file)
@@ -90,6 +90,14 @@ enum {
 #define AC_VERB_GET_CONFIG_DEFAULT             0x0f1c
 /* f20: AFG/MFG */
 #define AC_VERB_GET_SUBSYSTEM_ID               0x0f20
+#define AC_VERB_GET_CVT_CHAN_COUNT             0x0f2d
+#define AC_VERB_GET_HDMI_DIP_SIZE              0x0f2e
+#define AC_VERB_GET_HDMI_ELDD                  0x0f2f
+#define AC_VERB_GET_HDMI_DIP_INDEX             0x0f30
+#define AC_VERB_GET_HDMI_DIP_DATA              0x0f31
+#define AC_VERB_GET_HDMI_DIP_XMIT              0x0f32
+#define AC_VERB_GET_HDMI_CP_CTRL               0x0f33
+#define AC_VERB_GET_HDMI_CHAN_SLOT             0x0f34
 
 /*
  * SET verbs
@@ -121,7 +129,14 @@ enum {
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1     0x71d
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2     0x71e
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3     0x71f
+#define AC_VERB_SET_EAPD                               0x788
 #define AC_VERB_SET_CODEC_RESET                        0x7ff
+#define AC_VERB_SET_CVT_CHAN_COUNT             0x72d
+#define AC_VERB_SET_HDMI_DIP_INDEX             0x730
+#define AC_VERB_SET_HDMI_DIP_DATA              0x731
+#define AC_VERB_SET_HDMI_DIP_XMIT              0x732
+#define AC_VERB_SET_HDMI_CP_CTRL               0x733
+#define AC_VERB_SET_HDMI_CHAN_SLOT             0x734
 
 /*
  * Parameter IDs
@@ -143,6 +158,7 @@ enum {
 #define AC_PAR_GPIO_CAP                        0x11
 #define AC_PAR_AMP_OUT_CAP             0x12
 #define AC_PAR_VOL_KNB_CAP             0x13
+#define AC_PAR_HDMI_LPCM_CAP           0x20
 
 /*
  * AC_VERB_PARAMETERS results (32bit)
@@ -171,6 +187,8 @@ enum {
 #define AC_WCAP_DIGITAL                        (1<<9)  /* digital I/O */
 #define AC_WCAP_POWER                  (1<<10) /* power control */
 #define AC_WCAP_LR_SWAP                        (1<<11) /* L/R swap */
+#define AC_WCAP_CP_CAPS                        (1<<12) /* content protection */
+#define AC_WCAP_CHAN_CNT_EXT           (7<<13) /* channel count ext */
 #define AC_WCAP_DELAY                  (0xf<<16)
 #define AC_WCAP_DELAY_SHIFT            16
 #define AC_WCAP_TYPE                   (0xf<<20)
@@ -206,9 +224,20 @@ enum {
 /* Input converter SDI select */
 #define AC_SDI_SELECT                  (0xf<<0)
 
-/* Unsolicited response */
+/* Unsolicited response control */
 #define AC_UNSOL_TAG                   (0x3f<<0)
 #define AC_UNSOL_ENABLED               (1<<7)
+#define AC_USRSP_EN                    AC_UNSOL_ENABLED
+
+/* Unsolicited responses */
+#define AC_UNSOL_RES_TAG               (0x3f<<26)
+#define AC_UNSOL_RES_TAG_SHIFT         26
+#define AC_UNSOL_RES_SUBTAG            (0x1f<<21)
+#define AC_UNSOL_RES_SUBTAG_SHIFT      21
+#define AC_UNSOL_RES_ELDV              (1<<1)  /* ELD Data valid (for HDMI) */
+#define AC_UNSOL_RES_PD                        (1<<0)  /* pinsense detect */
+#define AC_UNSOL_RES_CP_STATE          (1<<1)  /* content protection */
+#define AC_UNSOL_RES_CP_READY          (1<<0)  /* content protection */
 
 /* Pin widget capabilies */
 #define AC_PINCAP_IMP_SENSE            (1<<0)  /* impedance sense capable */
@@ -222,6 +251,10 @@ enum {
  *       but is marked reserved in the Intel HDA specification.
  */
 #define AC_PINCAP_LR_SWAP              (1<<7)  /* L/R swap */
+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
+ *       in HD-audio specification
+ */
+#define AC_PINCAP_HDMI                 (1<<7)  /* HDMI pin */
 #define AC_PINCAP_VREF                 (0x37<<8)
 #define AC_PINCAP_VREF_SHIFT           8
 #define AC_PINCAP_EAPD                 (1<<16) /* EAPD capable */
@@ -272,6 +305,22 @@ enum {
 #define AC_KNBCAP_NUM_STEPS            (0x7f<<0)
 #define AC_KNBCAP_DELTA                        (1<<7)
 
+/* HDMI LPCM capabilities */
+#define AC_LPCMCAP_48K_CP_CHNS         (0x0f<<0) /* max channels w/ CP-on */   
+#define AC_LPCMCAP_48K_NO_CHNS         (0x0f<<4) /* max channels w/o CP-on */
+#define AC_LPCMCAP_48K_20BIT           (1<<8)  /* 20b bitrate supported */
+#define AC_LPCMCAP_48K_24BIT           (1<<9)  /* 24b bitrate supported */
+#define AC_LPCMCAP_96K_CP_CHNS         (0x0f<<10) /* max channels w/ CP-on */  
+#define AC_LPCMCAP_96K_NO_CHNS         (0x0f<<14) /* max channels w/o CP-on */
+#define AC_LPCMCAP_96K_20BIT           (1<<18) /* 20b bitrate supported */
+#define AC_LPCMCAP_96K_24BIT           (1<<19) /* 24b bitrate supported */
+#define AC_LPCMCAP_192K_CP_CHNS                (0x0f<<20) /* max channels w/ CP-on */  
+#define AC_LPCMCAP_192K_NO_CHNS                (0x0f<<24) /* max channels w/o CP-on */
+#define AC_LPCMCAP_192K_20BIT          (1<<28) /* 20b bitrate supported */
+#define AC_LPCMCAP_192K_24BIT          (1<<29) /* 24b bitrate supported */
+#define AC_LPCMCAP_44K                 (1<<30) /* 44.1kHz support */
+#define AC_LPCMCAP_44K_MS              (1<<31) /* 44.1kHz-multiplies support */
+
 /*
  * Control Parameters
  */
@@ -317,18 +366,44 @@ enum {
 #define AC_PINCTL_OUT_EN               (1<<6)
 #define AC_PINCTL_HP_EN                        (1<<7)
 
-/* Unsolicited response - 8bit */
-#define AC_USRSP_EN                    (1<<7)
-
 /* Pin sense - 32bit */
 #define AC_PINSENSE_IMPEDANCE_MASK     (0x7fffffff)
 #define AC_PINSENSE_PRESENCE           (1<<31)
+#define AC_PINSENSE_ELDV               (1<<30) /* ELD valid (HDMI) */
 
 /* EAPD/BTL enable - 32bit */
 #define AC_EAPDBTL_BALANCED            (1<<0)
 #define AC_EAPDBTL_EAPD                        (1<<1)
 #define AC_EAPDBTL_LR_SWAP             (1<<2)
 
+/* HDMI ELD data */
+#define AC_ELDD_ELD_VALID              (1<<31)
+#define AC_ELDD_ELD_DATA               0xff
+
+/* HDMI DIP size */
+#define AC_DIPSIZE_ELD_BUF             (1<<3) /* ELD buf size of packet size */
+#define AC_DIPSIZE_PACK_IDX            (0x07<<0) /* packet index */
+
+/* HDMI DIP index */
+#define AC_DIPIDX_PACK_IDX             (0x07<<5) /* packet idnex */
+#define AC_DIPIDX_BYTE_IDX             (0x1f<<0) /* byte index */
+
+/* HDMI DIP xmit (transmit) control */
+#define AC_DIPXMIT_MASK                        (0x3<<6)
+#define AC_DIPXMIT_DISABLE             (0x0<<6) /* disable xmit */
+#define AC_DIPXMIT_ONCE                        (0x2<<6) /* xmit once then disable */
+#define AC_DIPXMIT_BEST                        (0x3<<6) /* best effort */
+
+/* HDMI content protection (CP) control */
+#define AC_CPCTRL_CES                  (1<<9) /* current encryption state */
+#define AC_CPCTRL_READY                        (1<<8) /* ready bit */
+#define AC_CPCTRL_SUBTAG               (0x1f<<3) /* subtag for unsol-resp */
+#define AC_CPCTRL_STATE                        (3<<0) /* current CP request state */
+
+/* Converter channel <-> HDMI slot mapping */
+#define AC_CVTMAP_HDMI_SLOT            (0xf<<0) /* HDMI slot number */
+#define AC_CVTMAP_CHAN                 (0xf<<4) /* converter channel number */
+
 /* configuration default - 32bit */
 #define AC_DEFCFG_SEQUENCE             (0xf<<0)
 #define AC_DEFCFG_DEF_ASSOC            (0xf<<4)
@@ -449,6 +524,7 @@ enum {
  */
 
 struct hda_bus;
+struct hda_beep;
 struct hda_codec;
 struct hda_pcm;
 struct hda_pcm_stream;
@@ -634,6 +710,9 @@ struct hda_codec {
        /* codec specific info */
        void *spec;
 
+       /* beep device */
+       struct hda_beep *beep;
+
        /* widget capabilities cache */
        unsigned int num_nodes;
        hda_nid_t start_nid;
@@ -646,9 +725,15 @@ struct hda_codec {
        unsigned int spdif_status;      /* IEC958 status bits */
        unsigned short spdif_ctls;      /* SPDIF control bits */
        unsigned int spdif_in_enable;   /* SPDIF input enable? */
+       hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 
        struct snd_hwdep *hwdep;        /* assigned hwdep device */
 
+       /* misc flags */
+       unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
+                                            * status change
+                                            * (e.g. Realtek codecs)
+                                            */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        unsigned int power_on :1;       /* current (global) power-state */
        unsigned int power_transition :1; /* power-state in transition */
index 59e4389c94a4bb87b1aa85075d2d127e5ae542da..0ca30894f7c6fcf750ea46b3f009325388f7ecbb 100644 (file)
@@ -174,7 +174,8 @@ static int build_afg_tree(struct hda_codec *codec)
        int i, nodes, err;
        hda_nid_t nid;
 
-       snd_assert(spec, return -EINVAL);
+       if (snd_BUG_ON(!spec))
+               return -EINVAL;
 
        spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP);
        spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP);
index 1c53e337ecb2dce93b833dcce526f64288cc9136..9f316c1b2790851d6b6f83bcdd9a1e980ea2315b 100644 (file)
@@ -222,9 +222,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define RIRB_INT_OVERRUN       0x04
 #define RIRB_INT_MASK          0x05
 
-/* STATESTS int mask: SD2,SD1,SD0 */
-#define AZX_MAX_CODECS         3
-#define STATESTS_INT_MASK      0x07
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS         4
+#define STATESTS_INT_MASK      0x0f
 
 /* SD_CTL bits */
 #define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
@@ -286,6 +286,11 @@ enum {
 #define INTEL_SCH_HDA_DEVC      0x78
 #define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
 
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET        0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID             0x3288
+
 
 /*
  */
@@ -317,6 +322,12 @@ struct azx_dev {
        unsigned int running :1;
        unsigned int irq_pending :1;
        unsigned int irq_ignore :1;
+       /*
+        * For VIA:
+        *  A flag to ensure DMA position is 0
+        *  when link position is not greater than FIFO size
+        */
+       unsigned int insufficient :1;
 };
 
 /* CORB/RIRB */
@@ -379,6 +390,7 @@ struct azx {
        unsigned int polling_mode :1;
        unsigned int msi :1;
        unsigned int irq_pending_warned :1;
+       unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
 
        /* for debugging */
        unsigned int last_cmd;  /* last issued command (to sync) */
@@ -398,6 +410,7 @@ enum {
        AZX_DRIVER_ULI,
        AZX_DRIVER_NVIDIA,
        AZX_DRIVER_TERA,
+       AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
 static char *driver_short_names[] __devinitdata = {
@@ -818,6 +831,11 @@ static void azx_int_clear(struct azx *chip)
 /* start a stream */
 static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
 {
+       /*
+        * Before stream start, initialize parameter
+        */
+       azx_dev->insufficient = 1;
+
        /* enable SIE */
        azx_writeb(chip, INTCTL,
                   azx_readb(chip, INTCTL) | (1 << azx_dev->index));
@@ -998,7 +1016,6 @@ static int setup_bdle(struct snd_pcm_substream *substream,
                      struct azx_dev *azx_dev, u32 **bdlp,
                      int ofs, int size, int with_ioc)
 {
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
        u32 *bdl = *bdlp;
 
        while (size > 0) {
@@ -1008,14 +1025,12 @@ static int setup_bdle(struct snd_pcm_substream *substream,
                if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
                        return -EINVAL;
 
-               addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+               addr = snd_pcm_sgbuf_get_addr(substream, ofs);
                /* program the address field of the BDL entry */
                bdl[0] = cpu_to_le32((u32)addr);
                bdl[1] = cpu_to_le32(upper_32_bits(addr));
                /* program the size field of the BDL entry */
-               chunk = PAGE_SIZE - (ofs % PAGE_SIZE);
-               if (size < chunk)
-                       chunk = size;
+               chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
                bdl[2] = cpu_to_le32(chunk);
                /* program the IOC to enable interrupt
                 * only when the whole fragment is processed
@@ -1151,7 +1166,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 
        /* enable the position buffer */
        if (chip->position_fix == POS_FIX_POSBUF ||
-           chip->position_fix == POS_FIX_AUTO) {
+           chip->position_fix == POS_FIX_AUTO ||
+           chip->via_dmapos_patch) {
                if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
                        azx_writel(chip, DPLBASE,
                                (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1169,23 +1185,26 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
  * Codec initialization
  */
 
-static unsigned int azx_max_codecs[] __devinitdata = {
-       [AZX_DRIVER_ICH] = 4,           /* Some ICH9 boards use SD3 */
-       [AZX_DRIVER_SCH] = 3,
-       [AZX_DRIVER_ATI] = 4,
-       [AZX_DRIVER_ATIHDMI] = 4,
-       [AZX_DRIVER_VIA] = 3,           /* FIXME: correct? */
-       [AZX_DRIVER_SIS] = 3,           /* FIXME: correct? */
-       [AZX_DRIVER_ULI] = 3,           /* FIXME: correct? */
-       [AZX_DRIVER_NVIDIA] = 3,        /* FIXME: correct? */
+/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
+static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
        [AZX_DRIVER_TERA] = 1,
 };
 
+/* number of slots to probe as default
+ * this can be different from azx_max_codecs[] -- e.g. some boards
+ * report wrongly the non-existing 4th slot availability
+ */
+static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = {
+       [AZX_DRIVER_ICH] = 3,
+       [AZX_DRIVER_ATI] = 3,
+};
+
 static int __devinit azx_codec_create(struct azx *chip, const char *model,
                                      unsigned int codec_probe_mask)
 {
        struct hda_bus_template bus_temp;
        int c, codecs, audio_codecs, err;
+       int def_slots, max_slots;
 
        memset(&bus_temp, 0, sizeof(bus_temp));
        bus_temp.private_data = chip;
@@ -1201,8 +1220,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
        if (err < 0)
                return err;
 
+       if (chip->driver_type == AZX_DRIVER_NVIDIA)
+               chip->bus->needs_damn_long_delay = 1;
+
        codecs = audio_codecs = 0;
-       for (c = 0; c < AZX_MAX_CODECS; c++) {
+       max_slots = azx_max_codecs[chip->driver_type];
+       if (!max_slots)
+               max_slots = AZX_MAX_CODECS;
+       def_slots = azx_default_codecs[chip->driver_type];
+       if (!def_slots)
+               def_slots = max_slots;
+       for (c = 0; c < def_slots; c++) {
                if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                        struct hda_codec *codec;
                        err = snd_hda_codec_new(chip->bus, c, &codec);
@@ -1215,7 +1243,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
        }
        if (!audio_codecs) {
                /* probe additional slots if no codec is found */
-               for (; c < azx_max_codecs[chip->driver_type]; c++) {
+               for (; c < max_slots; c++) {
                        if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                                err = snd_hda_codec_new(chip->bus, c, NULL);
                                if (err < 0)
@@ -1507,13 +1535,71 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        return 0;
 }
 
+/* get the current DMA position with correction on VIA chips */
+static unsigned int azx_via_get_position(struct azx *chip,
+                                        struct azx_dev *azx_dev)
+{
+       unsigned int link_pos, mini_pos, bound_pos;
+       unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
+       unsigned int fifo_size;
+
+       link_pos = azx_sd_readl(azx_dev, SD_LPIB);
+       if (azx_dev->index >= 4) {
+               /* Playback, no problem using link position */
+               return link_pos;
+       }
+
+       /* Capture */
+       /* For new chipset,
+        * use mod to get the DMA position just like old chipset
+        */
+       mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
+       mod_dma_pos %= azx_dev->period_bytes;
+
+       /* azx_dev->fifo_size can't get FIFO size of in stream.
+        * Get from base address + offset.
+        */
+       fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
+
+       if (azx_dev->insufficient) {
+               /* Link position never gather than FIFO size */
+               if (link_pos <= fifo_size)
+                       return 0;
+
+               azx_dev->insufficient = 0;
+       }
+
+       if (link_pos <= fifo_size)
+               mini_pos = azx_dev->bufsize + link_pos - fifo_size;
+       else
+               mini_pos = link_pos - fifo_size;
+
+       /* Find nearest previous boudary */
+       mod_mini_pos = mini_pos % azx_dev->period_bytes;
+       mod_link_pos = link_pos % azx_dev->period_bytes;
+       if (mod_link_pos >= fifo_size)
+               bound_pos = link_pos - mod_link_pos;
+       else if (mod_dma_pos >= mod_mini_pos)
+               bound_pos = mini_pos - mod_mini_pos;
+       else {
+               bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
+               if (bound_pos >= azx_dev->bufsize)
+                       bound_pos = 0;
+       }
+
+       /* Calculate real DMA position we want */
+       return bound_pos + mod_dma_pos;
+}
+
 static unsigned int azx_get_position(struct azx *chip,
                                     struct azx_dev *azx_dev)
 {
        unsigned int pos;
 
-       if (chip->position_fix == POS_FIX_POSBUF ||
-           chip->position_fix == POS_FIX_AUTO) {
+       if (chip->via_dmapos_patch)
+               pos = azx_via_get_position(chip, azx_dev);
+       else if (chip->position_fix == POS_FIX_POSBUF ||
+                chip->position_fix == POS_FIX_AUTO) {
                /* use the position buffer */
                pos = le32_to_cpu(*azx_dev->posbuf);
        } else {
@@ -1559,6 +1645,8 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
                        chip->position_fix = POS_FIX_POSBUF;
        }
 
+       if (!bdl_pos_adj[chip->dev_index])
+               return 1; /* no delayed ack */
        if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
                return 0; /* NG - it's below the period boundary */
        return 1; /* OK, it's fine */
@@ -1646,7 +1734,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
        if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
                return 0;
 
-       snd_assert(cpcm->name, return -EINVAL);
+       if (snd_BUG_ON(!cpcm->name))
+               return -EINVAL;
 
        err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
                          cpcm->stream[0].substreams,
@@ -1670,7 +1759,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                                              snd_dma_pci_data(chip->pci),
-                                             1024 * 64, 1024 * 1024);
+                                             1024 * 64, 32 * 1024 * 1024);
        chip->pcm[cpcm->device] = pcm;
        return 0;
 }
@@ -1946,6 +2035,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 {
        const struct snd_pci_quirk *q;
 
+       /* Check VIA HD Audio Controller exist */
+       if (chip->pci->vendor == PCI_VENDOR_ID_VIA &&
+           chip->pci->device == VIA_HDAC_DEVICE_ID) {
+               chip->via_dmapos_patch = 1;
+               /* Use link position directly, avoid any transfer problem. */
+               return POS_FIX_LPIB;
+       }
+       chip->via_dmapos_patch = 0;
+
        if (fix == POS_FIX_AUTO) {
                q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
                if (q) {
index 5c9e578f7f2dd89b745d87594711ed3bec01ec3b..7957fefda730ca05da03160362688ae90119db98 100644 (file)
@@ -368,12 +368,15 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 #define AMP_OUT_UNMUTE 0xb000
 #define AMP_OUT_ZERO   0xb000
 /* pinctl values */
-#define PIN_IN         0x20
-#define PIN_VREF80     0x24
-#define PIN_VREF50     0x21
-#define PIN_OUT                0x40
-#define PIN_HP         0xc0
-#define PIN_HP_AMP     0x80
+#define PIN_IN                 (AC_PINCTL_IN_EN)
+#define PIN_VREFHIZ    (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
+#define PIN_VREF50             (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
+#define PIN_VREFGRD    (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
+#define PIN_VREF80             (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
+#define PIN_VREF100    (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
+#define PIN_OUT                (AC_PINCTL_OUT_EN)
+#define PIN_HP                 (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
+#define PIN_HP_AMP             (AC_PINCTL_HP_EN)
 
 /*
  * get widget capabilities
@@ -418,4 +421,13 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
                                 hda_nid_t nid);
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
+/*
+ * AMP control callbacks
+ */
+/* retrieve parameters from private_value */
+#define get_amp_nid(kc)                ((kc)->private_value & 0xffff)
+#define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
+#define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
+#define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
+
 #endif /* __SOUND_HDA_LOCAL_H */
index 2fdf2358dbc2aee3281bfd074ec883d545fa33af..dfbcfa88da44d630b00b3cfbe530c7c54d4821a0 100644 (file)
@@ -18,3 +18,5 @@ extern struct hda_codec_preset snd_hda_preset_atihdmi[];
 extern struct hda_codec_preset snd_hda_preset_conexant[];
 /* VIA codecs */
 extern struct hda_codec_preset snd_hda_preset_via[];
+/* NVIDIA HDMI codecs */
+extern struct hda_codec_preset snd_hda_preset_nvhdmi[];
index 1e5aff5c48d16910074503907775e6d17eac5d66..743d77922bceda139d3c4c3498d28fec27ce2272 100644 (file)
@@ -216,7 +216,7 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
        unsigned int caps, val;
 
        caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-       snd_iprintf(buffer, "  Pincap 0x08%x:", caps);
+       snd_iprintf(buffer, "  Pincap 0x%08x:", caps);
        if (caps & AC_PINCAP_IN)
                snd_iprintf(buffer, " IN");
        if (caps & AC_PINCAP_OUT)
@@ -229,8 +229,13 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
                snd_iprintf(buffer, " Detect");
        if (caps & AC_PINCAP_BALANCE)
                snd_iprintf(buffer, " Balanced");
-       if (caps & AC_PINCAP_LR_SWAP)
-               snd_iprintf(buffer, " R/L");
+       if (caps & AC_PINCAP_HDMI) {
+               /* Realtek uses this bit as a different meaning */
+               if ((codec->vendor_id >> 16) == 0x10ec)
+                       snd_iprintf(buffer, " R/L");
+               else
+                       snd_iprintf(buffer, " HDMI");
+       }
        if (caps & AC_PINCAP_TRIG_REQ)
                snd_iprintf(buffer, " Trigger");
        if (caps & AC_PINCAP_IMP_SENSE)
@@ -552,9 +557,15 @@ static void print_codec_info(struct snd_info_entry *entry,
 
                snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
                            get_wid_type_name(wid_type), wid_caps);
-               if (wid_caps & AC_WCAP_STEREO)
-                       snd_iprintf(buffer, " Stereo");
-               else
+               if (wid_caps & AC_WCAP_STEREO) {
+                       unsigned int chans;
+                       chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13;
+                       chans = ((chans << 1) | 1) + 1;
+                       if (chans == 2)
+                               snd_iprintf(buffer, " Stereo");
+                       else
+                               snd_iprintf(buffer, " %d-Channels", chans);
+               } else
                        snd_iprintf(buffer, " Mono");
                if (wid_caps & AC_WCAP_DIGITAL)
                        snd_iprintf(buffer, " Digital");
@@ -566,6 +577,8 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, " Stripe");
                if (wid_caps & AC_WCAP_LR_SWAP)
                        snd_iprintf(buffer, " R/L");
+               if (wid_caps & AC_WCAP_CP_CAPS)
+                       snd_iprintf(buffer, " CP");
                snd_iprintf(buffer, "\n");
 
                /* volume knob is a special widget that always have connection
index e8003d99f0bfe3bb071d761a9a84922dd7d8bd07..2b00c4afdf97c29b2761b374add4488b69916860 100644 (file)
@@ -1826,9 +1826,14 @@ static hda_nid_t ad1988_capsrc_nids[3] = {
        0x0c, 0x0d, 0x0e
 };
 
-#define AD1988_SPDIF_OUT       0x02
+#define AD1988_SPDIF_OUT               0x02
+#define AD1988_SPDIF_OUT_HDMI  0x0b
 #define AD1988_SPDIF_IN                0x07
 
+static hda_nid_t ad1989b_slave_dig_outs[2] = {
+       AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI
+};
+
 static struct hda_input_mux ad1988_6stack_capture_source = {
        .num_items = 5,
        .items = {
@@ -2143,6 +2148,7 @@ static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
 
 static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
        HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -2207,6 +2213,8 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
        {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
        /* Analog CD Input */
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
 
        { }
 };
@@ -2247,8 +2255,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = {
 
 /* AD1989 has no ADC -> SPDIF route */
 static struct hda_verb ad1989_spdif_init_verbs[] = {
-       /* SPDIF out pin */
+       /* SPDIF-1 out pin */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       /* SPDIF-2/HDMI out pin */
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
        { }
 };
 
@@ -2336,6 +2348,8 @@ static struct hda_verb ad1988_3stack_init_verbs[] = {
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
        { }
 };
 
@@ -2409,6 +2423,8 @@ static struct hda_verb ad1988_laptop_init_verbs[] = {
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
        { }
 };
 
@@ -2868,6 +2884,7 @@ static struct snd_pci_quirk ad1988_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
        SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
        SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
+       SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
        {}
 };
 
@@ -2975,6 +2992,7 @@ static int patch_ad1988(struct hda_codec *codec)
                                ad1989_spdif_out_mixers;
                        spec->init_verbs[spec->num_init_verbs++] =
                                ad1989_spdif_init_verbs;
+                       codec->slave_dig_outs = ad1989b_slave_dig_outs;
                } else {
                        spec->mixers[spec->num_mixers++] =
                                ad1988_spdif_out_mixers;
@@ -3911,7 +3929,7 @@ static int patch_ad1884a(struct hda_codec *codec)
 
 
 /*
- * AD1882
+ * AD1882 / AD1882A
  *
  * port-A - front hp-out
  * port-B - front mic-in
@@ -3948,6 +3966,18 @@ static struct hda_input_mux ad1882_capture_source = {
        },
 };
 
+/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
+static struct hda_input_mux ad1882a_capture_source = {
+       .num_items = 5,
+       .items = {
+               { "Front Mic", 0x1 },
+               { "Mic", 0x4},
+               { "Line", 0x2 },
+               { "Digital Mic", 0x06 },
+               { "Mix", 0x7 },
+       },
+};
+
 static struct snd_kcontrol_new ad1882_base_mixers[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -3957,16 +3987,7 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
        HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+
        HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
@@ -3999,6 +4020,35 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
        HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
@@ -4168,9 +4218,16 @@ static int patch_ad1882(struct hda_codec *codec)
        spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
        spec->adc_nids = ad1882_adc_nids;
        spec->capsrc_nids = ad1882_capsrc_nids;
-       spec->input_mux = &ad1882_capture_source;
-       spec->num_mixers = 1;
+       if (codec->vendor_id == 0x11d1882)
+               spec->input_mux = &ad1882_capture_source;
+       else
+               spec->input_mux = &ad1882a_capture_source;
+       spec->num_mixers = 2;
        spec->mixers[0] = ad1882_base_mixers;
+       if (codec->vendor_id == 0x11d1882)
+               spec->mixers[1] = ad1882_loopback_mixers;
+       else
+               spec->mixers[1] = ad1882a_loopback_mixers;
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1882_init_verbs;
        spec->spdif_route = 0;
@@ -4187,8 +4244,8 @@ static int patch_ad1882(struct hda_codec *codec)
        switch (board_config) {
        default:
        case AD1882_3STACK:
-               spec->num_mixers = 2;
-               spec->mixers[1] = ad1882_3stack_mixers;
+               spec->num_mixers = 3;
+               spec->mixers[2] = ad1882_3stack_mixers;
                spec->channel_mode = ad1882_modes;
                spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
                spec->need_dac_fix = 1;
@@ -4196,8 +4253,8 @@ static int patch_ad1882(struct hda_codec *codec)
                spec->multiout.num_dacs = 1;
                break;
        case AD1882_6STACK:
-               spec->num_mixers = 2;
-               spec->mixers[1] = ad1882_6stack_mixers;
+               spec->num_mixers = 3;
+               spec->mixers[2] = ad1882_6stack_mixers;
                break;
        }
        return 0;
@@ -4220,6 +4277,7 @@ struct hda_codec_preset snd_hda_preset_analog[] = {
        { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
        { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
        { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
+       { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
        { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
        { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
        {} /* terminator */
index 12272508b1124abebcb68fdcc06458727cbe86da..ba61575983fd68965ad5bd6b52e5439cad03da93 100644 (file)
@@ -35,6 +35,9 @@ struct atihdmi_spec {
        struct hda_pcm pcm_rec;
 };
 
+#define CVT_NID                0x02    /* audio converter */
+#define PIN_NID                0x03    /* HDMI output pin */
+
 static struct hda_verb atihdmi_basic_init[] = {
        /* enable digital output on pin widget */
        { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -60,8 +63,9 @@ static int atihdmi_init(struct hda_codec *codec)
 {
        snd_hda_sequence_write(codec, atihdmi_basic_init);
        /* SI codec requires to unmute the pin */
-       if (get_wcaps(codec, 0x03) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+       if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, PIN_NID, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_OUT_UNMUTE);
        return 0;
 }
@@ -92,15 +96,29 @@ static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                            struct snd_pcm_substream *substream)
 {
        struct atihdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                            format, substream);
+       int chans = substream->runtime->channels;
+       int i, err;
+
+       err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+                                           format, substream);
+       if (err < 0)
+               return err;
+       snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
+                           chans - 1);
+       /* FIXME: XXX */
+       for (i = 0; i < chans; i++) {
+               snd_hda_codec_write(codec, CVT_NID, 0,
+                                   AC_VERB_SET_HDMI_CHAN_SLOT,
+                                   (i << 4) | i);
+       }
+       return 0;
 }
 
 static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
-       .nid = 0x2, /* NID to query formats and rates and setup streams */
+       .nid = CVT_NID, /* NID to query formats and rates and setup streams */
        .ops = {
                .open = atihdmi_dig_playback_pcm_open,
                .close = atihdmi_dig_playback_pcm_close,
@@ -112,6 +130,7 @@ static int atihdmi_build_pcms(struct hda_codec *codec)
 {
        struct atihdmi_spec *spec = codec->spec;
        struct hda_pcm *info = &spec->pcm_rec;
+       unsigned int chans;
 
        codec->num_pcms = 1;
        codec->pcm_info = info;
@@ -120,6 +139,13 @@ static int atihdmi_build_pcms(struct hda_codec *codec)
        info->pcm_type = HDA_PCM_TYPE_HDMI;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
 
+       /* FIXME: we must check ELD and change the PCM parameters dynamically
+        */
+       chans = get_wcaps(codec, CVT_NID);
+       chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13;
+       chans = ((chans << 1) | 1) + 1;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
+
        return 0;
 }
 
@@ -147,9 +173,11 @@ static int patch_atihdmi(struct hda_codec *codec)
 
        spec->multiout.num_dacs = 0;      /* no analog */
        spec->multiout.max_channels = 2;
-       spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital,
-                                          * seems to be unused in pure-digital
-                                          * case. */
+       /* NID for copying analog to digital,
+        * seems to be unused in pure-digital
+        * case.
+        */
+       spec->multiout.dig_out_nid = CVT_NID;
 
        codec->patch_ops = atihdmi_patch_ops;
 
@@ -164,6 +192,7 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = {
        { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
+       { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
        { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
        { .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
        {} /* terminator */
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
new file mode 100644 (file)
index 0000000..1a65775
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for NVIDIA HDMI codecs
+ *
+ * Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
+ * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
+ *
+ *
+ *  This driver 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 driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+struct nvhdmi_spec {
+       struct hda_multi_out multiout;
+
+       struct hda_pcm pcm_rec;
+};
+
+static struct hda_verb nvhdmi_basic_init[] = {
+       /* enable digital output on pin widget */
+       { 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {} /* terminator */
+};
+
+/*
+ * Controls
+ */
+static int nvhdmi_build_controls(struct hda_codec *codec)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int nvhdmi_init(struct hda_codec *codec)
+{
+       snd_hda_sequence_write(codec, nvhdmi_basic_init);
+       return 0;
+}
+
+/*
+ * Digital out
+ */
+static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    struct snd_pcm_substream *substream)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     struct snd_pcm_substream *substream)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                           struct hda_codec *codec,
+                                           unsigned int stream_tag,
+                                           unsigned int format,
+                                           struct snd_pcm_substream *substream)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+                                            format, substream);
+}
+
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x4, /* NID to query formats and rates and setup streams */
+       .rates = SNDRV_PCM_RATE_48000,
+       .maxbps = 16,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .ops = {
+               .open = nvhdmi_dig_playback_pcm_open,
+               .close = nvhdmi_dig_playback_pcm_close,
+               .prepare = nvhdmi_dig_playback_pcm_prepare
+       },
+};
+
+static int nvhdmi_build_pcms(struct hda_codec *codec)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = &spec->pcm_rec;
+
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
+
+       info->name = "NVIDIA HDMI";
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback;
+
+       return 0;
+}
+
+static void nvhdmi_free(struct hda_codec *codec)
+{
+       kfree(codec->spec);
+}
+
+static struct hda_codec_ops nvhdmi_patch_ops = {
+       .build_controls = nvhdmi_build_controls,
+       .build_pcms = nvhdmi_build_pcms,
+       .init = nvhdmi_init,
+       .free = nvhdmi_free,
+};
+
+static int patch_nvhdmi(struct hda_codec *codec)
+{
+       struct nvhdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;      /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital,
+                                          * seems to be unused in pure-digital
+                                          * case. */
+
+       codec->patch_ops = nvhdmi_patch_ops;
+
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
+       { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi },
+       { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi },
+       {} /* terminator */
+};
index 66025161bd69fc0496973e1b9ee04fddc000c8d3..0b6e682c46d06d64cc94011c93003c8519592ce5 100644 (file)
@@ -72,6 +72,7 @@ enum {
 enum {
        ALC260_BASIC,
        ALC260_HP,
+       ALC260_HP_DC7600,
        ALC260_HP_3013,
        ALC260_FUJITSU_S702X,
        ALC260_ACER,
@@ -100,6 +101,9 @@ enum {
        ALC262_BENQ_T31,
        ALC262_ULTRA,
        ALC262_LENOVO_3000,
+       ALC262_NEC,
+       ALC262_TOSHIBA_S06,
+       ALC262_TOSHIBA_RX1,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
@@ -110,6 +114,7 @@ enum {
        ALC268_3ST,
        ALC268_TOSHIBA,
        ALC268_ACER,
+       ALC268_ACER_ASPIRE_ONE,
        ALC268_DELL,
        ALC268_ZEPTO,
 #ifdef CONFIG_SND_DEBUG
@@ -122,6 +127,7 @@ enum {
 /* ALC269 models */
 enum {
        ALC269_BASIC,
+       ALC269_QUANTA_FL1,
        ALC269_ASUS_EEEPC_P703,
        ALC269_ASUS_EEEPC_P901,
        ALC269_AUTO,
@@ -169,6 +175,13 @@ enum {
        ALC663_ASUS_G71V,
        ALC663_ASUS_H13,
        ALC663_ASUS_G50V,
+       ALC662_ECS,
+       ALC663_ASUS_MODE1,
+       ALC662_ASUS_MODE2,
+       ALC663_ASUS_MODE3,
+       ALC663_ASUS_MODE4,
+       ALC663_ASUS_MODE5,
+       ALC663_ASUS_MODE6,
        ALC662_AUTO,
        ALC662_MODEL_LAST,
 };
@@ -200,18 +213,21 @@ enum {
        ALC883_ACER,
        ALC883_ACER_ASPIRE,
        ALC883_MEDION,
-       ALC883_MEDION_MD2,      
+       ALC883_MEDION_MD2,
        ALC883_LAPTOP_EAPD,
        ALC883_LENOVO_101E_2ch,
        ALC883_LENOVO_NB0763,
        ALC888_LENOVO_MS7195_DIG,
-       ALC883_HAIER_W66,               
+       ALC888_LENOVO_SKY,
+       ALC883_HAIER_W66,
        ALC888_3ST_HP,
        ALC888_6ST_DELL,
        ALC883_MITAC,
        ALC883_CLEVO_M720,
        ALC883_FUJITSU_PI2515,
        ALC883_3ST_6ch_INTEL,
+       ALC888_ASUS_M90V,
+       ALC888_ASUS_EEE1601,
        ALC883_AUTO,
        ALC883_MODEL_LAST,
 };
@@ -398,7 +414,7 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
 
 /*
  * Control the mode of pin widget settings via the mixer.  "pc" is used
- * instead of "%" to avoid consequences of accidently treating the % as 
+ * instead of "%" to avoid consequences of accidently treating the % as
  * being part of a format specifier.  Maximum allowed length of a value is
  * 63 characters plus NULL terminator.
  *
@@ -429,7 +445,7 @@ static unsigned char alc_pin_mode_values[] = {
 #define ALC_PIN_DIR_IN_NOMICBIAS    0x03
 #define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
 
-/* Info about the pin modes supported by the different pin direction modes. 
+/* Info about the pin modes supported by the different pin direction modes.
  * For each direction the minimum and maximum values are given.
  */
 static signed char alc_pin_mode_dir_info[5][2] = {
@@ -502,7 +518,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
                                          alc_pin_mode_values[val]);
 
-               /* Also enable the retasking pin's input/output as required 
+               /* Also enable the retasking pin's input/output as required
                 * for the requested pin mode.  Enum values of 2 or less are
                 * input modes.
                 *
@@ -707,7 +723,7 @@ static void setup_preset(struct alc_spec *spec,
             i++)
                spec->init_verbs[spec->num_init_verbs++] =
                        preset->init_verbs[i];
-       
+
        spec->channel_mode = preset->channel_mode;
        spec->num_channel_mode = preset->num_channel_mode;
        spec->need_dac_fix = preset->need_dac_fix;
@@ -718,7 +734,7 @@ static void setup_preset(struct alc_spec *spec,
        spec->multiout.dac_nids = preset->dac_nids;
        spec->multiout.dig_out_nid = preset->dig_out_nid;
        spec->multiout.hp_nid = preset->hp_nid;
-       
+
        spec->num_mux_defs = preset->num_mux_defs;
        if (!spec->num_mux_defs)
                spec->num_mux_defs = 1;
@@ -855,7 +871,7 @@ static void alc_subsystem_id(struct hda_codec *codec,
        if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
                goto do_sku;
 
-       /*      
+       /*
         * 31~30        : port conetcivity
         * 29~21        : reserve
         * 20           : PCBEEP input
@@ -946,7 +962,7 @@ do_sku:
                        tmp = snd_hda_codec_read(codec, 0x20, 0,
                                                 AC_VERB_GET_PROC_COEF, 0);
                        snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7); 
+                                           AC_VERB_SET_COEF_INDEX, 7);
                        snd_hda_codec_write(codec, 0x20, 0,
                                            AC_VERB_SET_PROC_COEF,
                                            tmp | 0x2010);
@@ -961,7 +977,7 @@ do_sku:
                        tmp = snd_hda_codec_read(codec, 0x20, 0,
                                                 AC_VERB_GET_PROC_COEF, 0);
                        snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7); 
+                                           AC_VERB_SET_COEF_INDEX, 7);
                        snd_hda_codec_write(codec, 0x20, 0,
                                            AC_VERB_SET_PROC_COEF,
                                            tmp | 0x3000);
@@ -970,7 +986,7 @@ do_sku:
        default:
                break;
        }
-       
+
        /* is laptop or Desktop and enable the function "Mute internal speaker
         * when the external headphone out jack is plugged"
         */
@@ -1006,6 +1022,7 @@ do_sku:
        snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
                            AC_VERB_SET_UNSOLICITED_ENABLE,
                            AC_USRSP_EN | ALC880_HP_EVENT);
+
        spec->unsol_event = alc_sku_unsol_event;
 }
 
@@ -1296,7 +1313,7 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
  *
  * The system also has a pair of internal speakers, and a headphone jack.
  * These are both connected to Line2 on the codec, hence to DAC 02.
- * 
+ *
  * There is a variable resistor to control the speaker or headphone
  * volume. This is a hardware-only device without a software API.
  *
@@ -1824,7 +1841,7 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = {
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       
+
        { }
 };
 
@@ -1869,7 +1886,7 @@ static struct hda_verb alc880_uniwill_init_verbs[] = {
 
 /*
 * Uniwill P53
-* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, 
+* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
  */
 static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
        {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -1968,7 +1985,7 @@ static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
 {
        unsigned int present;
-       
+
        present = snd_hda_codec_read(codec, 0x21, 0,
                                     AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
        present &= HDA_AMP_VOLMASK;
@@ -2050,7 +2067,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = {
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       
+
        { }
 };
 
@@ -2632,12 +2649,14 @@ static int alc_build_pcms(struct hda_codec *codec)
 
        info->name = spec->stream_name_analog;
        if (spec->stream_analog_playback) {
-               snd_assert(spec->multiout.dac_nids, return -EINVAL);
+               if (snd_BUG_ON(!spec->multiout.dac_nids))
+                       return -EINVAL;
                info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
                info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
        }
        if (spec->stream_analog_capture) {
-               snd_assert(spec->adc_nids, return -EINVAL);
+               if (snd_BUG_ON(!spec->adc_nids))
+                       return -EINVAL;
                info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
                info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
        }
@@ -2667,6 +2686,8 @@ static int alc_build_pcms(struct hda_codec *codec)
                        info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
                        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
                }
+               /* FIXME: do we need this for all Realtek codec models? */
+               codec->spdif_status_reset = 1;
        }
 
        /* If the use of more than one ADC is requested for the current
@@ -3683,7 +3704,7 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        int i;
-       
+
        alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i < spec->autocfg.line_outs; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
@@ -4124,6 +4145,33 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
        { } /* end */
 };
 
+static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct hda_bind_ctls alc260_dc7600_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
+       HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
 static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
        {},
@@ -4147,7 +4195,30 @@ static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
                alc260_hp_3013_automute(codec);
 }
 
-/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12, 
+static void alc260_hp_3012_automute(struct hda_codec *codec)
+{
+       unsigned int present, bits;
+
+       present = snd_hda_codec_read(codec, 0x10, 0,
+                       AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
+
+       bits = present ? 0 : PIN_OUT;
+       snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+       snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+}
+
+static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc260_hp_3012_automute(codec);
+}
+
+/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  */
 static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
@@ -4478,7 +4549,7 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = {
        {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
        {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-       /* Ensure Line1 pin widget takes its input from the OUT1 sum bus 
+       /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
         * when acting as an output.
         */
        {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
@@ -4503,14 +4574,14 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = {
         * stage.
         */
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute input buffer of pin widget used for Line-in (no equiv 
+       /* Unmute input buffer of pin widget used for Line-in (no equiv
         * mixer ctrl)
         */
        {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
        /* Mute capture amp left and right */
        {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Set ADC connection select to match default mixer setting - line 
+       /* Set ADC connection select to match default mixer setting - line
         * in (on mic1 pin)
         */
        {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -4564,7 +4635,7 @@ static struct hda_verb alc260_acer_init_verbs[] = {
        {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
        {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum 
+       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
         * bus when acting as outputs.
         */
        {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
@@ -4675,6 +4746,20 @@ static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
                 alc260_replacer_672v_automute(codec);
 }
 
+static struct hda_verb alc260_hp_dc7600_verbs[] = {
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
 /* Test configuration for debugging, modelled after the ALC880 test
  * configuration.
  */
@@ -4686,7 +4771,7 @@ static hda_nid_t alc260_test_adc_nids[2] = {
        0x04, 0x05,
 };
 /* For testing the ALC260, each input MUX needs its own definition since
- * the signal assignments are different.  This assumes that the first ADC 
+ * the signal assignments are different.  This assumes that the first ADC
  * is NID 0x04.
  */
 static struct hda_input_mux alc260_test_capture_sources[2] = {
@@ -4769,7 +4854,7 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
 
        /* Switches to allow the digital IO pins to be enabled.  The datasheet
         * is ambigious as to which NID is which; testing on laptops which
-        * make this output available should provide clarification. 
+        * make this output available should provide clarification.
         */
        ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
        ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
@@ -4805,7 +4890,7 @@ static struct hda_verb alc260_test_init_verbs[] = {
        {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
        {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-       /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the 
+       /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
         * OUT1 sum bus when acting as an output.
         */
        {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
@@ -4897,7 +4982,7 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
                sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
        } else
                return 0; /* N/A */
-       
+
        snprintf(name, sizeof(name), "%s Playback Volume", pfx);
        err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
        if (err < 0)
@@ -5003,7 +5088,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
                alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
        }
-       
+
        nid = spec->autocfg.speaker_pins[0];
        if (nid)
                alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
@@ -5045,7 +5130,7 @@ static struct hda_verb alc260_volume_init_verbs[] = {
        {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       
+
        /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
         * Note: PASD motherboards uses the Line In 2 as the input for
@@ -5074,7 +5159,7 @@ static struct hda_verb alc260_volume_init_verbs[] = {
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       
+
        { }
 };
 
@@ -5155,6 +5240,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = {
        [ALC260_BASIC]          = "basic",
        [ALC260_HP]             = "hp",
        [ALC260_HP_3013]        = "hp-3013",
+       [ALC260_HP_DC7600]      = "hp-dc7600",
        [ALC260_FUJITSU_S702X]  = "fujitsu",
        [ALC260_ACER]           = "acer",
        [ALC260_WILL]           = "will",
@@ -5172,7 +5258,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
-       SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
+       SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
        SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
        SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
@@ -5218,6 +5304,22 @@ static struct alc_config_preset alc260_presets[] = {
                .unsol_event = alc260_hp_unsol_event,
                .init_hook = alc260_hp_automute,
        },
+       [ALC260_HP_DC7600] = {
+               .mixers = { alc260_hp_dc7600_mixer,
+                           alc260_input_mixer,
+                           alc260_capture_alt_mixer },
+               .init_verbs = { alc260_init_verbs,
+                               alc260_hp_dc7600_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
+               .adc_nids = alc260_hp_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+               .unsol_event = alc260_hp_3012_unsol_event,
+               .init_hook = alc260_hp_3012_automute,
+       },
        [ALC260_HP_3013] = {
                .mixers = { alc260_hp_3013_mixer,
                            alc260_input_mixer,
@@ -5933,7 +6035,7 @@ static struct hda_verb alc882_targa_verbs[] = {
 
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       
+
        {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
        {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
        {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -5949,7 +6051,7 @@ static struct hda_verb alc882_targa_verbs[] = {
 static void alc882_targa_automute(struct hda_codec *codec)
 {
        unsigned int present;
+
        present = snd_hda_codec_read(codec, 0x14, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
@@ -5975,7 +6077,7 @@ static struct hda_verb alc882_asus_a7j_verbs[] = {
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       
+
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
@@ -5993,7 +6095,7 @@ static struct hda_verb alc882_asus_a7m_verbs[] = {
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-        
+
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
@@ -6319,7 +6421,7 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc882_3ST_6ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc882_capture_source,
-       },      
+       },
        [ALC882_ASUS_A7M] = {
                .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
                .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
@@ -6332,14 +6434,14 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc880_threestack_modes,
                .need_dac_fix = 1,
                .input_mux = &alc882_capture_source,
-       },      
+       },
 };
 
 
 /*
  * Pin config fixes
  */
-enum { 
+enum {
        PINFIX_ABIT_AW9D_MAX
 };
 
@@ -6554,16 +6656,19 @@ static int patch_alc882(struct hda_codec *codec)
                        board_config = ALC885_MACPRO;
                        break;
                case 0x106b1000: /* iMac 24 */
+               case 0x106b2800: /* AppleTV */
                        board_config = ALC885_IMAC24;
                        break;
                case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
+               case 0x106b00a4: /* MacbookPro4,1 */
                case 0x106b2c00: /* Macbook Pro rev3 */
                case 0x106b3600: /* Macbook 3.1 */
                        board_config = ALC885_MBP3;
                        break;
                default:
                        /* ALC889A is handled better as ALC888-compatible */
-                       if (codec->revision_id == 0x100103) {
+                       if (codec->revision_id == 0x100101 ||
+                           codec->revision_id == 0x100103) {
                                alc_free(codec);
                                return patch_alc883(codec);
                        }
@@ -6718,6 +6823,23 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
        },
 };
 
+static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x4 },
+       },
+};
+
+static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               { "Line", 0x2 },
+       },
+};
+
 #define alc883_mux_enum_info alc_mux_enum_info
 #define alc883_mux_enum_get alc_mux_enum_get
 /* ALC883 has the ALC882-type input selection */
@@ -7032,13 +7154,11 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
        HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* .name = "Capture Source", */
                .name = "Input Source",
-               .count = 2,
+               .count = 1,
                .info = alc883_mux_enum_info,
                .get = alc883_mux_enum_get,
                .put = alc883_mux_enum_put,
@@ -7256,7 +7376,7 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
                .put = alc883_mux_enum_put,
        },
        { } /* end */
-};     
+};
 
 static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -7283,6 +7403,87 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume",
+                                               0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_bind_ctls alc883_bind_cap_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+               0
+       },
+};
+
+static struct hda_bind_ctls alc883_bind_cap_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
+       HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_chmode_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -7296,7 +7497,7 @@ static struct snd_kcontrol_new alc883_chmode_mixer[] = {
 
 static struct hda_verb alc883_init_verbs[] = {
        /* ADC1: mute amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
        /* ADC2: mute amp left and right */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -7361,14 +7562,14 @@ static struct hda_verb alc883_init_verbs[] = {
        /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
        /* Input mixer2 */
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        /* Input mixer3 */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        { }
 };
 
@@ -7468,7 +7669,7 @@ static struct hda_verb alc883_tagra_verbs[] = {
 
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       
+
        {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
        {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
        {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -7518,6 +7719,18 @@ static struct hda_verb alc883_haier_w66_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc888_lenovo_sky_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
 static struct hda_verb alc888_3st_hp_verbs[] = {
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
@@ -7555,7 +7768,7 @@ static struct hda_channel_mode alc888_3st_hp_modes[2] = {
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
        unsigned int present;
+
        present = snd_hda_codec_read(codec, 0x1b, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -7568,7 +7781,7 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
 {
        unsigned int present;
+
        present = snd_hda_codec_read(codec, 0x14, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -7598,7 +7811,7 @@ static struct hda_verb alc883_medion_md2_verbs[] = {
 static void alc883_medion_md2_automute(struct hda_codec *codec)
 {
        unsigned int present;
+
        present = snd_hda_codec_read(codec, 0x14, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -7753,7 +7966,7 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
 static void alc883_acer_aspire_automute(struct hda_codec *codec)
 {
        unsigned int present;
+
        present = snd_hda_codec_read(codec, 0x14, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -7790,7 +8003,7 @@ static struct hda_verb alc883_acer_eapd_verbs[] = {
 static void alc888_6st_dell_front_automute(struct hda_codec *codec)
 {
        unsigned int present;
+
        present = snd_hda_codec_read(codec, 0x1b, 0,
                                AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -7814,6 +8027,50 @@ static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
        }
 }
 
+static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
+{
+       unsigned int mute;
+       unsigned int present;
+
+       snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       present = (present & 0x80000000) != 0;
+       if (present) {
+               /* mute internal speaker */
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+               snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+               snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+       } else {
+               /* unmute internal speaker if necessary */
+               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+}
+
+static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
+                                            unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc888_lenovo_sky_front_automute(codec);
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -7898,35 +8155,135 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
        { } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc883_loopbacks       alc880_loopbacks
-#endif
+static struct hda_verb alc888_asus_m90v_verbs[] = {
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* enable unsolicited event */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
 
-/* pcm configuration: identiacal with ALC880 */
-#define alc883_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc883_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc883_pcm_analog_alt_capture  alc880_pcm_analog_alt_capture
-#define alc883_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc883_pcm_digital_capture     alc880_pcm_digital_capture
+static void alc883_nb_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
 
-/*
- * configuration and preset
- */
-static const char *alc883_models[ALC883_MODEL_LAST] = {
-       [ALC883_3ST_2ch_DIG]    = "3stack-dig",
-       [ALC883_3ST_6ch_DIG]    = "3stack-6ch-dig",
-       [ALC883_3ST_6ch]        = "3stack-6ch",
-       [ALC883_6ST_DIG]        = "6stack-dig",
-       [ALC883_TARGA_DIG]      = "targa-dig",
-       [ALC883_TARGA_2ch_DIG]  = "targa-2ch-dig",
-       [ALC883_ACER]           = "acer",
-       [ALC883_ACER_ASPIRE]    = "acer-aspire",
-       [ALC883_MEDION]         = "medion",
-       [ALC883_MEDION_MD2]     = "medion-md2",
-       [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
-       [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
-       [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+       snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc883_M90V_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+       bits = present ? 0 : PIN_OUT;
+       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+       snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+}
+
+static void alc883_mode2_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc883_M90V_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc883_nb_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc883_mode2_inithook(struct hda_codec *codec)
+{
+       alc883_M90V_speaker_automute(codec);
+       alc883_nb_mic_automute(codec);
+}
+
+static struct hda_verb alc888_asus_eee1601_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x0838},
+       /* enable unsolicited event */
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x14, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+       bits = present ? 0 : PIN_OUT;
+       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           bits);
+}
+
+static void alc883_eee1601_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc883_eee1601_speaker_automute(codec);
+               break;
+       }
+}
+
+static void alc883_eee1601_inithook(struct hda_codec *codec)
+{
+       alc883_eee1601_speaker_automute(codec);
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc883_loopbacks       alc880_loopbacks
+#endif
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc883_pcm_analog_playback     alc880_pcm_analog_playback
+#define alc883_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc883_pcm_analog_alt_capture  alc880_pcm_analog_alt_capture
+#define alc883_pcm_digital_playback    alc880_pcm_digital_playback
+#define alc883_pcm_digital_capture     alc880_pcm_digital_capture
+
+/*
+ * configuration and preset
+ */
+static const char *alc883_models[ALC883_MODEL_LAST] = {
+       [ALC883_3ST_2ch_DIG]    = "3stack-dig",
+       [ALC883_3ST_6ch_DIG]    = "3stack-6ch-dig",
+       [ALC883_3ST_6ch]        = "3stack-6ch",
+       [ALC883_6ST_DIG]        = "6stack-dig",
+       [ALC883_TARGA_DIG]      = "targa-dig",
+       [ALC883_TARGA_2ch_DIG]  = "targa-2ch-dig",
+       [ALC883_ACER]           = "acer",
+       [ALC883_ACER_ASPIRE]    = "acer-aspire",
+       [ALC883_MEDION]         = "medion",
+       [ALC883_MEDION_MD2]     = "medion-md2",
+       [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
+       [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
+       [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
        [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+       [ALC888_LENOVO_SKY] = "lenovo-sky",
        [ALC883_HAIER_W66]      = "haier-w66",
        [ALC888_3ST_HP]         = "3stack-hp",
        [ALC888_6ST_DELL]       = "6stack-dell",
@@ -7942,7 +8299,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), 
+       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
        SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -7950,10 +8307,13 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1043, 0x8317, "Asus M90V", ALC888_ASUS_M90V),
+       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
        SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
@@ -7989,6 +8349,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
        SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
        SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
@@ -8128,7 +8489,7 @@ static struct alc_config_preset alc883_presets[] = {
                .input_mux = &alc883_capture_source,
                .unsol_event = alc883_medion_md2_unsol_event,
                .init_hook = alc883_medion_md2_automute,
-       },      
+       },
        [ALC883_LAPTOP_EAPD] = {
                .mixers = { alc883_base_mixer },
                .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
@@ -8245,6 +8606,49 @@ static struct alc_config_preset alc883_presets[] = {
                .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
                .init_hook = alc883_2ch_fujitsu_pi2515_automute,
        },
+       [ALC888_LENOVO_SKY] = {
+               .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_lenovo_sky_capture_source,
+               .unsol_event = alc883_lenovo_sky_unsol_event,
+               .init_hook = alc888_lenovo_sky_front_automute,
+       },
+       [ALC888_ASUS_M90V] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_fujitsu_pi2515_capture_source,
+               .unsol_event = alc883_mode2_unsol_event,
+               .init_hook = alc883_mode2_inithook,
+       },
+       [ALC888_ASUS_EEE1601] = {
+               .mixers = { alc883_asus_eee1601_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_asus_eee1601_capture_source,
+               .unsol_event = alc883_eee1601_unsol_event,
+               .init_hook = alc883_eee1601_inithook,
+       },
 };
 
 
@@ -8452,6 +8856,13 @@ static int patch_alc883(struct hda_codec *codec)
 #define alc262_modes           alc260_modes
 #define alc262_capture_source  alc882_capture_source
 
+static hda_nid_t alc262_dmic_adc_nids[1] = {
+       /* ADC0 */
+       0x09
+};
+
+static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
+
 static struct snd_kcontrol_new alc262_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -8833,10 +9244,10 @@ static struct hda_verb alc262_init_verbs[] = {
        {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       
+
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       
+
        /* FIXME: use matrix-type input source selection */
        /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
        /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
@@ -8858,6 +9269,12 @@ static struct hda_verb alc262_init_verbs[] = {
        { }
 };
 
+static struct hda_verb alc262_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
 static struct hda_verb alc262_hippo_unsol_verbs[] = {
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -8884,6 +9301,91 @@ static struct hda_verb alc262_sony_unsol_verbs[] = {
        {}
 };
 
+static struct hda_input_mux alc262_dmic_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Int DMic", 0x9 },
+               { "Mic", 0x0 },
+       },
+};
+
+static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = alc_mux_enum_info,
+               .get = alc_mux_enum_get,
+               .put = alc_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb alc262_toshiba_s06_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static void alc262_dmic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_write(codec, 0x22, 0,
+                               AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       bits = present ? 0 : PIN_OUT;
+       snd_hda_codec_write(codec, 0x14, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
+}
+
+
+
+/* unsolicited event for HP jack sensing */
+static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc262_toshiba_s06_speaker_automute(codec);
+       if ((res >> 26) == ALC880_MIC_EVENT)
+               alc262_dmic_automute(codec);
+
+}
+
+static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
+{
+       alc262_toshiba_s06_speaker_automute(codec);
+       alc262_dmic_automute(codec);
+}
+
 /* mute/unmute internal speaker according to the hp jack and mute state */
 static void alc262_hippo_automute(struct hda_codec *codec)
 {
@@ -8947,6 +9449,41 @@ static void alc262_hippo1_unsol_event(struct hda_codec *codec,
        alc262_hippo1_automute(codec);
 }
 
+/*
+ * nec model
+ *  0x15 = headphone
+ *  0x16 = internal speaker
+ *  0x18 = external mic
+ */
+
+static struct snd_kcontrol_new alc262_nec_mixer[] = {
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc262_nec_verbs[] = {
+       /* Unmute Speaker */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Headphone */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* External mic to headphone */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* External mic to speaker */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {}
+};
+
 /*
  * fujitsu model
  *  0x14 = headphone/spdif-out, 0x15 = internal speaker,
@@ -9179,6 +9716,25 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc262_sony_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+       },
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
 /* additional init verbs for Benq laptops */
 static struct hda_verb alc262_EAPD_verbs[] = {
        {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -9427,7 +9983,7 @@ static struct hda_verb alc262_volume_init_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       
+
        /* set up input amps for analog loopback */
        /* Amp Indices: DAC = 0, mixer = 1 */
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -9482,7 +10038,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
         {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       
+
        /*
         * Set up output mixers (0x0c - 0x0e)
         */
@@ -9643,6 +10199,24 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
        { }
 };
 
+static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Front Speaker */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* MIC jack */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* Front MIC */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
+
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },        /* HP  jack */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc262_loopbacks       alc880_loopbacks
 #endif
@@ -9729,13 +10303,17 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_BENQ_ED8]       = "benq",
        [ALC262_BENQ_T31]       = "benq-t31",
        [ALC262_SONY_ASSAMD]    = "sony-assamd",
+       [ALC262_TOSHIBA_S06]    = "toshiba-s06",
+       [ALC262_TOSHIBA_RX1]    = "toshiba-rx1",
        [ALC262_ULTRA]          = "ultra",
        [ALC262_LENOVO_3000]    = "lenovo-3000",
+       [ALC262_NEC]            = "nec",
        [ALC262_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
+       SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
        SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
@@ -9764,7 +10342,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
-                     ALC262_SONY_ASSAMD),
+                     ALC262_TOSHIBA_RX1),
+       SND_PCI_QUIRK(0x1179, 0x0268, "Toshiba S06", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
@@ -9918,7 +10497,7 @@ static struct alc_config_preset alc262_presets[] = {
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
                .init_hook = alc262_hippo_automute,
-       },      
+       },
        [ALC262_ULTRA] = {
                .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
                .init_verbs = { alc262_ultra_verbs },
@@ -9946,19 +10525,56 @@ static struct alc_config_preset alc262_presets[] = {
                .input_mux = &alc262_fujitsu_capture_source,
                .unsol_event = alc262_lenovo_3000_unsol_event,
        },
-};
-
-static int patch_alc262(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int board_config;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       [ALC262_NEC] = {
+               .mixers = { alc262_nec_mixer },
+               .init_verbs = { alc262_nec_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+       },
+       [ALC262_TOSHIBA_S06] = {
+               .mixers = { alc262_toshiba_s06_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
+                                                       alc262_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .capsrc_nids = alc262_dmic_capsrc_nids,
+               .dac_nids = alc262_dac_nids,
+               .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_dmic_capture_source,
+               .unsol_event = alc262_toshiba_s06_unsol_event,
+               .init_hook = alc262_toshiba_s06_init_hook,
+       },
+       [ALC262_TOSHIBA_RX1] = {
+               .mixers = { alc262_toshiba_rx1_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc262_hippo_unsol_event,
+               .init_hook = alc262_hippo_automute,
+       },
+};
+
+static int patch_alc262(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int board_config;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
 #if 0
        /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
         * under-run
@@ -10004,7 +10620,7 @@ static int patch_alc262(struct hda_codec *codec)
        spec->stream_name_analog = "ALC262 Analog";
        spec->stream_analog_playback = &alc262_pcm_analog_playback;
        spec->stream_analog_capture = &alc262_pcm_analog_capture;
-               
+
        spec->stream_name_digital = "ALC262 Digital";
        spec->stream_digital_playback = &alc262_pcm_digital_playback;
        spec->stream_digital_capture = &alc262_pcm_digital_capture;
@@ -10040,7 +10656,7 @@ static int patch_alc262(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc262_loopbacks;
 #endif
-               
+
        return 0;
 }
 
@@ -10049,7 +10665,7 @@ static int patch_alc262(struct hda_codec *codec)
  */
 #define ALC268_DIGOUT_NID      ALC880_DIGOUT_NID
 #define alc268_modes           alc260_modes
-       
+
 static hda_nid_t alc268_dac_nids[2] = {
        /* front, hp */
        0x02, 0x03
@@ -10109,6 +10725,14 @@ static struct hda_verb alc268_toshiba_verbs[] = {
        { } /* end */
 };
 
+static struct hda_input_mux alc268_acer_lc_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "i-Mic", 0x6 },
+               { "E-Mic", 0x0 },
+       },
+};
+
 /* Acer specific */
 /* bind volumes of both NID 0x02 and 0x03 */
 static struct hda_bind_ctls alc268_acer_bind_master_vol = {
@@ -10161,6 +10785,21 @@ static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc268_acer_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+       },
+       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
+       { }
+};
+
 static struct snd_kcontrol_new alc268_acer_mixer[] = {
        /* output mixer control */
        HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
@@ -10178,6 +10817,16 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
        { }
 };
 
+static struct hda_verb alc268_acer_aspire_one_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
+       { }
+};
+
 static struct hda_verb alc268_acer_verbs[] = {
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
        {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -10185,7 +10834,6 @@ static struct hda_verb alc268_acer_verbs[] = {
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
        { }
 };
@@ -10212,6 +10860,47 @@ static void alc268_acer_init_hook(struct hda_codec *codec)
        alc268_acer_automute(codec, 1);
 }
 
+/* toggle speaker-output according to the hp-jack state */
+static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       bits = present ? AMP_IN_MUTE(0) : 0;
+       snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), bits);
+}
+
+
+static void alc268_acer_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
+                           present ? 0x0 : 0x6);
+}
+
+static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc268_aspire_one_speaker_automute(codec);
+       if ((res >> 26) == ALC880_MIC_EVENT)
+               alc268_acer_mic_automute(codec);
+}
+
+static void alc268_acer_lc_init_hook(struct hda_codec *codec)
+{
+       alc268_aspire_one_speaker_automute(codec);
+       alc268_acer_mic_automute(codec);
+}
+
 static struct snd_kcontrol_new alc268_dell_mixer[] = {
        /* output mixer control */
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
@@ -10360,7 +11049,7 @@ static struct hda_verb alc268_base_init_verbs[] = {
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
        /* Unmute Selector 23h,24h and set the default input to mic-in */
-       
+
        {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -10559,7 +11248,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        nid = cfg->line_out_pins[0];
        if (nid)
-               alc268_new_analog_output(spec, nid, "Front", 0);        
+               alc268_new_analog_output(spec, nid, "Front", 0);
 
        nid = cfg->speaker_pins[0];
        if (nid == 0x1d) {
@@ -10581,7 +11270,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
                if (err < 0)
                        return err;
        }
-       return 0;       
+       return 0;
 }
 
 /* create playback/capture controls for input pins */
@@ -10602,7 +11291,7 @@ static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
                case 0x1a:
                        idx1 = 2;       /* Line In */
                        break;
-               case 0x1c:      
+               case 0x1c:
                        idx1 = 3;       /* CD */
                        break;
                case 0x12:
@@ -10614,7 +11303,7 @@ static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
                }
                imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
                imux->items[imux->num_items].index = idx1;
-               imux->num_items++;      
+               imux->num_items++;
        }
        return 0;
 }
@@ -10644,11 +11333,11 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
        }
 
        dac_vol1 = dac_vol2 = 0xb000 | 0x40;    /* set max volume  */
-       if (line_nid == 0x14)   
+       if (line_nid == 0x14)
                dac_vol2 = AMP_OUT_ZERO;
        else if (line_nid == 0x15)
                dac_vol1 = AMP_OUT_ZERO;
-       if (hp_nid == 0x14)     
+       if (hp_nid == 0x14)
                dac_vol2 = AMP_OUT_ZERO;
        else if (hp_nid == 0x15)
                dac_vol1 = AMP_OUT_ZERO;
@@ -10739,6 +11428,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = {
        [ALC268_3ST]            = "3stack",
        [ALC268_TOSHIBA]        = "toshiba",
        [ALC268_ACER]           = "acer",
+       [ALC268_ACER_ASPIRE_ONE]        = "acer-aspire",
        [ALC268_DELL]           = "dell",
        [ALC268_ZEPTO]          = "zepto",
 #ifdef CONFIG_SND_DEBUG
@@ -10753,11 +11443,14 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
        SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
        SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
+                                               ALC268_ACER_ASPIRE_ONE),
        SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
        SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
        SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
+       SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
        SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
@@ -10830,6 +11523,23 @@ static struct alc_config_preset alc268_presets[] = {
                .unsol_event = alc268_acer_unsol_event,
                .init_hook = alc268_acer_init_hook,
        },
+       [ALC268_ACER_ASPIRE_ONE] = {
+               .mixers = { alc268_acer_aspire_one_mixer,
+                               alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_acer_aspire_one_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_acer_lc_capture_source,
+               .unsol_event = alc268_acer_lc_unsol_event,
+               .init_hook = alc268_acer_lc_init_hook,
+       },
        [ALC268_DELL] = {
                .mixers = { alc268_dell_mixer, alc268_beep_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
@@ -10974,7 +11684,7 @@ static int patch_alc268(struct hda_codec *codec)
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC268_AUTO)
                spec->init_hook = alc268_auto_init;
-               
+
        return 0;
 }
 
@@ -10990,6 +11700,14 @@ static hda_nid_t alc269_adc_nids[1] = {
        0x08,
 };
 
+static hda_nid_t alc269_capsrc_nids[1] = {
+       0x23,
+};
+
+/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
+ *       not a mux!
+ */
+
 static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
        .num_items = 2,
        .items = {
@@ -11016,6 +11734,8 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
@@ -11025,6 +11745,28 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc268_acer_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+       },
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       { }
+};
+
 /* bind volumes of both NID 0x0c and 0x0d */
 static struct hda_bind_ctls alc269_epc_bind_vol = {
        .ops = &snd_hda_bind_vol,
@@ -11068,75 +11810,72 @@ static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
        { } /* end */
 };
 
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static struct hda_verb alc269_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+/* beep control */
+static struct snd_kcontrol_new alc269_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
+       { } /* end */
+};
 
-       /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
-        * analog-loopback mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+static struct hda_verb alc269_quanta_fl1_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       { }
+};
 
-       /*
-        * Set up output mixers (0x0c - 0x0e)
-        */
-       /* set vol=0 to output mixers */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+/* toggle speaker-output according to the hp-jack state */
+static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
 
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       bits = present ? AMP_IN_MUTE(0) : 0;
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+                       AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+                       AMP_IN_MUTE(0), bits);
 
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_COEF_INDEX, 0x0c);
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_PROC_COEF, 0x680);
 
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_COEF_INDEX, 0x0c);
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_PROC_COEF, 0x480);
+}
 
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
 
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_write(codec, 0x23, 0,
+                           AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
+}
 
-       /* set EAPD */
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
+static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc269_quanta_fl1_speaker_automute(codec);
+       if ((res >> 26) == ALC880_MIC_EVENT)
+               alc269_quanta_fl1_mic_automute(codec);
+}
+
+static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
+{
+       alc269_quanta_fl1_speaker_automute(codec);
+       alc269_quanta_fl1_mic_automute(codec);
+}
 
 static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -11163,42 +11902,42 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
 static void alc269_speaker_automute(struct hda_codec *codec)
 {
        unsigned int present;
-       unsigned int bits;
+       unsigned char bits;
 
        present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-                                AMP_IN_MUTE(0), bits);
+                               AMP_IN_MUTE(0), bits);
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-                                AMP_IN_MUTE(0), bits);
+                               AMP_IN_MUTE(0), bits);
 }
 
 static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
-       snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
-                           present ? 0 : 5);
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_write(codec, 0x23, 0,
+                               AC_VERB_SET_CONNECT_SEL,  (present ? 0 : 5));
 }
 
 static void alc269_eeepc_amic_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           present ? AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0));
+                               0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
        snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           present ? AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1));
+                               0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
 }
 
 /* unsolicited event for HP jack sensing */
 static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
-                                         unsigned int res)
+                                    unsigned int res)
 {
        if ((res >> 26) == ALC880_HP_EVENT)
                alc269_speaker_automute(codec);
@@ -11215,7 +11954,7 @@ static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
 
 /* unsolicited event for HP jack sensing */
 static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
-                                         unsigned int res)
+                                    unsigned int res)
 {
        if ((res >> 26) == ALC880_HP_EVENT)
                alc269_speaker_automute(codec);
@@ -11230,18 +11969,88 @@ static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
        alc269_eeepc_amic_automute(codec);
 }
 
-/* add playback controls from the parsed DAC table */
-static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-
-       spec->multiout.num_dacs = 1;    /* only use one dac */
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->multiout.dac_nids[0] = 2;
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc269_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
-       nid = cfg->line_out_pins[0];
+       /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
+        * analog-loopback mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for
+        * front panel mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+       /* set EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/* add playback controls from the parsed DAC table */
+static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       hda_nid_t nid;
+       int err;
+
+       spec->multiout.num_dacs = 1;    /* only use one dac */
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       spec->multiout.dac_nids[0] = 2;
+
+       nid = cfg->line_out_pins[0];
        if (nid) {
                err = add_control(spec, ALC_CTL_WIDGET_VOL,
                                  "Front Playback Volume",
@@ -11330,7 +12139,7 @@ static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
 static int alc269_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
+       int i, err;
        static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -11353,9 +12162,20 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (spec->kctl_alloc)
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
+       /* create a beep mixer control if the pin 0x1d isn't assigned */
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
+               if (spec->autocfg.input_pins[i] == 0x1d)
+                       break;
+       if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
+               spec->mixers[spec->num_mixers++] = alc269_beep_mixer;
+
        spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux;
+       /* set default input source */
+       snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
+                                 0, AC_VERB_SET_CONNECT_SEL,
+                                 spec->input_mux->items[0].index);
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
@@ -11387,14 +12207,20 @@ static void alc269_auto_init(struct hda_codec *codec)
  * configuration and preset
  */
 static const char *alc269_models[ALC269_MODEL_LAST] = {
-       [ALC269_BASIC]          = "basic",
+       [ALC269_BASIC]                  = "basic",
+       [ALC269_QUANTA_FL1]             = "quanta",
+       [ALC269_ASUS_EEEPC_P703]        = "eeepc-p703",
+       [ALC269_ASUS_EEEPC_P901]        = "eeepc-p901"
 };
 
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
        SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
                      ALC269_ASUS_EEEPC_P703),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
                      ALC269_ASUS_EEEPC_P901),
+       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
+                     ALC269_ASUS_EEEPC_P901),
        {}
 };
 
@@ -11409,6 +12235,18 @@ static struct alc_config_preset alc269_presets[] = {
                .channel_mode = alc269_modes,
                .input_mux = &alc269_capture_source,
        },
+       [ALC269_QUANTA_FL1] = {
+               .mixers = { alc269_quanta_fl1_mixer },
+               .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .input_mux = &alc269_capture_source,
+               .unsol_event = alc269_quanta_fl1_unsol_event,
+               .init_hook = alc269_quanta_fl1_init_hook,
+       },
        [ALC269_ASUS_EEEPC_P703] = {
                .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
                .init_verbs = { alc269_init_verbs,
@@ -11488,6 +12326,7 @@ static int patch_alc269(struct hda_codec *codec)
 
        spec->adc_nids = alc269_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
+       spec->capsrc_nids = alc269_capsrc_nids;
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC269_AUTO)
@@ -11689,7 +12528,7 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
        HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-       
+
         /*Capture mixer control */
        HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
@@ -11832,20 +12671,20 @@ static struct hda_verb alc861_base_init_verbs[] = {
        /* route front mic to ADC1*/
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       
+
        /* Unmute DAC0~3 & spdif out*/
        {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       
+
        /* Unmute Mixer 14 (mic) 1c (Line in)*/
        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       
+
        /* Unmute Stereo Mixer 15 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -11901,13 +12740,13 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       
+
        /* Unmute Mixer 14 (mic) 1c (Line in)*/
        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       
+
        /* Unmute Stereo Mixer 15 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -11963,13 +12802,13 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       
+
        /* Unmute Mixer 14 (mic) 1c (Line in)*/
        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       
+
        /* Unmute Stereo Mixer 15 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12034,7 +12873,7 @@ static struct hda_verb alc861_asus_init_verbs[] = {
         {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
         {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       
+
        /* Unmute Stereo Mixer 15 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12071,20 +12910,20 @@ static struct hda_verb alc861_auto_init_verbs[] = {
         */
        /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       
+
        /* Unmute DAC0~3 & spdif out*/
        {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       
+
        /* Unmute Mixer 14 (mic) 1c (Line in)*/
        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       
+
        /* Unmute Stereo Mixer 15 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12659,7 +13498,7 @@ static int patch_alc861(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc861_loopbacks;
 #endif
-               
+
        return 0;
 }
 
@@ -12913,7 +13752,7 @@ static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       
+
        { } /* end */
 };
 
@@ -13058,7 +13897,7 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, 
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
        {}
 };
 
@@ -13120,7 +13959,7 @@ static struct hda_verb alc861vd_dallas_verbs[] = {
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       
+
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -13145,7 +13984,7 @@ static struct hda_verb alc861vd_dallas_verbs[] = {
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},  
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 
        { } /* end */
@@ -13304,7 +14143,7 @@ static struct alc_config_preset alc861vd_presets[] = {
                .input_mux = &alc861vd_hp_capture_source,
                .unsol_event = alc861vd_dallas_unsol_event,
                .init_hook = alc861vd_dallas_automute,
-       },              
+       },
 };
 
 /*
@@ -13883,13 +14722,120 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
        { } /* end */
 };
 
+static struct hda_bind_ctls alc663_asus_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct hda_bind_ctls alc663_asus_one_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
 static struct snd_kcontrol_new alc663_m51va_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+       { } /* end */
+};
+
+static struct hda_bind_ctls alc663_asus_four_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct hda_bind_ctls alc663_asus_two_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume",
+                               &alc663_asus_two_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
 
@@ -14074,14 +15020,81 @@ static struct hda_verb alc663_auto_init_verbs[] = {
 };
 
 static struct hda_verb alc663_m51va_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
        {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
 
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+static struct hda_verb alc663_21jd_amic_init_verbs[] = {
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
 
+static struct hda_verb alc663_15jd_amic_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x0},   /* Headphone */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},   /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
        {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
        {}
 };
 
@@ -14110,6 +15123,14 @@ static struct hda_verb alc663_g50v_init_verbs[] = {
        {}
 };
 
+static struct hda_verb alc662_ecs_init_verbs[] = {
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new alc662_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
@@ -14129,6 +15150,12 @@ static struct snd_kcontrol_new alc662_capture_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
 static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
 {
        unsigned int present;
@@ -14209,12 +15236,12 @@ static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
        if (present) {
                /* mute internal speaker */
                snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+                                       HDA_AMP_MUTE, HDA_AMP_MUTE);
        } else {
                /* unmute internal speaker if necessary */
                mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
                snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
+                                       HDA_AMP_MUTE, mute);
        }
 }
 
@@ -14237,11 +15264,108 @@ static void alc663_m51va_speaker_automute(struct hda_codec *codec)
        unsigned char bits;
 
        present = snd_hda_codec_read(codec, 0x21, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
        bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), bits);
+}
+
+static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x21, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), bits);
+}
+
+static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), bits);
+       snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), bits);
+}
+
+static void alc662_f5z_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+       bits = present ? 0 : PIN_OUT;
+       snd_hda_codec_write(codec, 0x14, 0,
+                        AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
+}
+
+static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present1, present2;
+
+       present1 = snd_hda_codec_read(codec, 0x21, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+       present2 = snd_hda_codec_read(codec, 0x15, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+
+       if (present1 || present2) {
+               snd_hda_codec_write_cache(codec, 0x14, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       } else {
+               snd_hda_codec_write_cache(codec, 0x14, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       }
+}
+
+static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present1, present2;
+
+       present1 = snd_hda_codec_read(codec, 0x1b, 0,
+                               AC_VERB_GET_PIN_SENSE, 0)
+                               & AC_PINSENSE_PRESENCE;
+       present2 = snd_hda_codec_read(codec, 0x15, 0,
+                               AC_VERB_GET_PIN_SENSE, 0)
+                               & AC_PINSENSE_PRESENCE;
+
+       if (present1 || present2) {
+               snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), AMP_IN_MUTE(0));
+               snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), AMP_IN_MUTE(0));
+       } else {
+               snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+                               AMP_IN_MUTE(0), 0);
+               snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+                               AMP_IN_MUTE(0), 0);
+       }
 }
 
 static void alc663_m51va_mic_automute(struct hda_codec *codec)
@@ -14249,16 +15373,16 @@ static void alc663_m51va_mic_automute(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
        snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+                       0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
        snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+                       0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
        snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+                       0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
        snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+                       0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
 }
 
 static void alc663_m51va_unsol_event(struct hda_codec *codec,
@@ -14280,6 +15404,121 @@ static void alc663_m51va_inithook(struct hda_codec *codec)
        alc663_m51va_mic_automute(codec);
 }
 
+/* ***************** Mode1 ******************************/
+static void alc663_mode1_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_m51va_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_mode1_inithook(struct hda_codec *codec)
+{
+       alc663_m51va_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode2 ******************************/
+static void alc662_mode2_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc662_f5z_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc662_mode2_inithook(struct hda_codec *codec)
+{
+       alc662_f5z_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode3 ******************************/
+static void alc663_mode3_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_two_hp_m1_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_mode3_inithook(struct hda_codec *codec)
+{
+       alc663_two_hp_m1_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode4 ******************************/
+static void alc663_mode4_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_21jd_two_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_mode4_inithook(struct hda_codec *codec)
+{
+       alc663_21jd_two_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode5 ******************************/
+static void alc663_mode5_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_15jd_two_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_mode5_inithook(struct hda_codec *codec)
+{
+       alc663_15jd_two_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+/* ***************** Mode6 ******************************/
+static void alc663_mode6_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_two_hp_m2_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_mode6_inithook(struct hda_codec *codec)
+{
+       alc663_two_hp_m2_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+
 static void alc663_g71v_hp_automute(struct hda_codec *codec)
 {
        unsigned int present;
@@ -14350,6 +15589,46 @@ static void alc663_g50v_inithook(struct hda_codec *codec)
        alc662_eeepc_mic_automute(codec);
 }
 
+/* bind hp and internal speaker mute (with plug check) */
+static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int change;
+
+       change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+                                         HDA_AMP_MUTE,
+                                         valp[0] ? 0 : HDA_AMP_MUTE);
+       change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+                                          HDA_AMP_MUTE,
+                                          valp[1] ? 0 : HDA_AMP_MUTE);
+       if (change)
+               alc262_hippo1_automute(codec);
+       return change;
+}
+
+static struct snd_kcontrol_new alc662_ecs_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc662_ecs_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+       },
+
+       HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks       alc880_loopbacks
 #endif
@@ -14372,21 +15651,67 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
        [ALC662_LENOVO_101E]    = "lenovo-101e",
        [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
        [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
+       [ALC662_ECS] = "ecs",
        [ALC663_ASUS_M51VA] = "m51va",
        [ALC663_ASUS_G71V] = "g71v",
        [ALC663_ASUS_H13] = "h13",
        [ALC663_ASUS_G50V] = "g50v",
+       [ALC663_ASUS_MODE1] = "asus-mode1",
+       [ALC662_ASUS_MODE2] = "asus-mode2",
+       [ALC663_ASUS_MODE3] = "asus-mode3",
+       [ALC663_ASUS_MODE4] = "asus-mode4",
+       [ALC663_ASUS_MODE5] = "asus-mode5",
+       [ALC663_ASUS_MODE6] = "asus-mode6",
        [ALC662_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
        SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
        SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
        SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
        SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
+       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
+       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
+                     ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
+       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
+       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
+                     ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
+                                       ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
        SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
        SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
@@ -14477,6 +15802,18 @@ static struct alc_config_preset alc662_presets[] = {
                .unsol_event = alc662_eeepc_ep20_unsol_event,
                .init_hook = alc662_eeepc_ep20_inithook,
        },
+       [ALC662_ECS] = {
+               .mixers = { alc662_ecs_mixer, alc662_capture_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_ecs_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc662_eeepc_unsol_event,
+               .init_hook = alc662_eeepc_inithook,
+       },
        [ALC663_ASUS_M51VA] = {
                .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
                .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
@@ -14524,6 +15861,91 @@ static struct alc_config_preset alc662_presets[] = {
                .unsol_event = alc663_g50v_unsol_event,
                .init_hook = alc663_g50v_inithook,
        },
+       [ALC663_ASUS_MODE1] = {
+               .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc663_21jd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc663_mode1_unsol_event,
+               .init_hook = alc663_mode1_inithook,
+       },
+       [ALC662_ASUS_MODE2] = {
+               .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_1bjd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc662_mode2_unsol_event,
+               .init_hook = alc662_mode2_inithook,
+       },
+       [ALC663_ASUS_MODE3] = {
+               .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc663_two_hp_amic_m1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc663_mode3_unsol_event,
+               .init_hook = alc663_mode3_inithook,
+       },
+       [ALC663_ASUS_MODE4] = {
+               .mixers = { alc663_asus_21jd_clfe_mixer,
+                               alc662_auto_capture_mixer},
+               .init_verbs = { alc662_init_verbs,
+                               alc663_21jd_amic_init_verbs},
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc663_mode4_unsol_event,
+               .init_hook = alc663_mode4_inithook,
+       },
+       [ALC663_ASUS_MODE5] = {
+               .mixers = { alc663_asus_15jd_clfe_mixer,
+                               alc662_auto_capture_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc663_15jd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc663_mode5_unsol_event,
+               .init_hook = alc663_mode5_inithook,
+       },
+       [ALC663_ASUS_MODE6] = {
+               .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc663_two_hp_amic_m2_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc663_mode6_unsol_event,
+               .init_hook = alc663_mode6_inithook,
+       },
 };
 
 
@@ -14560,15 +15982,15 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
                                          "Center Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 1, 2,
+                                         HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
                                                              HDA_INPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
                                          "LFE Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 2,
+                                         HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
                                                              HDA_INPUT));
                        if (err < 0)
                                return err;
@@ -14580,9 +16002,9 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
-                       err = add_control(spec, ALC_CTL_BIND_MUTE, name,
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 2,
-                                                             HDA_INPUT));
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+                               HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
+                                                   3, 0, HDA_INPUT));
                        if (err < 0)
                                return err;
                }
@@ -14777,7 +16199,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
 
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux;
-       
+
        spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
        if (codec->vendor_id == 0x10ec0663)
                spec->init_verbs[spec->num_init_verbs++] =
@@ -14896,6 +16318,8 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
        { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
        { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
+       { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
+         .patch = patch_alc882 }, /* should be patch_alc883() in future */
        { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
          .patch = patch_alc882 }, /* should be patch_alc883() in future */
        { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
index f3da621f25c533a48b5a710970381410e6006e45..c461baa83c2a9ead2c669bc86460215340bbe4aa 100644 (file)
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_patch.h"
+#include "hda_beep.h"
 
 #define NUM_CONTROL_ALLOC      32
 #define STAC_PWR_EVENT         0x20
 #define STAC_HP_EVENT          0x30
+#define STAC_VREF_EVENT                0x40
 
 enum {
        STAC_REF,
@@ -70,10 +72,16 @@ enum {
        STAC_92HD73XX_MODELS
 };
 
+enum {
+       STAC_92HD83XXX_REF,
+       STAC_92HD83XXX_MODELS
+};
+
 enum {
        STAC_92HD71BXX_REF,
        STAC_DELL_M4_1,
        STAC_DELL_M4_2,
+       STAC_HP_M4,
        STAC_92HD71BXX_MODELS
 };
 
@@ -104,6 +112,7 @@ enum {
        STAC_MACBOOK_PRO_V2,
        STAC_IMAC_INTEL,
        STAC_IMAC_INTEL_20,
+       STAC_ECS_202,
        STAC_922X_DELL_D81,
        STAC_922X_DELL_D82,
        STAC_922X_DELL_M81,
@@ -130,6 +139,7 @@ struct sigmatel_spec {
        unsigned int mic_switch: 1;
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
+       unsigned int spdif_mute: 1;
 
        /* gpio lines */
        unsigned int eapd_mask;
@@ -138,17 +148,22 @@ struct sigmatel_spec {
        unsigned int gpio_data;
        unsigned int gpio_mute;
 
+       /* stream */
+       unsigned int stream_delay;
+
        /* analog loopback */
        unsigned char aloopback_mask;
        unsigned char aloopback_shift;
 
        /* power management */
        unsigned int num_pwrs;
+       unsigned int *pwr_mapping;
        hda_nid_t *pwr_nids;
        hda_nid_t *dac_list;
 
        /* playback */
        struct hda_input_mux *mono_mux;
+       struct hda_input_mux *amp_mux;
        unsigned int cur_mmux;
        struct hda_multi_out multiout;
        hda_nid_t dac_nids[5];
@@ -162,8 +177,14 @@ struct sigmatel_spec {
        unsigned int num_dmics;
        hda_nid_t *dmux_nids;
        unsigned int num_dmuxes;
+       hda_nid_t *smux_nids;
+       unsigned int num_smuxes;
+       const char **spdif_labels;
+
        hda_nid_t dig_in_nid;
        hda_nid_t mono_nid;
+       hda_nid_t anabeep_nid;
+       hda_nid_t digbeep_nid;
 
        /* pin widgets */
        hda_nid_t *pin_nids;
@@ -180,6 +201,12 @@ struct sigmatel_spec {
        unsigned int cur_dmux[2];
        struct hda_input_mux *input_mux;
        unsigned int cur_mux[3];
+       struct hda_input_mux *sinput_mux;
+       unsigned int cur_smux[2];
+       unsigned int cur_amux;
+       hda_nid_t *amp_nids;
+       unsigned int num_amps;
+       unsigned int powerdown_adcs;
 
        /* i/o switches */
        unsigned int io_switch[2];
@@ -195,6 +222,8 @@ struct sigmatel_spec {
        struct snd_kcontrol_new *kctl_alloc;
        struct hda_input_mux private_dimux;
        struct hda_input_mux private_imux;
+       struct hda_input_mux private_smux;
+       struct hda_input_mux private_amp_mux;
        struct hda_input_mux private_mono_mux;
 };
 
@@ -215,10 +244,19 @@ static hda_nid_t stac92hd73xx_pwr_nids[8] = {
        0x0f, 0x10, 0x11
 };
 
+static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
+       0x26, 0,
+};
+
 static hda_nid_t stac92hd73xx_adc_nids[2] = {
        0x1a, 0x1b
 };
 
+#define DELL_M6_AMP 2
+static hda_nid_t stac92hd73xx_amp_nids[3] = {
+       0x0b, 0x0c, 0x0e
+};
+
 #define STAC92HD73XX_NUM_DMICS 2
 static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
        0x13, 0x14, 0
@@ -237,6 +275,41 @@ static hda_nid_t stac92hd73xx_dmux_nids[2] = {
        0x20, 0x21,
 };
 
+static hda_nid_t stac92hd73xx_smux_nids[2] = {
+       0x22, 0x23,
+};
+
+#define STAC92HD83XXX_NUM_DMICS        2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+       0x11, 0x12, 0
+};
+
+#define STAC92HD81_DAC_COUNT 2
+#define STAC92HD83_DAC_COUNT 3
+static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
+       0x13, 0x14, 0x22,
+};
+
+static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
+       0x17, 0x18,
+};
+
+static hda_nid_t stac92hd83xxx_adc_nids[2] = {
+       0x15, 0x16,
+};
+
+static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
+       0xa, 0xb, 0xd, 0xe,
+};
+
+static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
+       0x1e, 0,
+};
+
+static unsigned int stac92hd83xxx_pwr_mapping[4] = {
+       0x03, 0x0c, 0x10, 0x40,
+};
+
 static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
        0x0a, 0x0d, 0x0f
 };
@@ -253,6 +326,10 @@ static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
        0x1c,
 };
 
+static hda_nid_t stac92hd71bxx_smux_nids[2] = {
+       0x24, 0x25,
+};
+
 static hda_nid_t stac92hd71bxx_dac_nids[1] = {
        0x10, /*0x11, */
 };
@@ -262,6 +339,10 @@ static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
        0x18, 0x19, 0
 };
 
+static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
+       0x22, 0
+};
+
 static hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
@@ -299,6 +380,10 @@ static hda_nid_t stac927x_mux_nids[3] = {
         0x15, 0x16, 0x17
 };
 
+static hda_nid_t stac927x_smux_nids[1] = {
+       0x21,
+};
+
 static hda_nid_t stac927x_dac_nids[6] = {
        0x02, 0x03, 0x04, 0x05, 0x06, 0
 };
@@ -312,6 +397,11 @@ static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
        0x13, 0x14, 0
 };
 
+static const char *stac927x_spdif_labels[5] = {
+       "Digital Playback", "ADAT", "Analog Mux 1",
+       "Analog Mux 2", "Analog Mux 3"
+};
+
 static hda_nid_t stac9205_adc_nids[2] = {
         0x12, 0x13
 };
@@ -324,6 +414,10 @@ static hda_nid_t stac9205_dmux_nids[1] = {
        0x1d,
 };
 
+static hda_nid_t stac9205_smux_nids[1] = {
+       0x21,
+};
+
 #define STAC9205_NUM_DMICS     2
 static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
@@ -347,12 +441,18 @@ static hda_nid_t stac922x_pin_nids[10] = {
 static hda_nid_t stac92hd73xx_pin_nids[13] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x10, 0x11, 0x12, 0x13,
-       0x14, 0x1e, 0x22
+       0x14, 0x22, 0x23
 };
 
-static hda_nid_t stac92hd71bxx_pin_nids[10] = {
+static hda_nid_t stac92hd83xxx_pin_nids[14] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+       0x0f, 0x10, 0x11, 0x12, 0x13,
+       0x1d, 0x1e, 0x1f, 0x20
+};
+static hda_nid_t stac92hd71bxx_pin_nids[11] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x14, 0x18, 0x19, 0x1e,
+       0x1f,
 };
 
 static hda_nid_t stac927x_pin_nids[14] = {
@@ -367,6 +467,34 @@ static hda_nid_t stac9205_pin_nids[12] = {
        0x21, 0x22,
 };
 
+#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
+
+static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = spec->amp_nids[spec->cur_amux];
+
+       kcontrol->private_value ^= get_amp_nid(kcontrol);
+       kcontrol->private_value |= nid;
+
+       return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
+}
+
+static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = spec->amp_nids[spec->cur_amux];
+
+       kcontrol->private_value ^= get_amp_nid(kcontrol);
+       kcontrol->private_value |= nid;
+
+       return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+}
+
 static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_info *uinfo)
 {
@@ -397,6 +525,58 @@ static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
                        spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
 }
 
+static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
+}
+
+static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+       ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
+       return 0;
+}
+
+static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       struct hda_input_mux *smux = &spec->private_smux;
+       unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       int err, val;
+       hda_nid_t nid;
+
+       err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
+                       spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
+       if (err < 0)
+               return err;
+
+       if (spec->spdif_mute) {
+               if (smux_idx == 0)
+                       nid = spec->multiout.dig_out_nid;
+               else
+                       nid = codec->slave_dig_outs[smux_idx - 1];
+               if (spec->cur_smux[smux_idx] == smux->num_items - 1)
+                       val = AMP_OUT_MUTE;
+               if (smux_idx == 0)
+                       nid = spec->multiout.dig_out_nid;
+               else
+                       nid = codec->slave_dig_outs[smux_idx - 1];
+               /* un/mute SPDIF out */
+               snd_hda_codec_write_cache(codec, nid, 0,
+                       AC_VERB_SET_AMP_GAIN_MUTE, val);
+       }
+       return 0;
+}
+
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -452,6 +632,41 @@ static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
                                     spec->mono_nid, &spec->cur_mmux);
 }
 
+static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       return snd_hda_input_mux_info(spec->amp_mux, uinfo);
+}
+
+static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_amux;
+       return 0;
+}
+
+static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       struct snd_kcontrol *ctl =
+               snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
+       if (!ctl)
+               return -EINVAL;
+
+       snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
+               SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
+
+       return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
+                                    0, &spec->cur_amux);
+}
+
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
 
 static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
@@ -546,8 +761,8 @@ static struct hda_verb dell_eq_core_init[] = {
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
        /* setup audio connections */
        { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
+       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -628,6 +843,19 @@ static struct hda_verb stac92hd73xx_10ch_core_init[] = {
        {}
 };
 
+static struct hda_verb stac92hd83xxx_core_init[] = {
+       /* start of config #1 */
+       { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
+
+       /* start of config #2 */
+       { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
+       { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
+       { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+       /* power state controls amps */
+       { 0x01, AC_VERB_SET_EAPD, 1 << 2},
+};
+
 static struct hda_verb stac92hd71bxx_core_init[] = {
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -690,12 +918,16 @@ static struct hda_verb d965_core_init[] = {
 static struct hda_verb stac927x_core_init[] = {
        /* set master volume and direct control */      
        { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* enable analog pc beep path */
+       { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
        {}
 };
 
 static struct hda_verb stac9205_core_init[] = {
        /* set master volume and direct control */      
        { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* enable analog pc beep path */
+       { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
        {}
 };
 
@@ -709,6 +941,31 @@ static struct hda_verb stac9205_core_init[] = {
                .put = stac92xx_mono_mux_enum_put, \
        }
 
+#define STAC_AMP_MUX \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = "Amp Selector Capture Switch", \
+               .count = 1, \
+               .info = stac92xx_amp_mux_enum_info, \
+               .get = stac92xx_amp_mux_enum_get, \
+               .put = stac92xx_amp_mux_enum_put, \
+       }
+
+#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = xname, \
+               .index = 0, \
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
+               .info = stac92xx_amp_volume_info, \
+               .get = stac92xx_amp_volume_get, \
+               .put = stac92xx_amp_volume_put, \
+               .tlv = { .c = snd_hda_mixer_amp_tlv }, \
+               .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
+       }
+
 #define STAC_INPUT_SOURCE(cnt) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -736,33 +993,36 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
        STAC_INPUT_SOURCE(1),
        HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
        { } /* end */
 };
 
+#define DELL_M6_MIXER 6
 static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
+       /* start of config #1 */
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
-
        HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
        HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
 
+       HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+
+       /* start of config #2 */
+       HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
        HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
        { } /* end */
 };
 
@@ -818,19 +1078,46 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
        { } /* end */
 };
 
+
+static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
+
+       /*
+       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
+       */
+       { } /* end */
+};
+
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        STAC_INPUT_SOURCE(2),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
-
+       /* analog pc-beep replaced with digital beep support */
+       /*
        HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
        HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
+       */
 
        HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
@@ -843,11 +1130,9 @@ static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -855,7 +1140,6 @@ static struct snd_kcontrol_new stac925x_mixer[] = {
        STAC_INPUT_SOURCE(1),
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -865,12 +1149,9 @@ static struct snd_kcontrol_new stac9205_mixer[] = {
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
-
        { } /* end */
 };
 
@@ -879,11 +1160,9 @@ static struct snd_kcontrol_new stac922x_mixer[] = {
        STAC_INPUT_SOURCE(2),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -894,15 +1173,12 @@ static struct snd_kcontrol_new stac927x_mixer[] = {
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -915,6 +1191,15 @@ static struct snd_kcontrol_new stac_dmux_mixer = {
        .put = stac92xx_dmux_enum_put,
 };
 
+static struct snd_kcontrol_new stac_smux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Playback Source",
+       /* count set later */
+       .info = stac92xx_smux_enum_info,
+       .get = stac92xx_smux_enum_get,
+       .put = stac92xx_smux_enum_put,
+};
+
 static const char *slave_vols[] = {
        "Front Playback Volume",
        "Surround Playback Volume",
@@ -966,6 +1251,22 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+       if (spec->num_smuxes > 0) {
+               int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
+               struct hda_input_mux *smux = &spec->private_smux;
+               /* check for mute support on SPDIF out */
+               if (wcaps & AC_WCAP_OUT_AMP) {
+                       smux->items[smux->num_items].label = "Off";
+                       smux->items[smux->num_items].index = 0;
+                       smux->num_items++;
+                       spec->spdif_mute = 1;
+               }
+               stac_smux_mixer.count = spec->num_smuxes;
+               err = snd_ctl_add(codec->bus->card,
+                                 snd_ctl_new1(&stac_smux_mixer, codec));
+               if (err < 0)
+                       return err;
+       }
 
        if (spec->multiout.dig_out_nid) {
                err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
@@ -977,7 +1278,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                        return err;
                spec->multiout.share_spdif = 1;
        }
-       if (spec->dig_in_nid) {
+       if (spec->dig_in_nid && (!spec->gpio_dir & 0x01)) {
                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
                if (err < 0)
                        return err;
@@ -1325,40 +1626,65 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
        {} /* terminator */
 };
 
-static unsigned int ref92hd71bxx_pin_configs[10] = {
+static unsigned int ref92hd83xxx_pin_configs[14] = {
+       0x02214030, 0x02211010, 0x02a19020, 0x02170130,
+       0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
+       0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
+       0x01451160, 0x98560170,
+};
+
+static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
+       [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
+};
+
+static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+       [STAC_92HD83XXX_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_92HD71BXX_REF),
+};
+
+static unsigned int ref92hd71bxx_pin_configs[11] = {
        0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
        0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
-       0x90a000f0, 0x01452050,
+       0x90a000f0, 0x01452050, 0x01452050,
 };
 
-static unsigned int dell_m4_1_pin_configs[10] = {
+static unsigned int dell_m4_1_pin_configs[11] = {
        0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
-       0x40f000f0, 0x4f0000f0,
+       0x40f000f0, 0x4f0000f0, 0x4f0000f0,
 };
 
-static unsigned int dell_m4_2_pin_configs[10] = {
+static unsigned int dell_m4_2_pin_configs[11] = {
        0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
-       0x40f000f0, 0x044413b0,
+       0x40f000f0, 0x044413b0, 0x044413b0,
 };
 
 static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
        [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
        [STAC_DELL_M4_1]        = dell_m4_1_pin_configs,
        [STAC_DELL_M4_2]        = dell_m4_2_pin_configs,
+       [STAC_HP_M4]            = NULL,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
        [STAC_92HD71BXX_REF] = "ref",
        [STAC_DELL_M4_1] = "dell-m4-1",
        [STAC_DELL_M4_2] = "dell-m4-2",
+       [STAC_HP_M4] = "hp-m4",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
+                               "unknown HP", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
                                "unknown Dell", STAC_DELL_M4_1),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
@@ -1477,6 +1803,11 @@ static unsigned int intel_mac_v5_pin_configs[10] = {
        0x400000fc, 0x400000fb,
 };
 
+static unsigned int ecs202_pin_configs[10] = {
+       0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
+       0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
+       0x9037012e, 0x40e000f2,
+};
 
 static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
        [STAC_D945_REF] = ref922x_pin_configs,
@@ -1495,6 +1826,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
        [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
        [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
        [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
+       [STAC_ECS_202] = ecs202_pin_configs,
        [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
        [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,       
        [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
@@ -1518,6 +1850,7 @@ static const char *stac922x_models[STAC_922X_MODELS] = {
        [STAC_MACBOOK_PRO_V2]   = "macbook-pro",
        [STAC_IMAC_INTEL] = "imac-intel",
        [STAC_IMAC_INTEL_20] = "imac-intel-20",
+       [STAC_ECS_202] = "ecs202",
        [STAC_922X_DELL_D81] = "dell-d81",
        [STAC_922X_DELL_D82] = "dell-d82",
        [STAC_922X_DELL_M81] = "dell-m81",
@@ -1604,6 +1937,33 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
                      "unknown Dell", STAC_922X_DELL_D81),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
                      "Dell XPS M1210", STAC_922X_DELL_M82),
+       /* ECS/PC Chips boards */
+       SND_PCI_QUIRK(0x1019, 0x2144,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2608,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2633,
+                     "ECS/PC chips P17G/1333", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2811,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2812,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2813,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2814,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2815,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2816,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2817,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2818,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2819,
+                     "ECS/PC chips", STAC_ECS_202),
+       SND_PCI_QUIRK(0x1019, 0x2820,
+                     "ECS/PC chips", STAC_ECS_202),
        {} /* terminator */
 };
 
@@ -1867,6 +2227,8 @@ static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
                                      struct snd_pcm_substream *substream)
 {
        struct sigmatel_spec *spec = codec->spec;
+       if (spec->stream_delay)
+               msleep(spec->stream_delay);
        return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
                                             hinfo);
 }
@@ -1930,9 +2292,14 @@ static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        struct snd_pcm_substream *substream)
 {
        struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = spec->adc_nids[substream->number];
 
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-                                   stream_tag, 0, format);
+       if (spec->powerdown_adcs) {
+               msleep(40);
+               snd_hda_codec_write_cache(codec, nid, 0,
+                       AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       }
+       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
        return 0;
 }
 
@@ -1941,8 +2308,12 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
                                        struct snd_pcm_substream *substream)
 {
        struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = spec->adc_nids[substream->number];
 
-       snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
+       snd_hda_codec_cleanup_stream(codec, nid);
+       if (spec->powerdown_adcs)
+               snd_hda_codec_write_cache(codec, nid, 0,
+                       AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
        return 0;
 }
 
@@ -2193,6 +2564,8 @@ enum {
        STAC_CTL_WIDGET_VOL,
        STAC_CTL_WIDGET_MUTE,
        STAC_CTL_WIDGET_MONO_MUX,
+       STAC_CTL_WIDGET_AMP_MUX,
+       STAC_CTL_WIDGET_AMP_VOL,
        STAC_CTL_WIDGET_HP_SWITCH,
        STAC_CTL_WIDGET_IO_SWITCH,
        STAC_CTL_WIDGET_CLFE_SWITCH
@@ -2202,13 +2575,16 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
        HDA_CODEC_MUTE(NULL, 0, 0, 0),
        STAC_MONO_MUX,
+       STAC_AMP_MUX,
+       STAC_AMP_VOL(NULL, 0, 0, 0, 0),
        STAC_CODEC_HP_SWITCH(NULL),
        STAC_CODEC_IO_SWITCH(NULL, 0),
        STAC_CODEC_CLFE_SWITCH(NULL, 0),
 };
 
 /* add dynamic controls */
-static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
+static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
+               int idx, const char *name, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
@@ -2228,6 +2604,7 @@ static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char
 
        knew = &spec->kctl_alloc[spec->num_kctl_used];
        *knew = stac92xx_control_templates[type];
+       knew->index = idx;
        knew->name = kstrdup(name, GFP_KERNEL);
        if (! knew->name)
                return -ENOMEM;
@@ -2236,6 +2613,14 @@ static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char
        return 0;
 }
 
+
+/* add dynamic controls */
+static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
+               const char *name, unsigned long val)
+{
+       return stac92xx_add_control_idx(spec, type, 0, name, val);
+}
+
 /* flag inputs as additional dynamic lineouts */
 static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
 {
@@ -2467,6 +2852,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                }
        }
 
+       if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
+                       cfg->hp_outs && !spec->multiout.hp_nid)
+               spec->multiout.hp_nid = nid;
+
        if (cfg->hp_outs > 1) {
                err = stac92xx_add_control(spec,
                        STAC_CTL_WIDGET_HP_SWITCH,
@@ -2579,8 +2968,8 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
 }
 
 /* labels for mono mux outputs */
-static const char *stac92xx_mono_labels[3] = {
-       "DAC0", "DAC1", "Mixer"
+static const char *stac92xx_mono_labels[4] = {
+       "DAC0", "DAC1", "Mixer", "DAC2"
 };
 
 /* create mono mux for mono out on capable codecs */
@@ -2609,6 +2998,116 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
                                "Mono Mux", spec->mono_nid);
 }
 
+/* labels for amp mux outputs */
+static const char *stac92xx_amp_labels[3] = {
+       "Front Microphone", "Microphone", "Line In"
+};
+
+/* create amp out controls mux on capable codecs */
+static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct hda_input_mux *amp_mux = &spec->private_amp_mux;
+       int i, err;
+
+       for (i = 0; i < spec->num_amps; i++) {
+               amp_mux->items[amp_mux->num_items].label =
+                                       stac92xx_amp_labels[i];
+               amp_mux->items[amp_mux->num_items].index = i;
+               amp_mux->num_items++;
+       }
+
+       if (spec->num_amps > 1) {
+               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
+                       "Amp Selector Capture Switch", 0);
+               if (err < 0)
+                       return err;
+       }
+       return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
+               "Amp Capture Volume",
+               HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
+}
+
+
+/* create PC beep volume controls */
+static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
+                                               hda_nid_t nid)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+       int err;
+
+       /* check for mute support for the the amp */
+       if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
+               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
+                       "PC Beep Playback Switch",
+                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+       }
+
+       /* check to see if there is volume support for the amp */
+       if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
+                       "PC Beep Playback Volume",
+                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+       }
+       return 0;
+}
+
+static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int wcaps, nid, i, err = 0;
+
+       for (i = 0; i < spec->num_muxes; i++) {
+               nid = spec->mux_nids[i];
+               wcaps = get_wcaps(codec, nid);
+
+               if (wcaps & AC_WCAP_OUT_AMP) {
+                       err = stac92xx_add_control_idx(spec,
+                               STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
+                               HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+};
+
+static const char *stac92xx_spdif_labels[3] = {
+       "Digital Playback", "Analog Mux 1", "Analog Mux 2",
+};
+
+static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct hda_input_mux *spdif_mux = &spec->private_smux;
+       const char **labels = spec->spdif_labels;
+       int i, num_cons;
+       hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+
+       num_cons = snd_hda_get_connections(codec,
+                               spec->smux_nids[0],
+                               con_lst,
+                               HDA_MAX_NUM_INPUTS);
+       if (!num_cons)
+               return -EINVAL;
+
+       if (!labels)
+               labels = stac92xx_spdif_labels;
+
+       for (i = 0; i < num_cons; i++) {
+               spdif_mux->items[spdif_mux->num_items].label = labels[i];
+               spdif_mux->items[spdif_mux->num_items].index = i;
+               spdif_mux->num_items++;
+       }
+
+       return 0;
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
        "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -2656,16 +3155,19 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                        }
                continue;
 found:
-               wcaps = get_wcaps(codec, nid);
+               wcaps = get_wcaps(codec, nid) &
+                       (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
 
-               if (wcaps & AC_WCAP_OUT_AMP) {
+               if (wcaps) {
                        sprintf(name, "%s Capture Volume",
                                stac92xx_dmic_labels[dimux->num_items]);
 
                        err = stac92xx_add_control(spec,
                                STAC_CTL_WIDGET_VOL,
                                name,
-                               HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                               HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                               (wcaps & AC_WCAP_OUT_AMP) ?
+                               HDA_OUTPUT : HDA_INPUT));
                        if (err < 0)
                                return err;
                }
@@ -2789,8 +3291,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                hp_speaker_swap = 1;
        }
        if (spec->autocfg.mono_out_pin) {
-               int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
-                               & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
+               int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
+                       (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
                u32 caps = query_amp_caps(codec,
                                spec->autocfg.mono_out_pin, dir);
                hda_nid_t conn_list[1];
@@ -2812,21 +3314,26 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                                                !(wcaps & AC_WCAP_LR_SWAP))
                                        spec->mono_nid = conn_list[0];
                }
-               /* all mono outs have a least a mute/unmute switch */
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
-                       "Mono Playback Switch",
-                       HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
-                                       1, 0, dir));
-               if (err < 0)
-                       return err;
-               /* check to see if there is volume support for the amp */
-               if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
-                       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
-                               "Mono Playback Volume",
-                               HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
-                                       1, 0, dir));
+               if (dir) {
+                       hda_nid_t nid = spec->autocfg.mono_out_pin;
+
+                       /* most mono outs have a least a mute/unmute switch */
+                       dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
+                       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
+                               "Mono Playback Switch",
+                               HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
                        if (err < 0)
                                return err;
+                       /* check for volume support for the amp */
+                       if ((caps & AC_AMPCAP_NUM_STEPS)
+                                       >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+                               err = stac92xx_add_control(spec,
+                                       STAC_CTL_WIDGET_VOL,
+                                       "Mono Playback Volume",
+                               HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
+                               if (err < 0)
+                                       return err;
+                       }
                }
 
                stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
@@ -2844,6 +3351,28 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        if (err < 0)
                return err;
 
+       /* setup analog beep controls */
+       if (spec->anabeep_nid > 0) {
+               err = stac92xx_auto_create_beep_ctls(codec,
+                       spec->anabeep_nid);
+               if (err < 0)
+                       return err;
+       }
+
+       /* setup digital beep controls and input device */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+       if (spec->digbeep_nid > 0) {
+               hda_nid_t nid = spec->digbeep_nid;
+
+               err = stac92xx_auto_create_beep_ctls(codec, nid);
+               if (err < 0)
+                       return err;
+               err = snd_hda_attach_beep_device(codec, nid);
+               if (err < 0)
+                       return err;
+       }
+#endif
+
        if (hp_speaker_swap == 1) {
                /* Restore the hp_outs and line_outs */
                memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
@@ -2872,11 +3401,25 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                if (err < 0)
                        return err;
        }
-
-       if (spec->num_dmics > 0)
+       if (spec->num_amps > 0) {
+               err = stac92xx_auto_create_amp_output_ctls(codec);
+               if (err < 0)
+                       return err;
+       }
+       if (spec->num_dmics > 0 && !spec->dinput_mux)
                if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
                                                &spec->autocfg)) < 0)
                        return err;
+       if (spec->num_muxes > 0) {
+               err = stac92xx_auto_create_mux_input_ctls(codec);
+               if (err < 0)
+                       return err;
+       }
+       if (spec->num_smuxes > 0) {
+               err = stac92xx_auto_create_spdif_mux_ctls(codec);
+               if (err < 0)
+                       return err;
+       }
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
        if (spec->multiout.max_channels > 2)
@@ -2884,17 +3427,17 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 
        if (spec->autocfg.dig_out_pin)
                spec->multiout.dig_out_nid = dig_out;
-       if (spec->autocfg.dig_in_pin)
+       if (dig_in && spec->autocfg.dig_in_pin)
                spec->dig_in_nid = dig_in;
 
        if (spec->kctl_alloc)
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
        spec->input_mux = &spec->private_imux;
-       if (!spec->dinput_mux)
-               spec->dinput_mux = &spec->private_dimux;
+       spec->dinput_mux = &spec->private_dimux;
+       spec->sinput_mux = &spec->private_smux;
        spec->mono_mux = &spec->private_mono_mux;
-
+       spec->amp_mux = &spec->private_amp_mux;
        return 1;
 }
 
@@ -3074,6 +3617,12 @@ static int stac92xx_init(struct hda_codec *codec)
 
        snd_hda_sequence_write(codec, spec->init);
 
+       /* power down adcs initially */
+       if (spec->powerdown_adcs)
+               for (i = 0; i < spec->num_adcs; i++)
+                       snd_hda_codec_write_cache(codec,
+                               spec->adc_nids[i], 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
        /* set up pins */
        if (spec->hp_detect) {
                /* Enable unsolicited responses on the HP widget */
@@ -3095,7 +3644,12 @@ static int stac92xx_init(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = cfg->input_pins[i];
                if (nid) {
-                       unsigned int pinctl = AC_PINCTL_IN_EN;
+                       unsigned int pinctl = snd_hda_codec_read(codec, nid,
+                               0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       /* if PINCTL already set then skip */
+                       if (pinctl & AC_PINCAP_IN)
+                               continue;
+                       pinctl = AC_PINCTL_IN_EN;
                        if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
                                pinctl |= stac92xx_get_vref(codec, nid);
                        stac92xx_auto_set_pinctl(codec, nid, pinctl);
@@ -3158,6 +3712,7 @@ static void stac92xx_free(struct hda_codec *codec)
                kfree(spec->bios_pin_configs);
 
        kfree(spec);
+       snd_hda_detach_beep_device(codec);
 }
 
 static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -3279,7 +3834,12 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
        val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
                                                        & 0x000000ff;
        presence = get_hp_pin_presence(codec, nid);
-       idx = 1 << idx;
+
+       /* several codecs have two power down bits */
+       if (spec->pwr_mapping)
+               idx = spec->pwr_mapping[idx];
+       else
+               idx = 1 << idx;
 
        if (presence)
                val &= ~idx;
@@ -3295,13 +3855,22 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
        struct sigmatel_spec *spec = codec->spec;
        int idx = res >> 26 & 0x0f;
 
-       switch ((res >> 26) & 0x30) {
+       switch ((res >> 26) & 0x70) {
        case STAC_HP_EVENT:
                stac92xx_hp_detect(codec, res);
                /* fallthru */
        case STAC_PWR_EVENT:
                if (spec->num_pwrs > 0)
                        stac92xx_pin_sense(codec, idx);
+               break;
+       case STAC_VREF_EVENT: {
+               int data = snd_hda_codec_read(codec, codec->afg, 0,
+                       AC_VERB_GET_GPIO_DATA, 0);
+               /* toggle VREF state based on GPIOx status */
+               snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
+                       !!(data & (1 << idx)));
+               break;
+               }
        }
 }
 
@@ -3478,9 +4047,9 @@ static struct hda_input_mux stac92hd73xx_dmux = {
        .num_items = 4,
        .items = {
                { "Analog Inputs", 0x0b },
-               { "CD", 0x08 },
                { "Digital Mic 1", 0x09 },
                { "Digital Mic 2", 0x0a },
+               { "CD", 0x08 },
        }
 };
 
@@ -3495,6 +4064,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
        spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
        spec->pin_nids = stac92hd73xx_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec,
@@ -3527,17 +4097,14 @@ again:
 
        switch (spec->multiout.num_dacs) {
        case 0x3: /* 6 Channel */
-               spec->multiout.hp_nid = 0x17;
                spec->mixer = stac92hd73xx_6ch_mixer;
                spec->init = stac92hd73xx_6ch_core_init;
                break;
        case 0x4: /* 8 Channel */
-               spec->multiout.hp_nid = 0x18;
                spec->mixer = stac92hd73xx_8ch_mixer;
                spec->init = stac92hd73xx_8ch_core_init;
                break;
        case 0x5: /* 10 Channel */
-               spec->multiout.hp_nid = 0x19;
                spec->mixer = stac92hd73xx_10ch_mixer;
                spec->init = stac92hd73xx_10ch_core_init;
        };
@@ -3546,27 +4113,34 @@ again:
        spec->aloopback_mask = 0x01;
        spec->aloopback_shift = 8;
 
+       spec->digbeep_nid = 0x1c;
        spec->mux_nids = stac92hd73xx_mux_nids;
        spec->adc_nids = stac92hd73xx_adc_nids;
        spec->dmic_nids = stac92hd73xx_dmic_nids;
        spec->dmux_nids = stac92hd73xx_dmux_nids;
+       spec->smux_nids = stac92hd73xx_smux_nids;
+       spec->amp_nids = stac92hd73xx_amp_nids;
+       spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
 
        spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
        spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
-       spec->dinput_mux = &stac92hd73xx_dmux;
-       /* GPIO0 High = Enable EAPD */
-       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
-       spec->gpio_data = 0x01;
+       memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
+                       sizeof(stac92hd73xx_dmux));
 
        switch (spec->board_config) {
        case STAC_DELL_M6:
                spec->init = dell_eq_core_init;
+               spec->num_smuxes = 0;
+               spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
+               spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
+               spec->num_amps = 1;
                switch (codec->subsystem_id) {
                case 0x1028025e: /* Analog Mics */
                case 0x1028025f:
                        stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
                        spec->num_dmics = 0;
+                       spec->private_dimux.num_items = 1;
                        break;
                case 0x10280271: /* Digital Mics */
                case 0x10280272:
@@ -3576,23 +4150,32 @@ again:
                case 0x10280255:
                        stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
+                       spec->private_dimux.num_items = 2;
                        break;
                case 0x10280256: /* Both */
                case 0x10280057:
                        stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
                        stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
+                       spec->private_dimux.num_items = 2;
                        break;
                }
                break;
        default:
                spec->num_dmics = STAC92HD73XX_NUM_DMICS;
+               spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
        }
+       if (spec->board_config > STAC_92HD73XX_REF) {
+               /* GPIO0 High = Enable EAPD */
+               spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
+               spec->gpio_data = 0x01;
+       }
+       spec->dinput_mux = &spec->private_dimux;
 
        spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
        spec->pwr_nids = stac92hd73xx_pwr_nids;
 
-       err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
+       err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
 
        if (!err) {
                if (spec->board_config < 0) {
@@ -3614,6 +4197,136 @@ again:
        return 0;
 }
 
+static struct hda_input_mux stac92hd83xxx_dmux = {
+       .num_items = 3,
+       .items = {
+               { "Analog Inputs", 0x03 },
+               { "Digital Mic 1", 0x04 },
+               { "Digital Mic 2", 0x05 },
+       }
+};
+
+static int patch_stac92hd83xxx(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
+       spec->mono_nid = 0x19;
+       spec->digbeep_nid = 0x21;
+       spec->dmic_nids = stac92hd83xxx_dmic_nids;
+       spec->dmux_nids = stac92hd83xxx_dmux_nids;
+       spec->adc_nids = stac92hd83xxx_adc_nids;
+       spec->pwr_nids = stac92hd83xxx_pwr_nids;
+       spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
+       spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
+       spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
+
+       spec->init = stac92hd83xxx_core_init;
+       switch (codec->vendor_id) {
+       case 0x111d7605:
+               spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
+               break;
+       default:
+               spec->num_pwrs--;
+               spec->init++; /* switch to config #2 */
+               spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
+       }
+
+       spec->mixer = stac92hd83xxx_mixer;
+       spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
+       spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
+       spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
+       spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
+       spec->dinput_mux = &stac92hd83xxx_dmux;
+       spec->pin_nids = stac92hd83xxx_pin_nids;
+       spec->board_config = snd_hda_check_board_config(codec,
+                                                       STAC_92HD83XXX_MODELS,
+                                                       stac92hd83xxx_models,
+                                                       stac92hd83xxx_cfg_tbl);
+again:
+       if (spec->board_config < 0) {
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+                       " STAC92HD83XXX, using BIOS defaults\n");
+               err = stac92xx_save_bios_config_regs(codec);
+               if (err < 0) {
+                       stac92xx_free(codec);
+                       return err;
+               }
+               spec->pin_configs = spec->bios_pin_configs;
+       } else {
+               spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
+               stac92xx_set_config_regs(codec);
+       }
+
+       err = stac92xx_parse_auto_config(codec, 0x1d, 0);
+       if (!err) {
+               if (spec->board_config < 0) {
+                       printk(KERN_WARNING "hda_codec: No auto-config is "
+                              "available, default to model=ref\n");
+                       spec->board_config = STAC_92HD83XXX_REF;
+                       goto again;
+               }
+               err = -EINVAL;
+       }
+
+       if (err < 0) {
+               stac92xx_free(codec);
+               return err;
+       }
+
+       codec->patch_ops = stac92xx_patch_ops;
+
+       return 0;
+}
+
+#ifdef SND_HDA_NEEDS_RESUME
+static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i;
+       snd_hda_codec_write_cache(codec, codec->afg, 0,
+               AC_VERB_SET_POWER_STATE, pwr);
+
+       msleep(1);
+       for (i = 0; i < spec->num_adcs; i++) {
+               snd_hda_codec_write_cache(codec,
+                       spec->adc_nids[i], 0,
+                       AC_VERB_SET_POWER_STATE, pwr);
+       }
+};
+
+static int stac92hd71xx_resume(struct hda_codec *codec)
+{
+       stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
+       return stac92xx_resume(codec);
+}
+
+static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
+       return 0;
+};
+
+#endif
+
+static struct hda_codec_ops stac92hd71bxx_patch_ops = {
+       .build_controls = stac92xx_build_controls,
+       .build_pcms = stac92xx_build_pcms,
+       .init = stac92xx_init,
+       .free = stac92xx_free,
+       .unsol_event = stac92xx_unsol_event,
+#ifdef SND_HDA_NEEDS_RESUME
+       .resume = stac92hd71xx_resume,
+       .suspend = stac92hd71xx_suspend,
+#endif
+};
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
@@ -3624,6 +4337,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       codec->patch_ops = stac92xx_patch_ops;
        spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
        spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
        spec->pin_nids = stac92hd71bxx_pin_nids;
@@ -3653,8 +4367,28 @@ again:
        case 0x111d76b5:
                spec->mixer = stac92hd71bxx_mixer;
                spec->init = stac92hd71bxx_core_init;
+               codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                break;
        case 0x111d7608: /* 5 Port with Analog Mixer */
+               switch (codec->subsystem_id) {
+               case 0x103c361a:
+                       /* Enable VREF power saving on GPIO1 detect */
+                       snd_hda_codec_write(codec, codec->afg, 0,
+                               AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
+                       snd_hda_codec_write_cache(codec, codec->afg, 0,
+                                       AC_VERB_SET_UNSOLICITED_ENABLE,
+                                       (AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
+                       spec->gpio_mask |= 0x02;
+                       break;
+               }
+               if ((codec->revision_id & 0xf) == 0 ||
+                               (codec->revision_id & 0xf) == 1) {
+#ifdef SND_HDA_NEEDS_RESUME
+                       codec->patch_ops = stac92hd71bxx_patch_ops;
+#endif
+                       spec->stream_delay = 40; /* 40 milliseconds */
+               }
+
                /* no output amps */
                spec->num_pwrs = 0;
                spec->mixer = stac92hd71bxx_analog_mixer;
@@ -3664,32 +4398,60 @@ again:
                stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
                break;
        case 0x111d7603: /* 6 Port with Analog Mixer */
+               if ((codec->revision_id & 0xf) == 1) {
+#ifdef SND_HDA_NEEDS_RESUME
+                       codec->patch_ops = stac92hd71bxx_patch_ops;
+#endif
+                       spec->stream_delay = 40; /* 40 milliseconds */
+               }
+
                /* no output amps */
                spec->num_pwrs = 0;
                /* fallthru */
        default:
                spec->mixer = stac92hd71bxx_analog_mixer;
                spec->init = stac92hd71bxx_analog_core_init;
+               codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
        }
 
        spec->aloopback_mask = 0x20;
        spec->aloopback_shift = 0;
 
-       /* GPIO0 High = EAPD */
-       spec->gpio_mask = 0x01;
-       spec->gpio_dir = 0x01;
-       spec->gpio_data = 0x01;
+       if (spec->board_config > STAC_92HD71BXX_REF) {
+               /* GPIO0 = EAPD */
+               spec->gpio_mask = 0x01;
+               spec->gpio_dir = 0x01;
+               spec->gpio_data = 0x01;
+       }
 
+       spec->powerdown_adcs = 1;
+       spec->digbeep_nid = 0x26;
        spec->mux_nids = stac92hd71bxx_mux_nids;
        spec->adc_nids = stac92hd71bxx_adc_nids;
        spec->dmic_nids = stac92hd71bxx_dmic_nids;
        spec->dmux_nids = stac92hd71bxx_dmux_nids;
+       spec->smux_nids = stac92hd71bxx_smux_nids;
        spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
        spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
-       spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
-       spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+
+       switch (spec->board_config) {
+       case STAC_HP_M4:
+               spec->num_dmics = 0;
+               spec->num_smuxes = 0;
+               spec->num_dmuxes = 0;
+
+               /* enable internal microphone */
+               stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
+               stac92xx_auto_set_pinctl(codec, 0x0e,
+                       AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
+               break;
+       default:
+               spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
+               spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
+               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+       };
 
        spec->multiout.num_dacs = 1;
        spec->multiout.hp_nid = 0x11;
@@ -3711,8 +4473,6 @@ again:
                return err;
        }
 
-       codec->patch_ops = stac92xx_patch_ops;
-
        return 0;
 };
 
@@ -3854,10 +4614,14 @@ static int patch_stac927x(struct hda_codec *codec)
                stac92xx_set_config_regs(codec);
        }
 
+       spec->digbeep_nid = 0x23;
        spec->adc_nids = stac927x_adc_nids;
        spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
        spec->mux_nids = stac927x_mux_nids;
        spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
+       spec->smux_nids = stac927x_smux_nids;
+       spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
+       spec->spdif_labels = stac927x_spdif_labels;
        spec->dac_list = stac927x_dac_nids;
        spec->multiout.dac_nids = spec->dac_nids;
 
@@ -3900,9 +4664,11 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
                break;
        default:
-               /* GPIO0 High = Enable EAPD */
-               spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
-               spec->gpio_data = 0x01;
+               if (spec->board_config > STAC_D965_REF) {
+                       /* GPIO0 High = Enable EAPD */
+                       spec->eapd_mask = spec->gpio_mask = 0x01;
+                       spec->gpio_dir = spec->gpio_data = 0x01;
+               }
                spec->num_dmics = 0;
 
                spec->init = stac927x_core_init;
@@ -3974,10 +4740,13 @@ static int patch_stac9205(struct hda_codec *codec)
                stac92xx_set_config_regs(codec);
        }
 
+       spec->digbeep_nid = 0x23;
        spec->adc_nids = stac9205_adc_nids;
        spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
        spec->mux_nids = stac9205_mux_nids;
        spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
+       spec->smux_nids = stac9205_smux_nids;
+       spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
        spec->dmic_nids = stac9205_dmic_nids;
        spec->num_dmics = STAC9205_NUM_DMICS;
        spec->dmux_nids = stac9205_dmux_nids;
@@ -4013,6 +4782,9 @@ static int patch_stac9205(struct hda_codec *codec)
                 */
                spec->gpio_data = 0x01;
                break;
+       case STAC_9205_REF:
+               /* SPDIF-In enabled */
+               break;
        default:
                /* GPIO0 High = EAPD */
                spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
@@ -4332,6 +5104,8 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
        { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
        { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
+       { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
        { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
        { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
index e7e43524f8c732faeed283d6a223d30c918e5366..63e4871e5d8fed3344577c6e91c0a2d4ec82c506 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for VIA VT1708 codec
+ * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
  *
- * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
- *                    Takashi Iwai <tiwai@suse.de>
+ * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
+ *                        Takashi Iwai <tiwai@suse.de>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
 /* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization      */
 /* 2007-09-17  Lydia Wang  Add VT1708B codec support                        */
+/* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */
+/* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */
+/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support        */
+/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin             */
+/* 2008-04-09  Lydia Wang  Add Independent HP feature                        */
+/* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702         */
+/* 2008-09-15  Logan Li    Add VT1708S Mic Boost workaround/backdoor        */
 /*                                                                           */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -37,6 +44,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <sound/core.h>
+#include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_patch.h"
@@ -53,6 +61,8 @@
 #define VT1708_DIGOUT_NID      0x14
 #define VT1708_DIGIN_NID       0x16
 #define VT1708_DIGIN_PIN       0x26
+#define VT1708_HP_PIN_NID      0x20
+#define VT1708_CD_PIN_NID      0x24
 
 #define VT1709_HP_DAC_NID      0x28
 #define VT1709_DIGOUT_NID      0x13
 #define VT1708B_DIGIN_NID      0x15
 #define VT1708B_DIGIN_PIN      0x21
 
+#define VT1708S_HP_NID         0x25
+#define VT1708S_DIGOUT_NID     0x12
+
+#define VT1702_HP_NID          0x17
+#define VT1702_DIGOUT_NID      0x11
+
 #define IS_VT1708_VENDORID(x)          ((x) >= 0x11061708 && (x) <= 0x1106170b)
 #define IS_VT1709_10CH_VENDORID(x)     ((x) >= 0x1106e710 && (x) <= 0x1106e713)
 #define IS_VT1709_6CH_VENDORID(x)      ((x) >= 0x1106e714 && (x) <= 0x1106e717)
 #define IS_VT1708B_8CH_VENDORID(x)     ((x) >= 0x1106e720 && (x) <= 0x1106e723)
 #define IS_VT1708B_4CH_VENDORID(x)     ((x) >= 0x1106e724 && (x) <= 0x1106e727)
+#define IS_VT1708S_VENDORID(x)         ((x) >= 0x11060397 && (x) <= 0x11067397)
+#define IS_VT1702_VENDORID(x)          ((x) >= 0x11060398 && (x) <= 0x11067398)
+
+enum VIA_HDA_CODEC {
+       UNKNOWN = -1,
+       VT1708,
+       VT1709_10CH,
+       VT1709_6CH,
+       VT1708B_8CH,
+       VT1708B_4CH,
+       VT1708S,
+       VT1702,
+       CODEC_TYPES,
+};
+
+static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
+{
+       u16 ven_id = vendor_id >> 16;
+       u16 dev_id = vendor_id & 0xffff;
+       enum VIA_HDA_CODEC codec_type;
+
+       /* get codec type */
+       if (ven_id != 0x1106)
+               codec_type = UNKNOWN;
+       else if (dev_id >= 0x1708 && dev_id <= 0x170b)
+               codec_type = VT1708;
+       else if (dev_id >= 0xe710 && dev_id <= 0xe713)
+               codec_type = VT1709_10CH;
+       else if (dev_id >= 0xe714 && dev_id <= 0xe717)
+               codec_type = VT1709_6CH;
+       else if (dev_id >= 0xe720 && dev_id <= 0xe723)
+               codec_type = VT1708B_8CH;
+       else if (dev_id >= 0xe724 && dev_id <= 0xe727)
+               codec_type = VT1708B_4CH;
+       else if ((dev_id & 0xfff) == 0x397
+                && (dev_id >> 12) < 8)
+               codec_type = VT1708S;
+       else if ((dev_id & 0xfff) == 0x398
+                && (dev_id >> 12) < 8)
+               codec_type = VT1702;
+       else
+               codec_type = UNKNOWN;
+       return codec_type;
+};
 
+#define VIA_HP_EVENT           0x01
+#define VIA_GPIO_EVENT         0x02
 
 enum {
        VIA_CTL_WIDGET_VOL,
@@ -77,12 +139,54 @@ enum {
 };
 
 enum {
-       AUTO_SEQ_FRONT,
+       AUTO_SEQ_FRONT = 0,
        AUTO_SEQ_SURROUND,
        AUTO_SEQ_CENLFE,
        AUTO_SEQ_SIDE
 };
 
+#define get_amp_nid(kc)        ((kc)->private_value & 0xffff)
+
+/* Some VT1708S based boards gets the micboost setting wrong, so we have
+ * to apply some brute-force and re-write the TLV's by software. */
+static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                        unsigned int size, unsigned int __user *_tlv)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = get_amp_nid(kcontrol);
+
+       if (get_codec_type(codec->vendor_id) == VT1708S
+           && (nid == 0x1a || nid == 0x1e)) {
+               if (size < 4 * sizeof(unsigned int))
+                       return -ENOMEM;
+               if (put_user(1, _tlv))  /* SNDRV_CTL_TLVT_DB_SCALE */
+                       return -EFAULT;
+               if (put_user(2 * sizeof(unsigned int), _tlv + 1))
+                       return -EFAULT;
+               if (put_user(0, _tlv + 2)) /* offset = 0 */
+                       return -EFAULT;
+               if (put_user(1000, _tlv + 3)) /* step size = 10 dB */
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = get_amp_nid(kcontrol);
+
+       if (get_codec_type(codec->vendor_id) == VT1708S
+           && (nid == 0x1a || nid == 0x1e)) {
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->count = 2;
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = 3;
+       }
+       return 0;
+}
+
 static struct snd_kcontrol_new vt1708_control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
        HDA_CODEC_MUTE(NULL, 0, 0, 0),
@@ -94,7 +198,8 @@ struct via_spec {
        struct snd_kcontrol_new *mixers[3];
        unsigned int num_mixers;
 
-       struct hda_verb *init_verbs;
+       struct hda_verb *init_verbs[5];
+       unsigned int num_iverbs;
 
        char *stream_name_analog;
        struct hda_pcm_stream *stream_analog_playback;
@@ -106,6 +211,7 @@ struct via_spec {
 
        /* playback */
        struct hda_multi_out multiout;
+       hda_nid_t extra_dig_out_nid;
 
        /* capture */
        unsigned int num_adc_nids;
@@ -117,15 +223,19 @@ struct via_spec {
        unsigned int cur_mux[3];
 
        /* PCM information */
-       struct hda_pcm pcm_rec[2];
+       struct hda_pcm pcm_rec[3];
 
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        unsigned int num_kctl_alloc, num_kctl_used;
        struct snd_kcontrol_new *kctl_alloc;
-       struct hda_input_mux private_imux;
+       struct hda_input_mux private_imux[2];
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
+       /* HP mode source */
+       const struct hda_input_mux *hp_mux;
+       unsigned int hp_independent_mode;
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
 #endif
@@ -146,6 +256,16 @@ static hda_nid_t vt1708B_adc_nids[2] = {
        0x13, 0x14
 };
 
+static hda_nid_t vt1708S_adc_nids[2] = {
+       /* ADC1-2 */
+       0x13, 0x14
+};
+
+static hda_nid_t vt1702_adc_nids[3] = {
+       /* ADC1-2 */
+       0x12, 0x20, 0x1F
+};
+
 /* add dynamic controls */
 static int via_add_control(struct via_spec *spec, int type, const char *name,
                           unsigned long val)
@@ -283,19 +403,108 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             0x18, &spec->cur_mux[adc_idx]);
        else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-                 IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0)
+                 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             0x19, &spec->cur_mux[adc_idx]);
        else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
-                 IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0)
+                 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             0x17, &spec->cur_mux[adc_idx]);
+       else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
+               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+                                            0x13, &spec->cur_mux[adc_idx]);
        else
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             spec->adc_nids[adc_idx],
                                             &spec->cur_mux[adc_idx]);
 }
 
+static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       return snd_hda_input_mux_info(spec->hp_mux, uinfo);
+}
+
+static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid = spec->autocfg.hp_pins[0];
+       unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
+                                                AC_VERB_GET_CONNECT_SEL,
+                                                0x00);
+
+       ucontrol->value.enumerated.item[0] = pinsel;
+
+       return 0;
+}
+
+static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid = spec->autocfg.hp_pins[0];
+       unsigned int pinsel = ucontrol->value.enumerated.item[0];
+       unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
+                                        AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+
+       if (con_nid == spec->multiout.hp_nid) {
+               if (pinsel == 0) {
+                       if (!spec->hp_independent_mode) {
+                               if (spec->multiout.num_dacs > 1)
+                                       spec->multiout.num_dacs -= 1;
+                               spec->hp_independent_mode = 1;
+                       }
+               } else if (pinsel == 1) {
+                      if (spec->hp_independent_mode) {
+                               if (spec->multiout.num_dacs > 1)
+                                       spec->multiout.num_dacs += 1;
+                               spec->hp_independent_mode = 0;
+                      }
+               }
+       } else {
+               if (pinsel == 0) {
+                       if (spec->hp_independent_mode) {
+                               if (spec->multiout.num_dacs > 1)
+                                       spec->multiout.num_dacs += 1;
+                               spec->hp_independent_mode = 0;
+                       }
+               } else if (pinsel == 1) {
+                      if (!spec->hp_independent_mode) {
+                               if (spec->multiout.num_dacs > 1)
+                                       spec->multiout.num_dacs -= 1;
+                               spec->hp_independent_mode = 1;
+                      }
+               }
+       }
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+                           pinsel);
+
+       if (spec->multiout.hp_nid &&
+           spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
+                       snd_hda_codec_setup_stream(codec,
+                                                  spec->multiout.hp_nid,
+                                                  0, 0, 0);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new via_hp_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Independent HP",
+               .count = 1,
+               .info = via_independent_hp_info,
+               .get = via_independent_hp_get,
+               .put = via_independent_hp_put,
+       },
+       { } /* end */
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -380,6 +589,138 @@ static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
        return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 }
 
+
+static void playback_multi_pcm_prep_0(struct hda_codec *codec,
+                                     unsigned int stream_tag,
+                                     unsigned int format,
+                                     struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+       struct hda_multi_out *mout = &spec->multiout;
+       hda_nid_t *nids = mout->dac_nids;
+       int chs = substream->runtime->channels;
+       int i;
+
+       mutex_lock(&codec->spdif_mutex);
+       if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+               if (chs == 2 &&
+                   snd_hda_is_supported_format(codec, mout->dig_out_nid,
+                                               format) &&
+                   !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+                       mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+                       /* turn off SPDIF once; otherwise the IEC958 bits won't
+                        * be updated */
+                       if (codec->spdif_ctls & AC_DIG1_ENABLE)
+                               snd_hda_codec_write(codec, mout->dig_out_nid, 0,
+                                                   AC_VERB_SET_DIGI_CONVERT_1,
+                                                   codec->spdif_ctls &
+                                                       ~AC_DIG1_ENABLE & 0xff);
+                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+                                                  stream_tag, 0, format);
+                       /* turn on again (if needed) */
+                       if (codec->spdif_ctls & AC_DIG1_ENABLE)
+                               snd_hda_codec_write(codec, mout->dig_out_nid, 0,
+                                                   AC_VERB_SET_DIGI_CONVERT_1,
+                                                   codec->spdif_ctls & 0xff);
+               } else {
+                       mout->dig_out_used = 0;
+                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+                                                  0, 0, 0);
+               }
+       }
+       mutex_unlock(&codec->spdif_mutex);
+
+       /* front */
+       snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
+                                  0, format);
+
+       if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
+           !spec->hp_independent_mode)
+               /* headphone out will just decode front left/right (stereo) */
+               snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
+                                          0, format);
+
+       /* extra outputs copied from front */
+       for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+               if (mout->extra_out_nid[i])
+                       snd_hda_codec_setup_stream(codec,
+                                                  mout->extra_out_nid[i],
+                                                  stream_tag, 0, format);
+
+       /* surrounds */
+       for (i = 1; i < mout->num_dacs; i++) {
+               if (chs >= (i + 1) * 2) /* independent out */
+                       snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
+                                                  i * 2, format);
+               else /* copy front */
+                       snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
+                                                  0, format);
+       }
+}
+
+static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                         struct hda_codec *codec,
+                                         unsigned int stream_tag,
+                                         unsigned int format,
+                                         struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+       struct hda_multi_out *mout = &spec->multiout;
+       hda_nid_t *nids = mout->dac_nids;
+
+       if (substream->number == 0)
+               playback_multi_pcm_prep_0(codec, stream_tag, format,
+                                         substream);
+       else {
+               if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
+                   spec->hp_independent_mode)
+                       snd_hda_codec_setup_stream(codec, mout->hp_nid,
+                                                  stream_tag, 0, format);
+       }
+
+       return 0;
+}
+
+static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+       struct hda_multi_out *mout = &spec->multiout;
+       hda_nid_t *nids = mout->dac_nids;
+       int i;
+
+       if (substream->number == 0) {
+               for (i = 0; i < mout->num_dacs; i++)
+                       snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
+
+               if (mout->hp_nid && !spec->hp_independent_mode)
+                       snd_hda_codec_setup_stream(codec, mout->hp_nid,
+                                                  0, 0, 0);
+
+               for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+                       if (mout->extra_out_nid[i])
+                               snd_hda_codec_setup_stream(codec,
+                                                       mout->extra_out_nid[i],
+                                                       0, 0, 0);
+               mutex_lock(&codec->spdif_mutex);
+               if (mout->dig_out_nid &&
+                   mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
+                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+                                                  0, 0, 0);
+                       mout->dig_out_used = 0;
+               }
+               mutex_unlock(&codec->spdif_mutex);
+       } else {
+               if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
+                   spec->hp_independent_mode)
+                       snd_hda_codec_setup_stream(codec, mout->hp_nid,
+                                                  0, 0, 0);
+       }
+
+       return 0;
+}
+
 /*
  * Digital out
  */
@@ -399,6 +740,21 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
        return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+/* setup SPDIF output stream */
+static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int stream_tag, unsigned int format)
+{
+       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+       if (codec->spdif_ctls & AC_DIG1_ENABLE)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+       /* turn on again (if needed) */
+       if (codec->spdif_ctls & AC_DIG1_ENABLE)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+                                   codec->spdif_ctls & 0xff);
+}
+
 static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        unsigned int stream_tag,
@@ -406,8 +762,20 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-                                            stream_tag, format, substream);
+       hda_nid_t nid;
+
+       /* 1st or 2nd S/PDIF */
+       if (substream->number == 0)
+               nid = spec->multiout.dig_out_nid;
+       else if (substream->number == 1)
+               nid = spec->extra_dig_out_nid;
+       else
+               return -1;
+
+       mutex_lock(&codec->spdif_mutex);
+       setup_dig_playback_stream(codec, nid, stream_tag, format);
+       mutex_unlock(&codec->spdif_mutex);
+       return 0;
 }
 
 /*
@@ -436,14 +804,14 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 }
 
 static struct hda_pcm_stream vt1708_pcm_analog_playback = {
-       .substreams = 1,
+       .substreams = 2,
        .channels_min = 2,
        .channels_max = 8,
        .nid = 0x10, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup
        },
 };
 
@@ -515,6 +883,13 @@ static int via_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
                spec->multiout.share_spdif = 1;
+
+               if (spec->extra_dig_out_nid) {
+                       err = snd_hda_create_spdif_out_ctls(codec,
+                                                   spec->extra_dig_out_nid);
+                       if (err < 0)
+                               return err;
+               }
        }
        if (spec->dig_in_nid) {
                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -580,10 +955,89 @@ static void via_free(struct hda_codec *codec)
        kfree(codec->spec);
 }
 
+/* mute internal speaker if HP is plugged */
+static void via_hp_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       struct via_spec *spec = codec->spec;
+
+       present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
+                                HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                present ? HDA_AMP_MUTE : 0);
+}
+
+static void via_gpio_control(struct hda_codec *codec)
+{
+       unsigned int gpio_data;
+       unsigned int vol_counter;
+       unsigned int vol;
+       unsigned int master_vol;
+
+       struct via_spec *spec = codec->spec;
+
+       gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
+                                      AC_VERB_GET_GPIO_DATA, 0) & 0x03;
+
+       vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
+                                         0xF84, 0) & 0x3F0000) >> 16;
+
+       vol = vol_counter & 0x1F;
+       master_vol = snd_hda_codec_read(codec, 0x1A, 0,
+                                       AC_VERB_GET_AMP_GAIN_MUTE,
+                                       AC_AMP_GET_INPUT);
+
+       if (gpio_data == 0x02) {
+               /* unmute line out */
+               snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
+                                        HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
+
+               if (vol_counter & 0x20) {
+                       /* decrease volume */
+                       if (vol > master_vol)
+                               vol = master_vol;
+                       snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
+                                                0, HDA_AMP_VOLMASK,
+                                                master_vol-vol);
+               } else {
+                       /* increase volume */
+                       snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
+                                        HDA_AMP_VOLMASK,
+                                        ((master_vol+vol) > 0x2A) ? 0x2A :
+                                         (master_vol+vol));
+               }
+       } else if (!(gpio_data & 0x02)) {
+               /* mute line out */
+               snd_hda_codec_amp_stereo(codec,
+                                        spec->autocfg.line_out_pins[0],
+                                        HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                        HDA_AMP_MUTE);
+       }
+}
+
+/* unsolicited event for jack sensing */
+static void via_unsol_event(struct hda_codec *codec,
+                                 unsigned int res)
+{
+       res >>= 26;
+       if (res == VIA_HP_EVENT)
+               via_hp_automute(codec);
+       else if (res == VIA_GPIO_EVENT)
+               via_gpio_control(codec);
+}
+
+static hda_nid_t slave_dig_outs[] = {
+       0,
+};
+
 static int via_init(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
-       snd_hda_sequence_write(codec, spec->init_verbs);
+       int i;
+       for (i = 0; i < spec->num_iverbs; i++)
+               snd_hda_sequence_write(codec, spec->init_verbs[i]);
+
        /* Lydia Add for EAPD enable */
        if (!spec->dig_in_nid) { /* No Digital In connection */
                if (IS_VT1708_VENDORID(codec->vendor_id)) {
@@ -611,6 +1065,9 @@ static int via_init(struct hda_codec *codec)
                snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
 
+       /* no slave outs */
+       codec->slave_dig_outs = slave_dig_outs;
+
        return 0;
 }
 
@@ -657,10 +1114,10 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
                                spec->multiout.dac_nids[i] = 0x12;
                                break;
                        case AUTO_SEQ_SURROUND:
-                               spec->multiout.dac_nids[i] = 0x13;
+                               spec->multiout.dac_nids[i] = 0x11;
                                break;
                        case AUTO_SEQ_SIDE:
-                               spec->multiout.dac_nids[i] = 0x11;
+                               spec->multiout.dac_nids[i] = 0x13;
                                break;
                        }
                }
@@ -685,7 +1142,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
                        continue;
                
                if (i != AUTO_SEQ_FRONT)
-                       nid_vol = 0x1b - i + 1;
+                       nid_vol = 0x18 + i;
 
                if (i == AUTO_SEQ_CENLFE) {
                        /* Center/LFE */
@@ -760,6 +1217,24 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
        return 0;
 }
 
+static void create_hp_imux(struct via_spec *spec)
+{
+       int i;
+       struct hda_input_mux *imux = &spec->private_imux[1];
+       static const char *texts[] = { "OFF", "ON", NULL};
+
+       /* for hp mode select */
+       i = 0;
+       while (texts[i] != NULL) {
+               imux->items[imux->num_items].label =  texts[i];
+               imux->items[imux->num_items].index = i;
+               imux->num_items++;
+               i++;
+       }
+
+       spec->hp_mux = &spec->private_imux[1];
+}
+
 static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 {
        int err;
@@ -780,6 +1255,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
        if (err < 0)
                return err;
 
+       create_hp_imux(spec);
+
        return 0;
 }
 
@@ -790,7 +1267,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
        static char *labels[] = {
                "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
        };
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx = 0;
 
        /* for internal loopback recording select */
@@ -840,11 +1317,36 @@ static struct hda_amp_list vt1708_loopbacks[] = {
 };
 #endif
 
+static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int def_conf;
+       unsigned char seqassoc;
+
+       def_conf = snd_hda_codec_read(codec, nid, 0,
+                                     AC_VERB_GET_CONFIG_DEFAULT, 0);
+       seqassoc = (unsigned char) get_defcfg_association(def_conf);
+       seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
+       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
+               if (seqassoc == 0xff) {
+                       def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+                                           def_conf >> 24);
+               }
+       }
+
+       return;
+}
+
 static int vt1708_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        int err;
 
+       /* Add HP and CD pin config connect bit re-config action */
+       vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
+       vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
        if (err < 0)
                return err;
@@ -874,9 +1376,12 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
        if (spec->kctl_alloc)
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-       spec->init_verbs = vt1708_volume_init_verbs;    
+       spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
 
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
        return 1;
 }
@@ -897,7 +1402,7 @@ static int patch_vt1708(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
@@ -966,6 +1471,11 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
        { } /* end */
 };
 
+static struct hda_verb vt1709_uniwill_init_verbs[] = {
+       {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       { }
+};
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -1090,11 +1600,11 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
                                        break;
                                case AUTO_SEQ_SURROUND:
                                        /* AOW3 */
-                                       spec->multiout.dac_nids[i] = 0x27;
+                                       spec->multiout.dac_nids[i] = 0x11;
                                        break;
                                case AUTO_SEQ_SIDE:
                                        /* AOW1 */
-                                       spec->multiout.dac_nids[i] = 0x11;
+                                       spec->multiout.dac_nids[i] = 0x27;
                                        break;
                                default:
                                        break;
@@ -1203,26 +1713,26 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
                } else if (i == AUTO_SEQ_SURROUND) {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_SIDE) {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
                                                                  HDA_OUTPUT));
                        if (err < 0)
                                return err;
@@ -1265,7 +1775,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
        static char *labels[] = {
                "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
        };
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx = 0;
 
        /* for internal loopback recording select */
@@ -1339,7 +1849,10 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
        if (spec->kctl_alloc)
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
        return 1;
 }
@@ -1360,7 +1873,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
@@ -1375,7 +1888,8 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
                       "Using genenic mode...\n");
        }
 
-       spec->init_verbs = vt1709_10ch_volume_init_verbs;       
+       spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
 
        spec->stream_name_analog = "VT1709 Analog";
        spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
@@ -1396,6 +1910,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        codec->patch_ops = via_patch_ops;
 
        codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1709_loopbacks;
 #endif
@@ -1451,7 +1966,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
@@ -1466,7 +1981,8 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
                       "Using genenic mode...\n");
        }
 
-       spec->init_verbs = vt1709_6ch_volume_init_verbs;        
+       spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
 
        spec->stream_name_analog = "VT1709 Analog";
        spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
@@ -1487,6 +2003,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        codec->patch_ops = via_patch_ops;
 
        codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1709_loopbacks;
 #endif
@@ -1586,27 +2103,32 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
        { }
 };
 
+static struct hda_verb vt1708B_uniwill_init_verbs[] = {
+       {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       { }
+};
+
 static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
-       .substreams = 1,
+       .substreams = 2,
        .channels_min = 2,
        .channels_max = 8,
        .nid = 0x10, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup
        },
 };
 
 static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
-       .substreams = 1,
+       .substreams = 2,
        .channels_min = 2,
        .channels_max = 4,
        .nid = 0x10, /* NID to query formats and rates */
        .ops = {
                .open = via_playback_pcm_open,
-               .prepare = via_playback_pcm_prepare,
-               .cleanup = via_playback_pcm_cleanup
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup
        },
 };
 
@@ -1662,10 +2184,10 @@ static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
                                spec->multiout.dac_nids[i] = 0x24;
                                break;
                        case AUTO_SEQ_SURROUND:
-                               spec->multiout.dac_nids[i] = 0x25;
+                               spec->multiout.dac_nids[i] = 0x11;
                                break;
                        case AUTO_SEQ_SIDE:
-                               spec->multiout.dac_nids[i] = 0x11;
+                               spec->multiout.dac_nids[i] = 0x25;
                                break;
                        }
                }
@@ -1680,7 +2202,7 @@ static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
 {
        char name[32];
        static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
-       hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
+       hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
        hda_nid_t nid, nid_vol = 0;
        int i, err;
 
@@ -1785,6 +2307,8 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
        if (err < 0)
                return err;
 
+       create_hp_imux(spec);
+
        return 0;
 }
 
@@ -1795,7 +2319,7 @@ static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
        static char *labels[] = {
                "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
        };
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx = 0;
 
        /* for internal loopback recording select */
@@ -1869,7 +2393,10 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
        if (spec->kctl_alloc)
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
        return 1;
 }
@@ -1890,7 +2417,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
@@ -1906,7 +2433,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
 
-       spec->init_verbs = vt1708B_8ch_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
 
        spec->stream_name_analog = "VT1708B Analog";
        spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
@@ -1926,6 +2454,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        codec->patch_ops = via_patch_ops;
 
        codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1708B_loopbacks;
 #endif
@@ -1939,7 +2468,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
@@ -1955,7 +2484,8 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
 
-       spec->init_verbs = vt1708B_4ch_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
 
        spec->stream_name_analog = "VT1708B Analog";
        spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
@@ -1975,6 +2505,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        codec->patch_ops = via_patch_ops;
 
        codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1708B_loopbacks;
 #endif
@@ -1982,6 +2513,752 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        return 0;
 }
 
+/* Patch for VT1708S */
+
+/* VT1708S software backdoor based override for buggy hardware micboost
+ * setting */
+#define MIC_BOOST_VOLUME(xname, nid) {                         \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+       .name = xname,                                  \
+       .index = 0,                                     \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |     \
+       SNDRV_CTL_ELEM_ACCESS_TLV_READ |                \
+       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,             \
+       .info = mic_boost_volume_info,                  \
+       .get = snd_hda_mixer_amp_volume_get,            \
+       .put = snd_hda_mixer_amp_volume_put,            \
+       .tlv = { .c = mic_boost_tlv },                  \
+       .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) }
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
+       MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A),
+       MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb vt1708S_volume_init_verbs[] = {
+       /* Unmute ADC0-1 and set the default input to mic-in */
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
+        * analog-loopback mixer widget */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /* Setup default input of PW4 to MW0 */
+       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* PW9, PW10  Output enable */
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* Enable Mic Boost Volume backdoor */
+       {0x1, 0xf98, 0x1},
+       { }
+};
+
+static struct hda_verb vt1708S_uniwill_init_verbs[] = {
+       {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       { }
+};
+
+static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 8,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_pcm_prepare,
+               .cleanup = via_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x13, /* NID to query formats and rates */
+       .ops = {
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare
+       },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
+                                    const struct auto_pin_cfg *cfg)
+{
+       int i;
+       hda_nid_t nid;
+
+       spec->multiout.num_dacs = cfg->line_outs;
+
+       spec->multiout.dac_nids = spec->private_dac_nids;
+
+       for (i = 0; i < 4; i++) {
+               nid = cfg->line_out_pins[i];
+               if (nid) {
+                       /* config dac list */
+                       switch (i) {
+                       case AUTO_SEQ_FRONT:
+                               spec->multiout.dac_nids[i] = 0x10;
+                               break;
+                       case AUTO_SEQ_CENLFE:
+                               spec->multiout.dac_nids[i] = 0x24;
+                               break;
+                       case AUTO_SEQ_SURROUND:
+                               spec->multiout.dac_nids[i] = 0x11;
+                               break;
+                       case AUTO_SEQ_SIDE:
+                               spec->multiout.dac_nids[i] = 0x25;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       char name[32];
+       static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+       hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
+       hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
+       hda_nid_t nid, nid_vol, nid_mute;
+       int i, err;
+
+       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+               nid = cfg->line_out_pins[i];
+
+               if (!nid)
+                       continue;
+
+               nid_vol = nid_vols[i];
+               nid_mute = nid_mutes[i];
+
+               if (i == AUTO_SEQ_CENLFE) {
+                       /* Center/LFE */
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "Center Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "LFE Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "Center Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(nid_mute,
+                                                                 1, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "LFE Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(nid_mute,
+                                                                 2, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else if (i == AUTO_SEQ_FRONT) {
+                       /* add control to mixer index 0 */
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "Master Front Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
+                                                                 HDA_INPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "Master Front Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
+                                                                 HDA_INPUT));
+                       if (err < 0)
+                               return err;
+
+                       /* Front */
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+                                             HDA_COMPOSE_AMP_VAL(nid_mute,
+                                                                 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else {
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+                                             HDA_COMPOSE_AMP_VAL(nid_mute,
+                                                                 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err;
+
+       if (!pin)
+               return 0;
+
+       spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       create_hp_imux(spec);
+
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 5;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x1a: /* Mic */
+                       idx = 2;
+                       break;
+
+               case 0x1b: /* Line In */
+                       idx = 3;
+                       break;
+
+               case 0x1e: /* Front Mic */
+                       idx = 4;
+                       break;
+
+               case 0x1f: /* CD */
+                       idx = 1;
+                       break;
+               }
+               err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+                                          idx, 0x16);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx-1;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+static int vt1708S_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+       static hda_nid_t vt1708s_ignore[] = {0x21, 0};
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+                                          vt1708s_ignore);
+       if (err < 0)
+               return err;
+       err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       if (spec->autocfg.dig_out_pin)
+               spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
+
+       spec->extra_dig_out_nid = 0x15;
+
+       if (spec->kctl_alloc)
+               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1708S_loopbacks[] = {
+       { 0x16, HDA_INPUT, 1 },
+       { 0x16, HDA_INPUT, 2 },
+       { 0x16, HDA_INPUT, 3 },
+       { 0x16, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static int patch_vt1708S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1708S_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+
+       spec->stream_name_analog = "VT1708S Analog";
+       spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1708S Digital";
+       spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1708S_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+               spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1708S_loopbacks;
+#endif
+
+       return 0;
+}
+
+/* Patch for VT1702 */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1702_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
+                        HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb vt1702_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* Setup default input of PW4 to MW0 */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* PW6 PW7 Output enable */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       { }
+};
+
+static struct hda_verb vt1702_uniwill_init_verbs[] = {
+       {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
+       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+       { }
+};
+
+static struct hda_pcm_stream vt1702_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1702_pcm_analog_capture = {
+       .substreams = 3,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x12, /* NID to query formats and rates */
+       .ops = {
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1702_pcm_digital_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare
+       },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
+                                    const struct auto_pin_cfg *cfg)
+{
+       spec->multiout.num_dacs = 1;
+       spec->multiout.dac_nids = spec->private_dac_nids;
+
+       if (cfg->line_out_pins[0]) {
+               /* config dac list */
+               spec->multiout.dac_nids[0] = 0x10;
+       }
+
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       int err;
+
+       if (!cfg->line_out_pins[0])
+               return -1;
+
+       /* add control to mixer index 0 */
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Master Front Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+       if (err < 0)
+               return err;
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Master Front Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+       if (err < 0)
+               return err;
+
+       /* Front */
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Front Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Front Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err;
+
+       if (!pin)
+               return 0;
+
+       spec->multiout.hp_nid = 0x1D;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       create_hp_imux(spec);
+
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = 3;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x14: /* Mic */
+                       idx = 1;
+                       break;
+
+               case 0x15: /* Line In */
+                       idx = 2;
+                       break;
+
+               case 0x18: /* Front Mic */
+                       idx = 3;
+                       break;
+               }
+               err = via_new_analog_input(spec, cfg->input_pins[i],
+                                          labels[i], idx, 0x1A);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx-1;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+static int vt1702_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+       static hda_nid_t vt1702_ignore[] = {0x1C, 0};
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+                                          vt1702_ignore);
+       if (err < 0)
+               return err;
+       err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       if (spec->autocfg.dig_out_pin)
+               spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
+
+       spec->extra_dig_out_nid = 0x1B;
+
+       if (spec->kctl_alloc)
+               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+       spec->input_mux = &spec->private_imux[0];
+
+       if (spec->hp_mux)
+               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1702_loopbacks[] = {
+       { 0x1A, HDA_INPUT, 1 },
+       { 0x1A, HDA_INPUT, 2 },
+       { 0x1A, HDA_INPUT, 3 },
+       { 0x1A, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static int patch_vt1702(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+       unsigned int response;
+       unsigned char control;
+
+       /* create a codec specific record */
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1702_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
+       spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
+
+       spec->stream_name_analog = "VT1702 Analog";
+       spec->stream_analog_playback = &vt1702_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1702_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1702 Digital";
+       spec->stream_digital_playback = &vt1702_pcm_digital_playback;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1702_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+               spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+       codec->patch_ops.unsol_event = via_unsol_event;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1702_loopbacks;
+#endif
+
+       /* Open backdoor */
+       response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
+       control = (unsigned char)(response & 0xff);
+       control |= 0x3;
+       snd_hda_codec_write(codec,  codec->afg, 0, 0xF88, control);
+
+       /* Enable GPIO 0&1 for volume&mute control */
+       /* Enable GPIO 2 for DMIC-DATA */
+       response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
+       control = (unsigned char)((response >> 16) & 0x3f);
+       snd_hda_codec_write(codec,  codec->afg, 0, 0xF82, control);
+
+       return 0;
+}
+
 /*
  * patch entries
  */
@@ -2022,5 +3299,37 @@ struct hda_codec_preset snd_hda_preset_via[] = {
          .patch = patch_vt1708B_4ch},
        { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
          .patch = patch_vt1708B_4ch},
+       { .id = 0x11060397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11061397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11062397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11063397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11064397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11065397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11066397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11067397, .name = "VIA VT1708S",
+         .patch = patch_vt1708S},
+       { .id = 0x11060398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11061398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11062398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11063398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11064398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11065398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11066398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
+       { .id = 0x11067398, .name = "VIA VT1702",
+         .patch = patch_vt1702},
        {} /* terminator */
 };
index dab31b2756a608b2e52f60c31058e4e4f19cd306..03391da8c8c7741304fff11f4e8ccc044393e984 100644 (file)
@@ -59,7 +59,8 @@ static void snd_ice1712_akm4xxx_write(struct snd_akm4xxx *ak, int chip,
        struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
        struct snd_ice1712 *ice = ak->private_data[0];
 
-       snd_assert(chip >= 0 && chip < 4, return);
+       if (snd_BUG_ON(chip < 0 || chip >= 4))
+               return;
 
        tmp = snd_ice1712_gpio_read(ice);
        tmp |= priv->add_flags;
index 868ae291b960fd32f6054b322cdca8cd3bfad326..110d16e52733b5c10537c9addd7f555018bd78c5 100644 (file)
  *       not working: prety much everything else, at least i could verify that
  *                    we have no digital output, no capture, pretty bad clicks and poops
  *                    on mixer switch and other coll stuff.
- *
- */      
+ */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -131,7 +130,7 @@ static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
        snd_ice1712_gpio_write(ice, tmp);
        udelay(50);
 
-       /* 
+       /*
         * send i2c stop condition and start condition
         * to obtain sane state
         */
@@ -152,10 +151,16 @@ static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
         * skipping ack cycles inbetween
         */
        for (j = 0; j < 3; j++) {
-               switch(j) {
-               case 0: val = dev; break;
-               case 1: val = reg; break;
-               case 2: val = data; break;
+               switch (j) {
+               case 0:
+                       val = dev;
+                       break;
+               case 1:
+                       val = reg;
+                       break;
+               case 2:
+                       val = data;
+                       break;
                }
                for (i = 7; i >= 0; i--) {
                        tmp &= ~AUREON_SPI_CLK;
@@ -171,7 +176,7 @@ static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
                        snd_ice1712_gpio_write(ice, tmp);
                        udelay(40);
                }
-                tmp &= ~AUREON_SPI_CLK;
+               tmp &= ~AUREON_SPI_CLK;
                snd_ice1712_gpio_write(ice, tmp);
                udelay(40);
                tmp |= AUREON_SPI_CLK;
@@ -203,7 +208,7 @@ static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 3;
-       if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
        return 0;
@@ -231,12 +236,12 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        snd_ice1712_save_gpio_status(ice);
        oval = spec->pca9554_out;
-       if ((change = (oval != nval))) {
+       change = (oval != nval);
+       if (change) {
                aureon_pca9554_write(ice, PCA9554_OUT, nval);
                spec->pca9554_out = nval;
        }
        snd_ice1712_restore_gpio_status(ice);
-       
        return change;
 }
 
@@ -256,7 +261,7 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
        udelay(10);
        tmp &= ~AUREON_AC97_ADDR;
        snd_ice1712_gpio_write(ice, tmp);
-       udelay(10);     
+       udelay(10);
 
        /* Send low-order byte to XILINX chip */
        tmp &= ~AUREON_AC97_DATA_MASK;
@@ -269,7 +274,7 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
        tmp &= ~AUREON_AC97_DATA_LOW;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(10);
-       
+
        /* Send high-order byte to XILINX chip */
        tmp &= ~AUREON_AC97_DATA_MASK;
        tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
@@ -282,7 +287,7 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
        tmp &= ~AUREON_AC97_DATA_HIGH;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(10);
-       
+
        /* Instruct XILINX chip to parse the data to the STAC9744 chip */
        tmp |= AUREON_AC97_COMMIT;
        snd_ice1712_gpio_write(ice, tmp);
@@ -290,7 +295,7 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
        tmp &= ~AUREON_AC97_COMMIT;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(10);
-       
+
        /* Store the data in out private buffer */
        spec->stac9744[(reg & 0x7F) >> 1] = val;
 }
@@ -304,7 +309,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r
 /*
  * Initialize STAC9744 chip
  */
-static int aureon_ac97_init (struct snd_ice1712 *ice)
+static int aureon_ac97_init(struct snd_ice1712 *ice)
 {
        struct aureon_spec *spec = ice->spec;
        int i;
@@ -335,20 +340,21 @@ static int aureon_ac97_init (struct snd_ice1712 *ice)
        tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(3);
-       
+
        tmp &= ~AUREON_AC97_RESET;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(3);
-       
+
        tmp |= AUREON_AC97_RESET;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(3);
-       
+
        memset(&spec->stac9744, 0, sizeof(spec->stac9744));
-       for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
+       for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2)
                spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
-               
-       aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
+
+       /* Unmute AC'97 master volume permanently - muting is done by WM8770 */
+       aureon_ac97_write(ice, AC97_MASTER, 0x0000);
 
        return 0;
 }
@@ -388,7 +394,7 @@ static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned short ovol, nvol;
        int change;
-       
+
        snd_ice1712_save_gpio_status(ice);
 
        ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
@@ -396,13 +402,14 @@ static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
        if (kcontrol->private_value & AUREON_AC97_STEREO)
                nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
        nvol |= ovol & ~0x1F1F;
-       
-       if ((change = (ovol != nvol)))
+
+       change = (ovol != nvol);
+       if (change)
                aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
 
        snd_ice1712_restore_gpio_status(ice);
 
-       return change;          
+       return change;
 }
 
 /*
@@ -416,7 +423,8 @@ static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el
 
        mutex_lock(&ice->gpio_mutex);
 
-       ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
+       ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
+                       kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
 
        mutex_unlock(&ice->gpio_mutex);
        return 0;
@@ -429,13 +437,14 @@ static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        int change;
 
        snd_ice1712_save_gpio_status(ice);
-       
+
        ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
-       nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~ 0x8000);
-       
-       if ((change = (ovol != nvol)))
+       nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000);
+
+       change = (ovol != nvol);
+       if (change)
                aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
-               
+
        snd_ice1712_restore_gpio_status(ice);
 
        return change;
@@ -465,13 +474,14 @@ static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ct
        int change;
 
        snd_ice1712_save_gpio_status(ice);
-       
+
        ovol = aureon_ac97_read(ice, AC97_MIC);
        nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
-       
-       if ((change = (ovol != nvol)))
+
+       change = (ovol != nvol);
+       if (change)
                aureon_ac97_write(ice, AC97_MIC, nvol);
-               
+
        snd_ice1712_restore_gpio_status(ice);
 
        return change;
@@ -493,16 +503,15 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned
                snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
                mosi = PRODIGY_SPI_MOSI;
                clk = PRODIGY_SPI_CLK;
-       }
-       else {
+       } else {
                snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
                                                 AUREON_WM_CS|AUREON_CS8415_CS));
                mosi = AUREON_SPI_MOSI;
                clk = AUREON_SPI_CLK;
-               
+
                tmp |= AUREON_WM_RW;
        }
-       
+
        tmp &= ~cs;
        snd_ice1712_gpio_write(ice, tmp);
        udelay(1);
@@ -534,7 +543,9 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned
 /*
  * Read data in SPI mode
  */
-static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits, unsigned char *buffer, int size) {
+static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs,
+               unsigned int data, int bits, unsigned char *buffer, int size)
+{
        int i, j;
        unsigned int tmp;
 
@@ -544,7 +555,7 @@ static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned i
        snd_ice1712_gpio_write(ice, tmp);
        udelay(1);
 
-       for (i=bits-1; i>=0; i--) {
+       for (i = bits-1; i >= 0; i--) {
                if (data & (1 << i))
                        tmp |= AUREON_SPI_MOSI;
                else
@@ -561,9 +572,9 @@ static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned i
                udelay(1);
        }
 
-       for (j=0; j<size; j++) {
+       for (j = 0; j < size; j++) {
                unsigned char outdata = 0;
-               for (i=7; i>=0; i--) {
+               for (i = 7; i >= 0; i--) {
                        tmp = snd_ice1712_gpio_read(ice);
                        outdata <<= 1;
                        outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
@@ -584,19 +595,24 @@ static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned i
        snd_ice1712_gpio_write(ice, tmp);
 }
 
-static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
+static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg)
+{
        unsigned char val;
        aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
        aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
        return val;
 }
 
-static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
+static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg,
+                               unsigned char *buffer, int size)
+{
        aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
        aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
 }
 
-static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
+static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg,
+                                               unsigned char val)
+{
        aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
 }
 
@@ -654,18 +670,20 @@ static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        return 0;
 }
 
-static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned short ovol, nvol;
        int change;
-       
+
        snd_ice1712_save_gpio_status(ice);
-       
+
        ovol = wm_get(ice, WM_OUT_MUX1);
        nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
-       if ((change = (ovol != nvol)))
+       change = (ovol != nvol);
+       if (change)
                wm_put(ice, WM_OUT_MUX1, nvol);
-               
+
        snd_ice1712_restore_gpio_status(ice);
 
        return change;
@@ -702,12 +720,12 @@ static const unsigned char wm_vol[256] = {
 static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
 {
        unsigned char nvol;
-       
+
        if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
                nvol = 0;
        else
                nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
-       
+
        wm_put(ice, index, nvol);
        wm_put_nocache(ice, index, 0x180 | nvol);
 }
@@ -736,7 +754,8 @@ static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
        snd_ice1712_save_gpio_status(ice);
        oval = wm_get(ice, WM_MUTE);
        nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
-       if ((change = (nval != oval)))
+       change = (oval != nval);
+       if (change)
                wm_put(ice, WM_MUTE, nval);
        snd_ice1712_restore_gpio_status(ice);
 
@@ -760,7 +779,7 @@ static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct aureon_spec *spec = ice->spec;
        int i;
-       for (i=0; i<2; i++)
+       for (i = 0; i < 2; i++)
                ucontrol->value.integer.value[i] =
                        spec->master[i] & ~WM_VOL_MUTE;
        return 0;
@@ -849,7 +868,8 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *
 /*
  * WM8770 mute control
  */
-static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        uinfo->count = kcontrol->private_value >> 8;
        uinfo->value.integer.min = 0;
@@ -862,7 +882,7 @@ static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct aureon_spec *spec = ice->spec;
        int voices, ofs, i;
-       
+
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xFF;
 
@@ -907,7 +927,7 @@ static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct aureon_spec *spec = ice->spec;
-       
+
        ucontrol->value.integer.value[0] =
                (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
        ucontrol->value.integer.value[1] =
@@ -1083,21 +1103,21 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
 static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        static const char * const texts[] = {
-               "CD",           //AIN1
-               "Aux",          //AIN2
-               "Line",         //AIN3
-               "Mic",          //AIN4
-               "AC97"          //AIN5
+               "CD",           /* AIN1 */
+               "Aux",          /* AIN2 */
+               "Line",         /* AIN3 */
+               "Mic",          /* AIN4 */
+               "AC97"          /* AIN5 */
        };
        static const char * const universe_texts[] = {
-               "Aux1",         //AIN1
-               "CD",           //AIN2
-               "Phono",        //AIN3
-               "Line",         //AIN4
-               "Aux2",         //AIN5
-               "Mic",          //AIN6
-               "Aux3",         //AIN7
-               "AC97"          //AIN8
+               "Aux1",         /* AIN1 */
+               "CD",           /* AIN2 */
+               "Phono",        /* AIN3 */
+               "Line",         /* AIN4 */
+               "Aux2",         /* AIN5 */
+               "Mic",          /* AIN6 */
+               "Aux3",         /* AIN7 */
+               "AC97"          /* AIN8 */
        };
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
@@ -1108,8 +1128,7 @@ static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_in
                if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                        uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
                strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
-       }
-       else {
+       } else {
                uinfo->value.enumerated.items = 5;
                if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                        uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
@@ -1156,8 +1175,8 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        static const char * const aureon_texts[] = {
-               "CD",           //RXP0
-               "Optical"       //RXP1
+               "CD",           /* RXP0 */
+               "Optical"       /* RXP1 */
        };
        static const char * const prodigy_texts[] = {
                "CD",
@@ -1180,10 +1199,10 @@ static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct aureon_spec *spec = ice->spec;
 
-       //snd_ice1712_save_gpio_status(ice);
-       //val = aureon_cs8415_get(ice, CS8415_CTRL2);
+       /* snd_ice1712_save_gpio_status(ice); */
+       /* val = aureon_cs8415_get(ice, CS8415_CTRL2); */
        ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
-       //snd_ice1712_restore_gpio_status(ice);
+       /* snd_ice1712_restore_gpio_status(ice); */
        return 0;
 }
 
@@ -1206,7 +1225,7 @@ static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        return change;
 }
 
-static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
@@ -1215,7 +1234,7 @@ static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ct
        return 0;
 }
 
-static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int aureon_cs8415_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char ratio;
@@ -1229,7 +1248,7 @@ static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl
  */
 #define aureon_cs8415_mute_info                snd_ctl_boolean_mono_info
 
-static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        snd_ice1712_save_gpio_status(ice);
@@ -1238,7 +1257,7 @@ static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl
        return 0;
 }
 
-static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char oval, nval;
@@ -1249,7 +1268,8 @@ static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl
                nval = oval & ~0x20;
        else
                nval = oval | 0x20;
-       if ((change = (oval != nval)))
+       change = (oval != nval);
+       if (change)
                aureon_cs8415_put(ice, CS8415_CTRL1, nval);
        snd_ice1712_restore_gpio_status(ice);
        return change;
@@ -1258,15 +1278,17 @@ static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl
 /*
  * CS8415A Q-Sub info
  */
-static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
        uinfo->count = 10;
        return 0;
 }
 
-static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       
+
        snd_ice1712_save_gpio_status(ice);
        aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
        snd_ice1712_restore_gpio_status(ice);
@@ -1274,18 +1296,21 @@ static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl
        return 0;
 }
 
-static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
        uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
        uinfo->count = 1;
        return 0;
 }
 
-static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
        memset(ucontrol->value.iec958.status, 0xFF, 24);
        return 0;
 }
 
-static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
+static int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
        snd_ice1712_save_gpio_status(ice);
@@ -1311,9 +1336,9 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
        else
                if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
                    ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
-                       tmp &= ~ AUREON_HP_SEL;
+                       tmp &= ~AUREON_HP_SEL;
                else
-                       tmp &= ~ PRODIGY_HP_SEL;
+                       tmp &= ~PRODIGY_HP_SEL;
        if (tmp != tmp2) {
                snd_ice1712_gpio_write(ice, tmp);
                return 1;
@@ -1325,7 +1350,7 @@ static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
 {
        unsigned int tmp = snd_ice1712_gpio_read(ice);
 
-       return ( tmp & AUREON_HP_SEL )!= 0;
+       return (tmp & AUREON_HP_SEL) != 0;
 }
 
 #define aureon_hpamp_info      snd_ctl_boolean_mono_info
@@ -1343,7 +1368,7 @@ static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-       return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
+       return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]);
 }
 
 /*
@@ -1390,7 +1415,7 @@ static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_
                uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
 
-        return 0;
+       return 0;
 }
 
 static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1434,7 +1459,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Master Playback Volume",
                .info = wm_master_vol_info,
                .get = wm_master_vol_get,
@@ -1452,7 +1477,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Front Playback Volume",
                .info = wm_vol_info,
                .get = wm_vol_get,
@@ -1471,7 +1496,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Rear Playback Volume",
                .info = wm_vol_info,
                .get = wm_vol_get,
@@ -1490,7 +1515,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Center Playback Volume",
                .info = wm_vol_info,
                .get = wm_vol_get,
@@ -1509,7 +1534,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "LFE Playback Volume",
                .info = wm_vol_info,
                .get = wm_vol_get,
@@ -1528,7 +1553,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Side Playback Volume",
                .info = wm_vol_info,
                .get = wm_vol_get,
@@ -1539,23 +1564,23 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
 };
 
 static struct snd_kcontrol_new wm_controls[] __devinitdata = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "PCM Playback Switch",
                .info = wm_pcm_mute_info,
                .get = wm_pcm_mute_get,
                .put = wm_pcm_mute_put
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "PCM Playback Volume",
                .info = wm_pcm_vol_info,
                .get = wm_pcm_vol_get,
                .put = wm_pcm_vol_put,
                .tlv = { .p = db_scale_wm_pcm }
-       },
+       },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Capture Switch",
@@ -1566,7 +1591,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Capture Volume",
                .info = wm_adc_vol_info,
                .get = wm_adc_vol_get,
@@ -1605,232 +1630,232 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
 };
 
 static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "AC97 Playback Switch",
                .info = aureon_ac97_mmute_info,
                .get = aureon_ac97_mmute_get,
                .put = aureon_ac97_mmute_put,
                .private_value = AC97_MASTER
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "AC97 Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_MASTER|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "AC97 Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_MASTER|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_master }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "CD Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_CD
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "CD Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_CD
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "CD Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_CD|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "CD Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_CD|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Aux Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_AUX,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Aux Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_AUX,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Aux Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_AUX|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Aux Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_AUX|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Line Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_LINE
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Line Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_LINE
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Line Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_LINE|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Line Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_LINE|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Mic Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_MIC
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_MIC
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Mic Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_MIC,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Mic Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_MIC,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Mic Boost (+20dB)",
-               .info = aureon_ac97_micboost_info,
-               .get = aureon_ac97_micboost_get,
-               .put = aureon_ac97_micboost_put
-       }
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Boost (+20dB)",
+               .info = aureon_ac97_micboost_info,
+               .get = aureon_ac97_micboost_get,
+               .put = aureon_ac97_micboost_put
+       }
 };
 
 static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "AC97 Playback Switch",
                .info = aureon_ac97_mmute_info,
                .get = aureon_ac97_mmute_get,
                .put = aureon_ac97_mmute_put,
                .private_value = AC97_MASTER
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "AC97 Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_MASTER|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "AC97 Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_MASTER|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_master }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "CD Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_AUX
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "CD Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_AUX
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "CD Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_AUX|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "CD Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_AUX|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Phono Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_CD
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Phono Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_CD
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Phono Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_CD|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Phono Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_CD|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Line Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_LINE
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Line Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_LINE
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Line Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_LINE|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Line Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_LINE|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Mic Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_MIC
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_MIC
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Mic Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_MIC,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Mic Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_MIC,
                .tlv = { .p = db_scale_ac97_gain }
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Mic Boost (+20dB)",
-               .info = aureon_ac97_micboost_info,
-               .get = aureon_ac97_micboost_get,
-               .put = aureon_ac97_micboost_put
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Aux Playback Switch",
-               .info = aureon_ac97_mute_info,
-               .get = aureon_ac97_mute_get,
-               .put = aureon_ac97_mute_put,
-               .private_value = AC97_VIDEO,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Boost (+20dB)",
+               .info = aureon_ac97_micboost_info,
+               .get = aureon_ac97_micboost_get,
+               .put = aureon_ac97_micboost_put
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Aux Playback Switch",
+               .info = aureon_ac97_mute_info,
+               .get = aureon_ac97_mute_get,
+               .put = aureon_ac97_mute_put,
+               .private_value = AC97_VIDEO,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-               .name = "Aux Playback Volume",
-               .info = aureon_ac97_vol_info,
-               .get = aureon_ac97_vol_get,
-               .put = aureon_ac97_vol_put,
-               .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Aux Playback Volume",
+               .info = aureon_ac97_vol_info,
+               .get = aureon_ac97_vol_get,
+               .put = aureon_ac97_vol_put,
+               .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
                .tlv = { .p = db_scale_ac97_gain }
-       },
+       },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Aux Source",
@@ -1844,43 +1869,43 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
 static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
                .info = aureon_cs8415_mute_info,
                .get = aureon_cs8415_mute_get,
                .put = aureon_cs8415_mute_put
        },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source",
                .info = aureon_cs8415_mux_info,
                .get = aureon_cs8415_mux_get,
                .put = aureon_cs8415_mux_put,
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
+               .name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT),
                .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
                .info = aureon_cs8415_qsub_info,
                .get = aureon_cs8415_qsub_get,
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
                .info = aureon_cs8415_spdif_info,
                .get = aureon_cs8415_mask_get
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
                .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
                .info = aureon_cs8415_spdif_info,
                .get = aureon_cs8415_spdif_get
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
-               .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
                .info = aureon_cs8415_rate_info,
                .get = aureon_cs8415_rate_get
        }
@@ -1905,15 +1930,14 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
                if (err < 0)
                        return err;
        }
-       
+
        if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
                for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
                        err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
                        if (err < 0)
                                return err;
                }
-       }
-       else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+       } else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
                 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
                for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
                        err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
@@ -1932,7 +1956,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
                else if ((id & 0x0F) != 0x01)
                        snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
                else {
-                       for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
+                       for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
                                struct snd_kcontrol *kctl;
                                err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
                                if (err < 0)
@@ -1943,7 +1967,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
                }
                snd_ice1712_restore_gpio_status(ice);
        }
-       
+
        return 0;
 }
 
@@ -2059,11 +2083,12 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
 
        /* to remeber the register values of CS8415 */
        ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-       if (! ice->akm)
+       if (!ice->akm)
                return -ENOMEM;
        ice->akm_codecs = 1;
-       
-       if ((err = aureon_ac97_init(ice)) != 0)
+
+       err = aureon_ac97_init(ice);
+       if (err != 0)
                return err;
 
        snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
@@ -2086,7 +2111,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
        /* initialize WM8770 codec */
        if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
                ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
-               ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
+               ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
                p = wm_inits_prodigy;
        else
                p = wm_inits_aureon;
@@ -2105,10 +2130,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
 
        snd_ice1712_restore_gpio_status(ice);
 
-        /* initialize PCA9554 pin directions & set default input*/
+       /* initialize PCA9554 pin directions & set default input */
        aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
        aureon_pca9554_write(ice, PCA9554_OUT, 0x00);   /* internal AUX */
-       
+
        spec->master[0] = WM_VOL_MUTE;
        spec->master[1] = WM_VOL_MUTE;
        for (i = 0; i < ice->num_total_dacs; i++) {
@@ -2158,6 +2183,24 @@ static unsigned char aureon71_eeprom[] __devinitdata = {
 };
 #define prodigy71_eeprom aureon71_eeprom
 
+static unsigned char aureon71_universe_eeprom[] __devinitdata = {
+       [ICE_EEP2_SYSCONF]     = 0x2b,  /* clock 512, mpu401, spdif-in/ADC,
+                                        * 4DACs
+                                        */
+       [ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
+       [ICE_EEP2_I2S]         = 0xfc,  /* vol, 96k, 24bit, 192k */
+       [ICE_EEP2_SPDIF]       = 0xc3,  /* out-en, out-int, spdif-in */
+       [ICE_EEP2_GPIO_DIR]    = 0xff,
+       [ICE_EEP2_GPIO_DIR1]   = 0xff,
+       [ICE_EEP2_GPIO_DIR2]   = 0x5f,
+       [ICE_EEP2_GPIO_MASK]   = 0x00,
+       [ICE_EEP2_GPIO_MASK1]  = 0x00,
+       [ICE_EEP2_GPIO_MASK2]  = 0x00,
+       [ICE_EEP2_GPIO_STATE]  = 0x00,
+       [ICE_EEP2_GPIO_STATE1] = 0x00,
+       [ICE_EEP2_GPIO_STATE2] = 0x00,
+};
+
 static unsigned char prodigy71lt_eeprom[] __devinitdata = {
        [ICE_EEP2_SYSCONF]     = 0x4b,  /* clock 384, spdif-in/ADC, 4DACs */
        [ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
@@ -2197,14 +2240,14 @@ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
                .eeprom_data = aureon71_eeprom,
                .driver = "Aureon71",
        },
-       {
-               .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
-               .name = "Terratec Aureon 7.1-Universe",
+       {
+               .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
+               .name = "Terratec Aureon 7.1-Universe",
                .model = "universe",
-               .chip_init = aureon_init,
-               .build_controls = aureon_add_controls,
-               .eeprom_size = sizeof(aureon71_eeprom),
-               .eeprom_data = aureon71_eeprom,
+               .chip_init = aureon_init,
+               .build_controls = aureon_add_controls,
+               .eeprom_size = sizeof(aureon71_universe_eeprom),
+               .eeprom_data = aureon71_universe_eeprom,
                .driver = "Aureon71Univ", /* keep in 15 letters */
        },
        {
index 0ed96c1780593f7d9e1f3efab180d4cbb2bcc022..d216362626d019826adb262da1341c898666c65d 100644 (file)
@@ -400,7 +400,7 @@ static void delta_setup_spdif(struct snd_ice1712 *ice, int rate)
 static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
-       char reg = 0x10; // cs8427 receiver error register
+       char reg = 0x10; /* CS8427 receiver error register */
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
        if (snd_i2c_sendbytes(ice->cs8427, &reg, 1) != 1)
index ea7116c304c04bce4635ce308b422cf33f6674c4..f7f14df81f26e301089b77bcf26825872d8045c5 100644 (file)
@@ -31,6 +31,7 @@
                "{MidiMan M Audio,Delta DiO 2496},"\
                "{MidiMan M Audio,Delta 66},"\
                "{MidiMan M Audio,Delta 44},"\
+               "{MidiMan M Audio,Delta 410},"\
                "{MidiMan M Audio,Audiophile 24/96},"\
                "{Digigram,VX442},"\
                "{Lionstracs,Mediastation},"
index 013fc4f0482282fce0fb25da5a0a63b2012c6956..6fe35b8120400ddb8c073f9166879b9821984a33 100644 (file)
@@ -149,7 +149,8 @@ static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mas
        struct ews_spec *spec = ice->spec;
        unsigned char data, ndata;
 
-       snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL);
+       if (snd_BUG_ON(chip_mask < 0 || chip_mask > 0x0f))
+               return -EINVAL;
        snd_i2c_lock(ice->i2c);
        if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1)
                goto __error;
@@ -685,7 +686,8 @@ static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, st
        int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned char data;
 
-       snd_assert(channel >= 0 && channel <= 7, return 0);
+       if (snd_BUG_ON(channel < 0 || channel > 7))
+               return 0;
        snd_i2c_lock(ice->i2c);
        if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
@@ -705,7 +707,8 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st
        int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned char data, ndata;
 
-       snd_assert(channel >= 0 && channel <= 7, return 0);
+       if (snd_BUG_ON(channel < 0 || channel > 7))
+               return 0;
        snd_i2c_lock(ice->i2c);
        if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
index 29d449d73c9864132d15ea0e4cd3313634870231..5b442383fcdabb7b3655ebcc575109933a554639 100644 (file)
@@ -17,7 +17,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 /*
   NOTES:
@@ -35,7 +35,7 @@
  *
  *  2002.11.26 James Stafford <jstafford@ampltd.com>
  *     Added support for VT1724 (Envy24HT)
- *     I have left out support for 176.4 and 192 KHz for the moment. 
+ *     I have left out support for 176.4 and 192 KHz for the moment.
  *  I also haven't done anything with the internal S/PDIF transmitter or the MPU-401
  *
  *  2003.02.20  Taksahi Iwai <tiwai@suse.de>
@@ -47,7 +47,7 @@
  */
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -123,7 +123,7 @@ static unsigned int PRO_RATE_DEFAULT = 44100;
 /*
  *  Basic I/O
  */
+
 /* check whether the clock mode is spdif-in */
 static inline int is_spdif_master(struct snd_ice1712 *ice)
 {
@@ -135,13 +135,13 @@ static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
        return is_spdif_master(ice) || PRO_RATE_LOCKED;
 }
 
-static inline void snd_ice1712_ds_write(struct snd_ice1712 * ice, u8 channel, u8 addr, u32 data)
+static inline void snd_ice1712_ds_write(struct snd_ice1712 *ice, u8 channel, u8 addr, u32 data)
 {
        outb((channel << 4) | addr, ICEDS(ice, INDEX));
        outl(data, ICEDS(ice, DATA));
 }
 
-static inline u32 snd_ice1712_ds_read(struct snd_ice1712 * ice, u8 channel, u8 addr)
+static inline u32 snd_ice1712_ds_read(struct snd_ice1712 *ice, u8 channel, u8 addr)
 {
        outb((channel << 4) | addr, ICEDS(ice, INDEX));
        return inl(ICEDS(ice, DATA));
@@ -260,7 +260,7 @@ static unsigned short snd_ice1712_pro_ac97_read(struct snd_ac97 *ac97,
 static int snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_ROUTECTRL)) & ICE1712_ROUTE_AC97 ? 1 : 0;
        return 0;
 }
@@ -269,11 +269,12 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char val, nval;
-       
+
        spin_lock_irq(&ice->reg_lock);
        val = inb(ICEMT(ice, MONITOR_ROUTECTRL));
        nval = val & ~ICE1712_ROUTE_AC97;
-       if (ucontrol->value.integer.value[0]) nval |= ICE1712_ROUTE_AC97;
+       if (ucontrol->value.integer.value[0])
+               nval |= ICE1712_ROUTE_AC97;
        outb(nval, ICEMT(ice, MONITOR_ROUTECTRL));
        spin_unlock_irq(&ice->reg_lock);
        return val != nval;
@@ -329,7 +330,7 @@ static int snd_ice1712_cs8427_set_input_clock(struct snd_ice1712 *ice, int spdif
        unsigned char reg[2] = { 0x80 | 4, 0 };   /* CS8427 auto increment | register number 4 + data */
        unsigned char val, nval;
        int res = 0;
-       
+
        snd_i2c_lock(ice->i2c);
        if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
@@ -381,9 +382,9 @@ int __devinit snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr)
 {
        int err;
 
-       if ((err = snd_cs8427_create(ice->i2c, addr,
-                                    (ice->cs8427_timeout * HZ) / 1000,
-                                    &ice->cs8427)) < 0) {
+       err = snd_cs8427_create(ice->i2c, addr,
+               (ice->cs8427_timeout * HZ) / 1000, &ice->cs8427);
+       if (err < 0) {
                snd_printk(KERN_ERR "CS8427 initialization failed\n");
                return err;
        }
@@ -395,9 +396,9 @@ int __devinit snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr)
 
 static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master)
 {
-        /* change CS8427 clock source too */
-        if (ice->cs8427)
-                snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
+       /* change CS8427 clock source too */
+       if (ice->cs8427)
+               snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
        /* notify ak4524 chip as well */
        if (spdif_is_master) {
                unsigned int i;
@@ -457,11 +458,12 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
                        u16 pbkstatus;
                        struct snd_pcm_substream *substream;
                        pbkstatus = inw(ICEDS(ice, INTSTAT));
-                       //printk("pbkstatus = 0x%x\n", pbkstatus);
+                       /* printk("pbkstatus = 0x%x\n", pbkstatus); */
                        for (idx = 0; idx < 6; idx++) {
                                if ((pbkstatus & (3 << (idx * 2))) == 0)
                                        continue;
-                               if ((substream = ice->playback_con_substream_ds[idx]) != NULL)
+                               substream = ice->playback_con_substream_ds[idx];
+                               if (substream != NULL)
                                        snd_pcm_period_elapsed(substream);
                                outw(3 << (idx * 2), ICEDS(ice, INTSTAT));
                        }
@@ -507,7 +509,7 @@ static int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream,
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
        int result = 0;
        u32 tmp;
-       
+
        spin_lock(&ice->reg_lock);
        tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL);
        if (cmd == SNDRV_PCM_TRIGGER_START) {
@@ -532,7 +534,7 @@ static int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream,
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
        int result = 0;
        u32 tmp;
-       
+
        spin_lock(&ice->reg_lock);
        tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL);
        if (cmd == SNDRV_PCM_TRIGGER_START) {
@@ -557,7 +559,7 @@ static int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream,
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
        int result = 0;
        u8 tmp;
-       
+
        spin_lock(&ice->reg_lock);
        tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL);
        if (cmd == SNDRV_PCM_TRIGGER_START) {
@@ -711,8 +713,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s
        return bytes_to_frames(substream->runtime, ptr);
 }
 
-static const struct snd_pcm_hardware snd_ice1712_playback =
-{
+static const struct snd_pcm_hardware snd_ice1712_playback = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -731,8 +732,7 @@ static const struct snd_pcm_hardware snd_ice1712_playback =
        .fifo_size =            0,
 };
 
-static const struct snd_pcm_hardware snd_ice1712_playback_ds =
-{
+static const struct snd_pcm_hardware snd_ice1712_playback_ds = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -751,8 +751,7 @@ static const struct snd_pcm_hardware snd_ice1712_playback_ds =
        .fifo_size =            0,
 };
 
-static const struct snd_pcm_hardware snd_ice1712_capture =
-{
+static const struct snd_pcm_hardware snd_ice1712_capture = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID),
@@ -788,7 +787,7 @@ static int snd_ice1712_playback_ds_open(struct snd_pcm_substream *substream)
 
        ice->playback_con_substream_ds[substream->number] = substream;
        runtime->hw = snd_ice1712_playback_ds;
-       spin_lock_irq(&ice->reg_lock); 
+       spin_lock_irq(&ice->reg_lock);
        tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2));
        outw(tmp, ICEDS(ice, INTMASK));
        spin_unlock_irq(&ice->reg_lock);
@@ -821,7 +820,7 @@ static int snd_ice1712_playback_ds_close(struct snd_pcm_substream *substream)
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
        u32 tmp;
 
-       spin_lock_irq(&ice->reg_lock); 
+       spin_lock_irq(&ice->reg_lock);
        tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2));
        outw(tmp, ICEDS(ice, INTMASK));
        spin_unlock_irq(&ice->reg_lock);
@@ -870,7 +869,7 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = {
        .pointer =      snd_ice1712_capture_pointer,
 };
 
-static int __devinit snd_ice1712_pcm(struct snd_ice1712 * ice, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
 {
        struct snd_pcm *pcm;
        int err;
@@ -900,7 +899,7 @@ static int __devinit snd_ice1712_pcm(struct snd_ice1712 * ice, int device, struc
        return 0;
 }
 
-static int __devinit snd_ice1712_pcm_ds(struct snd_ice1712 * ice, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
 {
        struct snd_pcm *pcm;
        int err;
@@ -1029,14 +1028,14 @@ static void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
        if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
                                                 ICE1712_PLAYBACK_PAUSE|
                                                 ICE1712_PLAYBACK_START)) {
-             __out:
+__out:
                spin_unlock_irqrestore(&ice->reg_lock, flags);
                return;
        }
        if (!force && is_pro_rate_locked(ice))
                goto __out;
 
-        old = inb(ICEMT(ice, RATE));
+       old = inb(ICEMT(ice, RATE));
        if (!force && old == val)
                goto __out;
        outb(val, ICEMT(ice, RATE));
@@ -1123,8 +1122,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea
        return bytes_to_frames(substream->runtime, ptr);
 }
 
-static const struct snd_pcm_hardware snd_ice1712_playback_pro =
-{
+static const struct snd_pcm_hardware snd_ice1712_playback_pro = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -1143,8 +1141,7 @@ static const struct snd_pcm_hardware snd_ice1712_playback_pro =
        .fifo_size =            0,
 };
 
-static const struct snd_pcm_hardware snd_ice1712_capture_pro =
-{
+static const struct snd_pcm_hardware snd_ice1712_capture_pro = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -1238,7 +1235,7 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = {
        .pointer =      snd_ice1712_capture_pro_pointer,
 };
 
-static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 * ice, int device, struct snd_pcm ** rpcm)
+static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
 {
        struct snd_pcm *pcm;
        int err;
@@ -1262,7 +1259,7 @@ static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 * ice, int device,
        ice->pcm_pro = pcm;
        if (rpcm)
                *rpcm = pcm;
-       
+
        if (ice->cs8427) {
                /* assign channels to iec958 */
                err = snd_cs8427_iec958_build(ice->cs8427,
@@ -1272,7 +1269,8 @@ static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 * ice, int device,
                        return err;
        }
 
-       if ((err = snd_ice1712_build_pro_mixer(ice)) < 0)
+       err = snd_ice1712_build_pro_mixer(ice);
+       if (err < 0)
                return err;
        return 0;
 }
@@ -1299,7 +1297,7 @@ static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struc
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
                kcontrol->private_value;
-       
+
        spin_lock_irq(&ice->reg_lock);
        ucontrol->value.integer.value[0] =
                !((ice->pro_volumes[priv_idx] >> 15) & 1);
@@ -1341,7 +1339,7 @@ static int snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol *kcontrol, struc
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
                kcontrol->private_value;
-       
+
        spin_lock_irq(&ice->reg_lock);
        ucontrol->value.integer.value[0] =
                (ice->pro_volumes[priv_idx] >> 0) & 127;
@@ -1406,7 +1404,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit
 
 static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
+       .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH),
        .info = snd_ice1712_pro_mixer_switch_info,
        .get = snd_ice1712_pro_mixer_switch_get,
        .put = snd_ice1712_pro_mixer_switch_put,
@@ -1428,7 +1426,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit
 
 static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
+       .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME),
        .info = snd_ice1712_pro_mixer_volume_info,
        .get = snd_ice1712_pro_mixer_volume_get,
        .put = snd_ice1712_pro_mixer_volume_put,
@@ -1448,7 +1446,7 @@ static int __devinit snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice)
                if (err < 0)
                        return err;
        }
-       
+
        if (ice->num_total_adcs > 0) {
                struct snd_kcontrol_new tmp = snd_ice1712_multi_capture_analog_switch;
                tmp.count = ice->num_total_adcs;
@@ -1495,7 +1493,7 @@ static void snd_ice1712_mixer_free_ac97(struct snd_ac97 *ac97)
        ice->ac97 = NULL;
 }
 
-static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 * ice)
+static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
 {
        int err, bus_num = 0;
        struct snd_ac97_template ac97;
@@ -1510,27 +1508,32 @@ static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 * ice)
        };
 
        if (ice_has_con_ac97(ice)) {
-               if ((err = snd_ac97_bus(ice->card, bus_num++, &con_ops, NULL, &pbus)) < 0)
+               err = snd_ac97_bus(ice->card, bus_num++, &con_ops, NULL, &pbus);
+               if (err < 0)
                        return err;
                memset(&ac97, 0, sizeof(ac97));
                ac97.private_data = ice;
                ac97.private_free = snd_ice1712_mixer_free_ac97;
-               if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0)
+               err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
+               if (err < 0)
                        printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
                else {
-                       if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0)
+                       err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice));
+                       if (err < 0)
                                return err;
                        return 0;
                }
        }
 
-       if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
-               if ((err = snd_ac97_bus(ice->card, bus_num, &pro_ops, NULL, &pbus)) < 0)
+       if (!(ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
+               err = snd_ac97_bus(ice->card, bus_num, &pro_ops, NULL, &pbus);
+               if (err < 0)
                        return err;
                memset(&ac97, 0, sizeof(ac97));
                ac97.private_data = ice;
                ac97.private_free = snd_ice1712_mixer_free_ac97;
-               if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0)
+               err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
+               if (err < 0)
                        printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
                else
                        return 0;
@@ -1549,7 +1552,7 @@ static inline unsigned int eeprom_double(struct snd_ice1712 *ice, int idx)
        return (unsigned int)ice->eeprom.data[idx] | ((unsigned int)ice->eeprom.data[idx + 1] << 8);
 }
 
-static void snd_ice1712_proc_read(struct snd_info_entry *entry, 
+static void snd_ice1712_proc_read(struct snd_info_entry *entry,
                                  struct snd_info_buffer *buffer)
 {
        struct snd_ice1712 *ice = entry->private_data;
@@ -1585,15 +1588,15 @@ static void snd_ice1712_proc_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "  SPDOUT           : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT)));
        snd_iprintf(buffer, "  RATE             : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE)));
        snd_iprintf(buffer, "  GPIO_DATA        : 0x%02x\n", (unsigned)snd_ice1712_get_gpio_data(ice));
-        snd_iprintf(buffer, "  GPIO_WRITE_MASK  : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK));
+       snd_iprintf(buffer, "  GPIO_WRITE_MASK  : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK));
        snd_iprintf(buffer, "  GPIO_DIRECTION   : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION));
 }
 
-static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice)
+static void __devinit snd_ice1712_proc_init(struct snd_ice1712 *ice)
 {
        struct snd_info_entry *entry;
 
-       if (! snd_card_proc_new(ice->card, "ice1712", &entry))
+       if (!snd_card_proc_new(ice->card, "ice1712", &entry))
                snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read);
 }
 
@@ -1613,7 +1616,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       
+
        memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
        return 0;
 }
@@ -1641,7 +1644,7 @@ static int snd_ice1712_spdif_default_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        if (ice->spdif.ops.default_get)
-               ice->spdif.ops.default_get(ice, ucontrol); 
+               ice->spdif.ops.default_get(ice, ucontrol);
        return 0;
 }
 
@@ -1657,7 +1660,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol,
 static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_default_get,
        .put =          snd_ice1712_spdif_default_put
@@ -1709,7 +1712,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_maskc_get,
 };
@@ -1718,7 +1721,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_maskp_get,
 };
@@ -1746,7 +1749,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
        .access =       (SNDRV_CTL_ELEM_ACCESS_READWRITE |
                         SNDRV_CTL_ELEM_ACCESS_INACTIVE),
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_stream_get,
        .put =          snd_ice1712_spdif_stream_put
@@ -1758,7 +1761,7 @@ int snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol,
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char mask = kcontrol->private_value & 0xff;
        int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
-       
+
        snd_ice1712_save_gpio_status(ice);
        ucontrol->value.integer.value[0] =
                (snd_ice1712_gpio_read(ice) & mask ? 1 : 0) ^ invert;
@@ -1825,7 +1828,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
                9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
        };
        unsigned char val;
-       
+
        spin_lock_irq(&ice->reg_lock);
        if (is_spdif_master(ice)) {
                ucontrol->value.enumerated.item[0] = 13;
@@ -1867,7 +1870,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
 
        if ((oval & ICE1712_SPDIF_MASTER) !=
            (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER))
-               snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
+               snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
 
        return change;
 }
@@ -1897,7 +1900,7 @@ static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcon
                "64000",        /* 10: 15 */
                "88200",        /* 11: 11 */
                "96000",        /* 12: 7 */
-               // "IEC958 Input",      /* 13: -- */
+               /* "IEC958 Input",      13: -- */
        };
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
@@ -2026,7 +2029,7 @@ static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
                "IEC958 In L", "IEC958 In R", /* 9-10 */
                "Digital Mixer", /* 11 - optional */
        };
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items =
@@ -2070,7 +2073,7 @@ static int snd_ice1712_pro_route_analog_put(struct snd_kcontrol *kcontrol,
        int change, shift;
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned int val, old_val, nval;
-       
+
        /* update PSDOUT */
        if (ucontrol->value.enumerated.item[0] >= 11)
                nval = idx < 2 ? 1 : 0; /* dig mixer (or pcm) */
@@ -2140,7 +2143,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
        int change, shift;
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned int val, old_val, nval;
-       
+
        /* update SPDOUT */
        spin_lock_irq(&ice->reg_lock);
        val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT));
@@ -2182,7 +2185,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata
 
 static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+       .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
        .info = snd_ice1712_pro_route_info,
        .get = snd_ice1712_pro_route_spdif_get,
        .put = snd_ice1712_pro_route_spdif_put,
@@ -2204,7 +2207,7 @@ static int snd_ice1712_pro_volume_rate_get(struct snd_kcontrol *kcontrol,
                                           struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_RATE));
        return 0;
 }
@@ -2245,7 +2248,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx;
-       
+
        spin_lock_irq(&ice->reg_lock);
        for (idx = 0; idx < 22; idx++) {
                outb(idx, ICEMT(ice, MONITOR_PEAKINDEX));
@@ -2296,12 +2299,12 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
        unsigned int i, size;
        struct snd_ice1712_card_info * const *tbl, *c;
 
-       if (! modelname || ! *modelname) {
+       if (!modelname || !*modelname) {
                ice->eeprom.subvendor = 0;
                if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) != 0)
                        ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) |
-                               (snd_ice1712_read_i2c(ice, dev, 0x01) << 8) | 
-                               (snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | 
+                               (snd_ice1712_read_i2c(ice, dev, 0x01) << 8) |
+                               (snd_ice1712_read_i2c(ice, dev, 0x02) << 16) |
                                (snd_ice1712_read_i2c(ice, dev, 0x03) << 24);
                if (ice->eeprom.subvendor == 0 ||
                    ice->eeprom.subvendor == (unsigned int)-1) {
@@ -2318,12 +2321,12 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
        }
        for (tbl = card_tables; *tbl; tbl++) {
                for (c = *tbl; c->subvendor; c++) {
-                       if (modelname && c->model && ! strcmp(modelname, c->model)) {
+                       if (modelname && c->model && !strcmp(modelname, c->model)) {
                                printk(KERN_INFO "ice1712: Using board model %s\n", c->name);
                                ice->eeprom.subvendor = c->subvendor;
                        } else if (c->subvendor != ice->eeprom.subvendor)
                                continue;
-                       if (! c->eeprom_size || ! c->eeprom_data)
+                       if (!c->eeprom_size || !c->eeprom_data)
                                goto found;
                        /* if the EEPROM is given by the driver, use it */
                        snd_printdd("using the defined eeprom..\n");
@@ -2416,7 +2419,8 @@ int __devinit snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice)
        int err;
        struct snd_kcontrol *kctl;
 
-       snd_assert(ice->pcm_pro != NULL, return -EIO);
+       if (snd_BUG_ON(!ice->pcm_pro))
+               return -EIO;
        err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice));
        if (err < 0)
                return err;
@@ -2483,13 +2487,13 @@ static int __devinit snd_ice1712_build_controls(struct snd_ice1712 *ice)
 
 static int snd_ice1712_free(struct snd_ice1712 *ice)
 {
-       if (! ice->port)
+       if (!ice->port)
                goto __hw_end;
        /* mask all interrupts */
        outb(0xc0, ICEMT(ice, IRQ));
        outb(0xff, ICEREG(ice, IRQMASK));
        /* --- */
-      __hw_end:
+__hw_end:
        if (ice->irq >= 0)
                free_irq(ice->irq, ice);
 
@@ -2514,7 +2518,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
                                        int omni,
                                        int cs8427_timeout,
                                        int dxr_enable,
-                                       struct snd_ice1712 ** r_ice1712)
+                                       struct snd_ice1712 **r_ice1712)
 {
        struct snd_ice1712 *ice;
        int err;
@@ -2524,8 +2528,9 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
 
        *r_ice1712 = NULL;
 
-        /* enable PCI device */
-       if ((err = pci_enable_device(pci)) < 0)
+       /* enable PCI device */
+       err = pci_enable_device(pci);
+       if (err < 0)
                return err;
        /* check, if we can restrict PCI DMA transfers to 28 bits */
        if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
@@ -2569,7 +2574,8 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
        snd_ice1712_proc_init(ice);
        synchronize_irq(pci->irq);
 
-       if ((err = pci_request_regions(pci, "ICE1712")) < 0) {
+       err = pci_request_regions(pci, "ICE1712");
+       if (err < 0) {
                kfree(ice);
                pci_disable_device(pci);
                return err;
@@ -2585,7 +2591,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
                snd_ice1712_free(ice);
                return -EIO;
        }
-       
+
        ice->irq = pci->irq;
 
        if (snd_ice1712_read_eeprom(ice, modelname) < 0) {
@@ -2605,9 +2611,10 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
             ICEREG(ice, IRQMASK));
        outb(0x00, ICEMT(ice, IRQ));
 
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
+       if (err < 0) {
                snd_ice1712_free(ice);
-               return err;
+               return err;
        }
 
        snd_card_set_dev(card, &pci->dev);
@@ -2647,10 +2654,10 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
 
        strcpy(card->driver, "ICE1712");
        strcpy(card->shortname, "ICEnsemble ICE1712");
-       
-       if ((err = snd_ice1712_create(card, pci, model[dev], omni[dev],
-                                     cs8427_timeout[dev], dxr_enable[dev],
-                                     &ice)) < 0) {
+
+       err = snd_ice1712_create(card, pci, model[dev], omni[dev],
+               cs8427_timeout[dev], dxr_enable[dev], &ice);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
@@ -2662,7 +2669,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
                                if (c->driver) /* specific driver? */
                                        strcpy(card->driver, c->driver);
                                if (c->chip_init) {
-                                       if ((err = c->chip_init(ice)) < 0) {
+                                       err = c->chip_init(ice);
+                                       if (err < 0) {
                                                snd_card_free(card);
                                                return err;
                                        }
@@ -2674,47 +2682,52 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
        c = &no_matched;
  __found:
 
-       if ((err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL)) < 0) {
+       err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
-       
+
        if (ice_has_con_ac97(ice))
-               if ((err = snd_ice1712_pcm(ice, pcm_dev++, NULL)) < 0) {
+               err = snd_ice1712_pcm(ice, pcm_dev++, NULL);
+               if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
 
-       if ((err = snd_ice1712_ac97_mixer(ice)) < 0) {
+       err = snd_ice1712_ac97_mixer(ice);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
-       if ((err = snd_ice1712_build_controls(ice)) < 0) {
+       err = snd_ice1712_build_controls(ice);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        if (c->build_controls) {
-               if ((err = c->build_controls(ice)) < 0) {
+               err = c->build_controls(ice);
+               if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
        }
 
        if (ice_has_con_ac97(ice))
-               if ((err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL)) < 0) {
+               err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL);
+               if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
 
-       if (! c->no_mpu401) {
-               if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
-                                              ICEREG(ice, MPU1_CTRL),
-                                              (c->mpu401_1_info_flags |
-                                               MPU401_INFO_INTEGRATED),
-                                              ice->irq, 0,
-                                              &ice->rmidi[0])) < 0) {
+       if (!c->no_mpu401) {
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
+                       ICEREG(ice, MPU1_CTRL),
+                       (c->mpu401_1_info_flags | MPU401_INFO_INTEGRATED),
+                       ice->irq, 0, &ice->rmidi[0]);
+               if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
@@ -2726,12 +2739,12 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
 
                if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) {
                        /*  2nd port used  */
-                       if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
-                                                      ICEREG(ice, MPU2_CTRL),
-                                                      (c->mpu401_2_info_flags |
-                                                       MPU401_INFO_INTEGRATED),
-                                                      ice->irq, 0,
-                                                      &ice->rmidi[1])) < 0) {
+                       err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
+                               ICEREG(ice, MPU2_CTRL),
+                               (c->mpu401_2_info_flags | MPU401_INFO_INTEGRATED),
+                               ice->irq, 0, &ice->rmidi[1]);
+
+                       if (err < 0) {
                                snd_card_free(card);
                                return err;
                        }
@@ -2749,7 +2762,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, ice->port, ice->irq);
 
-       if ((err = snd_card_register(card)) < 0) {
+       err = snd_card_register(card);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
index 762fbd7a750710dec0ede3ee426f20cc70668b2f..fdae6deba16bc8df8e07690db8ee14d16b869168 100644 (file)
@@ -20,7 +20,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
  */
 
 #define ICEDS(ice, x) ((ice)->dmapath_port + ICE1712_DS_##x)
+
 #define ICE1712_DS_INTMASK             0x00    /* word - interrupt mask */
 #define ICE1712_DS_INTSTAT             0x02    /* word - interrupt status */
 #define ICE1712_DS_DATA                        0x04    /* dword - channel data */
 /*
  *  Consumer section channel registers
  */
+
 #define ICE1712_DSC_ADDR0              0x00    /* dword - base address 0 */
 #define ICE1712_DSC_COUNT0             0x01    /* word - count 0 */
 #define ICE1712_DSC_ADDR1              0x02    /* dword - base address 1 */
 #define ICE1712_DSC_RATE               0x05    /* dword - rate */
 #define ICE1712_DSC_VOLUME             0x06    /* word - volume control */
 
-/* 
+/*
  *  Professional multi-track direct control registers
  */
 
 
 
 /*
- *  
+ *
  */
 
 struct snd_ice1712;
@@ -253,12 +253,12 @@ enum {
        ICE_EEP1_ADC_ID2,
        ICE_EEP1_ADC_ID3
 };
-       
+
 #define ice_has_con_ac97(ice)  (!((ice)->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97))
 
 
 struct snd_ak4xxx_private {
-       unsigned int cif: 1;            /* CIF mode */
+       unsigned int cif:1;             /* CIF mode */
        unsigned char caddr;            /* C0 and C1 bits */
        unsigned int data_mask;         /* DATA gpio bit */
        unsigned int clk_mask;          /* CLK gpio bit */
@@ -306,11 +306,11 @@ struct snd_ice1712 {
        struct snd_pcm *pcm;
        struct snd_pcm *pcm_ds;
        struct snd_pcm *pcm_pro;
-        struct snd_pcm_substream *playback_con_substream;
-        struct snd_pcm_substream *playback_con_substream_ds[6];
-        struct snd_pcm_substream *capture_con_substream;
-        struct snd_pcm_substream *playback_pro_substream;
-        struct snd_pcm_substream *capture_pro_substream;
+       struct snd_pcm_substream *playback_con_substream;
+       struct snd_pcm_substream *playback_con_substream_ds[6];
+       struct snd_pcm_substream *capture_con_substream;
+       struct snd_pcm_substream *playback_pro_substream;
+       struct snd_pcm_substream *capture_pro_substream;
        unsigned int playback_pro_size;
        unsigned int capture_pro_size;
        unsigned int playback_con_virt_addr[6];
@@ -326,15 +326,15 @@ struct snd_ice1712 {
        struct snd_ice1712_eeprom eeprom;
 
        unsigned int pro_volumes[20];
-       unsigned int omni: 1;           /* Delta Omni I/O */
-       unsigned int dxr_enable: 1;     /* Terratec DXR enable for DMX6FIRE */
-       unsigned int vt1724: 1;
-       unsigned int vt1720: 1;
-       unsigned int has_spdif: 1;      /* VT1720/4 - has SPDIF I/O */
-       unsigned int force_pdma4: 1;    /* VT1720/4 - PDMA4 as non-spdif */
-       unsigned int force_rdma1: 1;    /* VT1720/4 - RDMA1 as non-spdif */
-       unsigned int midi_output: 1;    /* VT1720/4: MIDI output triggered */
-       unsigned int midi_input: 1;     /* VT1720/4: MIDI input triggered */
+       unsigned int omni:1;            /* Delta Omni I/O */
+       unsigned int dxr_enable:1;      /* Terratec DXR enable for DMX6FIRE */
+       unsigned int vt1724:1;
+       unsigned int vt1720:1;
+       unsigned int has_spdif:1;       /* VT1720/4 - has SPDIF I/O */
+       unsigned int force_pdma4:1;     /* VT1720/4 - PDMA4 as non-spdif */
+       unsigned int force_rdma1:1;     /* VT1720/4 - RDMA1 as non-spdif */
+       unsigned int midi_output:1;     /* VT1720/4: MIDI output triggered */
+       unsigned int midi_input:1;      /* VT1720/4: MIDI input triggered */
        unsigned int num_total_dacs;    /* total DACs */
        unsigned int num_total_adcs;    /* total ADCs */
        unsigned int cur_rate;          /* current rate */
@@ -351,7 +351,7 @@ struct snd_ice1712 {
        struct snd_i2c_bus *i2c;                /* I2C bus */
        struct snd_i2c_device *cs8427;  /* CS8427 I2C device */
        unsigned int cs8427_timeout;    /* CS8427 reset timeout in HZ/100 */
-       
+
        struct ice1712_gpio {
                unsigned int direction;         /* current direction bits */
                unsigned int write_mask;        /* current mask bits */
@@ -455,7 +455,7 @@ static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
 {
        ice->gpio.direction &= ~mask;
        snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
-       return  (snd_ice1712_gpio_read(ice) & mask);
+       return  snd_ice1712_gpio_read(ice) & mask;
 }
 
 int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
@@ -467,13 +467,13 @@ int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice);
 
 int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr);
 
-static inline void snd_ice1712_write(struct snd_ice1712 * ice, u8 addr, u8 data)
+static inline void snd_ice1712_write(struct snd_ice1712 *ice, u8 addr, u8 data)
 {
        outb(addr, ICEREG(ice, INDEX));
        outb(data, ICEREG(ice, DATA));
 }
 
-static inline u8 snd_ice1712_read(struct snd_ice1712 * ice, u8 addr)
+static inline u8 snd_ice1712_read(struct snd_ice1712 *ice, u8 addr)
 {
        outb(addr, ICEREG(ice, INDEX));
        return inb(ICEREG(ice, DATA));
@@ -491,7 +491,7 @@ struct snd_ice1712_card_info {
        char *driver;
        int (*chip_init)(struct snd_ice1712 *);
        int (*build_controls)(struct snd_ice1712 *);
-       unsigned int no_mpu401: 1;
+       unsigned int no_mpu401:1;
        unsigned int mpu401_1_info_flags;
        unsigned int mpu401_2_info_flags;
        const char *mpu401_1_name;
index e596d777d9dde630d12532c55a578937f8d5b2ee..1b3f11702713624b3cc5f344e598fcce7f5af70c 100644 (file)
@@ -20,9 +20,9 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -105,7 +105,7 @@ static unsigned int PRO_RATE_DEFAULT = 44100;
 /*
  *  Basic I/O
  */
+
 /*
  *  default rates, default clock routines
  */
@@ -198,7 +198,7 @@ static void snd_vt1724_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
 static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
 {
        outw(data, ICEREG1724(ice, GPIO_WRITE_MASK));
-       if (! ice->vt1720) /* VT1720 supports only 16 GPIO bits */
+       if (!ice->vt1720) /* VT1720 supports only 16 GPIO bits */
                outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22));
        inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */
 }
@@ -206,7 +206,7 @@ static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
 static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data)
 {
        outw(data, ICEREG1724(ice, GPIO_DATA));
-       if (! ice->vt1720)
+       if (!ice->vt1720)
                outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22));
        inw(ICEREG1724(ice, GPIO_DATA)); /* dummy read for pci-posting */
 }
@@ -214,7 +214,7 @@ static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data)
 static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice)
 {
        unsigned int data;
-       if (! ice->vt1720)
+       if (!ice->vt1720)
                data = (unsigned int)inb(ICEREG1724(ice, GPIO_DATA_22));
        else
                data = 0;
@@ -399,7 +399,7 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
                        break;
                }
 #endif
-               handled = 1;            
+               handled = 1;
                if (status & VT1724_IRQ_MPU_TX) {
                        spin_lock(&ice->reg_lock);
                        if (ice->midi_output)
@@ -468,8 +468,8 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
                        /* ought to really handle this properly */
                        if (mtstat & VT1724_MULTI_FIFO_ERR) {
                                unsigned char fstat = inb(ICEMT1724(ice, DMA_FIFO_ERR));
-                               outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR));      
-                               outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK));  
+                               outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR));
+                               outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK));
                                /* If I don't do this, I get machine lockup due to continual interrupts */
                        }
 
@@ -733,17 +733,17 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream)
        outl(substream->runtime->dma_addr, ICEMT1724(ice, PLAYBACK_ADDR));
 
        size = (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1;
-       // outl(size, ICEMT1724(ice, PLAYBACK_SIZE));
+       /* outl(size, ICEMT1724(ice, PLAYBACK_SIZE)); */
        outw(size, ICEMT1724(ice, PLAYBACK_SIZE));
        outb(size >> 16, ICEMT1724(ice, PLAYBACK_SIZE) + 2);
        size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
-       // outl(size, ICEMT1724(ice, PLAYBACK_COUNT));
+       /* outl(size, ICEMT1724(ice, PLAYBACK_COUNT)); */
        outw(size, ICEMT1724(ice, PLAYBACK_COUNT));
        outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2);
 
        spin_unlock_irq(&ice->reg_lock);
 
-       // printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream));
+       /* printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream)); */
        return 0;
 }
 
@@ -771,7 +771,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
        ptr = inl(ICEMT1724(ice, PLAYBACK_SIZE)) & 0xffffff;
        ptr = (ptr + 1) << 2;
        ptr = bytes_to_frames(substream->runtime, ptr);
-       if (! ptr)
+       if (!ptr)
                ;
        else if (ptr <= substream->runtime->buffer_size)
                ptr = substream->runtime->buffer_size - ptr;
@@ -815,7 +815,7 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr
        ptr = inw(ice->profi_port + reg->size);
        ptr = (ptr + 1) << 2;
        ptr = bytes_to_frames(substream->runtime, ptr);
-       if (! ptr)
+       if (!ptr)
                ;
        else if (ptr <= substream->runtime->buffer_size)
                ptr = substream->runtime->buffer_size - ptr;
@@ -842,8 +842,7 @@ static const struct vt1724_pcm_reg vt1724_capture_pro_reg = {
        .start = VT1724_RDMA0_START,
 };
 
-static const struct snd_pcm_hardware snd_vt1724_playback_pro =
-{
+static const struct snd_pcm_hardware snd_vt1724_playback_pro = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -861,8 +860,7 @@ static const struct snd_pcm_hardware snd_vt1724_playback_pro =
        .periods_max =          1024,
 };
 
-static const struct snd_pcm_hardware snd_vt1724_spdif =
-{
+static const struct snd_pcm_hardware snd_vt1724_spdif = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -883,8 +881,7 @@ static const struct snd_pcm_hardware snd_vt1724_spdif =
        .periods_max =          1024,
 };
 
-static const struct snd_pcm_hardware snd_vt1724_2ch_stereo =
-{
+static const struct snd_pcm_hardware snd_vt1724_2ch_stereo = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
@@ -942,7 +939,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-       int chs;
+       int chs, num_indeps;
 
        runtime->private_data = (void *)&vt1724_playback_pro_reg;
        ice->playback_pro_substream = substream;
@@ -952,7 +949,8 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
        set_rate_constraints(ice, substream);
        mutex_lock(&ice->open_mutex);
        /* calculate the currently available channels */
-       for (chs = 0; chs < 3; chs++) {
+       num_indeps = ice->num_total_dacs / 2 - 1;
+       for (chs = 0; chs < num_indeps; chs++) {
                if (ice->pcm_reserved[chs])
                        break;
        }
@@ -1029,7 +1027,7 @@ static struct snd_pcm_ops snd_vt1724_capture_pro_ops = {
        .pointer =      snd_vt1724_pcm_pointer,
 };
 
-static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 * ice, int device)
+static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device)
 {
        struct snd_pcm *pcm;
        int err;
@@ -1114,7 +1112,7 @@ static void update_spdif_rate(struct snd_ice1712 *ice, unsigned int rate)
 static int snd_vt1724_playback_spdif_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-       if (! ice->force_pdma4)
+       if (!ice->force_pdma4)
                update_spdif_rate(ice, substream->runtime->rate);
        return snd_vt1724_pcm_prepare(substream);
 }
@@ -1214,7 +1212,7 @@ static struct snd_pcm_ops snd_vt1724_capture_spdif_ops = {
 };
 
 
-static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device)
+static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device)
 {
        char *name;
        struct snd_pcm *pcm;
@@ -1233,7 +1231,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device)
                ice->has_spdif = 1;
        } else
                capt = 0;
-       if (! play && ! capt)
+       if (!play && !capt)
                return 0; /* no spdif device */
 
        if (ice->force_pdma4 || ice->force_rdma1)
@@ -1348,7 +1346,7 @@ static struct snd_pcm_ops snd_vt1724_playback_indep_ops = {
 };
 
 
-static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 * ice, int device)
+static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device)
 {
        struct snd_pcm *pcm;
        int play;
@@ -1383,11 +1381,11 @@ static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 * ice, int device)
  *  Mixer section
  */
 
-static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 * ice)
+static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 *ice)
 {
        int err;
 
-       if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) {
+       if (!(ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) {
                struct snd_ac97_bus *pbus;
                struct snd_ac97_template ac97;
                static struct snd_ac97_bus_ops ops = {
@@ -1400,11 +1398,13 @@ static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 * ice)
                mdelay(5); /* FIXME */
                outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
 
-               if ((err = snd_ac97_bus(ice->card, 0, &ops, NULL, &pbus)) < 0)
+               err = snd_ac97_bus(ice->card, 0, &ops, NULL, &pbus);
+               if (err < 0)
                        return err;
                memset(&ac97, 0, sizeof(ac97));
                ac97.private_data = ice;
-               if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0)
+               err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
+               if (err < 0)
                        printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
                else
                        return 0;
@@ -1425,7 +1425,7 @@ static inline unsigned int eeprom_triple(struct snd_ice1712 *ice, int idx)
                ((unsigned int)ice->eeprom.data[idx + 2] << 16);
 }
 
-static void snd_vt1724_proc_read(struct snd_info_entry *entry, 
+static void snd_vt1724_proc_read(struct snd_info_entry *entry,
                                 struct snd_info_buffer *buffer)
 {
        struct snd_ice1712 *ice = entry->private_data;
@@ -1467,11 +1467,11 @@ static void snd_vt1724_proc_read(struct snd_info_entry *entry,
                            idx, inb(ice->profi_port+idx));
 }
 
-static void __devinit snd_vt1724_proc_init(struct snd_ice1712 * ice)
+static void __devinit snd_vt1724_proc_init(struct snd_ice1712 *ice)
 {
        struct snd_info_entry *entry;
 
-       if (! snd_card_proc_new(ice->card, "ice1724", &entry))
+       if (!snd_card_proc_new(ice->card, "ice1724", &entry))
                snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read);
 }
 
@@ -1491,7 +1491,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       
+
        memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
        return 0;
 }
@@ -1606,13 +1606,13 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol,
        if (val != old)
                update_spdif_bits(ice, val);
        spin_unlock_irq(&ice->reg_lock);
-       return (val != old);
+       return val != old;
 }
 
 static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_default_get,
        .put =          snd_vt1724_spdif_default_put
@@ -1645,7 +1645,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_maskc_get,
 };
@@ -1654,7 +1654,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+       .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_maskp_get,
 };
@@ -1691,8 +1691,8 @@ static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
        /* FIXME: the following conflict with IEC958 Playback Route */
-       // .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
-       .name =         SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
+       /* .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), */
+       .name =         SNDRV_CTL_NAME_IEC958("Output ", NONE, SWITCH),
        .info =         snd_vt1724_spdif_sw_info,
        .get =          snd_vt1724_spdif_sw_get,
        .put =          snd_vt1724_spdif_sw_put
@@ -1712,7 +1712,7 @@ int snd_vt1724_gpio_get(struct snd_kcontrol *kcontrol,
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int shift = kcontrol->private_value & 0xff;
        int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
-       
+
        snd_ice1712_save_gpio_status(ice);
        ucontrol->value.integer.value[0] =
                (snd_ice1712_gpio_read(ice) & (1 << shift) ? 1 : 0) ^ invert;
@@ -1767,7 +1767,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned int i, rate;
-       
+
        spin_lock_irq(&ice->reg_lock);
        if (ice->is_spdif_master(ice)) {
                ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
@@ -1923,7 +1923,7 @@ static int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol,
                "H/W In 0", "H/W In 1", /* 1-2 */
                "IEC958 In L", "IEC958 In R", /* 3-4 */
        };
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 5;
@@ -1953,7 +1953,7 @@ static int get_route_val(struct snd_ice1712 *ice, int shift)
 
        val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
        val >>= shift;
-       val &= 7;       //we now have 3 bits per output
+       val &= 7; /* we now have 3 bits per output */
        eitem = xlate[val];
        if (eitem == 255) {
                snd_BUG();
@@ -2032,7 +2032,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata =
 
 static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+       .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
        .info = snd_vt1724_pro_route_info,
        .get = snd_vt1724_pro_route_spdif_get,
        .put = snd_vt1724_pro_route_spdif_put,
@@ -2055,7 +2055,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx;
-       
+
        spin_lock_irq(&ice->reg_lock);
        for (idx = 0; idx < 22; idx++) {
                outb(idx, ICEMT1724(ice, MONITOR_PEAKINDEX));
@@ -2082,7 +2082,7 @@ static struct snd_ice1712_card_info no_matched __devinitdata;
 
 static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
        snd_vt1724_revo_cards,
-       snd_vt1724_amp_cards, 
+       snd_vt1724_amp_cards,
        snd_vt1724_aureon_cards,
        snd_vt1720_mobo_cards,
        snd_vt1720_pontis_cards,
@@ -2120,7 +2120,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
        wait_i2c_busy(ice);
        val = inb(ICEREG1724(ice, I2C_DATA));
        mutex_unlock(&ice->i2c_mutex);
-       //printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
+       /* printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); */
        return val;
 }
 
@@ -2129,7 +2129,7 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
 {
        mutex_lock(&ice->i2c_mutex);
        wait_i2c_busy(ice);
-       //printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
+       /* printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); */
        outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
        outb(data, ICEREG1724(ice, I2C_DATA));
        outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
@@ -2144,13 +2144,13 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
        unsigned int i, size;
        struct snd_ice1712_card_info * const *tbl, *c;
 
-       if (! modelname || ! *modelname) {
+       if (!modelname || !*modelname) {
                ice->eeprom.subvendor = 0;
                if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) != 0)
                        ice->eeprom.subvendor =
                                (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
-                               (snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | 
-                               (snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | 
+                               (snd_vt1724_read_i2c(ice, dev, 0x01) << 8) |
+                               (snd_vt1724_read_i2c(ice, dev, 0x02) << 16) |
                                (snd_vt1724_read_i2c(ice, dev, 0x03) << 24);
                if (ice->eeprom.subvendor == 0 ||
                    ice->eeprom.subvendor == (unsigned int)-1) {
@@ -2173,13 +2173,13 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
        for (tbl = card_tables; *tbl; tbl++) {
                for (c = *tbl; c->subvendor; c++) {
                        if (modelname && c->model &&
-                           ! strcmp(modelname, c->model)) {
+                           !strcmp(modelname, c->model)) {
                                printk(KERN_INFO "ice1724: Using board model %s\n",
                                       c->name);
                                ice->eeprom.subvendor = c->subvendor;
                        } else if (c->subvendor != ice->eeprom.subvendor)
                                continue;
-                       if (! c->eeprom_size || ! c->eeprom_data)
+                       if (!c->eeprom_size || !c->eeprom_data)
                                goto found;
                        /* if the EEPROM is given by the driver, use it */
                        snd_printdd("using the defined eeprom..\n");
@@ -2250,7 +2250,8 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice)
        int err;
        struct snd_kcontrol *kctl;
 
-       snd_assert(ice->pcm != NULL, return -EIO);
+       if (snd_BUG_ON(!ice->pcm))
+               return -EIO;
 
        err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice));
        if (err < 0)
@@ -2320,13 +2321,13 @@ static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice)
 
 static int snd_vt1724_free(struct snd_ice1712 *ice)
 {
-       if (! ice->port)
+       if (!ice->port)
                goto __hw_end;
        /* mask all interrupts */
        outb(0xff, ICEMT1724(ice, DMA_INT_MASK));
        outb(0xff, ICEREG1724(ice, IRQMASK));
        /* --- */
-      __hw_end:
+__hw_end:
        if (ice->irq >= 0)
                free_irq(ice->irq, ice);
        pci_release_regions(ice->pci);
@@ -2346,7 +2347,7 @@ static int snd_vt1724_dev_free(struct snd_device *device)
 static int __devinit snd_vt1724_create(struct snd_card *card,
                                       struct pci_dev *pci,
                                       const char *modelname,
-                                      struct snd_ice1712 ** r_ice1712)
+                                      struct snd_ice1712 **r_ice1712)
 {
        struct snd_ice1712 *ice;
        int err;
@@ -2357,8 +2358,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
 
        *r_ice1712 = NULL;
 
-        /* enable PCI device */
-       if ((err = pci_enable_device(pci)) < 0)
+       /* enable PCI device */
+       err = pci_enable_device(pci);
+       if (err < 0)
                return err;
 
        ice = kzalloc(sizeof(*ice), GFP_KERNEL);
@@ -2382,7 +2384,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
        snd_vt1724_proc_init(ice);
        synchronize_irq(pci->irq);
 
-       if ((err = pci_request_regions(pci, "ICE1724")) < 0) {
+       err = pci_request_regions(pci, "ICE1724");
+       if (err < 0) {
                kfree(ice);
                pci_disable_device(pci);
                return err;
@@ -2417,9 +2420,10 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
         */
        outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
 
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
+       if (err < 0) {
                snd_vt1724_free(ice);
-               return err;
+               return err;
        }
 
        snd_card_set_dev(card, &pci->dev);
@@ -2457,8 +2461,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
 
        strcpy(card->driver, "ICE1724");
        strcpy(card->shortname, "ICEnsemble ICE1724");
-       
-       if ((err = snd_vt1724_create(card, pci, model[dev], &ice)) < 0) {
+
+       err = snd_vt1724_create(card, pci, model[dev], &ice);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
@@ -2470,7 +2475,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
                                if (c->driver) /* specific driver? */
                                        strcpy(card->driver, c->driver);
                                if (c->chip_init) {
-                                       if ((err = c->chip_init(ice)) < 0) {
+                                       err = c->chip_init(ice);
+                                       if (err < 0) {
                                                snd_card_free(card);
                                                return err;
                                        }
@@ -2480,15 +2486,15 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
                }
        }
        c = &no_matched;
- __found:
-       /*
-        * VT1724 has separate DMAs for the analog and the SPDIF streams while
-        * ICE1712 has only one for both (mixed up).
-        *
-        * Confusingly the analog PCM is named "professional" here because it
-        * was called so in ice1712 driver, and vt1724 driver is derived from
-        * ice1712 driver.
-        */
+__found:
+       /*
+       * VT1724 has separate DMAs for the analog and the SPDIF streams while
+       * ICE1712 has only one for both (mixed up).
+       *
+       * Confusingly the analog PCM is named "professional" here because it
+       * was called so in ice1712 driver, and vt1724 driver is derived from
+       * ice1712 driver.
+       */
        ice->pro_rate_default = PRO_RATE_DEFAULT;
        if (!ice->is_spdif_master)
                ice->is_spdif_master = stdclock_is_spdif_master;
@@ -2503,46 +2509,53 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
        if (!ice->hw_rates)
                set_std_hw_rates(ice);
 
-       if ((err = snd_vt1724_pcm_profi(ice, pcm_dev++)) < 0) {
+       err = snd_vt1724_pcm_profi(ice, pcm_dev++);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
-       
-       if ((err = snd_vt1724_pcm_spdif(ice, pcm_dev++)) < 0) {
+
+       err = snd_vt1724_pcm_spdif(ice, pcm_dev++);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
-       
-       if ((err = snd_vt1724_pcm_indep(ice, pcm_dev++)) < 0) {
+
+       err = snd_vt1724_pcm_indep(ice, pcm_dev++);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
-       if ((err = snd_vt1724_ac97_mixer(ice)) < 0) {
+       err = snd_vt1724_ac97_mixer(ice);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
-       if ((err = snd_vt1724_build_controls(ice)) < 0) {
+       err = snd_vt1724_build_controls(ice);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        if (ice->pcm && ice->has_spdif) { /* has SPDIF I/O */
-               if ((err = snd_vt1724_spdif_build_controls(ice)) < 0) {
+               err = snd_vt1724_spdif_build_controls(ice);
+               if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
        }
 
        if (c->build_controls) {
-               if ((err = c->build_controls(ice)) < 0) {
+               err = c->build_controls(ice);
+               if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
        }
 
-       if (! c->no_mpu401) {
+       if (!c->no_mpu401) {
                if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
                        struct snd_rawmidi *rmidi;
 
@@ -2574,7 +2587,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, ice->port, ice->irq);
 
-       if ((err = snd_card_register(card)) < 0) {
+       err = snd_card_register(card);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
index b4e0c16852a6a07ab4b35fe28c14d92466160ba2..c51659b9caf6cfd5fa44a47337c664b729246194 100644 (file)
@@ -21,7 +21,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 #include <asm/io.h>
 #include <linux/delay.h>
 #include "ice1712.h"
 #include "envy24ht.h"
 #include "juli.h"
+
 struct juli_spec {
        struct ak4114 *ak4114;
-       unsigned int analog: 1;
+       unsigned int analog:1;
 };
 
 /*
@@ -160,14 +161,17 @@ static int get_gpio_val(int rate)
        return 0;
 }
 
-static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val)
+static void juli_ak4114_write(void *private_data, unsigned char reg,
+                               unsigned char val)
 {
-       snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR, reg, val);
+       snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR,
+                               reg, val);
 }
-        
+
 static unsigned char juli_ak4114_read(void *private_data, unsigned char reg)
 {
-       return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR, reg);
+       return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data,
+                                       AK4114_ADDR, reg);
 }
 
 /*
@@ -175,7 +179,7 @@ static unsigned char juli_ak4114_read(void *private_data, unsigned char reg)
  * to the external rate
  */
 static void juli_spdif_in_open(struct snd_ice1712 *ice,
-                              struct snd_pcm_substream *substream)
+                               struct snd_pcm_substream *substream)
 {
        struct juli_spec *spec = ice->spec;
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -208,7 +212,8 @@ static void juli_akm_write(struct snd_akm4xxx *ak, int chip,
 {
        struct snd_ice1712 *ice = ak->private_data[0];
         
-       snd_assert(chip == 0, return);
+       if (snd_BUG_ON(chip))
+               return;
        snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data);
 }
 
@@ -571,10 +576,12 @@ static void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0,
 static int __devinit juli_init(struct snd_ice1712 *ice)
 {
        static const unsigned char ak4114_init_vals[] = {
-               /* AK4117_REG_PWRDN */  AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+               /* AK4117_REG_PWRDN */  AK4114_RST | AK4114_PWN |
+                                       AK4114_OCKS0 | AK4114_OCKS1,
                /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S,
                /* AK4114_REG_IO0 */    AK4114_TX1E,
-               /* AK4114_REG_IO1 */    AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+               /* AK4114_REG_IO1 */    AK4114_EFH_1024 | AK4114_DIT |
+                                       AK4114_IPS(1),
                /* AK4114_REG_INT0_MASK */ 0,
                /* AK4114_REG_INT1_MASK */ 0
        };
@@ -604,12 +611,14 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
        spec->ak4114->check_flags = 0;
 
 #if 0
-        /* it seems that the analog doughter board detection does not work
-           reliably, so force the analog flag; it should be very rare
-           to use Juli@ without the analog doughter board */
+/*
+ * it seems that the analog doughter board detection does not work reliably, so
+ * force the analog flag; it should be very rare (if ever) to come at Juli@
+ * used without the analog daughter board
+ */
        spec->analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1;
 #else
-        spec->analog = 1;
+       spec->analog = 1;
 #endif
 
        if (spec->analog) {
@@ -617,14 +626,16 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
                ice->num_total_dacs = 2;
                ice->num_total_adcs = 2;
 
-               ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-               if (! ak)
+               ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+               ak = ice->akm;
+               if (!ak)
                        return -ENOMEM;
                ice->akm_codecs = 1;
-               if ((err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice)) < 0)
+               err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice);
+               if (err < 0)
                        return err;
        }
-       
+
        /* juli is clocked by Xilinx array */
        ice->hw_rates = &juli_rates_info;
        ice->is_spdif_master = juli_is_spdif_master;
index 5a158b73dcaa2050211bf55291d3de67b0621ebd..de29be8c96574e8bd89eacf81b9aee5eb8a51518 100644 (file)
  */
 
 /* PHASE 22 overview:
- *   Audio controller: VIA Envy24HT-S (slightly trimmed down version of Envy24HT)
+ *   Audio controller: VIA Envy24HT-S (slightly trimmed down Envy24HT, 4in/4out)
  *   Analog chip: AK4524 (partially via Philip's 74HCT125)
- *   Digital receiver: CS8414-CS (not supported in this release)
+ *   Digital receiver: CS8414-CS (supported in this release)
+ *             PHASE 22 revision 2.0 and Terrasoniq/Musonik TS22PCI have CS8416
+ *             (support status unknown, please test and report)
  *
  *   Envy connects to AK4524
  *     - CS directly from GPIO 10
  *     - CCLK via 74HCT125's gate #4 from GPIO 4
  *     - CDTI via 74HCT125's gate #2 from GPIO 5
- *             CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3
+ *             CDTI may be completely blocked by 74HCT125's gate #1
+ *             controlled by GPIO 3
+ */
+
+/* PHASE 28 overview:
+ *   Audio controller: VIA Envy24HT (full untrimmed version, 4in/8out)
+ *   Analog chip: WM8770 (8 channel 192k DAC, 2 channel 96k ADC)
+ *   Digital receiver: CS8414-CS (supported in this release)
  */
 
 #include <asm/io.h>
@@ -77,18 +86,18 @@ struct phase28_spec {
  * Computed as 20 * Log10(255 / x)
  */
 static const unsigned char wm_vol[256] = {
-       127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
-       23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
-       17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
-       13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
-       11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
-       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
-       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-       5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
-       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0
+       127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24,
+       24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18,
+       17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,
+       14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
+       11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5,
+       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+       4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 #define WM_VOL_MAX     (sizeof(wm_vol) - 1)
@@ -117,26 +126,31 @@ static int __devinit phase22_init(struct snd_ice1712 *ice)
        struct snd_akm4xxx *ak;
        int err;
 
-       // Configure DAC/ADC description for generic part of ice1724
+       /* Configure DAC/ADC description for generic part of ice1724 */
        switch (ice->eeprom.subvendor) {
        case VT1724_SUBDEVICE_PHASE22:
+       case VT1724_SUBDEVICE_TS22:
                ice->num_total_dacs = 2;
                ice->num_total_adcs = 2;
-               ice->vt1720 = 1; // Envy24HT-S have 16 bit wide GPIO
+               ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */
                break;
        default:
                snd_BUG();
                return -EINVAL;
        }
 
-       // Initialize analog chips
-       ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-       if (! ak)
+       /* Initialize analog chips */
+       ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       ak = ice->akm;
+       if (!ak)
                return -ENOMEM;
        ice->akm_codecs = 1;
        switch (ice->eeprom.subvendor) {
        case VT1724_SUBDEVICE_PHASE22:
-               if ((err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, &akm_phase22_priv, ice)) < 0)
+       case VT1724_SUBDEVICE_TS22:
+               err = snd_ice1712_akm4xxx_init(ak, &akm_phase22,
+                                               &akm_phase22_priv, ice);
+               if (err < 0)
                        return err;
                break;
        }
@@ -150,6 +164,7 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
 
        switch (ice->eeprom.subvendor) {
        case VT1724_SUBDEVICE_PHASE22:
+       case VT1724_SUBDEVICE_TS22:
                err = snd_ice1712_akm4xxx_build_controls(ice);
                if (err < 0)
                        return err;
@@ -158,9 +173,10 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
 }
 
 static unsigned char phase22_eeprom[] __devinitdata = {
-       [ICE_EEP2_SYSCONF]     = 0x00,  /* 1xADC, 1xDACs */
+       [ICE_EEP2_SYSCONF]     = 0x28,  /* clock 512, mpu 401,
+                                       spdif-in/1xADC, 1xDACs */
        [ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
-       [ICE_EEP2_I2S]         = 0xf8,  /* vol, 96k, 24bit */
+       [ICE_EEP2_I2S]         = 0xf0,  /* vol, 96k, 24bit */
        [ICE_EEP2_SPDIF]       = 0xc3,  /* out-en, out-int, spdif-in */
        [ICE_EEP2_GPIO_DIR]    = 0xff,
        [ICE_EEP2_GPIO_DIR1]   = 0xff,
@@ -174,7 +190,8 @@ static unsigned char phase22_eeprom[] __devinitdata = {
 };
 
 static unsigned char phase28_eeprom[] __devinitdata = {
-       [ICE_EEP2_SYSCONF]     = 0x0b,  /* clock 512, spdif-in/ADC, 4DACs */
+       [ICE_EEP2_SYSCONF]     = 0x2b,  /* clock 512, mpu401,
+                                       spdif-in/1xADC, 4xDACs */
        [ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
        [ICE_EEP2_I2S]         = 0xfc,  /* vol, 96k, 24bit, 192k */
        [ICE_EEP2_SPDIF]       = 0xc3,  /* out-en, out-int, spdif-in */
@@ -192,15 +209,16 @@ static unsigned char phase28_eeprom[] __devinitdata = {
 /*
  * write data in the SPI mode
  */
-static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
+static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs,
+                               unsigned int data, int bits)
 {
        unsigned int tmp;
        int i;
 
        tmp = snd_ice1712_gpio_read(ice);
 
-       snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK|
-                                        PHASE28_WM_CS));
+       snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|
+                                       PHASE28_SPI_CLK|PHASE28_WM_CS));
        tmp |= PHASE28_WM_RW;
        tmp &= ~cs;
        snd_ice1712_gpio_write(ice, tmp);
@@ -259,14 +277,16 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
        ice->akm[0].images[reg + 1] = val;
 }
 
-static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
+static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
+                       unsigned short vol, unsigned short master)
 {
        unsigned char nvol;
 
        if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
                nvol = 0;
        else
-               nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
+               nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) *
+                       (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
 
        wm_put(ice, index, nvol);
        wm_put_nocache(ice, index, 0x180 | nvol);
@@ -277,17 +297,20 @@ static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned sho
  */
 #define wm_pcm_mute_info       snd_ctl_boolean_mono_info
 
-static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
        mutex_lock(&ice->gpio_mutex);
-       ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
+       ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?
+                                               0 : 1;
        mutex_unlock(&ice->gpio_mutex);
        return 0;
 }
 
-static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned short nval, oval;
@@ -296,7 +319,8 @@ static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
        snd_ice1712_save_gpio_status(ice);
        oval = wm_get(ice, WM_MUTE);
        nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
-       if ((change = (nval != oval)))
+       change = (nval != oval);
+       if (change)
                wm_put(ice, WM_MUTE, nval);
        snd_ice1712_restore_gpio_status(ice);
 
@@ -306,7 +330,8 @@ static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
 /*
  * Master volume attenuation mixer control
  */
-static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 2;
@@ -315,17 +340,20 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
        return 0;
 }
 
-static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
        int i;
-       for (i=0; i<2; i++)
-               ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE;
+       for (i = 0; i < 2; i++)
+               ucontrol->value.integer.value[i] = spec->master[i] &
+                                                       ~WM_VOL_MUTE;
        return 0;
 }
 
-static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -355,38 +383,38 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
 {
        static const unsigned short wm_inits_phase28[] = {
                /* These come first to reduce init pop noise */
-               0x1b, 0x044,            /* ADC Mux (AC'97 source) */
-               0x1c, 0x00B,            /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
-               0x1d, 0x009,            /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
-
-               0x18, 0x000,            /* All power-up */
-
-               0x16, 0x122,            /* I2S, normal polarity, 24bit */
-               0x17, 0x022,            /* 256fs, slave mode */
-               0x00, 0,                /* DAC1 analog mute */
-               0x01, 0,                /* DAC2 analog mute */
-               0x02, 0,                /* DAC3 analog mute */
-               0x03, 0,                /* DAC4 analog mute */
-               0x04, 0,                /* DAC5 analog mute */
-               0x05, 0,                /* DAC6 analog mute */
-               0x06, 0,                /* DAC7 analog mute */
-               0x07, 0,                /* DAC8 analog mute */
-               0x08, 0x100,            /* master analog mute */
-               0x09, 0xff,             /* DAC1 digital full */
-               0x0a, 0xff,             /* DAC2 digital full */
-               0x0b, 0xff,             /* DAC3 digital full */
-               0x0c, 0xff,             /* DAC4 digital full */
-               0x0d, 0xff,             /* DAC5 digital full */
-               0x0e, 0xff,             /* DAC6 digital full */
-               0x0f, 0xff,             /* DAC7 digital full */
-               0x10, 0xff,             /* DAC8 digital full */
-               0x11, 0x1ff,            /* master digital full */
-               0x12, 0x000,            /* phase normal */
-               0x13, 0x090,            /* unmute DAC L/R */
-               0x14, 0x000,            /* all unmute */
-               0x15, 0x000,            /* no deemphasis, no ZFLG */
-               0x19, 0x000,            /* -12dB ADC/L */
-               0x1a, 0x000,            /* -12dB ADC/R */
+               0x1b, 0x044,    /* ADC Mux (AC'97 source) */
+               0x1c, 0x00B,    /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
+               0x1d, 0x009,    /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
+
+               0x18, 0x000,    /* All power-up */
+
+               0x16, 0x122,    /* I2S, normal polarity, 24bit */
+               0x17, 0x022,    /* 256fs, slave mode */
+               0x00, 0,        /* DAC1 analog mute */
+               0x01, 0,        /* DAC2 analog mute */
+               0x02, 0,        /* DAC3 analog mute */
+               0x03, 0,        /* DAC4 analog mute */
+               0x04, 0,        /* DAC5 analog mute */
+               0x05, 0,        /* DAC6 analog mute */
+               0x06, 0,        /* DAC7 analog mute */
+               0x07, 0,        /* DAC8 analog mute */
+               0x08, 0x100,    /* master analog mute */
+               0x09, 0xff,     /* DAC1 digital full */
+               0x0a, 0xff,     /* DAC2 digital full */
+               0x0b, 0xff,     /* DAC3 digital full */
+               0x0c, 0xff,     /* DAC4 digital full */
+               0x0d, 0xff,     /* DAC5 digital full */
+               0x0e, 0xff,     /* DAC6 digital full */
+               0x0f, 0xff,     /* DAC7 digital full */
+               0x10, 0xff,     /* DAC8 digital full */
+               0x11, 0x1ff,    /* master digital full */
+               0x12, 0x000,    /* phase normal */
+               0x13, 0x090,    /* unmute DAC L/R */
+               0x14, 0x000,    /* all unmute */
+               0x15, 0x000,    /* no deemphasis, no ZFLG */
+               0x19, 0x000,    /* -12dB ADC/L */
+               0x1a, 0x000,    /* -12dB ADC/R */
                (unsigned short)-1
        };
 
@@ -404,17 +432,19 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
                return -ENOMEM;
        ice->spec = spec;
 
-       // Initialize analog chips
-       ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       /* Initialize analog chips */
+       ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       ak = ice->akm;
        if (!ak)
                return -ENOMEM;
        ice->akm_codecs = 1;
 
-       snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
+       snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */
 
        /* reset the wm codec as the SPI mode */
        snd_ice1712_save_gpio_status(ice);
-       snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL));
+       snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|
+                                       PHASE28_HP_SEL));
 
        tmp = snd_ice1712_gpio_read(ice);
        tmp &= ~PHASE28_WM_RESET;
@@ -446,7 +476,8 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
 /*
  * DAC volume attenuation mixer control
  */
-static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int wm_vol_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
 {
        int voices = kcontrol->private_value >> 8;
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -456,7 +487,8 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *
        return 0;
 }
 
-static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_vol_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -470,7 +502,8 @@ static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *
        return 0;
 }
 
-static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_vol_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -501,7 +534,8 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *
 /*
  * WM8770 mute control
  */
-static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
+static int wm_mute_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo) {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        uinfo->count = kcontrol->private_value >> 8;
        uinfo->value.integer.min = 0;
@@ -509,7 +543,8 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info
        return 0;
 }
 
-static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_mute_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -524,7 +559,8 @@ static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
        return 0;
 }
 
-static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_mute_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -539,9 +575,10 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
                if (ucontrol->value.integer.value[i] != val) {
                        spec->vol[ofs + i] &= ~WM_VOL_MUTE;
                        spec->vol[ofs + i] |=
-                               ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
+                               ucontrol->value.integer.value[i] ? 0 :
+                               WM_VOL_MUTE;
                        wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
-                                  spec->master[i]);
+                                       spec->master[i]);
                        change = 1;
                }
        }
@@ -555,7 +592,8 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
  */
 #define wm_master_mute_info            snd_ctl_boolean_stereo_info
 
-static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_mute_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -567,7 +605,8 @@ static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
        return 0;
 }
 
-static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_master_mute_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        struct phase28_spec *spec = ice->spec;
@@ -580,11 +619,12 @@ static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
                        int dac;
                        spec->master[i] &= ~WM_VOL_MUTE;
                        spec->master[i] |=
-                               ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
+                               ucontrol->value.integer.value[i] ? 0 :
+                               WM_VOL_MUTE;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
-                                          spec->vol[dac + i],
-                                          spec->master[i]);
+                                               spec->vol[dac + i],
+                                               spec->master[i]);
                        change = 1;
                }
        }
@@ -597,7 +637,8 @@ static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 #define PCM_0dB 0xff
 #define PCM_RES 128    /* -64dB */
 #define PCM_MIN (PCM_0dB - PCM_RES)
-static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
@@ -606,7 +647,8 @@ static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_in
        return 0;
 }
 
-static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned short val;
@@ -619,7 +661,8 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
        return 0;
 }
 
-static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned short ovol, nvol;
@@ -633,7 +676,8 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
        ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
        if (ovol != nvol) {
                wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
-               wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
+               /* update */
+               wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100);
                change = 1;
        }
        snd_ice1712_restore_gpio_status(ice);
@@ -645,18 +689,22 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
  */
 #define phase28_deemp_info     snd_ctl_boolean_mono_info
 
-static int phase28_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_deemp_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
+       ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) ==
+                                               0xf;
        return 0;
 }
 
-static int phase28_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_deemp_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int temp, temp2;
-       temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
+       temp = wm_get(ice, WM_DAC_CTRL2);
+       temp2 = temp;
        if (ucontrol->value.integer.value[0])
                temp |= 0xf;
        else
@@ -671,7 +719,8 @@ static int phase28_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
 /*
  * ADC Oversampling
  */
-static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
+static int phase28_oversampling_info(struct snd_kcontrol *k,
+                                       struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[2] = { "128x", "64x" };
 
@@ -680,25 +729,31 @@ static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem
        uinfo->value.enumerated.items = 2;
 
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items -
+                                               1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
 
-        return 0;
+       return 0;
 }
 
-static int phase28_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
+       ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) ==
+                                               0x8;
        return 0;
 }
 
-static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int phase28_oversampling_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        int temp, temp2;
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-       temp2 = temp = wm_get(ice, WM_MASTER);
+       temp = wm_get(ice, WM_MASTER);
+       temp2 = temp;
 
        if (ucontrol->value.enumerated.item[0])
                temp |= 0x8;
@@ -871,13 +926,16 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice)
 
        counts = ARRAY_SIZE(phase28_dac_controls);
        for (i = 0; i < counts; i++) {
-               err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice));
+               err = snd_ctl_add(ice->card,
+                                       snd_ctl_new1(&phase28_dac_controls[i],
+                                                       ice));
                if (err < 0)
                        return err;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
-               err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
+               err = snd_ctl_add(ice->card,
+                                       snd_ctl_new1(&wm_controls[i], ice));
                if (err < 0)
                        return err;
        }
@@ -904,5 +962,14 @@ struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
                .eeprom_size = sizeof(phase28_eeprom),
                .eeprom_data = phase28_eeprom,
        },
+       {
+               .subvendor = VT1724_SUBDEVICE_TS22,
+               .name = "Terrasoniq TS22 PCI",
+               .model = "TS22",
+               .chip_init = phase22_init,
+               .build_controls = phase22_add_controls,
+               .eeprom_size = sizeof(phase22_eeprom),
+               .eeprom_data = phase22_eeprom,
+       },
        { } /* terminator */
 };
index 13e841b554887a8c6b8ae9eac8ff3d17c762087c..7fc22d9d442fc47e0c61d6c6de78a8cefd26071a 100644 (file)
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
-#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"\
-                          "{Terratec,Phase 28},"
+#define PHASE_DEVICE_DESC      "{Terratec,Phase 22},"\
+                               "{Terratec,Phase 28},"\
+                               "{Terrasoniq,TS22},"
 
 #define VT1724_SUBDEVICE_PHASE22       0x3b155011
 #define VT1724_SUBDEVICE_PHASE28       0x3b154911
+#define VT1724_SUBDEVICE_TS22          0x3b157b11
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
index 203cdc1bf8da3d99d3f1b6e23668c59049568ca6..6bc3f91b728149ef7ab180856bcfd46b6ef8397e 100644 (file)
@@ -43,7 +43,8 @@
 /* WM8776 registers */
 #define WM_HP_ATTEN_L          0x00    /* headphone left attenuation */
 #define WM_HP_ATTEN_R          0x01    /* headphone left attenuation */
-#define WM_HP_MASTER           0x02    /* headphone master (both channels), override LLR */
+#define WM_HP_MASTER           0x02    /* headphone master (both channels) */
+                                       /* override LLR */
 #define WM_DAC_ATTEN_L         0x03    /* digital left attenuation */
 #define WM_DAC_ATTEN_R         0x04
 #define WM_DAC_MASTER          0x05
@@ -740,7 +741,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
                WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */
                WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */
                WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */
-               // WM_DAC_MASTER,       0x0100, /* DAC master muted */
+               /* WM_DAC_MASTER,       0x0100, */      /* DAC master muted */
                WM_PHASE_SWAP,  0x0000, /* phase normal */
                WM_DAC_CTRL2,   0x0000, /* no deemphasis, no ZFLG */
                WM_ADC_ATTEN_L, 0x0000, /* ADC muted */
index 4d2631434dc81bdb83720ea717c1d6a613fdc51d..b508bb360b97d1499eea3902cade76ff83f4b3f1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
  *
- *   Lowlevel functions for M-Audio Revolution 7.1
+ *   Lowlevel functions for M-Audio Audiophile 192, Revolution 7.1 and 5.1
  *
  *     Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
  *
@@ -48,7 +48,7 @@ static void revo_i2s_mclk_changed(struct snd_ice1712 *ice)
 }
 
 /*
- * change the rate of envy24HT, AK4355 and AK4381
+ * change the rate of Envy24HT, AK4355 and AK4381
  */
 static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
 {
@@ -83,8 +83,8 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
        tmp = snd_akm4xxx_get(ak, 0, reg);
        tmp &= ~(0x03 << shift);
        tmp |= dfs << shift;
-       // snd_akm4xxx_write(ak, 0, reg, tmp);
-       snd_akm4xxx_set(ak, 0, reg, tmp); /* the value is written in reset(0) */
+       /* snd_akm4xxx_write(ak, 0, reg, tmp); */
+       snd_akm4xxx_set(ak, 0, reg, tmp); /* value is written in reset(0) */
        snd_akm4xxx_reset(ak, 0);
 }
 
@@ -216,6 +216,7 @@ static const struct snd_akm4xxx_dac_channel revo51_dac[] = {
        AK_DAC("PCM Center Playback Volume", 1),
        AK_DAC("PCM LFE Playback Volume", 1),
        AK_DAC("PCM Rear Playback Volume", 2),
+       AK_DAC("PCM Headphone Volume", 2),
 };
 
 static const char *revo51_adc_input_names[] = {
@@ -279,7 +280,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
 
 static struct snd_akm4xxx akm_revo51 __devinitdata = {
        .type = SND_AK4358,
-       .num_dacs = 6,
+       .num_dacs = 8,
        .ops = {
                .set_rate_val = revo_set_rate_val
        },
@@ -508,7 +509,7 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
                ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed;
                break;
        case VT1724_SUBDEVICE_REVOLUTION51:
-               ice->num_total_dacs = 6;
+               ice->num_total_dacs = 8;
                ice->num_total_adcs = 2;
                break;
        case VT1724_SUBDEVICE_AUDIOPHILE192:
@@ -524,16 +525,20 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
        ak = ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
        if (! ak)
                return -ENOMEM;
-       ice->akm_codecs = 2;
        switch (ice->eeprom.subvendor) {
        case VT1724_SUBDEVICE_REVOLUTION71:
                ice->akm_codecs = 2;
-               if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0)
+               err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front,
+                                               &akm_revo_front_priv, ice);
+               if (err < 0)
                        return err;
-               if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0)
+               err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo_surround,
+                                               &akm_revo_surround_priv, ice);
+               if (err < 0)
                        return err;
                /* unmute all codecs */
-               snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+               snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+                                               VT1724_REVO_MUTE);
                break;
        case VT1724_SUBDEVICE_REVOLUTION51:
                ice->akm_codecs = 2;
index a08d17c7e6515f5ede5066097f712b89f2101448..5af9e84456d1c801be959f1053d01c4a6a57b3cc 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *     ALSA driver for ICEnsemble VT1724 (Envy24HT)
- *     
+ *
  *     Lowlevel functions for Ego Sys Waveterminal 192M
  *
  *             Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
  *             Some functions are taken from the Prodigy192 driver
  *             source
- *             
+ *
  *     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
  *     You should have received a copy of the GNU General Public License
  *     along with this program; if not, write to the Free Software
  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *     
- */    
+ *
+ */
 
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -39,9 +39,9 @@
 
 
 /*
- *     2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 
+ *     2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
  */
-static inline void stac9460_put(struct snd_ice1712 *ice, int reg, 
+static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
                                                unsigned char val)
 {
        snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
@@ -73,7 +73,7 @@ static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
 #define stac9460_dac_mute_info         snd_ctl_boolean_mono_info
 
 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char val;
@@ -88,14 +88,14 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
        }
        if (id < 6)
                val = stac9460_get(ice, idx);
-       else 
-               val = stac9460_2_get(ice,idx - 6);
+       else
+               val = stac9460_2_get(ice, idx - 6);
        ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
        return 0;
 }
 
 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char new, old;
@@ -105,8 +105,8 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
        if (kcontrol->private_value) {
                idx = STAC946X_MASTER_VOLUME;
                old = stac9460_get(ice, idx);
-               new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
-                                                       (old & ~0x80);
+               new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
+                                                       (old & ~0x80);
                change = (new != old);
                if (change) {
                        stac9460_put(ice, idx, new);
@@ -117,16 +117,16 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
                idx = id + STAC946X_LF_VOLUME;
                if (id < 6)
                        old = stac9460_get(ice, idx);
-               else 
+               else
                        old = stac9460_2_get(ice, idx - 6);
-               new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+               new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
                                                        (old & ~0x80);
                change = (new != old);
                if (change) {
                        if (id < 6)
-                               stac9460_put(ice, idx, new);
+                               stac9460_put(ice, idx, new);
                        else
-                               stac9460_2_put(ice, idx - 6, new);
+                               stac9460_2_put(ice, idx - 6, new);
                }
        }
        return change;
@@ -136,7 +136,7 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
  *     DAC volume attenuation mixer control
  */
 static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_info *uinfo)
+                               struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
@@ -146,7 +146,7 @@ static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
 }
 
 static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx, id;
@@ -161,14 +161,14 @@ static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
        }
        if (id < 6)
                vol = stac9460_get(ice, idx) & 0x7f;
-       else 
+       else
                vol = stac9460_2_get(ice, idx - 6) & 0x7f;
        ucontrol->value.integer.value[0] = 0x7f - vol;
        return 0;
 }
 
 static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx, id;
@@ -182,8 +182,8 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
                ovol = 0x7f - (tmp & 0x7f);
                change = (ovol != nvol);
                if (change) {
-                        stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
-                        stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+                       stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+                       stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
                }
        } else {
                id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
@@ -191,17 +191,17 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
                nvol = ucontrol->value.integer.value[0] & 0x7f;
                if (id < 6)
                        tmp = stac9460_get(ice, idx);
-               else 
+               else
                        tmp = stac9460_2_get(ice, idx - 6);
                ovol = 0x7f - (tmp & 0x7f);
                change = (ovol != nvol);
                if (change) {
                        if (id < 6)
                                stac9460_put(ice, idx, (0x7f - nvol) |
-                                                       (tmp & 0x80));
-                       else 
+                                                       (tmp & 0x80));
+                       else
                                stac9460_2_put(ice, idx-6, (0x7f - nvol) |
-                                                               (tmp & 0x80));
+                                                       (tmp & 0x80));
                }
        }
        return change;
@@ -213,12 +213,12 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
 #define stac9460_adc_mute_info         snd_ctl_boolean_stereo_info
 
 static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char val;
        int i, id;
-       
+
        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        if (id == 0) {
                for (i = 0; i < 2; ++i) {
@@ -235,20 +235,20 @@ static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
 }
 
 static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char new, old;
        int i, reg, id;
        int change;
-       
+
        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        if (id == 0) {
                for (i = 0; i < 2; ++i) {
                        reg = STAC946X_MIC_L_VOLUME + i;
                        old = stac9460_get(ice, reg);
                        new = (~ucontrol->value.integer.value[i]<<7&0x80) |
-                                                               (old&~0x80);
+                                                               (old&~0x80);
                        change = (new != old);
                        if (change)
                                stac9460_put(ice, reg, new);
@@ -258,7 +258,7 @@ static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
                        reg = STAC946X_MIC_L_VOLUME + i;
                        old = stac9460_2_get(ice, reg);
                        new = (~ucontrol->value.integer.value[i]<<7&0x80) |
-                                                               (old&~0x80);
+                                                               (old&~0x80);
                        change = (new != old);
                        if (change)
                                stac9460_2_put(ice, reg, new);
@@ -271,7 +271,7 @@ static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
  *ADC gain mixer control
  */
 static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_info *uinfo)
+                               struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 2;
@@ -281,12 +281,12 @@ static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
 }
 
 static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int i, reg, id;
        unsigned char vol;
-       
+
        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        if (id == 0) {
                for (i = 0; i < 2; ++i) {
@@ -305,13 +305,13 @@ static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
 }
 
 static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int i, reg, id;
        unsigned char ovol, nvol;
        int change;
-       
+
        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        if (id == 0) {
                for (i = 0; i < 2; ++i) {
@@ -321,7 +321,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
                        change = ((ovol & 0x0f) != nvol);
                        if (change)
                                stac9460_put(ice, reg, (0x0f - nvol) |
-                                                       (ovol & ~0x0f));
+                                                       (ovol & ~0x0f));
                }
        } else {
                for (i = 0; i < 2; ++i) {
@@ -331,7 +331,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
                        change = ((ovol & 0x0f) != nvol);
                        if (change)
                                stac9460_2_put(ice, reg, (0x0f - nvol) |
-                                                       (ovol & ~0x0f));
+                                                       (ovol & ~0x0f));
                }
        }
        return change;
@@ -344,23 +344,23 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
 #define stac9460_mic_sw_info           snd_ctl_boolean_mono_info
 
 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char val;
        int id;
-               
+
        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        if (id == 0)
-               val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+               val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
        else
-               val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+               val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
        ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
        return 0;
 }
 
 static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        unsigned char new, old;
@@ -368,16 +368,16 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
 
        id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        if (id == 0)
-               old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+               old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
        else
-               old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-       new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
+               old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+       new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
        change = (new != old);
        if (change) {
                if (id == 0)
-                       stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
+                       stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
                else
-                       stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
+                       stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
        }
        return change;
 }
@@ -443,7 +443,7 @@ static struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
                .get = stac9460_adc_vol_get,
                .put = stac9460_adc_vol_put,
 
-       }       
+       }
 };
 
 
@@ -470,7 +470,7 @@ static int __devinit wtm_init(struct snd_ice1712 *ice)
                (unsigned short)-1
        };
        unsigned short *p;
-               
+
        /*WTM 192M*/
        ice->num_total_dacs = 8;
        ice->num_total_adcs = 4;
index 03a394e442f18520c538763d12ea77b2d43a59e3..423c1a204c0bb9e1ee799aed303b8c7706c97fc9 100644 (file)
@@ -10,8 +10,8 @@
  */
 
 #define        AK4114_ADDR             0x20    /*S/PDIF receiver*/
-#define STAC9460_I2C_ADDR      0x54    /* ADC*2 | DAC*6 */     
-#define STAC9460_2_I2C_ADDR    0x56    /* ADC|DAC *2 */        
+#define STAC9460_I2C_ADDR      0x54    /* ADC*2 | DAC*6 */
+#define STAC9460_2_I2C_ADDR    0x56    /* ADC|DAC *2 */
 
 
 extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[];
index 048d99e25ab0f0010ea1f4c7a7a06b553e1449d6..c88d1eace1c475ac81ecb07fa8f3994a05c4d994 100644 (file)
@@ -59,6 +59,12 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
                "{SiS,SI7012},"
                "{NVidia,nForce Audio},"
                "{NVidia,nForce2 Audio},"
+               "{NVidia,nForce3 Audio},"
+               "{NVidia,MCP04},"
+               "{NVidia,MCP501},"
+               "{NVidia,CK804},"
+               "{NVidia,CK8},"
+               "{NVidia,CK8S},"
                "{AMD,AMD768},"
                "{AMD,AMD8111},"
                "{ALI,M5455}}");
@@ -77,7 +83,7 @@ MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
 module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard.");
 module_param(ac97_clock, int, 0444);
-MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
+MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = whitelist + auto-detect, 1 = force autodetect).");
 module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 module_param(buggy_semaphore, bool, 0444);
@@ -1955,6 +1961,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "Fujitsu S6210",        /* STAC9750/51 */
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x10cf,
+               .subdevice = 0x127d,
+               .name = "Fujitsu Lifebook P7010",
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x10cf,
                .subdevice = 0x127e,
@@ -2132,8 +2144,8 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
                                snd_intel8x0_codec_read_test(chip, codecs);
                                chip->ac97_sdin[codecs] =
                                        igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
-                               snd_assert(chip->ac97_sdin[codecs] < 3,
-                                          chip->ac97_sdin[codecs] = 0);
+                               if (snd_BUG_ON(chip->ac97_sdin[codecs] >= 3))
+                                       chip->ac97_sdin[codecs] = 0;
                        } else
                                chip->ac97_sdin[codecs] = i;
                        codecs++;
@@ -2686,6 +2698,28 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
        snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
 }
 
+static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = {
+       SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000),
+       SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100),
+       SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000),
+       SND_PCI_QUIRK(0x1043, 0x80f3, "AD1985", 48000),
+       { }     /* terminator */
+};
+
+static int __devinit intel8x0_in_clock_list(struct intel8x0 *chip)
+{
+       struct pci_dev *pci = chip->pci;
+       const struct snd_pci_quirk *wl;
+
+       wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list);
+       if (!wl)
+               return 0;
+       printk(KERN_INFO "intel8x0: white list rate for %04x:%04x is %i\n",
+              pci->subsystem_vendor, pci->subsystem_device, wl->value);
+       chip->ac97_bus->clock = wl->value;
+       return 1;
+}
+
 #ifdef CONFIG_PROC_FS
 static void snd_intel8x0_proc_read(struct snd_info_entry * entry,
                                   struct snd_info_buffer *buffer)
@@ -3081,8 +3115,14 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
                 "%s with %s at irq %i", card->shortname,
                 snd_ac97_get_short_name(chip->ac97[0]), chip->irq);
 
-       if (! ac97_clock)
-               intel8x0_measure_ac97_clock(chip);
+       if (ac97_clock == 0 || ac97_clock == 1) {
+               if (ac97_clock == 0) {
+                       if (intel8x0_in_clock_list(chip) == 0)
+                               intel8x0_measure_ac97_clock(chip);
+               } else {
+                       intel8x0_measure_ac97_clock(chip);
+               }
+       }
 
        if ((err = snd_card_register(card)) < 0) {
                snd_card_free(card);
index faf674e671aca3c1432cf4d04860bb69f210d5df..93449e464566c019a5a0a3c11677bd8b2654fc56 100644 (file)
@@ -306,7 +306,8 @@ static unsigned int get_ich_codec_bit(struct intel8x0m *chip, unsigned int codec
        static unsigned int codec_bit[3] = {
                ICH_PCR, ICH_SCR, ICH_TCR
        };
-       snd_assert(codec < 3, return ICH_PCR);
+       if (snd_BUG_ON(codec >= 3))
+               return ICH_PCR;
        return codec_bit[codec];
 }
 
index 4a44c0f20f7605ebb754089ed281da1e279e1a69..5f8006b4275019ddd475e55e0ea7c8238b514b47 100644 (file)
@@ -1281,7 +1281,8 @@ static int snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int coun
 
        K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_silence pos=%d offset=%d size=%d count=%d\n",
                                   pos, offset, size, count);
-       snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+       if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
+               return -EINVAL;
 
        for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
@@ -1306,7 +1307,8 @@ static int snd_korg1212_copy_to(struct snd_korg1212 *korg1212, void __user *dst,
 
        K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_to pos=%d offset=%d size=%d\n",
                                   pos, offset, size);
-       snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+       if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
+               return -EINVAL;
 
        for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
@@ -1336,7 +1338,8 @@ static int snd_korg1212_copy_from(struct snd_korg1212 *korg1212, void __user *sr
        K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_from pos=%d offset=%d size=%d count=%d\n",
                                   pos, offset, size, count);
 
-       snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+       if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
+               return -EINVAL;
 
        for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
index 0037be74fdea9d87aaa7c89bbadf11e45d4a899c..9ff3f9e34404c4fa4c9c0b9b46a3b503d3c2fb03 100644 (file)
@@ -1175,7 +1175,8 @@ snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
        struct m3_dma *s = subs->runtime->private_data;
        int err = -EINVAL;
 
-       snd_assert(s != NULL, return -ENXIO);
+       if (snd_BUG_ON(!s))
+               return -ENXIO;
 
        spin_lock(&chip->reg_lock);
        switch (cmd) {
@@ -1487,7 +1488,8 @@ snd_m3_pcm_prepare(struct snd_pcm_substream *subs)
        struct snd_pcm_runtime *runtime = subs->runtime;
        struct m3_dma *s = runtime->private_data;
 
-       snd_assert(s != NULL, return -ENXIO);
+       if (snd_BUG_ON(!s))
+               return -ENXIO;
 
        if (runtime->format != SNDRV_PCM_FORMAT_U8 &&
            runtime->format != SNDRV_PCM_FORMAT_S16_LE)
@@ -1546,7 +1548,9 @@ snd_m3_pcm_pointer(struct snd_pcm_substream *subs)
        struct snd_m3 *chip = snd_pcm_substream_chip(subs);
        unsigned int ptr;
        struct m3_dma *s = subs->runtime->private_data;
-       snd_assert(s != NULL, return 0);
+
+       if (snd_BUG_ON(!s))
+               return 0;
 
        spin_lock(&chip->reg_lock);
        ptr = snd_m3_get_pointer(chip, s, subs);
index 3dd0c7963273c0f7bea2fcab56df88355900a6e2..2d0dce649a644fe4a5adc479ae76e53a541b3025 100644 (file)
@@ -708,7 +708,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
                pcm_number = MIXART_PCM_ANALOG;
                runtime->hw = snd_mixart_analog_caps;
        } else {
-               snd_assert ( pcm == chip->pcm_dig ); 
+               snd_BUG_ON(pcm != chip->pcm_dig);
                pcm_number = MIXART_PCM_DIGITAL;
                runtime->hw = snd_mixart_digital_caps;
        }
@@ -783,7 +783,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
                pcm_number = MIXART_PCM_ANALOG;
                runtime->hw = snd_mixart_analog_caps;
        } else {
-               snd_assert ( pcm == chip->pcm_dig ); 
+               snd_BUG_ON(pcm != chip->pcm_dig);
                pcm_number = MIXART_PCM_DIGITAL;
                runtime->hw = snd_mixart_digital_caps;
        }
index 785085e48353c3111f4e29085be77ade17298750..b9a06c2793970d4d13a29e6c2ca3f9a4cae7faa4 100644 (file)
@@ -56,8 +56,10 @@ static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame)
        if (tailptr == headptr)
                return 0; /* no message posted */
 
-       snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */
-       snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */
+       if (tailptr < MSG_OUTBOUND_POST_STACK)
+               return 0; /* error */
+       if (tailptr >= MSG_OUTBOUND_POST_STACK + MSG_BOUND_STACK_SIZE)
+               return 0; /* error */
 
        *msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
 
@@ -149,7 +151,8 @@ static int send_msg( struct mixart_mgr *mgr,
        u32 msg_frame_address;
        int err, i;
 
-       snd_assert(msg->size % 4 == 0, return -EINVAL);
+       if (snd_BUG_ON(msg->size % 4))
+               return -EINVAL;
 
        err = 0;
 
@@ -289,9 +292,12 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
        wait_queue_t wait;
        long timeout;
 
-       snd_assert(notif_event != 0, return -EINVAL);
-       snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
-       snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
+       if (snd_BUG_ON(!notif_event))
+               return -EINVAL;
+       if (snd_BUG_ON((notif_event & MSG_TYPE_MASK) != MSG_TYPE_NOTIFY))
+               return -EINVAL;
+       if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK))
+               return -EINVAL;
 
        mutex_lock(&mgr->msg_mutex);
 
index f98603146132cd7b6aabfbb6862aa0c1f50e69ee..3782b52bc0e8cb714466f0466991050e52c29b15 100644 (file)
@@ -288,7 +288,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr)
                return -EINVAL;
        }
 
-       snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2),  return -EINVAL); /* min 2 phys io per card (analog in + analog out) */
+       /* min 2 phys io per card (analog in + analog out) */
+       if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
+               return -EINVAL;
 
        for(k=0; k<mgr->num_cards; k++) {
                mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
@@ -363,8 +365,10 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                }
 
                /* check xilinx validity */
-               snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
-               snd_assert(dsp->size % 4 == 0, return -EINVAL);
+               if (((u32*)(dsp->data))[0] == 0xffffffff)
+                       return -EINVAL;
+               if (dsp->size % 4)
+                       return -EINVAL;
 
                /* set xilinx status to copying */
                writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
@@ -462,8 +466,10 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                }
  
                /* check daughterboard xilinx validity */
-               snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
-               snd_assert(dsp->size % 4 == 0, return -EINVAL);
+               if (((u32*)(dsp->data))[0] == 0xffffffff)
+                       return -EINVAL;
+               if (dsp->size % 4)
+                       return -EINVAL;
 
                /* inform mixart about the size of the file */
                writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
@@ -480,7 +486,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
                /* get the address where to write the file */
                val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
-               snd_assert(val != 0, return -EINVAL);
+               if (!val)
+                       return -EINVAL;
 
                /* copy daughterboard xilinx code */
                memcpy_toio(  MIXART_MEM( mgr, val),  dsp->data,  dsp->size);
index 6fdda1f70b25d45b718e82bb9a3afc050b15741b..3ba6174c3df1d80a6d714ddc836b751bbf917bc5 100644 (file)
@@ -837,7 +837,7 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
                if(is_aes)      stored_volume = chip->digital_capture_volume[1];        /* AES capture */
                else            stored_volume = chip->digital_capture_volume[0];        /* analog capture */
        } else {
-               snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+               snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
                if(is_aes)      stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
                else            stored_volume = chip->digital_playback_volume[idx];     /* analog playback */
        }
@@ -863,7 +863,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
                else            /* analog capture */
                        stored_volume = chip->digital_capture_volume[0];
        } else {
-               snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+               snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
                if (is_aes)     /* AES playback */
                        stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx];
                else            /* analog playback */
@@ -909,7 +909,7 @@ static int mixart_pcm_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
 {
        struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
-       snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+       snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
        mutex_lock(&chip->mgr->mixer_mutex);
        if(kcontrol->private_value & MIXART_VOL_AES_MASK)       /* AES playback */
                idx += MIXART_PLAYBACK_STREAMS;
@@ -926,7 +926,7 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
        int i, j;
-       snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+       snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
        mutex_lock(&chip->mgr->mixer_mutex);
        j = idx;
        if (is_aes)
index 06d13e7171148d261fdeeccd21563da3ef59d577..50c9f8a05082fa6c5aa67919203d80e030895b18 100644 (file)
@@ -562,7 +562,8 @@ snd_nm256_playback_trigger(struct snd_pcm_substream *substream, int cmd)
        struct nm256_stream *s = substream->runtime->private_data;
        int err = 0;
 
-       snd_assert(s != NULL, return -ENXIO);
+       if (snd_BUG_ON(!s))
+               return -ENXIO;
 
        spin_lock(&chip->reg_lock);
        switch (cmd) {
@@ -599,7 +600,8 @@ snd_nm256_capture_trigger(struct snd_pcm_substream *substream, int cmd)
        struct nm256_stream *s = substream->runtime->private_data;
        int err = 0;
 
-       snd_assert(s != NULL, return -ENXIO);
+       if (snd_BUG_ON(!s))
+               return -ENXIO;
 
        spin_lock(&chip->reg_lock);
        switch (cmd) {
@@ -635,7 +637,8 @@ static int snd_nm256_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct nm256_stream *s = runtime->private_data;
 
-       snd_assert(s, return -ENXIO);
+       if (snd_BUG_ON(!s))
+               return -ENXIO;
        s->dma_size = frames_to_bytes(runtime, substream->runtime->buffer_size);
        s->period_size = frames_to_bytes(runtime, substream->runtime->period_size);
        s->periods = substream->runtime->periods;
@@ -660,7 +663,8 @@ snd_nm256_playback_pointer(struct snd_pcm_substream *substream)
        struct nm256_stream *s = substream->runtime->private_data;
        unsigned long curp;
 
-       snd_assert(s, return 0);
+       if (snd_BUG_ON(!s))
+               return 0;
        curp = snd_nm256_readl(chip, NM_PBUFFER_CURRP) - (unsigned long)s->buf;
        curp %= s->dma_size;
        return bytes_to_frames(substream->runtime, curp);
@@ -673,7 +677,8 @@ snd_nm256_capture_pointer(struct snd_pcm_substream *substream)
        struct nm256_stream *s = substream->runtime->private_data;
        unsigned long curp;
 
-       snd_assert(s != NULL, return 0);
+       if (snd_BUG_ON(!s))
+               return 0;
        curp = snd_nm256_readl(chip, NM_RBUFFER_CURRP) - (unsigned long)s->buf;
        curp %= s->dma_size;    
        return bytes_to_frames(substream->runtime, curp);
index dad393ae040a2dc474f638ff8e95817bed95ed57..1ab833f843eb70404a586a59da232eff20ce4467 100644 (file)
@@ -94,6 +94,11 @@ static void hifier_cleanup(struct oxygen *chip)
 {
 }
 
+static void hifier_resume(struct oxygen *chip)
+{
+       hifier_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
                               struct snd_pcm_hw_params *params)
 {
@@ -150,16 +155,16 @@ static const struct oxygen_model model_hifier = {
        .init = hifier_init,
        .control_filter = hifier_control_filter,
        .cleanup = hifier_cleanup,
-       .resume = hifier_registers_init,
+       .resume = hifier_resume,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_cs5340_params,
        .update_dac_volume = update_ak4396_volume,
        .update_dac_mute = update_ak4396_mute,
        .dac_tlv = ak4396_db_scale,
        .model_data_size = sizeof(struct hifier_data),
-       .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                      PLAYBACK_1_TO_SPDIF |
-                      CAPTURE_0_FROM_I2S_1,
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_1,
        .dac_channels = 2,
        .dac_volume_min = 0,
        .dac_volume_max = 255,
@@ -180,7 +185,7 @@ static int __devinit hifier_probe(struct pci_dev *pci,
                ++dev;
                return -ENOENT;
        }
-       err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier);
+       err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier, 0);
        if (err >= 0)
                ++dev;
        return err;
index c5829d30ef8640519becefaa8a2f2ca130523297..b60f6212745a9ad6506e147697c23d8d17212df0 100644 (file)
@@ -58,17 +58,22 @@ MODULE_PARM_DESC(id, "ID string");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
+enum {
+       MODEL_CMEDIA_REF,       /* C-Media's reference design */
+       MODEL_MERIDIAN,         /* AuzenTech X-Meridian */
+};
+
 static struct pci_device_id oxygen_ids[] __devinitdata = {
-       { OXYGEN_PCI_SUBID(0x10b0, 0x0216) },
-       { OXYGEN_PCI_SUBID(0x10b0, 0x0218) },
-       { OXYGEN_PCI_SUBID(0x10b0, 0x0219) },
-       { OXYGEN_PCI_SUBID(0x13f6, 0x0001) },
-       { OXYGEN_PCI_SUBID(0x13f6, 0x0010) },
-       { OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
-       { OXYGEN_PCI_SUBID(0x147a, 0xa017) },
-       { OXYGEN_PCI_SUBID(0x1a58, 0x0910) },
-       { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = 1 },
-       { OXYGEN_PCI_SUBID(0x7284, 0x9761) },
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
+       { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
        { }
 };
 MODULE_DEVICE_TABLE(pci, oxygen_ids);
@@ -199,6 +204,11 @@ static void generic_resume(struct oxygen *chip)
        wm8785_registers_init(chip);
 }
 
+static void meridian_resume(struct oxygen *chip)
+{
+       ak4396_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
                              struct snd_pcm_hw_params *params)
 {
@@ -281,11 +291,28 @@ static void set_ak5385_params(struct oxygen *chip,
 
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
+static int generic_probe(struct oxygen *chip, unsigned long driver_data)
+{
+       if (driver_data == MODEL_MERIDIAN) {
+               chip->model.init = meridian_init;
+               chip->model.resume = meridian_resume;
+               chip->model.set_adc_params = set_ak5385_params;
+               chip->model.device_config = PLAYBACK_0_TO_I2S |
+                                           PLAYBACK_1_TO_SPDIF |
+                                           CAPTURE_0_FROM_I2S_2 |
+                                           CAPTURE_1_FROM_SPDIF;
+               chip->model.misc_flags = OXYGEN_MISC_MIDI;
+               chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
+       }
+       return 0;
+}
+
 static const struct oxygen_model model_generic = {
        .shortname = "C-Media CMI8788",
        .longname = "C-Media Oxygen HD Audio",
        .chip = "CMI8788",
        .owner = THIS_MODULE,
+       .probe = generic_probe,
        .init = generic_init,
        .cleanup = generic_cleanup,
        .resume = generic_resume,
@@ -295,44 +322,15 @@ static const struct oxygen_model model_generic = {
        .update_dac_mute = update_ak4396_mute,
        .dac_tlv = ak4396_db_scale,
        .model_data_size = sizeof(struct generic_data),
-       .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                      PLAYBACK_1_TO_SPDIF |
-                      PLAYBACK_2_TO_AC97_1 |
-                      CAPTURE_0_FROM_I2S_1 |
-                      CAPTURE_1_FROM_SPDIF |
-                      CAPTURE_2_FROM_AC97_1,
-       .dac_channels = 8,
-       .dac_volume_min = 0,
-       .dac_volume_max = 255,
-       .function_flags = OXYGEN_FUNCTION_SPI |
-                         OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-static const struct oxygen_model model_meridian = {
-       .shortname = "C-Media CMI8788",
-       .longname = "C-Media Oxygen HD Audio",
-       .chip = "CMI8788",
-       .owner = THIS_MODULE,
-       .init = meridian_init,
-       .cleanup = generic_cleanup,
-       .resume = ak4396_registers_init,
-       .set_dac_params = set_ak4396_params,
-       .set_adc_params = set_ak5385_params,
-       .update_dac_volume = update_ak4396_volume,
-       .update_dac_mute = update_ak4396_mute,
-       .dac_tlv = ak4396_db_scale,
-       .model_data_size = sizeof(struct generic_data),
-       .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                      PLAYBACK_1_TO_SPDIF |
-                      PLAYBACK_2_TO_AC97_1 |
-                      CAPTURE_0_FROM_I2S_2 |
-                      CAPTURE_1_FROM_SPDIF |
-                      CAPTURE_2_FROM_AC97_1,
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        PLAYBACK_2_TO_AC97_1 |
+                        CAPTURE_0_FROM_I2S_1 |
+                        CAPTURE_1_FROM_SPDIF |
+                        CAPTURE_2_FROM_AC97_1,
        .dac_channels = 8,
        .dac_volume_min = 0,
        .dac_volume_max = 255,
-       .misc_flags = OXYGEN_MISC_MIDI,
        .function_flags = OXYGEN_FUNCTION_SPI |
                          OXYGEN_FUNCTION_ENABLE_SPI_4_5,
        .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
@@ -343,7 +341,6 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
                                          const struct pci_device_id *pci_id)
 {
        static int dev;
-       int is_meridian;
        int err;
 
        if (dev >= SNDRV_CARDS)
@@ -352,9 +349,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
                ++dev;
                return -ENOENT;
        }
-       is_meridian = pci_id->driver_data;
        err = oxygen_pci_probe(pci, index[dev], id[dev],
-                              is_meridian ? &model_meridian : &model_generic);
+                              &model_generic, pci_id->driver_data);
        if (err >= 0)
                ++dev;
        return err;
index 74a6448800747acb0de19ce4eb70db51a4c67f7c..19107c6307e5e297c35555ee3c66ea2e70672e43 100644 (file)
 #define OXYGEN_IO_SIZE 0x100
 
 /* model-specific configuration of outputs/inputs */
-#define PLAYBACK_0_TO_I2S      0x001
-#define PLAYBACK_1_TO_SPDIF    0x004
-#define PLAYBACK_2_TO_AC97_1   0x008
-#define CAPTURE_0_FROM_I2S_1   0x010
-#define CAPTURE_0_FROM_I2S_2   0x020
-#define CAPTURE_1_FROM_SPDIF   0x080
-#define CAPTURE_2_FROM_I2S_2   0x100
-#define CAPTURE_2_FROM_AC97_1  0x200
+#define PLAYBACK_0_TO_I2S      0x0001
+     /* PLAYBACK_0_TO_AC97_0           not implemented */
+#define PLAYBACK_1_TO_SPDIF    0x0004
+#define PLAYBACK_2_TO_AC97_1   0x0008
+#define CAPTURE_0_FROM_I2S_1   0x0010
+#define CAPTURE_0_FROM_I2S_2   0x0020
+     /* CAPTURE_0_FROM_AC97_0          not implemented */
+#define CAPTURE_1_FROM_SPDIF   0x0080
+#define CAPTURE_2_FROM_I2S_2   0x0100
+#define CAPTURE_2_FROM_AC97_1  0x0200
+     /* CAPTURE_3_FROM_I2S_3           not implemented */
+#define MIDI_OUTPUT            0x0800
+#define MIDI_INPUT             0x1000
 
 enum {
        CONTROL_SPDIF_PCM,
@@ -51,7 +56,43 @@ struct snd_pcm_hardware;
 struct snd_pcm_hw_params;
 struct snd_kcontrol_new;
 struct snd_rawmidi;
-struct oxygen_model;
+struct oxygen;
+
+struct oxygen_model {
+       const char *shortname;
+       const char *longname;
+       const char *chip;
+       struct module *owner;
+       int (*probe)(struct oxygen *chip, unsigned long driver_data);
+       void (*init)(struct oxygen *chip);
+       int (*control_filter)(struct snd_kcontrol_new *template);
+       int (*mixer_init)(struct oxygen *chip);
+       void (*cleanup)(struct oxygen *chip);
+       void (*suspend)(struct oxygen *chip);
+       void (*resume)(struct oxygen *chip);
+       void (*pcm_hardware_filter)(unsigned int channel,
+                                   struct snd_pcm_hardware *hardware);
+       void (*set_dac_params)(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params);
+       void (*set_adc_params)(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params);
+       void (*update_dac_volume)(struct oxygen *chip);
+       void (*update_dac_mute)(struct oxygen *chip);
+       void (*gpio_changed)(struct oxygen *chip);
+       void (*uart_input)(struct oxygen *chip);
+       void (*ac97_switch)(struct oxygen *chip,
+                           unsigned int reg, unsigned int mute);
+       const unsigned int *dac_tlv;
+       size_t model_data_size;
+       unsigned int device_config;
+       u8 dac_channels;
+       u8 dac_volume_min;
+       u8 dac_volume_max;
+       u8 misc_flags;
+       u8 function_flags;
+       u16 dac_i2s_format;
+       u16 adc_i2s_format;
+};
 
 struct oxygen {
        unsigned long addr;
@@ -61,7 +102,6 @@ struct oxygen {
        struct pci_dev *pci;
        struct snd_rawmidi *midi;
        int irq;
-       const struct oxygen_model *model;
        void *model_data;
        unsigned int interrupt_mask;
        u8 dac_volume[8];
@@ -86,46 +126,16 @@ struct oxygen {
                __le32 _32[OXYGEN_IO_SIZE / 4];
        } saved_registers;
        u16 saved_ac97_registers[2][0x40];
-};
-
-struct oxygen_model {
-       const char *shortname;
-       const char *longname;
-       const char *chip;
-       struct module *owner;
-       void (*init)(struct oxygen *chip);
-       int (*control_filter)(struct snd_kcontrol_new *template);
-       int (*mixer_init)(struct oxygen *chip);
-       void (*cleanup)(struct oxygen *chip);
-       void (*suspend)(struct oxygen *chip);
-       void (*resume)(struct oxygen *chip);
-       void (*pcm_hardware_filter)(unsigned int channel,
-                                   struct snd_pcm_hardware *hardware);
-       void (*set_dac_params)(struct oxygen *chip,
-                              struct snd_pcm_hw_params *params);
-       void (*set_adc_params)(struct oxygen *chip,
-                              struct snd_pcm_hw_params *params);
-       void (*update_dac_volume)(struct oxygen *chip);
-       void (*update_dac_mute)(struct oxygen *chip);
-       void (*gpio_changed)(struct oxygen *chip);
-       void (*ac97_switch)(struct oxygen *chip,
-                           unsigned int reg, unsigned int mute);
-       const unsigned int *dac_tlv;
-       size_t model_data_size;
-       unsigned int pcm_dev_cfg;
-       u8 dac_channels;
-       u8 dac_volume_min;
-       u8 dac_volume_max;
-       u8 misc_flags;
-       u8 function_flags;
-       u16 dac_i2s_format;
-       u16 adc_i2s_format;
+       unsigned int uart_input_count;
+       u8 uart_input[32];
+       struct oxygen_model model;
 };
 
 /* oxygen_lib.c */
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-                    const struct oxygen_model *model);
+                    const struct oxygen_model *model,
+                    unsigned long driver_data);
 void oxygen_pci_remove(struct pci_dev *pci);
 #ifdef CONFIG_PM
 int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
@@ -167,6 +177,9 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
 void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
 void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
 
+void oxygen_reset_uart(struct oxygen *chip);
+void oxygen_write_uart(struct oxygen *chip, u8 data);
+
 static inline void oxygen_set_bits8(struct oxygen *chip,
                                    unsigned int reg, u8 value)
 {
index 83f135f80df44439f62aed9f0b2e3b72d76172a8..3126c4b403dd2634e2f29c0d1c5ca68a566c2370 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <sound/core.h>
+#include <sound/mpu401.h>
 #include <asm/io.h>
 #include "oxygen.h"
 
@@ -232,3 +233,24 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data)
                      device | OXYGEN_2WIRE_DIR_WRITE);
 }
 EXPORT_SYMBOL(oxygen_write_i2c);
+
+static void _write_uart(struct oxygen *chip, unsigned int port, u8 data)
+{
+       if (oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_TX_FULL)
+               msleep(1);
+       oxygen_write8(chip, OXYGEN_MPU401 + port, data);
+}
+
+void oxygen_reset_uart(struct oxygen *chip)
+{
+       _write_uart(chip, 1, MPU401_RESET);
+       msleep(1); /* wait for ACK */
+       _write_uart(chip, 1, MPU401_ENTER_UART);
+}
+EXPORT_SYMBOL(oxygen_reset_uart);
+
+void oxygen_write_uart(struct oxygen *chip, u8 data)
+{
+       _write_uart(chip, 0, data);
+}
+EXPORT_SYMBOL(oxygen_write_uart);
index 22f37851045e9639032b55960abcd3edb88c973e..84f481d41efa5910eeda20b0b8840556d6fd6183 100644 (file)
@@ -35,6 +35,30 @@ MODULE_DESCRIPTION("C-Media CMI8788 helper library");
 MODULE_LICENSE("GPL v2");
 
 
+static inline int oxygen_uart_input_ready(struct oxygen *chip)
+{
+       return !(oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_RX_EMPTY);
+}
+
+static void oxygen_read_uart(struct oxygen *chip)
+{
+       if (unlikely(!oxygen_uart_input_ready(chip))) {
+               /* no data, but read it anyway to clear the interrupt */
+               oxygen_read8(chip, OXYGEN_MPU401);
+               return;
+       }
+       do {
+               u8 data = oxygen_read8(chip, OXYGEN_MPU401);
+               if (data == MPU401_ACK)
+                       continue;
+               if (chip->uart_input_count >= ARRAY_SIZE(chip->uart_input))
+                       chip->uart_input_count = 0;
+               chip->uart_input[chip->uart_input_count++] = data;
+       } while (oxygen_uart_input_ready(chip));
+       if (chip->model.uart_input)
+               chip->model.uart_input(chip);
+}
+
 static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
 {
        struct oxygen *chip = dev_id;
@@ -87,8 +111,12 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
        if (status & OXYGEN_INT_GPIO)
                schedule_work(&chip->gpio_work);
 
-       if ((status & OXYGEN_INT_MIDI) && chip->midi)
-               snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+       if (status & OXYGEN_INT_MIDI) {
+               if (chip->midi)
+                       snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+               else
+                       oxygen_read_uart(chip);
+       }
 
        if (status & OXYGEN_INT_AC97)
                wake_up(&chip->ac97_waitqueue);
@@ -161,8 +189,8 @@ static void oxygen_gpio_changed(struct work_struct *work)
 {
        struct oxygen *chip = container_of(work, struct oxygen, gpio_work);
 
-       if (chip->model->gpio_changed)
-               chip->model->gpio_changed(chip);
+       if (chip->model.gpio_changed)
+               chip->model.gpio_changed(chip);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -221,7 +249,7 @@ static void oxygen_init(struct oxygen *chip)
 
        chip->dac_routing = 1;
        for (i = 0; i < 8; ++i)
-               chip->dac_volume[i] = chip->model->dac_volume_min;
+               chip->dac_volume[i] = chip->model.dac_volume_min;
        chip->dac_mute = 1;
        chip->spdif_playback_enable = 1;
        chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL |
@@ -243,7 +271,7 @@ static void oxygen_init(struct oxygen *chip)
 
        oxygen_write8_masked(chip, OXYGEN_FUNCTION,
                             OXYGEN_FUNCTION_RESET_CODEC |
-                            chip->model->function_flags,
+                            chip->model.function_flags,
                             OXYGEN_FUNCTION_RESET_CODEC |
                             OXYGEN_FUNCTION_2WIRE_SPI_MASK |
                             OXYGEN_FUNCTION_ENABLE_SPI_4_5);
@@ -255,7 +283,7 @@ static void oxygen_init(struct oxygen *chip)
                      OXYGEN_DMA_MULTICH_BURST_8);
        oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
        oxygen_write8_masked(chip, OXYGEN_MISC,
-                            chip->model->misc_flags,
+                            chip->model.misc_flags,
                             OXYGEN_MISC_WRITE_PCI_SUBID |
                             OXYGEN_MISC_REC_C_FROM_SPDIF |
                             OXYGEN_MISC_REC_B_FROM_AC97 |
@@ -270,21 +298,21 @@ static void oxygen_init(struct oxygen *chip)
                      (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
        oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
        oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
-                      OXYGEN_RATE_48000 | chip->model->dac_i2s_format |
+                      OXYGEN_RATE_48000 | chip->model.dac_i2s_format |
                       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
-       if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_1)
+       if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
                oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-                              OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+                              OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
                               OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                               OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
        else
                oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
                               OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
-       if (chip->model->pcm_dev_cfg & (CAPTURE_0_FROM_I2S_2 |
-                                       CAPTURE_2_FROM_I2S_2))
+       if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 |
+                                        CAPTURE_2_FROM_I2S_2))
                oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
-                              OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+                              OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
                               OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                               OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
        else
@@ -295,7 +323,7 @@ static void oxygen_init(struct oxygen *chip)
        oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
                            OXYGEN_SPDIF_OUT_ENABLE |
                            OXYGEN_SPDIF_LOOPBACK);
-       if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF)
+       if (chip->model.device_config & CAPTURE_1_FROM_SPDIF)
                oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
                                      OXYGEN_SPDIF_SENSE_MASK |
                                      OXYGEN_SPDIF_LOCK_MASK |
@@ -417,14 +445,15 @@ static void oxygen_card_free(struct snd_card *card)
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
        flush_scheduled_work();
-       chip->model->cleanup(chip);
+       chip->model.cleanup(chip);
        mutex_destroy(&chip->mutex);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
 }
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-                    const struct oxygen_model *model)
+                    const struct oxygen_model *model,
+                    unsigned long driver_data)
 {
        struct snd_card *card;
        struct oxygen *chip;
@@ -439,7 +468,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
-       chip->model = model;
+       chip->model = *model;
        chip->model_data = chip + 1;
        spin_lock_init(&chip->reg_lock);
        mutex_init(&chip->mutex);
@@ -470,23 +499,28 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        snd_card_set_dev(card, &pci->dev);
        card->private_free = oxygen_card_free;
 
+       if (chip->model.probe) {
+               err = chip->model.probe(chip, driver_data);
+               if (err < 0)
+                       goto err_card;
+       }
        oxygen_init(chip);
-       model->init(chip);
+       chip->model.init(chip);
 
        err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
-                         model->chip, chip);
+                         chip->model.chip, chip);
        if (err < 0) {
                snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
                goto err_card;
        }
        chip->irq = pci->irq;
 
-       strcpy(card->driver, model->chip);
-       strcpy(card->shortname, model->shortname);
+       strcpy(card->driver, chip->model.chip);
+       strcpy(card->shortname, chip->model.shortname);
        sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
-               model->longname, chip->revision, chip->addr, chip->irq);
-       strcpy(card->mixername, model->chip);
-       snd_component_add(card, model->chip);
+               chip->model.longname, chip->revision, chip->addr, chip->irq);
+       strcpy(card->mixername, chip->model.chip);
+       snd_component_add(card, chip->model.chip);
 
        err = oxygen_pcm_init(chip);
        if (err < 0)
@@ -496,10 +530,15 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        if (err < 0)
                goto err_card;
 
-       if (model->misc_flags & OXYGEN_MISC_MIDI) {
+       if (chip->model.device_config & (MIDI_OUTPUT | MIDI_INPUT)) {
+               unsigned int info_flags = MPU401_INFO_INTEGRATED;
+               if (chip->model.device_config & MIDI_OUTPUT)
+                       info_flags |= MPU401_INFO_OUTPUT;
+               if (chip->model.device_config & MIDI_INPUT)
+                       info_flags |= MPU401_INFO_INPUT;
                err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
                                          chip->addr + OXYGEN_MPU401,
-                                         MPU401_INFO_INTEGRATED, 0, 0,
+                                         info_flags, 0, 0,
                                          &chip->midi);
                if (err < 0)
                        goto err_card;
@@ -508,7 +547,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        oxygen_proc_init(chip);
 
        spin_lock_irq(&chip->reg_lock);
-       if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF)
+       if (chip->model.device_config & CAPTURE_1_FROM_SPDIF)
                chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
        if (chip->has_ac97_0 | chip->has_ac97_1)
                chip->interrupt_mask |= OXYGEN_INT_AC97;
@@ -552,8 +591,8 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
                if (chip->streams[i])
                        snd_pcm_suspend(chip->streams[i]);
 
-       if (chip->model->suspend)
-               chip->model->suspend(chip);
+       if (chip->model.suspend)
+               chip->model.suspend(chip);
 
        spin_lock_irq(&chip->reg_lock);
        saved_interrupt_mask = chip->interrupt_mask;
@@ -624,8 +663,8 @@ int oxygen_pci_resume(struct pci_dev *pci)
        if (chip->has_ac97_1)
                oxygen_restore_ac97(chip, 1);
 
-       if (chip->model->resume)
-               chip->model->resume(chip);
+       if (chip->model.resume)
+               chip->model.resume(chip);
 
        oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
 
index 05eb8994c141a899966a5f9ce791b1fa0ef28343..304da169bfdcbeacb669a338a25a5f4c12271de9 100644 (file)
@@ -31,9 +31,9 @@ static int dac_volume_info(struct snd_kcontrol *ctl,
        struct oxygen *chip = ctl->private_data;
 
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       info->count = chip->model->dac_channels;
-       info->value.integer.min = chip->model->dac_volume_min;
-       info->value.integer.max = chip->model->dac_volume_max;
+       info->count = chip->model.dac_channels;
+       info->value.integer.min = chip->model.dac_volume_min;
+       info->value.integer.max = chip->model.dac_volume_max;
        return 0;
 }
 
@@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl,
        unsigned int i;
 
        mutex_lock(&chip->mutex);
-       for (i = 0; i < chip->model->dac_channels; ++i)
+       for (i = 0; i < chip->model.dac_channels; ++i)
                value->value.integer.value[i] = chip->dac_volume[i];
        mutex_unlock(&chip->mutex);
        return 0;
@@ -59,13 +59,13 @@ static int dac_volume_put(struct snd_kcontrol *ctl,
 
        changed = 0;
        mutex_lock(&chip->mutex);
-       for (i = 0; i < chip->model->dac_channels; ++i)
+       for (i = 0; i < chip->model.dac_channels; ++i)
                if (value->value.integer.value[i] != chip->dac_volume[i]) {
                        chip->dac_volume[i] = value->value.integer.value[i];
                        changed = 1;
                }
        if (changed)
-               chip->model->update_dac_volume(chip);
+               chip->model.update_dac_volume(chip);
        mutex_unlock(&chip->mutex);
        return changed;
 }
@@ -91,7 +91,7 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
        changed = !value->value.integer.value[0] != chip->dac_mute;
        if (changed) {
                chip->dac_mute = !value->value.integer.value[0];
-               chip->model->update_dac_mute(chip);
+               chip->model.update_dac_mute(chip);
        }
        mutex_unlock(&chip->mutex);
        return changed;
@@ -103,7 +103,7 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
                "Front", "Front+Surround", "Front+Surround+Back"
        };
        struct oxygen *chip = ctl->private_data;
-       unsigned int count = 2 + (chip->model->dac_channels == 8);
+       unsigned int count = 2 + (chip->model.dac_channels == 8);
 
        info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        info->count = 1;
@@ -172,7 +172,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
-       unsigned int count = 2 + (chip->model->dac_channels == 8);
+       unsigned int count = 2 + (chip->model.dac_channels == 8);
        int changed;
 
        mutex_lock(&chip->mutex);
@@ -211,13 +211,13 @@ static unsigned int oxygen_spdif_rate(unsigned int oxygen_rate)
        case OXYGEN_RATE_64000:
                return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT;
        case OXYGEN_RATE_88200:
-               return 0x8 << OXYGEN_SPDIF_CS_RATE_SHIFT;
+               return IEC958_AES3_CON_FS_88200 << OXYGEN_SPDIF_CS_RATE_SHIFT;
        case OXYGEN_RATE_96000:
-               return 0xa << OXYGEN_SPDIF_CS_RATE_SHIFT;
+               return IEC958_AES3_CON_FS_96000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
        case OXYGEN_RATE_176400:
-               return 0xc << OXYGEN_SPDIF_CS_RATE_SHIFT;
+               return IEC958_AES3_CON_FS_176400 << OXYGEN_SPDIF_CS_RATE_SHIFT;
        case OXYGEN_RATE_192000:
-               return 0xe << OXYGEN_SPDIF_CS_RATE_SHIFT;
+               return IEC958_AES3_CON_FS_192000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
        }
 }
 
@@ -521,8 +521,8 @@ static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
        value = oxygen_read_ac97(chip, 0, priv_idx);
        if (!(value & 0x8000)) {
                oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000);
-               if (chip->model->ac97_switch)
-                       chip->model->ac97_switch(chip, priv_idx, 0x8000);
+               if (chip->model.ac97_switch)
+                       chip->model.ac97_switch(chip, priv_idx, 0x8000);
                snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
                               &chip->controls[control]->id);
        }
@@ -549,8 +549,8 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
        change = newreg != oldreg;
        if (change) {
                oxygen_write_ac97(chip, codec, index, newreg);
-               if (codec == 0 && chip->model->ac97_switch)
-                       chip->model->ac97_switch(chip, index, newreg & 0x8000);
+               if (codec == 0 && chip->model.ac97_switch)
+                       chip->model.ac97_switch(chip, index, newreg & 0x8000);
                if (index == AC97_LINE) {
                        oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
                                                 newreg & 0x8000 ?
@@ -939,16 +939,16 @@ static int add_controls(struct oxygen *chip,
 
        for (i = 0; i < count; ++i) {
                template = controls[i];
-               if (chip->model->control_filter) {
-                       err = chip->model->control_filter(&template);
+               if (chip->model.control_filter) {
+                       err = chip->model.control_filter(&template);
                        if (err < 0)
                                return err;
                        if (err == 1)
                                continue;
                }
                if (!strcmp(template.name, "Master Playback Volume") &&
-                   chip->model->dac_tlv) {
-                       template.tlv.p = chip->model->dac_tlv;
+                   chip->model.dac_tlv) {
+                       template.tlv.p = chip->model.dac_tlv;
                        template.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
                }
                ctl = snd_ctl_new1(&template, chip);
@@ -974,14 +974,14 @@ int oxygen_mixer_init(struct oxygen *chip)
        err = add_controls(chip, controls, ARRAY_SIZE(controls));
        if (err < 0)
                return err;
-       if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF) {
+       if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
                err = add_controls(chip, spdif_input_controls,
                                   ARRAY_SIZE(spdif_input_controls));
                if (err < 0)
                        return err;
        }
        for (i = 0; i < ARRAY_SIZE(monitor_controls); ++i) {
-               if (!(chip->model->pcm_dev_cfg & monitor_controls[i].pcm_dev))
+               if (!(chip->model.device_config & monitor_controls[i].pcm_dev))
                        continue;
                err = add_controls(chip, monitor_controls[i].controls,
                                   ARRAY_SIZE(monitor_controls[i].controls));
@@ -1000,5 +1000,5 @@ int oxygen_mixer_init(struct oxygen *chip)
                if (err < 0)
                        return err;
        }
-       return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0;
+       return chip->model.mixer_init ? chip->model.mixer_init(chip) : 0;
 }
index c4ad65a3406fd61ea6bcb016d8b979def759691a..c262049961e15a0dd9840645f753584373dac52a 100644 (file)
@@ -129,7 +129,7 @@ static int oxygen_open(struct snd_pcm_substream *substream,
 
        runtime->private_data = (void *)(uintptr_t)channel;
        if (channel == PCM_B && chip->has_ac97_1 &&
-           (chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1))
+           (chip->model.device_config & CAPTURE_2_FROM_AC97_1))
                runtime->hw = oxygen_ac97_hardware;
        else
                runtime->hw = *oxygen_hardware[channel];
@@ -140,11 +140,11 @@ static int oxygen_open(struct snd_pcm_substream *substream,
                runtime->hw.rate_min = 44100;
                break;
        case PCM_MULTICH:
-               runtime->hw.channels_max = chip->model->dac_channels;
+               runtime->hw.channels_max = chip->model.dac_channels;
                break;
        }
-       if (chip->model->pcm_hardware_filter)
-               chip->model->pcm_hardware_filter(channel, &runtime->hw);
+       if (chip->model.pcm_hardware_filter)
+               chip->model.pcm_hardware_filter(channel, &runtime->hw);
        err = snd_pcm_hw_constraint_step(runtime, 0,
                                         SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
        if (err < 0)
@@ -355,7 +355,7 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
        oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
                              oxygen_rate(hw_params) |
                              oxygen_i2s_mclk(hw_params) |
-                             chip->model->adc_i2s_format |
+                             chip->model.adc_i2s_format |
                              oxygen_i2s_bits(hw_params),
                              OXYGEN_I2S_RATE_MASK |
                              OXYGEN_I2S_FORMAT_MASK |
@@ -364,7 +364,7 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
        spin_unlock_irq(&chip->reg_lock);
 
        mutex_lock(&chip->mutex);
-       chip->model->set_adc_params(chip, hw_params);
+       chip->model.set_adc_params(chip, hw_params);
        mutex_unlock(&chip->mutex);
        return 0;
 }
@@ -381,7 +381,7 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        is_ac97 = chip->has_ac97_1 &&
-               (chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1);
+               (chip->model.device_config & CAPTURE_2_FROM_AC97_1);
 
        spin_lock_irq(&chip->reg_lock);
        oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
@@ -391,7 +391,7 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
                oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
                                      oxygen_rate(hw_params) |
                                      oxygen_i2s_mclk(hw_params) |
-                                     chip->model->adc_i2s_format |
+                                     chip->model.adc_i2s_format |
                                      oxygen_i2s_bits(hw_params),
                                      OXYGEN_I2S_RATE_MASK |
                                      OXYGEN_I2S_FORMAT_MASK |
@@ -401,7 +401,7 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
 
        if (!is_ac97) {
                mutex_lock(&chip->mutex);
-               chip->model->set_adc_params(chip, hw_params);
+               chip->model.set_adc_params(chip, hw_params);
                mutex_unlock(&chip->mutex);
        }
        return 0;
@@ -468,7 +468,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
                             OXYGEN_MULTICH_FORMAT_MASK);
        oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
                              oxygen_rate(hw_params) |
-                             chip->model->dac_i2s_format |
+                             chip->model.dac_i2s_format |
                              oxygen_i2s_bits(hw_params),
                              OXYGEN_I2S_RATE_MASK |
                              OXYGEN_I2S_FORMAT_MASK |
@@ -478,7 +478,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
        spin_unlock_irq(&chip->reg_lock);
 
        mutex_lock(&chip->mutex);
-       chip->model->set_dac_params(chip, hw_params);
+       chip->model.set_dac_params(chip, hw_params);
        mutex_unlock(&chip->mutex);
        return 0;
 }
@@ -657,25 +657,26 @@ int oxygen_pcm_init(struct oxygen *chip)
        int outs, ins;
        int err;
 
-       outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_0_TO_I2S);
-       ins = !!(chip->model->pcm_dev_cfg & (CAPTURE_0_FROM_I2S_1 |
-                                            CAPTURE_0_FROM_I2S_2));
+       outs = !!(chip->model.device_config & PLAYBACK_0_TO_I2S);
+       ins = !!(chip->model.device_config & (CAPTURE_0_FROM_I2S_1 |
+                                             CAPTURE_0_FROM_I2S_2));
        if (outs | ins) {
-               err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm);
+               err = snd_pcm_new(chip->card, "Multichannel",
+                                 0, outs, ins, &pcm);
                if (err < 0)
                        return err;
                if (outs)
                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                        &oxygen_multich_ops);
-               if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_1)
+               if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                                        &oxygen_rec_a_ops);
-               else if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_2)
+               else if (chip->model.device_config & CAPTURE_0_FROM_I2S_2)
                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                                        &oxygen_rec_b_ops);
                pcm->private_data = chip;
                pcm->private_free = oxygen_pcm_free;
-               strcpy(pcm->name, "Analog");
+               strcpy(pcm->name, "Multichannel");
                if (outs)
                        snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
                                                      SNDRV_DMA_TYPE_DEV,
@@ -690,8 +691,8 @@ int oxygen_pcm_init(struct oxygen *chip)
                                                      BUFFER_BYTES_MAX);
        }
 
-       outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF);
-       ins = !!(chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF);
+       outs = !!(chip->model.device_config & PLAYBACK_1_TO_SPDIF);
+       ins = !!(chip->model.device_config & CAPTURE_1_FROM_SPDIF);
        if (outs | ins) {
                err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm);
                if (err < 0)
@@ -712,11 +713,11 @@ int oxygen_pcm_init(struct oxygen *chip)
        }
 
        if (chip->has_ac97_1) {
-               outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_2_TO_AC97_1);
-               ins = !!(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1);
+               outs = !!(chip->model.device_config & PLAYBACK_2_TO_AC97_1);
+               ins = !!(chip->model.device_config & CAPTURE_2_FROM_AC97_1);
        } else {
                outs = 0;
-               ins = !!(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_I2S_2);
+               ins = !!(chip->model.device_config & CAPTURE_2_FROM_I2S_2);
        }
        if (outs | ins) {
                err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2",
index 01d7b75f91828144f16c33b4ce81fb4e47ce7438..98c6a8c65d813cb9f816d3e2d83a206cdbb1935e 100644 (file)
  * AD0 <- 0
  */
 
+/*
+ * Xonar HDAV1.3 (Deluxe)
+ * ----------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1796 (front)
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ *
+ * PCM1796 front: AD1,0 <- 0,0
+ *
+ * no daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 1
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ *
+ * I²C <-> PCM1796 (surround)
+ *     <-> PCM1796 (center/LFE)
+ *     <-> PCM1796 (back)
+ *
+ * PCM1796 surround:   AD1,0 <- 0,1
+ * PCM1796 center/LFE: AD1,0 <- 1,0
+ * PCM1796 back:       AD1,0 <- 1,1
+ *
+ * unknown daughterboard
+ * ---------------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 1
+ *
+ * I²C <-> CS4362A (surround, center/LFE, back)
+ *
+ * CS4362A: AD0 <- 0
+ */
+
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
 #include <sound/control.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include "oxygen.h"
 #include "cm9780.h"
@@ -98,12 +150,15 @@ enum {
        MODEL_D2X,
        MODEL_D1,
        MODEL_DX,
+       MODEL_HDAV,     /* without daughterboard */
+       MODEL_HDAV_H6,  /* with H6 daughterboard */
 };
 
 static struct pci_device_id xonar_ids[] __devinitdata = {
        { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 },
        { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
        { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
        { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
        { }
 };
@@ -124,11 +179,18 @@ MODULE_DEVICE_TABLE(pci, xonar_ids);
 #define GPIO_DX_FRONT_PANEL    0x0002
 #define GPIO_DX_INPUT_ROUTE    0x0100
 
+#define GPIO_HDAV_DB_MASK      0x0030
+#define GPIO_HDAV_DB_H6                0x0000
+#define GPIO_HDAV_DB_XX                0x0020
+
+#define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ADx=i, /W=0 */
 #define I2C_DEVICE_CS4398      0x9e    /* 10011, AD1=1, AD0=1, /W=0 */
 #define I2C_DEVICE_CS4362A     0x30    /* 001100, AD0=0, /W=0 */
 
 struct xonar_data {
+       unsigned int model;
        unsigned int anti_pop_delay;
+       unsigned int dacs;
        u16 output_enable_bit;
        u8 ext_power_reg;
        u8 ext_power_int_reg;
@@ -137,10 +199,13 @@ struct xonar_data {
        u8 pcm1796_oversampling;
        u8 cs4398_fm;
        u8 cs4362a_fm;
+       u8 hdmi_params[5];
 };
 
-static void pcm1796_write(struct oxygen *chip, unsigned int codec,
-                         u8 reg, u8 value)
+static void xonar_gpio_changed(struct oxygen *chip);
+
+static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
+                                    u8 reg, u8 value)
 {
        /* maps ALSA channel pair number to SPI output */
        static const u8 codec_map[4] = {
@@ -154,6 +219,22 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec,
                         (reg << 8) | value);
 }
 
+static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
+                                    u8 reg, u8 value)
+{
+       oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
+}
+
+static void pcm1796_write(struct oxygen *chip, unsigned int codec,
+                         u8 reg, u8 value)
+{
+       if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
+           OXYGEN_FUNCTION_SPI)
+               pcm1796_write_spi(chip, codec, reg, value);
+       else
+               pcm1796_write_i2c(chip, codec, reg, value);
+}
+
 static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
 {
        oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
@@ -164,6 +245,24 @@ static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
        oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
 }
 
+static void hdmi_write_command(struct oxygen *chip, u8 command,
+                              unsigned int count, const u8 *params)
+{
+       unsigned int i;
+       u8 checksum;
+
+       oxygen_write_uart(chip, 0xfb);
+       oxygen_write_uart(chip, 0xef);
+       oxygen_write_uart(chip, command);
+       oxygen_write_uart(chip, count);
+       for (i = 0; i < count; ++i)
+               oxygen_write_uart(chip, params[i]);
+       checksum = 0xfb + 0xef + command + count;
+       for (i = 0; i < count; ++i)
+               checksum += params[i];
+       oxygen_write_uart(chip, checksum);
+}
+
 static void xonar_enable_output(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
@@ -180,6 +279,7 @@ static void xonar_common_init(struct oxygen *chip)
                oxygen_set_bits8(chip, data->ext_power_int_reg,
                                 data->ext_power_bit);
                chip->interrupt_mask |= OXYGEN_INT_GPIO;
+               chip->model.gpio_changed = xonar_gpio_changed;
                data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
                                     & data->ext_power_bit);
        }
@@ -193,9 +293,10 @@ static void xonar_common_init(struct oxygen *chip)
 
 static void update_pcm1796_volume(struct oxygen *chip)
 {
+       struct xonar_data *data = chip->model_data;
        unsigned int i;
 
-       for (i = 0; i < 4; ++i) {
+       for (i = 0; i < data->dacs; ++i) {
                pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
                pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
        }
@@ -203,13 +304,14 @@ static void update_pcm1796_volume(struct oxygen *chip)
 
 static void update_pcm1796_mute(struct oxygen *chip)
 {
+       struct xonar_data *data = chip->model_data;
        unsigned int i;
        u8 value;
 
        value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
        if (chip->dac_mute)
                value |= PCM1796_MUTE;
-       for (i = 0; i < 4; ++i)
+       for (i = 0; i < data->dacs; ++i)
                pcm1796_write(chip, i, 18, value);
 }
 
@@ -218,7 +320,7 @@ static void pcm1796_init(struct oxygen *chip)
        struct xonar_data *data = chip->model_data;
        unsigned int i;
 
-       for (i = 0; i < 4; ++i) {
+       for (i = 0; i < data->dacs; ++i) {
                pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
                pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
                pcm1796_write(chip, i, 21, 0);
@@ -234,6 +336,13 @@ static void xonar_d2_init(struct oxygen *chip)
        data->anti_pop_delay = 300;
        data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
        data->pcm1796_oversampling = PCM1796_OS_64;
+       if (data->model == MODEL_D2X) {
+               data->ext_power_reg = OXYGEN_GPIO_DATA;
+               data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
+               data->ext_power_bit = GPIO_D2X_EXT_POWER;
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                                   GPIO_D2X_EXT_POWER);
+       }
 
        pcm1796_init(chip);
 
@@ -246,17 +355,6 @@ static void xonar_d2_init(struct oxygen *chip)
        snd_component_add(chip->card, "CS5381");
 }
 
-static void xonar_d2x_init(struct oxygen *chip)
-{
-       struct xonar_data *data = chip->model_data;
-
-       data->ext_power_reg = OXYGEN_GPIO_DATA;
-       data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
-       data->ext_power_bit = GPIO_D2X_EXT_POWER;
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
-       xonar_d2_init(chip);
-}
-
 static void update_cs4362a_volumes(struct oxygen *chip)
 {
        u8 mute;
@@ -324,6 +422,11 @@ static void xonar_d1_init(struct oxygen *chip)
        data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
        data->cs4362a_fm = CS4362A_FM_SINGLE |
                CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+       if (data->model == MODEL_DX) {
+               data->ext_power_reg = OXYGEN_GPI_DATA;
+               data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+               data->ext_power_bit = GPI_DX_EXT_POWER;
+       }
 
        oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
                       OXYGEN_2WIRE_LENGTH_8 |
@@ -344,30 +447,86 @@ static void xonar_d1_init(struct oxygen *chip)
        snd_component_add(chip->card, "CS5361");
 }
 
-static void xonar_dx_init(struct oxygen *chip)
+static void xonar_hdav_init(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
+       u8 param;
 
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_FAST);
+
+       data->anti_pop_delay = 100;
+       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
        data->ext_power_reg = OXYGEN_GPI_DATA;
        data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
        data->ext_power_bit = GPI_DX_EXT_POWER;
-       xonar_d1_init(chip);
+       data->pcm1796_oversampling = PCM1796_OS_64;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE);
+
+       oxygen_reset_uart(chip);
+       param = 0;
+       hdmi_write_command(chip, 0x61, 1, &param);
+       param = 1;
+       hdmi_write_command(chip, 0x74, 1, &param);
+       data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
+       data->hdmi_params[4] = 1;
+       hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
+
+       xonar_common_init(chip);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
 }
 
-static void xonar_cleanup(struct oxygen *chip)
+static void xonar_disable_output(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
 
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
 }
 
+static void xonar_d2_cleanup(struct oxygen *chip)
+{
+       xonar_disable_output(chip);
+}
+
 static void xonar_d1_cleanup(struct oxygen *chip)
 {
-       xonar_cleanup(chip);
+       xonar_disable_output(chip);
        cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
        oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
 }
 
+static void xonar_hdav_cleanup(struct oxygen *chip)
+{
+       u8 param = 0;
+
+       hdmi_write_command(chip, 0x74, 1, &param);
+       xonar_disable_output(chip);
+}
+
+static void xonar_d2_suspend(struct oxygen *chip)
+{
+       xonar_d2_cleanup(chip);
+}
+
+static void xonar_d1_suspend(struct oxygen *chip)
+{
+       xonar_d1_cleanup(chip);
+}
+
+static void xonar_hdav_suspend(struct oxygen *chip)
+{
+       xonar_hdav_cleanup(chip);
+       msleep(2);
+}
+
 static void xonar_d2_resume(struct oxygen *chip)
 {
        pcm1796_init(chip);
@@ -380,6 +539,33 @@ static void xonar_d1_resume(struct oxygen *chip)
        xonar_enable_output(chip);
 }
 
+static void xonar_hdav_resume(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+       u8 param;
+
+       oxygen_reset_uart(chip);
+       param = 0;
+       hdmi_write_command(chip, 0x61, 1, &param);
+       param = 1;
+       hdmi_write_command(chip, 0x74, 1, &param);
+       hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
+       pcm1796_init(chip);
+       xonar_enable_output(chip);
+}
+
+static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
+                                          struct snd_pcm_hardware *hardware)
+{
+       if (channel == PCM_MULTICH) {
+               hardware->rates = SNDRV_PCM_RATE_44100 |
+                                 SNDRV_PCM_RATE_48000 |
+                                 SNDRV_PCM_RATE_96000 |
+                                 SNDRV_PCM_RATE_192000;
+               hardware->rate_min = 44100;
+       }
+}
+
 static void set_pcm1796_params(struct oxygen *chip,
                               struct snd_pcm_hw_params *params)
 {
@@ -388,7 +574,7 @@ static void set_pcm1796_params(struct oxygen *chip,
 
        data->pcm1796_oversampling =
                params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
-       for (i = 0; i < 4; ++i)
+       for (i = 0; i < data->dacs; ++i)
                pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
 }
 
@@ -430,6 +616,42 @@ static void set_cs43xx_params(struct oxygen *chip,
        cs4362a_write(chip, 0x0c, data->cs4362a_fm);
 }
 
+static void set_hdmi_params(struct oxygen *chip,
+                           struct snd_pcm_hw_params *params)
+{
+       struct xonar_data *data = chip->model_data;
+
+       data->hdmi_params[0] = 0; /* 1 = non-audio */
+       switch (params_rate(params)) {
+       case 44100:
+               data->hdmi_params[1] = IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
+               break;
+       default: /* 96000 */
+               data->hdmi_params[1] = IEC958_AES3_CON_FS_96000;
+               break;
+       case 192000:
+               data->hdmi_params[1] = IEC958_AES3_CON_FS_192000;
+               break;
+       }
+       data->hdmi_params[2] = params_channels(params) / 2 - 1;
+       if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+               data->hdmi_params[3] = 0;
+       else
+               data->hdmi_params[3] = 0xc0;
+       data->hdmi_params[4] = 1; /* ? */
+       hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
+}
+
+static void set_hdav_params(struct oxygen *chip,
+                           struct snd_pcm_hw_params *params)
+{
+       set_pcm1796_params(chip, params);
+       set_hdmi_params(chip, params);
+}
+
 static void xonar_gpio_changed(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
@@ -449,29 +671,43 @@ static void xonar_gpio_changed(struct oxygen *chip)
        }
 }
 
-static int alt_switch_get(struct snd_kcontrol *ctl,
-                         struct snd_ctl_elem_value *value)
+static void xonar_hdav_uart_input(struct oxygen *chip)
+{
+       if (chip->uart_input_count >= 2 &&
+           chip->uart_input[chip->uart_input_count - 2] == 'O' &&
+           chip->uart_input[chip->uart_input_count - 1] == 'K') {
+               printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:");
+               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+                                    chip->uart_input, chip->uart_input_count);
+               chip->uart_input_count = 0;
+       }
+}
+
+static int gpio_bit_switch_get(struct snd_kcontrol *ctl,
+                              struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
+       u16 bit = ctl->private_value;
 
        value->value.integer.value[0] =
-               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_D2_ALT);
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
        return 0;
 }
 
-static int alt_switch_put(struct snd_kcontrol *ctl,
-                         struct snd_ctl_elem_value *value)
+static int gpio_bit_switch_put(struct snd_kcontrol *ctl,
+                              struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
+       u16 bit = ctl->private_value;
        u16 old_bits, new_bits;
        int changed;
 
        spin_lock_irq(&chip->reg_lock);
        old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
        if (value->value.integer.value[0])
-               new_bits = old_bits | GPIO_D2_ALT;
+               new_bits = old_bits | bit;
        else
-               new_bits = old_bits & ~GPIO_D2_ALT;
+               new_bits = old_bits & ~bit;
        changed = new_bits != old_bits;
        if (changed)
                oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
@@ -483,47 +719,22 @@ static const struct snd_kcontrol_new alt_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Analog Loopback Switch",
        .info = snd_ctl_boolean_mono_info,
-       .get = alt_switch_get,
-       .put = alt_switch_put,
+       .get = gpio_bit_switch_get,
+       .put = gpio_bit_switch_put,
+       .private_value = GPIO_D2_ALT,
 };
 
-static int front_panel_get(struct snd_kcontrol *ctl,
-                          struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-
-       value->value.integer.value[0] =
-               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DX_FRONT_PANEL);
-       return 0;
-}
-
-static int front_panel_put(struct snd_kcontrol *ctl,
-                          struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       u16 old_reg, new_reg;
-
-       spin_lock_irq(&chip->reg_lock);
-       old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       if (value->value.integer.value[0])
-               new_reg = old_reg | GPIO_DX_FRONT_PANEL;
-       else
-               new_reg = old_reg & ~GPIO_DX_FRONT_PANEL;
-       oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
-       spin_unlock_irq(&chip->reg_lock);
-       return old_reg != new_reg;
-}
-
 static const struct snd_kcontrol_new front_panel_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Front Panel Switch",
        .info = snd_ctl_boolean_mono_info,
-       .get = front_panel_get,
-       .put = front_panel_put,
+       .get = gpio_bit_switch_get,
+       .put = gpio_bit_switch_put,
+       .private_value = GPIO_DX_FRONT_PANEL,
 };
 
-static void xonar_d1_ac97_switch(struct oxygen *chip,
-                                unsigned int reg, unsigned int mute)
+static void xonar_line_mic_ac97_switch(struct oxygen *chip,
+                                      unsigned int reg, unsigned int mute)
 {
        if (reg == AC97_LINE) {
                spin_lock_irq(&chip->reg_lock);
@@ -552,7 +763,7 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
        return 0;
 }
 
-static int xonar_mixer_init(struct oxygen *chip)
+static int xonar_d2_mixer_init(struct oxygen *chip)
 {
        return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
 }
@@ -562,130 +773,147 @@ static int xonar_d1_mixer_init(struct oxygen *chip)
        return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
 }
 
-static const struct oxygen_model xonar_models[] = {
-       [MODEL_D2] = {
-               .shortname = "Xonar D2",
-               .longname = "Asus Virtuoso 200",
-               .chip = "AV200",
-               .owner = THIS_MODULE,
-               .init = xonar_d2_init,
-               .control_filter = xonar_d2_control_filter,
-               .mixer_init = xonar_mixer_init,
-               .cleanup = xonar_cleanup,
-               .suspend = xonar_cleanup,
-               .resume = xonar_d2_resume,
-               .set_dac_params = set_pcm1796_params,
-               .set_adc_params = set_cs53x1_params,
-               .update_dac_volume = update_pcm1796_volume,
-               .update_dac_mute = update_pcm1796_mute,
-               .dac_tlv = pcm1796_db_scale,
-               .model_data_size = sizeof(struct xonar_data),
-               .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                              PLAYBACK_1_TO_SPDIF |
-                              CAPTURE_0_FROM_I2S_2 |
-                              CAPTURE_1_FROM_SPDIF,
-               .dac_channels = 8,
-               .dac_volume_min = 0x0f,
-               .dac_volume_max = 0xff,
-               .misc_flags = OXYGEN_MISC_MIDI,
-               .function_flags = OXYGEN_FUNCTION_SPI |
-                                 OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-               .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-               .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       },
-       [MODEL_D2X] = {
-               .shortname = "Xonar D2X",
-               .longname = "Asus Virtuoso 200",
-               .chip = "AV200",
-               .owner = THIS_MODULE,
-               .init = xonar_d2x_init,
-               .control_filter = xonar_d2_control_filter,
-               .mixer_init = xonar_mixer_init,
-               .cleanup = xonar_cleanup,
-               .suspend = xonar_cleanup,
-               .resume = xonar_d2_resume,
-               .set_dac_params = set_pcm1796_params,
-               .set_adc_params = set_cs53x1_params,
-               .update_dac_volume = update_pcm1796_volume,
-               .update_dac_mute = update_pcm1796_mute,
-               .gpio_changed = xonar_gpio_changed,
-               .dac_tlv = pcm1796_db_scale,
-               .model_data_size = sizeof(struct xonar_data),
-               .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                              PLAYBACK_1_TO_SPDIF |
-                              CAPTURE_0_FROM_I2S_2 |
-                              CAPTURE_1_FROM_SPDIF,
-               .dac_channels = 8,
-               .dac_volume_min = 0x0f,
-               .dac_volume_max = 0xff,
-               .misc_flags = OXYGEN_MISC_MIDI,
-               .function_flags = OXYGEN_FUNCTION_SPI |
-                                 OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-               .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-               .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       },
-       [MODEL_D1] = {
-               .shortname = "Xonar D1",
-               .longname = "Asus Virtuoso 100",
-               .chip = "AV200",
-               .owner = THIS_MODULE,
-               .init = xonar_d1_init,
-               .control_filter = xonar_d1_control_filter,
-               .mixer_init = xonar_d1_mixer_init,
-               .cleanup = xonar_d1_cleanup,
-               .suspend = xonar_d1_cleanup,
-               .resume = xonar_d1_resume,
-               .set_dac_params = set_cs43xx_params,
-               .set_adc_params = set_cs53x1_params,
-               .update_dac_volume = update_cs43xx_volume,
-               .update_dac_mute = update_cs43xx_mute,
-               .ac97_switch = xonar_d1_ac97_switch,
-               .dac_tlv = cs4362a_db_scale,
-               .model_data_size = sizeof(struct xonar_data),
-               .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                              PLAYBACK_1_TO_SPDIF |
-                              CAPTURE_0_FROM_I2S_2,
-               .dac_channels = 8,
-               .dac_volume_min = 0,
-               .dac_volume_max = 127,
-               .function_flags = OXYGEN_FUNCTION_2WIRE,
-               .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-               .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       },
-       [MODEL_DX] = {
-               .shortname = "Xonar DX",
-               .longname = "Asus Virtuoso 100",
-               .chip = "AV200",
-               .owner = THIS_MODULE,
-               .init = xonar_dx_init,
-               .control_filter = xonar_d1_control_filter,
-               .mixer_init = xonar_d1_mixer_init,
-               .cleanup = xonar_d1_cleanup,
-               .suspend = xonar_d1_cleanup,
-               .resume = xonar_d1_resume,
-               .set_dac_params = set_cs43xx_params,
-               .set_adc_params = set_cs53x1_params,
-               .update_dac_volume = update_cs43xx_volume,
-               .update_dac_mute = update_cs43xx_mute,
-               .gpio_changed = xonar_gpio_changed,
-               .ac97_switch = xonar_d1_ac97_switch,
-               .dac_tlv = cs4362a_db_scale,
-               .model_data_size = sizeof(struct xonar_data),
-               .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
-                              PLAYBACK_1_TO_SPDIF |
-                              CAPTURE_0_FROM_I2S_2,
-               .dac_channels = 8,
-               .dac_volume_min = 0,
-               .dac_volume_max = 127,
-               .function_flags = OXYGEN_FUNCTION_2WIRE,
-               .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-               .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       },
+static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data)
+{
+       static const char *const names[] = {
+               [MODEL_D1]      = "Xonar D1",
+               [MODEL_DX]      = "Xonar DX",
+               [MODEL_D2]      = "Xonar D2",
+               [MODEL_D2X]     = "Xonar D2X",
+               [MODEL_HDAV]    = "Xonar HDAV1.3",
+               [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
+       };
+       static const u8 dacs[] = {
+               [MODEL_D1]      = 2,
+               [MODEL_DX]      = 2,
+               [MODEL_D2]      = 4,
+               [MODEL_D2X]     = 4,
+               [MODEL_HDAV]    = 1,
+               [MODEL_HDAV_H6] = 4,
+       };
+       struct xonar_data *data = chip->model_data;
+
+       data->model = driver_data;
+       if (data->model == MODEL_HDAV) {
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                                   GPIO_HDAV_DB_MASK);
+               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                       GPIO_HDAV_DB_MASK) {
+               case GPIO_HDAV_DB_H6:
+                       data->model = MODEL_HDAV_H6;
+                       break;
+               case GPIO_HDAV_DB_XX:
+                       snd_printk(KERN_ERR "unknown daughterboard\n");
+                       return -ENODEV;
+               }
+       }
+
+       data->dacs = dacs[data->model];
+       chip->model.shortname = names[data->model];
+       return 0;
+}
+
+static const struct oxygen_model model_xonar_d2 = {
+       .longname = "Asus Virtuoso 200",
+       .chip = "AV200",
+       .owner = THIS_MODULE,
+       .probe = xonar_model_probe,
+       .init = xonar_d2_init,
+       .control_filter = xonar_d2_control_filter,
+       .mixer_init = xonar_d2_mixer_init,
+       .cleanup = xonar_d2_cleanup,
+       .suspend = xonar_d2_suspend,
+       .resume = xonar_d2_resume,
+       .set_dac_params = set_pcm1796_params,
+       .set_adc_params = set_cs53x1_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .dac_tlv = pcm1796_db_scale,
+       .model_data_size = sizeof(struct xonar_data),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2 |
+                        CAPTURE_1_FROM_SPDIF |
+                        MIDI_OUTPUT |
+                        MIDI_INPUT,
+       .dac_channels = 8,
+       .dac_volume_min = 0x0f,
+       .dac_volume_max = 0xff,
+       .misc_flags = OXYGEN_MISC_MIDI,
+       .function_flags = OXYGEN_FUNCTION_SPI |
+                         OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_d1 = {
+       .longname = "Asus Virtuoso 100",
+       .chip = "AV200",
+       .owner = THIS_MODULE,
+       .probe = xonar_model_probe,
+       .init = xonar_d1_init,
+       .control_filter = xonar_d1_control_filter,
+       .mixer_init = xonar_d1_mixer_init,
+       .cleanup = xonar_d1_cleanup,
+       .suspend = xonar_d1_suspend,
+       .resume = xonar_d1_resume,
+       .set_dac_params = set_cs43xx_params,
+       .set_adc_params = set_cs53x1_params,
+       .update_dac_volume = update_cs43xx_volume,
+       .update_dac_mute = update_cs43xx_mute,
+       .ac97_switch = xonar_line_mic_ac97_switch,
+       .dac_tlv = cs4362a_db_scale,
+       .model_data_size = sizeof(struct xonar_data),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2,
+       .dac_channels = 8,
+       .dac_volume_min = 0,
+       .dac_volume_max = 127,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_hdav = {
+       .longname = "Asus Virtuoso 200",
+       .chip = "AV200",
+       .owner = THIS_MODULE,
+       .probe = xonar_model_probe,
+       .init = xonar_hdav_init,
+       .cleanup = xonar_hdav_cleanup,
+       .suspend = xonar_hdav_suspend,
+       .resume = xonar_hdav_resume,
+       .pcm_hardware_filter = xonar_hdav_pcm_hardware_filter,
+       .set_dac_params = set_hdav_params,
+       .set_adc_params = set_cs53x1_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .uart_input = xonar_hdav_uart_input,
+       .ac97_switch = xonar_line_mic_ac97_switch,
+       .dac_tlv = pcm1796_db_scale,
+       .model_data_size = sizeof(struct xonar_data),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2,
+       .dac_channels = 8,
+       .dac_volume_min = 0x0f,
+       .dac_volume_max = 0xff,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
 static int __devinit xonar_probe(struct pci_dev *pci,
                                 const struct pci_device_id *pci_id)
 {
+       static const struct oxygen_model *const models[] = {
+               [MODEL_D1]      = &model_xonar_d1,
+               [MODEL_DX]      = &model_xonar_d1,
+               [MODEL_D2]      = &model_xonar_d2,
+               [MODEL_D2X]     = &model_xonar_d2,
+               [MODEL_HDAV]    = &model_xonar_hdav,
+       };
        static int dev;
        int err;
 
@@ -695,8 +923,10 @@ static int __devinit xonar_probe(struct pci_dev *pci,
                ++dev;
                return -ENOENT;
        }
+       BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models));
        err = oxygen_pci_probe(pci, index[dev], id[dev],
-                              &xonar_models[pci_id->driver_data]);
+                              models[pci_id->driver_data],
+                              pci_id->driver_data);
        if (err >= 0)
                ++dev;
        return err;
index 2c7e25336795d6bfb6588019069ff77947163e61..0e06c6c9fcc01d1406e3ba61921aece7bef9196f 100644 (file)
@@ -464,7 +464,8 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
        pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
        pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
 
-       snd_assert(subs->runtime->dma_bytes < 0x200000);        /* max buffer size is 2 MByte */
+       /* max buffer size is 2 MByte */
+       snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000);
        rmh.cmd[1] = subs->runtime->dma_bytes * 8;              /* size in bits */
        rmh.cmd[2] = subs->runtime->dma_addr >> 24;             /* most significant byte */
        rmh.cmd[2] |= 1<<19;                                    /* this is a circular buffer */
@@ -1228,7 +1229,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
                return -ENOMEM;
        }
 
-       snd_assert(pci_id->driver_data < PCI_ID_LAST, return -ENODEV);
+       if (snd_BUG_ON(pci_id->driver_data >= PCI_ID_LAST))
+               return -ENODEV;
        card_name = pcxhr_board_params[pci_id->driver_data].board_name;
        mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips;
        mgr->capture_chips  = pcxhr_board_params[pci_id->driver_data].capture_chips;
index 000e6fed6e3985c1a8ff1ceb5caab0c2acc23e13..7143259cfe3432f339c363d47a0589956f41b8d9 100644 (file)
@@ -319,16 +319,20 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
        const unsigned char *data;
        unsigned char dummy;
        /* check the length of boot image */
-       snd_assert(dsp->size > 0, return -EINVAL);
-       snd_assert(dsp->size % 3 == 0, return -EINVAL);
-       snd_assert(dsp->data, return -EINVAL);
+       if (dsp->size <= 0)
+               return -EINVAL;
+       if (dsp->size % 3)
+               return -EINVAL;
+       if (snd_BUG_ON(!dsp->data))
+               return -EINVAL;
        /* transfert data buffer from PC to DSP */
        for (i = 0; i < dsp->size; i += 3) {
                data = dsp->data + i;
                if (i == 0) {
                        /* test data header consistency */
                        len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]);
-                       snd_assert((len==0) || (dsp->size == (len+2)*3), return -EINVAL);
+                       if (len && dsp->size != (len + 2) * 3)
+                               return -EINVAL;
                }
                /* wait DSP ready for new transfer */
                err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
@@ -389,7 +393,8 @@ int pcxhr_load_boot_binary(struct pcxhr_mgr *mgr, const struct firmware *boot)
        unsigned char dummy;
 
        /* send the hostport address to the DSP (only the upper 24 bit !) */
-       snd_assert((physaddr & 0xff) == 0, return -EINVAL);
+       if (snd_BUG_ON(physaddr & 0xff))
+               return -EINVAL;
        PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX1, (physaddr >> 8));
 
        err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_BOOT, 0);
@@ -570,7 +575,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
        u32 data;
        unsigned char reg;
 
-       snd_assert(rmh->cmd_len<PCXHR_SIZE_MAX_CMD, return -EINVAL);
+       if (snd_BUG_ON(rmh->cmd_len >= PCXHR_SIZE_MAX_CMD))
+               return -EINVAL;
        err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
        if (err) {
                snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n");
@@ -677,7 +683,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
  */
 void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd)
 {
-       snd_assert(cmd < CMD_LAST_INDEX, return);
+       if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
+               return;
        rmh->cmd[0] = pcxhr_dsp_cmds[cmd].opcode;
        rmh->cmd_len = 1;
        rmh->stat_len = pcxhr_dsp_cmds[cmd].st_length;
@@ -690,17 +697,17 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
                               unsigned int param1, unsigned int param2,
                               unsigned int param3)
 {
-       snd_assert(param1 <= MASK_FIRST_FIELD);
+       snd_BUG_ON(param1 > MASK_FIRST_FIELD);
        if (capture)
                rmh->cmd[0] |= 0x800;           /* COMMAND_RECORD_MASK */
        if (param1)
                rmh->cmd[0] |= (param1 << FIELD_SIZE);
        if (param2) {
-               snd_assert(param2 <= MASK_FIRST_FIELD);
+               snd_BUG_ON(param2 > MASK_FIRST_FIELD);
                rmh->cmd[0] |= param2;
        }
        if(param3) {
-               snd_assert(param3 <= MASK_DSP_WORD);
+               snd_BUG_ON(param3 > MASK_DSP_WORD);
                rmh->cmd[1] = param3;
                rmh->cmd_len = 2;
        }
index d2f043278cf4f8a329affc0116d6d122f1f586ee..96640d9c227d83628234c81033fd31b870b00b4e 100644 (file)
@@ -65,15 +65,18 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
        if (err)
                return err;
        /* test 8 or 12 phys out */
-       snd_assert((rmh.stat[0] & MASK_FIRST_FIELD) == mgr->playback_chips*2,
-                  return -EINVAL);
+       if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
+               return -EINVAL;
        /* test 8 or 2 phys in */
-       snd_assert(((rmh.stat[0] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD) ==
-                  mgr->capture_chips * 2, return -EINVAL);
+       if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) !=
+           mgr->capture_chips * 2)
+               return -EINVAL;
        /* test max nb substream per board */
-       snd_assert((rmh.stat[1] & 0x5F) >= card_streams, return -EINVAL);
+       if ((rmh.stat[1] & 0x5F) < card_streams)
+               return -EINVAL;
        /* test max nb substream per pipe */
-       snd_assert(((rmh.stat[1]>>7)&0x5F) >= PCXHR_PLAYBACK_STREAMS, return -EINVAL);
+       if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
+               return -EINVAL;
 
        pcxhr_init_rmh(&rmh, CMD_VERSION);
        /* firmware num for DSP */
index 6a35962473482bf9c46ce32e0baed87ac56963ad..e9f0706ed3e45d2368ebe7170682b74290b15159 100644 (file)
@@ -865,7 +865,8 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm,
        struct riptideport *hwport;
        struct cmdport *cmdport = NULL;
 
-       snd_assert(cif, return -EINVAL);
+       if (snd_BUG_ON(!cif))
+               return -EINVAL;
 
        hwport = cif->hwport;
        if (cif->errcnt > MAX_ERROR_COUNT) {
@@ -1482,7 +1483,6 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_riptide *chip = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
        struct pcmhw *data = get_pcmhwdev(substream);
        struct cmdif *cif = chip->cif;
        unsigned char *lbuspath = NULL;
@@ -1490,7 +1490,8 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
        int err = 0;
        snd_pcm_format_t format;
 
-       snd_assert(cif && data, return -EINVAL);
+       if (snd_BUG_ON(!cif || !data))
+               return -EINVAL;
 
        snd_printdd("prepare id %d ch: %d f:0x%x r:%d\n", data->id,
                    runtime->channels, runtime->format, runtime->rate);
@@ -1513,9 +1514,9 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
                        lbuspath = data->paths.stereo;
                break;
        }
-       snd_printdd("use sgdlist at 0x%p and buffer at 0x%p\n",
-                   data->sgdlist.area, sgbuf);
-       if (data->sgdlist.area && sgbuf) {
+       snd_printdd("use sgdlist at 0x%p\n",
+                   data->sgdlist.area);
+       if (data->sgdlist.area) {
                unsigned int i, j, size, pages, f, pt, period;
                struct sgd *c, *p = NULL;
 
@@ -1533,6 +1534,7 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
                pt = 0;
                j = 0;
                for (i = 0; i < pages; i++) {
+                       unsigned int ofs, addr;
                        c = &data->sgdbuf[i];
                        if (p)
                                p->dwNextLink = cpu_to_le32(data->sgdlist.addr +
@@ -1540,8 +1542,9 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
                                                             sizeof(struct
                                                                    sgd)));
                        c->dwNextLink = cpu_to_le32(data->sgdlist.addr);
-                       c->dwSegPtrPhys =
-                           cpu_to_le32(sgbuf->table[j].addr + pt);
+                       ofs = j << PAGE_SHIFT;
+                       addr = snd_pcm_sgbuf_get_addr(substream, ofs) + pt;
+                       c->dwSegPtrPhys = cpu_to_le32(addr);
                        pt = (pt + f) % PAGE_SIZE;
                        if (pt == 0)
                                j++;
@@ -1772,7 +1775,8 @@ snd_riptide_codec_write(struct snd_ac97 *ac97, unsigned short reg,
        union cmdret rptr = CMDRET_ZERO;
        int i = 0;
 
-       snd_assert(cif, return);
+       if (snd_BUG_ON(!cif))
+               return;
 
        snd_printdd("Write AC97 reg 0x%x 0x%x\n", reg, val);
        do {
@@ -1790,7 +1794,8 @@ static unsigned short snd_riptide_codec_read(struct snd_ac97 *ac97,
        struct cmdif *cif = chip->cif;
        union cmdret rptr = CMDRET_ZERO;
 
-       snd_assert(cif, return 0);
+       if (snd_BUG_ON(!cif))
+               return 0;
 
        if (SEND_RACR(cif, reg, &rptr) != 0)
                SEND_RACR(cif, reg, &rptr);
@@ -1804,7 +1809,8 @@ static int snd_riptide_initialize(struct snd_riptide *chip)
        unsigned int device_id;
        int err;
 
-       snd_assert(chip, return -EINVAL);
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
 
        cif = chip->cif;
        if (!cif) {
@@ -1836,7 +1842,8 @@ static int snd_riptide_free(struct snd_riptide *chip)
 {
        struct cmdif *cif;
 
-       snd_assert(chip, return 0);
+       if (!chip)
+               return 0;
 
        if ((cif = chip->cif)) {
                SET_GRESET(cif->hwport);
index 4d6fbb36ab8af1f2b7df881ff402402af28f8b53..d723543beadd68af5fb9f88540412210c7e819be 100644 (file)
@@ -1036,7 +1036,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
        n = DDS_NUMERATOR;
        div64_32(&n, rate, &r);
        /* n should be less than 2^32 for being written to FREQ register */
-       snd_assert((n >> 32) == 0);
+       snd_BUG_ON(n >> 32);
        /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
           value to write it after a reset */
        hdsp->dds_value = n;
@@ -3043,7 +3043,7 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
 
        offset = ucontrol->id.index - 1;
-       snd_assert(offset >= 0);
+       snd_BUG_ON(offset < 0);
 
        switch (hdsp->io_type) {
        case Digiface:
@@ -3767,7 +3767,8 @@ static char *hdsp_channel_buffer_location(struct hdsp *hdsp,
 {
        int mapped_channel;
 
-        snd_assert(channel >= 0 && channel < hdsp->max_channels, return NULL);
+        if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels))
+               return NULL;
         
        if ((mapped_channel = hdsp->channel_map[channel]) < 0)
                return NULL;
@@ -3784,10 +3785,12 @@ static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream, int chann
        struct hdsp *hdsp = snd_pcm_substream_chip(substream);
        char *channel_buf;
 
-       snd_assert(pos + count <= HDSP_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+       if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4))
+               return -EINVAL;
 
        channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        if (copy_from_user(channel_buf + pos * 4, src, count * 4))
                return -EFAULT;
        return count;
@@ -3799,10 +3802,12 @@ static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream, int channe
        struct hdsp *hdsp = snd_pcm_substream_chip(substream);
        char *channel_buf;
 
-       snd_assert(pos + count <= HDSP_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+       if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4))
+               return -EINVAL;
 
        channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
                return -EFAULT;
        return count;
@@ -3815,7 +3820,8 @@ static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream, int channel,
        char *channel_buf;
 
        channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        memset(channel_buf + pos * 4, 0, count * 4);
        return count;
 }
@@ -3927,7 +3933,8 @@ static int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
        struct hdsp *hdsp = snd_pcm_substream_chip(substream);
        int mapped_channel;
 
-       snd_assert(info->channel < hdsp->max_channels, return -EINVAL);
+       if (snd_BUG_ON(info->channel >= hdsp->max_channels))
+               return -EINVAL;
 
        if ((mapped_channel = hdsp->channel_map[info->channel]) < 0)
                return -EINVAL;
index ab423bc823425834c108a3f84d060094324970ea..98762f909d6407b75495e4cbc98ad3640d9ea9cb 100644 (file)
@@ -535,7 +535,8 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm);
 static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm);
 static int hdspm_autosync_ref(struct hdspm * hdspm);
 static int snd_hdspm_set_defaults(struct hdspm * hdspm);
-static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
+static void hdspm_set_sgbuf(struct hdspm * hdspm,
+                           struct snd_pcm_substream *substream,
                             unsigned int reg, int channels);
 
 static inline int HDSPM_bit2freq(int n)
@@ -845,7 +846,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
        n = 110100480000000ULL;    /* Value checked for AES32 and MADI */
        div64_32(&n, rate, &r);
        /* n should be less than 2^32 for being written to FREQ register */
-       snd_assert((n >> 32) == 0);
+       snd_BUG_ON(n >> 32);
        hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
 }
 
@@ -2617,8 +2618,8 @@ static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol,
 
        channel = ucontrol->id.index - 1;
 
-       snd_assert(channel >= 0
-                  || channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+       if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
+               return -EINVAL;
 
        mapped_channel = hdspm->channel_map[channel];
        if (mapped_channel < 0)
@@ -2652,8 +2653,8 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
 
        channel = ucontrol->id.index - 1;
 
-       snd_assert(channel >= 0
-                  || channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+       if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
+               return -EINVAL;
 
        mapped_channel = hdspm->channel_map[channel];
        if (mapped_channel < 0)
@@ -3496,8 +3497,8 @@ static char *hdspm_channel_buffer_location(struct hdspm * hdspm,
 {
        int mapped_channel;
 
-       snd_assert(channel >= 0
-                  || channel < HDSPM_MAX_CHANNELS, return NULL);
+       if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
+               return NULL;
 
        mapped_channel = hdspm->channel_map[channel];
        if (mapped_channel < 0)
@@ -3520,14 +3521,15 @@ static int snd_hdspm_playback_copy(struct snd_pcm_substream *substream,
        struct hdspm *hdspm = snd_pcm_substream_chip(substream);
        char *channel_buf;
 
-       snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4,
-                  return -EINVAL);
+       if (snd_BUG_ON(pos + count > HDSPM_CHANNEL_BUFFER_BYTES / 4))
+               return -EINVAL;
 
        channel_buf =
                hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
                                              channel);
 
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
 
        return copy_from_user(channel_buf + pos * 4, src, count * 4);
 }
@@ -3539,13 +3541,14 @@ static int snd_hdspm_capture_copy(struct snd_pcm_substream *substream,
        struct hdspm *hdspm = snd_pcm_substream_chip(substream);
        char *channel_buf;
 
-       snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4,
-                  return -EINVAL);
+       if (snd_BUG_ON(pos + count > HDSPM_CHANNEL_BUFFER_BYTES / 4))
+               return -EINVAL;
 
        channel_buf =
                hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
                                              channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        return copy_to_user(dst, channel_buf + pos * 4, count * 4);
 }
 
@@ -3559,7 +3562,8 @@ static int snd_hdspm_hw_silence(struct snd_pcm_substream *substream,
        channel_buf =
                hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
                                              channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        memset(channel_buf + pos * 4, 0, count * 4);
        return 0;
 }
@@ -3601,8 +3605,6 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
        int i;
        pid_t this_pid;
        pid_t other_pid;
-       struct snd_sg_buf *sgbuf;
-
 
        spin_lock_irq(&hdspm->lock);
 
@@ -3670,11 +3672,9 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
        if (err < 0)
                return err;
 
-       sgbuf = snd_pcm_substream_sgbuf(substream);
-
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 
-               hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferOut,
+               hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferOut,
                                params_channels(params));
 
                for (i = 0; i < params_channels(params); ++i)
@@ -3685,7 +3685,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
                snd_printdd("Allocated sample buffer for playback at %p\n",
                                hdspm->playback_buffer);
        } else {
-               hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn,
+               hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn,
                                params_channels(params));
 
                for (i = 0; i < params_channels(params); ++i)
@@ -3700,7 +3700,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
           snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
           substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
           "playback" : "capture",
-          snd_pcm_sgbuf_get_addr(sgbuf, 0));
+          snd_pcm_sgbuf_get_addr(substream, 0));
         */
        /*
        snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
@@ -3744,7 +3744,8 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
        struct hdspm *hdspm = snd_pcm_substream_chip(substream);
        int mapped_channel;
 
-       snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+       if (snd_BUG_ON(info->channel >= HDSPM_MAX_CHANNELS))
+               return -EINVAL;
 
        mapped_channel = hdspm->channel_map[info->channel];
        if (mapped_channel < 0)
@@ -4249,13 +4250,14 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm)
        return 0;
 }
 
-static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
+static void hdspm_set_sgbuf(struct hdspm * hdspm,
+                           struct snd_pcm_substream *substream,
                             unsigned int reg, int channels)
 {
        int i;
        for (i = 0; i < (channels * 16); i++)
                hdspm_write(hdspm, reg + 4 * i,
-                           snd_pcm_sgbuf_get_addr(sgbuf, (size_t) 4096 * i));
+                           snd_pcm_sgbuf_get_addr(substream, 4096 * i));
 }
 
 /* ------------- ALSA Devices ---------------------------- */
index a123f0e6ba23386213738dfdb835c7fa5a55353b..2570907134d75cd89067b14865fbd90355749df9 100644 (file)
@@ -595,8 +595,6 @@ static void rme9652_set_thru(struct snd_rme9652 *rme9652, int channel, int enabl
        } else {
                int mapped_channel;
 
-               snd_assert(channel == RME9652_NCHANNELS, return);
-
                mapped_channel = rme9652->channel_map[channel];
 
                if (enable) {
@@ -1893,7 +1891,8 @@ static char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652,
 {
        int mapped_channel;
 
-        snd_assert(channel >= 0 || channel < RME9652_NCHANNELS, return NULL);
+       if (snd_BUG_ON(channel < 0 || channel >= RME9652_NCHANNELS))
+               return NULL;
         
        if ((mapped_channel = rme9652->channel_map[channel]) < 0) {
                return NULL;
@@ -1914,12 +1913,14 @@ static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, int ch
        struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
        char *channel_buf;
 
-       snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+       if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4))
+               return -EINVAL;
 
        channel_buf = rme9652_channel_buffer_location (rme9652,
                                                       substream->pstr->stream,
                                                       channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        if (copy_from_user(channel_buf + pos * 4, src, count * 4))
                return -EFAULT;
        return count;
@@ -1931,12 +1932,14 @@ static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, int cha
        struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
        char *channel_buf;
 
-       snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);
+       if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4))
+               return -EINVAL;
 
        channel_buf = rme9652_channel_buffer_location (rme9652,
                                                       substream->pstr->stream,
                                                       channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
                return -EFAULT;
        return count;
@@ -1951,7 +1954,8 @@ static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, int chann
        channel_buf = rme9652_channel_buffer_location (rme9652,
                                                       substream->pstr->stream,
                                                       channel);
-       snd_assert(channel_buf != NULL, return -EIO);
+       if (snd_BUG_ON(!channel_buf))
+               return -EIO;
        memset(channel_buf + pos * 4, 0, count * 4);
        return count;
 }
@@ -2053,7 +2057,8 @@ static int snd_rme9652_channel_info(struct snd_pcm_substream *substream,
        struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
        int chn;
 
-       snd_assert(info->channel < RME9652_NCHANNELS, return -EINVAL);
+       if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS))
+               return -EINVAL;
 
        if ((chn = rme9652->channel_map[info->channel]) < 0) {
                return -EINVAL;
index 0d3d305b0a0b0c2805ebf26cc1a0cd004a89db4d..cd408b86c839b1833e6f6a743f3459cc780cf10a 100644 (file)
@@ -534,8 +534,8 @@ static int snd_sonicvibes_hw_constraint_dac_rate(struct snd_pcm_hw_params *param
                        params->rate_den = 1;
                } else {
                        snd_sonicvibes_pll(rate, &r, &m, &n);
-                       snd_assert((SV_REFFREQUENCY % 16) == 0, return -EINVAL);
-                       snd_assert((SV_ADCMULT % 512) == 0, return -EINVAL);
+                       snd_BUG_ON(SV_REFFREQUENCY % 16);
+                       snd_BUG_ON(SV_ADCMULT % 512);
                        params->rate_num = (SV_REFFREQUENCY/16) * (n+2) * r;
                        params->rate_den = (SV_ADCMULT/512) * (m+2);
                }
@@ -849,7 +849,8 @@ static int __devinit snd_sonicvibes_pcm(struct sonicvibes * sonic, int device, s
 
        if ((err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm)) < 0)
                return err;
-       snd_assert(pcm != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pcm))
+               return -EINVAL;
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sonicvibes_playback_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sonicvibes_capture_ops);
@@ -1089,7 +1090,8 @@ static int __devinit snd_sonicvibes_mixer(struct sonicvibes * sonic)
        unsigned int idx;
        int err;
 
-       snd_assert(sonic != NULL && sonic->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!sonic || !sonic->card))
+               return -EINVAL;
        card = sonic->card;
        strcpy(card->mixername, "S3 SonicVibes");
 
index a69b4206c69e205f9a88726f63182f75b36491ee..c612b435ca2bc6cd43a7ba77ce8ceb4dd81c6a3a 100644 (file)
@@ -2931,7 +2931,8 @@ static int snd_trident_pcm_mixer_build(struct snd_trident *trident,
 {
        struct snd_trident_pcm_mixer *tmix;
 
-       snd_assert(trident != NULL && voice != NULL && substream != NULL, return -EINVAL);
+       if (snd_BUG_ON(!trident || !voice || !substream))
+               return -EINVAL;
        tmix = &trident->pcm_mixer[substream->number];
        tmix->voice = voice;
        tmix->vol = T4D_DEFAULT_PCM_VOL;
@@ -2946,7 +2947,8 @@ static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_tr
 {
        struct snd_trident_pcm_mixer *tmix;
 
-       snd_assert(trident != NULL && substream != NULL, return -EINVAL);
+       if (snd_BUG_ON(!trident || !substream))
+               return -EINVAL;
        tmix = &trident->pcm_mixer[substream->number];
        tmix->voice = NULL;
        snd_trident_notify_pcm_change(trident, tmix, substream->number, 0);
@@ -3131,7 +3133,8 @@ static unsigned char snd_trident_gameport_read(struct gameport *gameport)
 {
        struct snd_trident *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
        return inb(TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
@@ -3139,7 +3142,8 @@ static void snd_trident_gameport_trigger(struct gameport *gameport)
 {
        struct snd_trident *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return);
+       if (snd_BUG_ON(!chip))
+               return;
        outb(0xff, TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
@@ -3148,7 +3152,8 @@ static int snd_trident_gameport_cooked_read(struct gameport *gameport, int *axes
        struct snd_trident *chip = gameport_get_port_data(gameport);
        int i;
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
 
        *buttons = (~inb(TRID_REG(chip, GAMEPORT_LEGACY)) >> 4) & 0xf;
 
@@ -3164,7 +3169,8 @@ static int snd_trident_gameport_open(struct gameport *gameport, int mode)
 {
        struct snd_trident *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
 
        switch (mode) {
                case GAMEPORT_MODE_COOKED:
@@ -3891,8 +3897,8 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor
 {
        unsigned int i, val, mask[2] = { 0, 0 };
 
-       snd_assert(v_min <= 63, return);
-       snd_assert(v_max <= 63, return);
+       if (snd_BUG_ON(v_min > 63 || v_max > 63))
+               return;
        for (i = v_min; i <= v_max; i++)
                mask[i >> 5] |= 1 << (i & 0x1f);
        if (mask[0]) {
index 3fd7f1b29b0f57840192aff0e4a97294134c0a5b..f9779e23fe5782668ba997e3a4b0400cef80de0a 100644 (file)
@@ -194,11 +194,14 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident,
        struct snd_util_memblk *blk;
        struct snd_pcm_runtime *runtime = substream->runtime;
        int idx, page;
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
-       snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
+       if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
+                      runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES *
+                                       SNDRV_TRIDENT_PAGE_SIZE))
+               return NULL;
        hdr = trident->tlb.memhdr;
-       snd_assert(hdr != NULL, return NULL);
+       if (snd_BUG_ON(!hdr))
+               return NULL;
 
        
 
@@ -208,18 +211,14 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident,
                mutex_unlock(&hdr->block_mutex);
                return NULL;
        }
-       if (lastpg(blk) - firstpg(blk) >= sgbuf->pages) {
-               snd_printk(KERN_ERR "page calculation doesn't match: allocated pages = %d, trident = %d/%d\n", sgbuf->pages, firstpg(blk), lastpg(blk));
-               __snd_util_mem_free(hdr, blk);
-               mutex_unlock(&hdr->block_mutex);
-               return NULL;
-       }
                           
        /* set TLB entries */
        idx = 0;
        for (page = firstpg(blk); page <= lastpg(blk); page++, idx++) {
-               dma_addr_t addr = sgbuf->table[idx].addr;
-               unsigned long ptr = (unsigned long)sgbuf->table[idx].buf;
+               unsigned long ofs = idx << PAGE_SHIFT;
+               dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+               unsigned long ptr = (unsigned long)
+                       snd_pcm_sgbuf_get_ptr(substream, ofs);
                if (! is_valid_page(addr)) {
                        __snd_util_mem_free(hdr, blk);
                        mutex_unlock(&hdr->block_mutex);
@@ -245,9 +244,13 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident,
        dma_addr_t addr;
        unsigned long ptr;
 
-       snd_assert(runtime->dma_bytes> 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
+       if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
+                      runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES *
+                                       SNDRV_TRIDENT_PAGE_SIZE))
+               return NULL;
        hdr = trident->tlb.memhdr;
-       snd_assert(hdr != NULL, return NULL);
+       if (snd_BUG_ON(!hdr))
+               return NULL;
 
        mutex_lock(&hdr->block_mutex);
        blk = search_empty(hdr, runtime->dma_bytes);
@@ -279,8 +282,8 @@ struct snd_util_memblk *
 snd_trident_alloc_pages(struct snd_trident *trident,
                        struct snd_pcm_substream *substream)
 {
-       snd_assert(trident != NULL, return NULL);
-       snd_assert(substream != NULL, return NULL);
+       if (snd_BUG_ON(!trident || !substream))
+               return NULL;
        if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_SG)
                return snd_trident_alloc_sg_pages(trident, substream);
        else
@@ -297,8 +300,8 @@ int snd_trident_free_pages(struct snd_trident *trident,
        struct snd_util_memhdr *hdr;
        int page;
 
-       snd_assert(trident != NULL, return -EINVAL);
-       snd_assert(blk != NULL, return -EINVAL);
+       if (snd_BUG_ON(!trident || !blk))
+               return -EINVAL;
 
        hdr = trident->tlb.memhdr;
        mutex_lock(&hdr->block_mutex);
index 6781be9e3078ac702364770f407fbc4458486882..1aafe956ee2b348d07d02925b6aa1fdd9ec7f7ee 100644 (file)
@@ -313,6 +313,7 @@ struct snd_via_sg_table {
 } ;
 
 #define VIA_TABLE_SIZE 255
+#define VIA_MAX_BUFSIZE        (1<<24)
 
 struct viadev {
        unsigned int reg_offset;
@@ -420,7 +421,6 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
 {
        unsigned int i, idx, ofs, rest;
        struct via82xx *chip = snd_pcm_substream_chip(substream);
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
        if (dev->table.area == NULL) {
                /* the start of each lists must be aligned to 8 bytes,
@@ -449,15 +449,15 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                do {
                        unsigned int r;
                        unsigned int flag;
+                       unsigned int addr;
 
                        if (idx >= VIA_TABLE_SIZE) {
                                snd_printk(KERN_ERR "via82xx: too much table size!\n");
                                return -EINVAL;
                        }
-                       ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
-                       r = PAGE_SIZE - (ofs % PAGE_SIZE);
-                       if (rest < r)
-                               r = rest;
+                       addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+                       ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32(addr);
+                       r = snd_pcm_sgbuf_get_chunk_size(substream, ofs, rest);
                        rest -= r;
                        if (! rest) {
                                if (i == periods - 1)
@@ -824,7 +824,8 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
        struct viadev *viadev = substream->runtime->private_data;
        unsigned int idx, ptr, count, res;
 
-       snd_assert(viadev->tbl_entries, return 0);
+       if (snd_BUG_ON(!viadev->tbl_entries))
+               return 0;
        if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
                return 0;
 
@@ -855,7 +856,8 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst
        unsigned int idx, count, res;
        int status;
        
-       snd_assert(viadev->tbl_entries, return 0);
+       if (snd_BUG_ON(!viadev->tbl_entries))
+               return 0;
 
        spin_lock(&chip->reg_lock);
        count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT));
@@ -1037,7 +1039,7 @@ static int snd_via8233_playback_prepare(struct snd_pcm_substream *substream)
        else
                rbits = (0x100000 / 48000) * runtime->rate +
                        ((0x100000 % 48000) * runtime->rate) / 48000;
-       snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
+       snd_BUG_ON(rbits & ~0xfffff);
        snd_via82xx_channel_reset(chip, viadev);
        snd_via82xx_set_table_ptr(chip, viadev);
        outb(chip->playback_volume[viadev->reg_offset / 0x10][0],
@@ -1144,9 +1146,9 @@ static struct snd_pcm_hardware snd_via82xx_hw =
        .rate_max =             48000,
        .channels_min =         1,
        .channels_max =         2,
-       .buffer_bytes_max =     128 * 1024,
+       .buffer_bytes_max =     VIA_MAX_BUFSIZE,
        .period_bytes_min =     32,
-       .period_bytes_max =     128 * 1024,
+       .period_bytes_max =     VIA_MAX_BUFSIZE / 2,
        .periods_min =          2,
        .periods_max =          VIA_TABLE_SIZE / 2,
        .fifo_size =            0,
@@ -1398,10 +1400,9 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
        /* capture */
        init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1);
 
-       if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                                        snd_dma_pci_data(chip->pci),
-                                                        64*1024, 128*1024)) < 0)
-               return err;
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             snd_dma_pci_data(chip->pci),
+                                             64*1024, VIA_MAX_BUFSIZE);
 
        /* PCM #1:  multi-channel playback and 2nd capture */
        err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
@@ -1417,11 +1418,9 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
        /* set up capture */
        init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 7, 1);
 
-       if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                                        snd_dma_pci_data(chip->pci),
-                                                        64*1024, 128*1024)) < 0)
-               return err;
-
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             snd_dma_pci_data(chip->pci),
+                                             64*1024, VIA_MAX_BUFSIZE);
        return 0;
 }
 
@@ -1453,10 +1452,9 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
        /* capture */
        init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1);
 
-       if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                                        snd_dma_pci_data(chip->pci),
-                                                        64*1024, 128*1024)) < 0)
-               return err;
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             snd_dma_pci_data(chip->pci),
+                                             64*1024, VIA_MAX_BUFSIZE);
 
        /* SPDIF supported? */
        if (! ac97_can_spdif(chip->ac97))
@@ -1473,11 +1471,9 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
        /* set up playback */
        init_viadev(chip, chip->playback_devno, 0x30, 3, 0);
 
-       if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                                        snd_dma_pci_data(chip->pci),
-                                                        64*1024, 128*1024)) < 0)
-               return err;
-
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             snd_dma_pci_data(chip->pci),
+                                             64*1024, VIA_MAX_BUFSIZE);
        return 0;
 }
 
@@ -1505,11 +1501,9 @@ static int __devinit snd_via686_pcm_new(struct via82xx *chip)
        init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0, 0);
        init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 0, 1);
 
-       if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                                        snd_dma_pci_data(chip->pci),
-                                                        64*1024, 128*1024)) < 0)
-               return err;
-
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             snd_dma_pci_data(chip->pci),
+                                             64*1024, VIA_MAX_BUFSIZE);
        return 0;
 }
 
index 31f64ee398820c62ffb8c9b51318a2c4e122e9b0..5bd79d2a5a1555d80ba7466eca75baab6804714b 100644 (file)
@@ -281,7 +281,6 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
 {
        unsigned int i, idx, ofs, rest;
        struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
        if (dev->table.area == NULL) {
                /* the start of each lists must be aligned to 8 bytes,
@@ -310,12 +309,14 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                do {
                        unsigned int r;
                        unsigned int flag;
+                       unsigned int addr;
 
                        if (idx >= VIA_TABLE_SIZE) {
                                snd_printk(KERN_ERR "via82xx: too much table size!\n");
                                return -EINVAL;
                        }
-                       ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
+                       addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+                       ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32(addr);
                        r = PAGE_SIZE - (ofs % PAGE_SIZE);
                        if (rest < r)
                                r = rest;
@@ -612,7 +613,8 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
        struct viadev *viadev = substream->runtime->private_data;
        unsigned int idx, ptr, count, res;
 
-       snd_assert(viadev->tbl_entries, return 0);
+       if (snd_BUG_ON(!viadev->tbl_entries))
+               return 0;
        if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
                return 0;
 
index 631f3a63999329a8bef69ac0afbc825aac47ae1b..7e87f398ff0bda688caa6f212198b881da687445 100644 (file)
@@ -253,7 +253,8 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        int offset = pipe->hw_ptr;
        u32 *addr = (u32 *)(runtime->dma_area + offset);
 
-       snd_assert(count % 4 == 0, return);
+       if (snd_BUG_ON(count % 4))
+               return;
 
        vx2_setup_pseudo_dma(chip, 1);
 
@@ -291,7 +292,8 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        u32 *addr = (u32 *)(runtime->dma_area + offset);
        unsigned long port = vx2_reg_addr(chip, VX_DMA);
 
-       snd_assert(count % 4 == 0, return);
+       if (snd_BUG_ON(count % 4))
+               return;
 
        vx2_setup_pseudo_dma(chip, 0);
        /* Transfer using pseudo-dma.
@@ -675,7 +677,8 @@ static void vx2_write_akm(struct vx_core *chip, int reg, unsigned int data)
           a look up table, as there is no linear matching between the driver codec values
           and the real dBu value
        */
-       snd_assert(data < sizeof(vx2_akm_gains_lut), return);
+       if (snd_BUG_ON(data >= sizeof(vx2_akm_gains_lut)))
+               return;
 
        switch (reg) {
        case XX_CODEC_LEVEL_LEFT_REGISTER:
@@ -823,7 +826,8 @@ static void vx2_set_input_level(struct snd_vx222 *chip)
                preamp++;       /* raise pre ampli + 18dB */
                miclevel -= (18 * 2);   /* lower level 18 dB (*2 because of 0.5 dB steps !) */
         }
-       snd_assert(preamp < 4, return);
+       if (snd_BUG_ON(preamp >= 4))
+               return;
 
        /* set pre-amp level */
        chip->regSELMIC &= ~MICRO_SELECT_PREAMPLI_MASK;
index 92d49aadf579666a0c837ab692678fc414fece28..90d0d62bd0b40648406bd1db328c280fc572dbfe 100644 (file)
@@ -259,8 +259,10 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip,
        unsigned long flags;
        int result;
        
-       snd_assert(rvoice != NULL, return -EINVAL);
-       snd_assert(!pair || type == YMFPCI_PCM, return -EINVAL);
+       if (snd_BUG_ON(!rvoice))
+               return -EINVAL;
+       if (snd_BUG_ON(pair && type != YMFPCI_PCM))
+               return -EINVAL;
        
        spin_lock_irqsave(&chip->voice_lock, flags);
        for (;;) {
@@ -278,7 +280,8 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic
 {
        unsigned long flags;
        
-       snd_assert(pvoice != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pvoice))
+               return -EINVAL;
        snd_ymfpci_hw_stop(chip);
        spin_lock_irqsave(&chip->voice_lock, flags);
        if (pvoice->number == chip->src441_used) {
@@ -494,7 +497,8 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
        u8 use_left, use_right;
        unsigned long flags;
 
-       snd_assert(voice != NULL, return);
+       if (snd_BUG_ON(!voice))
+               return;
        if (runtime->channels == 1) {
                use_left = 1;
                use_right = 1;
@@ -1813,7 +1817,8 @@ int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
        }
 
        /* add S/PDIF control */
-       snd_assert(chip->pcm_spdif != NULL, return -EIO);
+       if (snd_BUG_ON(!chip->pcm_spdif))
+               return -ENXIO;
        if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip))) < 0)
                return err;
        kctl->id.device = chip->pcm_spdif->device;
@@ -2133,7 +2138,8 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
        chip->work_base = ptr;
        chip->work_base_addr = ptr_addr;
        
-       snd_assert(ptr + chip->work_size == chip->work_ptr.area + chip->work_ptr.bytes, );
+       snd_BUG_ON(ptr + chip->work_size !=
+                  chip->work_ptr.area + chip->work_ptr.bytes);
 
        snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
        snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr);
@@ -2168,7 +2174,8 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
 {
        u16 ctrl;
 
-       snd_assert(chip != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
 
        if (chip->res_reg_area) {       /* don't touch busy hardware */
                snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
index 99bf2a65a6f5ce82260b2f7d0f8fdbf56b804c7f..989e04abb5209ca796fd92606b24fa63e573afaa 100644 (file)
@@ -408,7 +408,8 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        int offset = pipe->hw_ptr;
        unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
 
-       snd_assert(count % 2 == 0, return);
+       if (snd_BUG_ON(count % 2))
+               return;
        vx_setup_pseudo_dma(chip, 0);
        if (offset + count > pipe->buffer_bytes) {
                int length = pipe->buffer_bytes - offset;
index 106c48225bbadd2978a10b325fe80badcc7f086d..7bd33e6552ab813967d44b19aca364801a9a93ba 100644 (file)
@@ -319,7 +319,8 @@ static void awacs_amp_set_master(struct awacs_amp *amp, int vol)
 static void awacs_amp_free(struct snd_pmac *chip)
 {
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return);
+       if (!amp)
+               return;
        kfree(amp);
        chip->mixer_data = NULL;
        chip->mixer_free = NULL;
@@ -345,8 +346,7 @@ static int snd_pmac_awacs_get_volume_amp(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        int index = kcontrol->private_value;
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return -EINVAL);
-       snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
        ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31);
        ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31);
        return 0;
@@ -359,8 +359,6 @@ static int snd_pmac_awacs_put_volume_amp(struct snd_kcontrol *kcontrol,
        int index = kcontrol->private_value;
        int vol[2];
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return -EINVAL);
-       snd_assert(index >= 0 && index <= 1, return -EINVAL);
 
        vol[0] = (31 - (ucontrol->value.integer.value[0] & 31))
                | (amp->amp_vol[index][0] & 32);
@@ -375,8 +373,7 @@ static int snd_pmac_awacs_get_switch_amp(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        int index = kcontrol->private_value;
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return -EINVAL);
-       snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
        ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32)
                                        ? 0 : 1;
        ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32)
@@ -391,8 +388,6 @@ static int snd_pmac_awacs_put_switch_amp(struct snd_kcontrol *kcontrol,
        int index = kcontrol->private_value;
        int vol[2];
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return -EINVAL);
-       snd_assert(index >= 0 && index <= 1, return -EINVAL);
 
        vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32)
                | (amp->amp_vol[index][0] & 31);
@@ -417,8 +412,7 @@ static int snd_pmac_awacs_get_tone_amp(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        int index = kcontrol->private_value;
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return -EINVAL);
-       snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
        ucontrol->value.integer.value[0] = amp->amp_tone[index];
        return 0;
 }
@@ -430,8 +424,7 @@ static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol,
        int index = kcontrol->private_value;
        struct awacs_amp *amp = chip->mixer_data;
        unsigned int val;
-       snd_assert(amp, return -EINVAL);
-       snd_assert(index >= 0 && index <= 1, return -EINVAL);
+
        val = ucontrol->value.integer.value[0];
        if (val > 14)
                return -EINVAL;
@@ -458,7 +451,7 @@ static int snd_pmac_awacs_get_master_amp(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct awacs_amp *amp = chip->mixer_data;
-       snd_assert(amp, return -EINVAL);
+
        ucontrol->value.integer.value[0] = amp->amp_master;
        return 0;
 }
@@ -469,7 +462,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct awacs_amp *amp = chip->mixer_data;
        unsigned int val;
-       snd_assert(amp, return -EINVAL);
+
        val = ucontrol->value.integer.value[0];
        if (val > 99)
                return -EINVAL;
index baa2a7237370af2db7a0160e8bcc5502b82b945f..89f5c328acfe04952c1dcb4a2c0c66b0a16a70ea 100644 (file)
@@ -185,7 +185,8 @@ static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-       snd_assert(chip->beep, return -ENXIO);
+       if (snd_BUG_ON(!chip->beep))
+               return -ENXIO;
        ucontrol->value.integer.value[0] = chip->beep->volume;
        return 0;
 }
@@ -195,7 +196,8 @@ static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        unsigned int oval, nval;
-       snd_assert(chip->beep, return -ENXIO);
+       if (snd_BUG_ON(!chip->beep))
+               return -ENXIO;
        oval = chip->beep->volume;
        nval = ucontrol->value.integer.value[0];
        if (nval > 100)
index 009df8dd37a8483a10987b948ecd3329dd1e556c..f746e15b8481b8ee8d3bbe10a9a1c13be436ad4a 100644 (file)
@@ -263,7 +263,7 @@ static int tumbler_get_master_volume(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix = chip->mixer_data;
-       snd_assert(mix, return -ENODEV);
+
        ucontrol->value.integer.value[0] = mix->master_vol[0];
        ucontrol->value.integer.value[1] = mix->master_vol[1];
        return 0;
@@ -277,7 +277,6 @@ static int tumbler_put_master_volume(struct snd_kcontrol *kcontrol,
        unsigned int vol[2];
        int change;
 
-       snd_assert(mix, return -ENODEV);
        vol[0] = ucontrol->value.integer.value[0];
        vol[1] = ucontrol->value.integer.value[1];
        if (vol[0] >= ARRAY_SIZE(master_volume_table) ||
@@ -299,7 +298,7 @@ static int tumbler_get_master_switch(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix = chip->mixer_data;
-       snd_assert(mix, return -ENODEV);
+
        ucontrol->value.integer.value[0] = mix->master_switch[0];
        ucontrol->value.integer.value[1] = mix->master_switch[1];
        return 0;
@@ -312,7 +311,6 @@ static int tumbler_put_master_switch(struct snd_kcontrol *kcontrol,
        struct pmac_tumbler *mix = chip->mixer_data;
        int change;
 
-       snd_assert(mix, return -ENODEV);
        change = mix->master_switch[0] != ucontrol->value.integer.value[0] ||
                mix->master_switch[1] != ucontrol->value.integer.value[1];
        if (change) {
@@ -807,7 +805,6 @@ static int snapper_get_capture_source(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix = chip->mixer_data;
 
-       snd_assert(mix, return -ENODEV);
        ucontrol->value.enumerated.item[0] = mix->capture_source;
        return 0;
 }
@@ -819,7 +816,6 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol,
        struct pmac_tumbler *mix = chip->mixer_data;
        int change;
 
-       snd_assert(mix, return -ENODEV);
        change = ucontrol->value.enumerated.item[0] != mix->capture_source;
        if (change) {
                mix->capture_source = !!ucontrol->value.enumerated.item[0];
@@ -978,7 +974,8 @@ static void device_change_handler(struct work_struct *work)
                return;
 
        mix = chip->mixer_data;
-       snd_assert(mix, return);
+       if (snd_BUG_ON(!mix))
+               return;
 
        headphone = tumbler_detect_headphone(chip);
        lineout = tumbler_detect_lineout(chip);
@@ -1033,7 +1030,8 @@ static void tumbler_update_automute(struct snd_pmac *chip, int do_notify)
        if (chip->auto_mute) {
                struct pmac_tumbler *mix;
                mix = chip->mixer_data;
-               snd_assert(mix, return);
+               if (snd_BUG_ON(!mix))
+                       return;
                mix->auto_mute_notify = do_notify;
                schedule_work(&device_change);
        }
@@ -1227,8 +1225,6 @@ static void tumbler_resume(struct snd_pmac *chip)
 {
        struct pmac_tumbler *mix = chip->mixer_data;
 
-       snd_assert(mix, return);
-
        mix->acs &= ~1;
        mix->master_switch[0] = mix->save_master_switch[0];
        mix->master_switch[1] = mix->save_master_switch[1];
@@ -1275,7 +1271,6 @@ static int __init tumbler_init(struct snd_pmac *chip)
 {
        int irq;
        struct pmac_tumbler *mix = chip->mixer_data;
-       snd_assert(mix, return -EINVAL);
 
        if (tumbler_find_device("audio-hw-reset",
                                "platform-do-hw-reset",
index 54df8baf916f4f8462c0a44105bf49c6c0bb3e6d..7c920f3e7fe35e4a917597d92b736011e8a62ba4 100644 (file)
@@ -106,7 +106,8 @@ static void spu_memset(u32 toi, u32 what, int length)
 {
        int i;
        unsigned long flags;
-       snd_assert(length % 4 == 0, return);
+       if (snd_BUG_ON(length % 4))
+               return;
        for (i = 0; i < length; i++) {
                if (!(i % 8))
                        spu_write_wait();
@@ -589,7 +590,7 @@ static int __devinit add_aicamixer_controls(struct snd_card_aica
        return 0;
 }
 
-static int snd_aica_remove(struct platform_device *devptr)
+static int __devexit snd_aica_remove(struct platform_device *devptr)
 {
        struct snd_card_aica *dreamcastcard;
        dreamcastcard = platform_get_drvdata(devptr);
@@ -601,7 +602,7 @@ static int snd_aica_remove(struct platform_device *devptr)
        return 0;
 }
 
-static int __init snd_aica_probe(struct platform_device *devptr)
+static int __devinit snd_aica_probe(struct platform_device *devptr)
 {
        int err;
        struct snd_card_aica *dreamcastcard;
@@ -650,7 +651,7 @@ static int __init snd_aica_probe(struct platform_device *devptr)
 
 static struct platform_driver snd_aica_driver = {
        .probe = snd_aica_probe,
-       .remove = snd_aica_remove,
+       .remove = __devexit_p(snd_aica_remove),
        .driver = {
                   .name = SND_AICA_DRIVER},
 };
index f743530add8f2bf8a9b58a345ec515b62e3a056b..4dfda6674bec98507ee354a5c7a84f9606a9ab37 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig SND_SOC
        tristate "ALSA for SoC audio support"
        select SND_PCM
+       select AC97_BUS if SND_SOC_AC97_BUS
        ---help---
 
          If you want ASoC support, you should say Y here and also to the
@@ -31,6 +32,7 @@ source "sound/soc/sh/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/omap/Kconfig"
+source "sound/soc/blackfin/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 933a66d30804950b96b1e185285880bf204d673f..d849349f2c6607ddb5a0da9a1097eae024b22848 100644 (file)
@@ -2,4 +2,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
 obj-$(CONFIG_SND_SOC)  += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
-obj-$(CONFIG_SND_SOC)  += omap/ au1x/
+obj-$(CONFIG_SND_SOC)  += omap/ au1x/ blackfin/
index 3f326219f1ec182dba666bcf01d5c12e4d258377..98a2d5826a85649e9efda2ee236a6371276317e2 100644 (file)
@@ -377,6 +377,7 @@ static struct snd_soc_machine snd_soc_machine_playpaq = {
 
 
 static struct wm8510_setup_data playpaq_wm8510_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1a,
 };
 
@@ -405,7 +406,6 @@ static int __init playpaq_asoc_init(void)
        ssc = ssc_request(0);
        if (IS_ERR(ssc)) {
                ret = PTR_ERR(ssc);
-               ssc = NULL;
                goto err_ssc;
        }
        ssc_p->ssc = ssc;
@@ -476,10 +476,7 @@ err_pll0:
                _gclk0 = NULL;
        }
 err_gclk0:
-       if (ssc != NULL) {
-               ssc_free(ssc);
-               ssc = NULL;
-       }
+       ssc_free(ssc);
 err_ssc:
        return ret;
 }
index 5d44515e62e0b58e6d316e517d749bfd8cca681e..a5b1a79ebffb5f72968ac949546bd59b1ae2dc5f 100644 (file)
@@ -408,7 +408,7 @@ static int at91_ssc_hw_params(struct snd_pcm_substream *substream,
                dma_params->pdc_xfer_size = 4;
                break;
        default:
-               printk(KERN_WARNING "at91-ssc: unsupported PCM format");
+               printk(KERN_WARNING "at91-ssc: unsupported PCM format\n");
                return -EINVAL;
        }
 
index b81d6b2cfa1d73ca2f393ab97ee803066a67a262..684781e4088b5fbac480a7307c7b5f420ce68291 100644 (file)
@@ -243,6 +243,7 @@ static struct snd_soc_machine snd_soc_machine_eti_b1 = {
 };
 
 static struct wm8731_setup_data eti_b1_wm8731_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1a,
 };
 
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
new file mode 100644 (file)
index 0000000..f98331d
--- /dev/null
@@ -0,0 +1,85 @@
+config SND_BF5XX_I2S
+       tristate "SoC I2S Audio for the ADI BF5xx chip"
+       depends on BLACKFIN && SND_SOC
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the Blackfin SPORT (synchronous serial ports) interface in I2S
+         mode (supports single stereo In/Out).
+         You will also need to select the audio interfaces to support below.
+
+config SND_BF5XX_SOC_SSM2602
+       tristate "SoC SSM2602 Audio support for BF52x ezkit"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_SSM2602
+       select I2C
+       select I2C_BLACKFIN_TWI
+       help
+         Say Y if you want to add support for SoC audio on BF527-EZKIT.
+
+config SND_BF5XX_AC97
+       tristate "SoC AC97 Audio for the ADI BF5xx chip"
+       depends on BLACKFIN && SND_SOC
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the Blackfin SPORT (synchronous serial ports) interface in slot 16
+         mode (pseudo AC97 interface).
+         You will also need to select the audio interfaces to support below.
+
+         Note:
+         AC97 codecs which do not implment the slot-16 mode will not function
+         properly with this driver. This driver is known to work with the
+         Analog Devices line of AC97 codecs.
+
+config SND_MMAP_SUPPORT
+       bool "Enable MMAP Support"
+       depends on SND_BF5XX_AC97
+       default y
+       help
+         Say y if you want AC97 driver to support mmap mode.
+         We introduce an intermediate buffer to simulate mmap.
+
+config SND_BF5XX_SOC_SPORT
+       tristate
+       
+config SND_BF5XX_SOC_I2S
+       tristate
+       select SND_BF5XX_SOC_SPORT
+
+config SND_BF5XX_SOC_AC97
+       tristate
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+       select SND_BF5XX_SOC_SPORT
+
+config SND_BF5XX_SOC_AD1980
+       tristate "SoC AD1980/1 Audio support for BF5xx"
+       depends on SND_BF5XX_AC97
+       select SND_BF5XX_SOC_AC97
+       select SND_SOC_AD1980
+       help
+         Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
+
+config SND_BF5XX_SPORT_NUM
+       int "Set a SPORT for Sound chip"
+       depends on (SND_BF5XX_I2S || SND_BF5XX_AC97)
+       range 0 3 if BF54x
+       range 0 1 if (BF53x || BF561)
+       default 0
+       help
+         Set the correct SPORT for sound chip.
+
+config SND_BF5XX_HAVE_COLD_RESET
+       bool "BOARD has COLD Reset GPIO"
+       depends on SND_BF5XX_AC97
+       default y if BFIN548_EZKIT
+       default n if !BFIN548_EZKIT
+       
+config SND_BF5XX_RESET_GPIO_NUM
+       int "Set a GPIO for cold reset"
+       depends on SND_BF5XX_HAVE_COLD_RESET
+       range 0 159
+       default 19 if BFIN548_EZKIT
+       default 5 if BFIN537_STAMP
+       help
+         Set the correct GPIO for RESET the sound chip.
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
new file mode 100644 (file)
index 0000000..9ea8bd9
--- /dev/null
@@ -0,0 +1,20 @@
+# Blackfin Platform Support
+snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
+snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
+snd-soc-bf5xx-sport-objs := bf5xx-sport.o
+snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
+snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
+
+obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
+obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
+obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
+obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
+obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
+
+# Blackfin Machine Support
+snd-ad1980-objs := bf5xx-ad1980.o
+snd-ssm2602-objs := bf5xx-ssm2602.o
+
+
+obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
+obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
new file mode 100644 (file)
index 0000000..51f4907
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ac97-pcm.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  DMA Driver for AC97 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "bf5xx-ac97-pcm.h"
+#include "bf5xx-ac97.h"
+#include "bf5xx-sport.h"
+
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
+        snd_pcm_uframes_t count)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               bf5xx_pcm_to_ac97(
+                       (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos,
+                       (__u32 *)runtime->dma_area + sport->tx_pos, count);
+               sport->tx_pos += runtime->period_size;
+               if (sport->tx_pos >= runtime->buffer_size)
+                       sport->tx_pos %= runtime->buffer_size;
+       } else {
+               bf5xx_ac97_to_pcm(
+                       (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
+                       (__u32 *)runtime->dma_area + sport->rx_pos, count);
+               sport->rx_pos += runtime->period_size;
+               if (sport->rx_pos >= runtime->buffer_size)
+                       sport->rx_pos %= runtime->buffer_size;
+       }
+}
+#endif
+
+static void bf5xx_dma_irq(void *data)
+{
+       struct snd_pcm_substream *pcm = data;
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       bf5xx_mmap_copy(pcm, runtime->period_size);
+#endif
+       snd_pcm_period_elapsed(pcm);
+}
+
+/* The memory size for pure pcm data is 128*1024 = 0x20000 bytes.
+ * The total rx/tx buffer is for ac97 frame to hold all pcm data
+ * is  0x20000 * sizeof(struct ac97_frame) / 4.
+ */
+#ifdef CONFIG_SND_MMAP_SUPPORT
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_MMAP_VALID |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+#else
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_BLOCK_TRANSFER,
+#endif
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 0x10000,
+       .periods_min            = 1,
+       .periods_max            = PAGE_SIZE/32,
+       .buffer_bytes_max       = 0x20000, /* 128 kbytes */
+       .fifo_size              = 16,
+};
+
+static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max
+                       * sizeof(struct ac97_frame) / 4;
+
+       snd_pcm_lib_malloc_pages(substream, size);
+
+       return 0;
+}
+
+static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+
+       /* An intermediate buffer is introduced for implementing mmap for
+        * SPORT working in TMD mode(include AC97).
+        */
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max
+                       * sizeof(struct ac97_frame) / 4;
+       /*clean up intermediate buffer*/
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               memset(sport->tx_dma_buf, 0, size);
+               sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+               sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
+                       runtime->period_size * sizeof(struct ac97_frame));
+       } else {
+               memset(sport->rx_dma_buf, 0, size);
+               sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+               sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
+                       runtime->period_size * sizeof(struct ac97_frame));
+       }
+#else
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+               sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
+                       runtime->period_size * sizeof(struct ac97_frame));
+       } else {
+               sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+               sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
+                       runtime->period_size * sizeof(struct ac97_frame));
+       }
+#endif
+       return 0;
+}
+
+static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       int ret = 0;
+
+       pr_debug("%s enter\n", __func__);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_tx_start(sport);
+               else
+                       sport_rx_start(sport);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+                       sport->tx_pos = 0;
+#endif
+                       sport_tx_stop(sport);
+               } else {
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+                       sport->rx_pos = 0;
+#endif
+                       sport_rx_stop(sport);
+               }
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       unsigned int curr;
+
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               curr = sport->tx_pos;
+       else
+               curr = sport->rx_pos;
+#else
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame);
+       else
+               curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame);
+
+#endif
+       return curr;
+}
+
+static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               goto out;
+
+       if (sport_handle != NULL)
+               runtime->private_data = sport_handle;
+       else {
+               pr_err("sport_handle is NULL\n");
+               return -1;
+       }
+       return 0;
+
+ out:
+       return ret;
+}
+
+#ifdef CONFIG_SND_MMAP_SUPPORT
+static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       size_t size = vma->vm_end - vma->vm_start;
+       vma->vm_start = (unsigned long)runtime->dma_area;
+       vma->vm_end = vma->vm_start + size;
+       vma->vm_flags |=  VM_SHARED;
+       return 0 ;
+}
+#else
+static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+                   snd_pcm_uframes_t pos,
+                   void __user *buf, snd_pcm_uframes_t count)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       pr_debug("%s copy pos:0x%lx count:0x%lx\n",
+                       substream->stream ? "Capture" : "Playback", pos, count);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               bf5xx_pcm_to_ac97(
+                               (struct ac97_frame *)runtime->dma_area + pos,
+                               buf, count);
+       else
+               bf5xx_ac97_to_pcm(
+                               (struct ac97_frame *)runtime->dma_area + pos,
+                               buf, count);
+       return 0;
+}
+#endif
+
+struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
+       .open           = bf5xx_pcm_open,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = bf5xx_pcm_hw_params,
+       .hw_free        = bf5xx_pcm_hw_free,
+       .prepare        = bf5xx_pcm_prepare,
+       .trigger        = bf5xx_pcm_trigger,
+       .pointer        = bf5xx_pcm_pointer,
+#ifdef CONFIG_SND_MMAP_SUPPORT
+       .mmap           = bf5xx_pcm_mmap,
+#else
+       .copy           = bf5xx_pcm_copy,
+#endif
+};
+
+static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max
+                       * sizeof(struct ac97_frame) / 4;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_coherent(pcm->card->dev, size,
+                       &buf->addr, GFP_KERNEL);
+       if (!buf->area) {
+               pr_err("Failed to allocate dma memory\n");
+               pr_err("Please increase uncached DMA memory region\n");
+               return -ENOMEM;
+       }
+       buf->bytes = size;
+
+       pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
+                       buf->area, buf->bytes);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               sport_handle->tx_buf = buf->area;
+       else
+               sport_handle->rx_buf = buf->area;
+
+/*
+ * Need to allocate local buffer when enable
+ * MMAP for SPORT working in TMD mode (include AC97).
+ */
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (!sport_handle->tx_dma_buf) {
+                       sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
+                               size, &sport_handle->tx_dma_phy, GFP_KERNEL);
+                       if (!sport_handle->tx_dma_buf) {
+                               pr_err("Failed to allocate memory for tx dma \
+                                       buf - Please increase uncached DMA \
+                                       memory region\n");
+                               return -ENOMEM;
+                       } else
+                               memset(sport_handle->tx_dma_buf, 0, size);
+               } else
+                       memset(sport_handle->tx_dma_buf, 0, size);
+       } else {
+               if (!sport_handle->rx_dma_buf) {
+                       sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \
+                               size, &sport_handle->rx_dma_phy, GFP_KERNEL);
+                       if (!sport_handle->rx_dma_buf) {
+                               pr_err("Failed to allocate memory for rx dma \
+                                       buf - Please increase uncached DMA \
+                                       memory region\n");
+                               return -ENOMEM;
+                       } else
+                               memset(sport_handle->rx_dma_buf, 0, size);
+               } else
+                       memset(sport_handle->rx_dma_buf, 0, size);
+       }
+#endif
+       return 0;
+}
+
+static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
+               sizeof(struct ac97_frame) / 4;
+#endif
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+               dma_free_coherent(NULL, buf->bytes, buf->area, 0);
+               buf->area = NULL;
+#if defined(CONFIG_SND_MMAP_SUPPORT)
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (sport_handle->tx_dma_buf)
+                       dma_free_coherent(NULL, size, \
+                               sport_handle->tx_dma_buf, 0);
+               sport_handle->tx_dma_buf = NULL;
+       } else {
+
+               if (sport_handle->rx_dma_buf)
+                       dma_free_coherent(NULL, size, \
+                               sport_handle->rx_dma_buf, 0);
+               sport_handle->rx_dma_buf = NULL;
+       }
+#endif
+       }
+       if (sport_handle)
+               sport_done(sport_handle);
+}
+
+static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
+       struct snd_pcm *pcm)
+{
+       int ret = 0;
+
+       pr_debug("%s enter\n", __func__);
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &bf5xx_pcm_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+       if (dai->playback.channels_min) {
+               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (dai->capture.channels_min) {
+               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+ out:
+       return ret;
+}
+
+struct snd_soc_platform bf5xx_ac97_soc_platform = {
+       .name           = "bf5xx-audio",
+       .pcm_ops        = &bf5xx_pcm_ac97_ops,
+       .pcm_new        = bf5xx_pcm_ac97_new,
+       .pcm_free       = bf5xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
new file mode 100644 (file)
index 0000000..350125a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/bf5xx-ac97-pcm.h -- ALSA PCM interface for the Blackfin
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * 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 _BF5XX_AC97_PCM_H
+#define _BF5XX_AC97_PCM_H
+
+struct bf5xx_pcm_dma_params {
+       char *name;                     /* stream identifier */
+};
+
+struct bf5xx_gpio {
+       u32 sys;
+       u32 rx;
+       u32 tx;
+       u32 clk;
+       u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform bf5xx_ac97_soc_platform;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
new file mode 100644 (file)
index 0000000..c782e31
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * bf5xx-ac97.c -- AC97 support for the ADI blackfin chip.
+ *
+ * Author:     Roy Huang
+ * Created:    11th. June 2007
+ * Copyright:  Analog Device Inc.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <asm/portmux.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include "bf5xx-sport.h"
+#include "bf5xx-ac97.h"
+
+#if defined(CONFIG_BF54x)
+#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, \
+               P_SPORT0_RFS, P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, \
+               P_SPORT1_RFS, P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+
+#define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, \
+               P_SPORT2_RFS, P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0}
+
+#define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, \
+               P_SPORT3_RFS, P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0}
+#else
+#define PIN_REQ_SPORT_0 {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+                P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+                P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+#endif
+
+static int *cmd_count;
+static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+#if defined(CONFIG_BF54x)
+static struct sport_param sport_params[4] = {
+       {
+               .dma_rx_chan    = CH_SPORT0_RX,
+               .dma_tx_chan    = CH_SPORT0_TX,
+               .err_irq        = IRQ_SPORT0_ERR,
+               .regs           = (struct sport_register *)SPORT0_TCR1,
+       },
+       {
+               .dma_rx_chan    = CH_SPORT1_RX,
+               .dma_tx_chan    = CH_SPORT1_TX,
+               .err_irq        = IRQ_SPORT1_ERR,
+               .regs           = (struct sport_register *)SPORT1_TCR1,
+       },
+       {
+               .dma_rx_chan    = CH_SPORT2_RX,
+               .dma_tx_chan    = CH_SPORT2_TX,
+               .err_irq        = IRQ_SPORT2_ERR,
+               .regs           = (struct sport_register *)SPORT2_TCR1,
+       },
+       {
+               .dma_rx_chan    = CH_SPORT3_RX,
+               .dma_tx_chan    = CH_SPORT3_TX,
+               .err_irq        = IRQ_SPORT3_ERR,
+               .regs           = (struct sport_register *)SPORT3_TCR1,
+       }
+};
+#else
+static struct sport_param sport_params[2] = {
+       {
+               .dma_rx_chan    = CH_SPORT0_RX,
+               .dma_tx_chan    = CH_SPORT0_TX,
+               .err_irq        = IRQ_SPORT0_ERROR,
+               .regs           = (struct sport_register *)SPORT0_TCR1,
+       },
+       {
+               .dma_rx_chan    = CH_SPORT1_RX,
+               .dma_tx_chan    = CH_SPORT1_TX,
+               .err_irq        = IRQ_SPORT1_ERROR,
+               .regs           = (struct sport_register *)SPORT1_TCR1,
+       }
+};
+#endif
+
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
+               size_t count)
+{
+       while (count--) {
+               dst->ac97_tag = TAG_VALID | TAG_PCM;
+               (dst++)->ac97_pcm = *src++;
+       }
+}
+EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
+
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+               size_t count)
+{
+       while (count--)
+               *(dst++) = (src++)->ac97_pcm;
+}
+EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
+
+static unsigned int sport_tx_curr_frag(struct sport_device *sport)
+{
+       return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \
+                       sport->tx_fragsize;
+}
+
+static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
+{
+       struct sport_device *sport = sport_handle;
+       int nextfrag = sport_tx_curr_frag(sport);
+       struct ac97_frame *nextwrite;
+
+       sport_incfrag(sport, &nextfrag, 1);
+       sport_incfrag(sport, &nextfrag, 1);
+
+       nextwrite = (struct ac97_frame *)(sport->tx_buf + \
+                       nextfrag * sport->tx_fragsize);
+       pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
+               sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
+       nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD;
+       nextwrite[cmd_count[nextfrag]].ac97_addr = addr;
+       nextwrite[cmd_count[nextfrag]].ac97_data = data;
+       ++cmd_count[nextfrag];
+       pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n",
+                       addr >> 8, data, nextfrag);
+}
+
+static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
+       unsigned short reg)
+{
+       struct ac97_frame out_frame[2], in_frame[2];
+
+       pr_debug("%s enter 0x%x\n", __func__, reg);
+
+       /* When dma descriptor is enabled, the register should not be read */
+       if (sport_handle->tx_run || sport_handle->rx_run) {
+               pr_err("Could you send a mail to cliff.cai@analog.com "
+                               "to report this?\n");
+               return -EFAULT;
+       }
+
+       memset(&out_frame, 0, 2 * sizeof(struct ac97_frame));
+       memset(&in_frame, 0, 2 * sizeof(struct ac97_frame));
+       out_frame[0].ac97_tag = TAG_VALID | TAG_CMD;
+       out_frame[0].ac97_addr = ((reg << 8) | 0x8000);
+       sport_send_and_recv(sport_handle, (unsigned char *)&out_frame,
+                       (unsigned char *)&in_frame,
+                       2 * sizeof(struct ac97_frame));
+       return in_frame[1].ac97_data;
+}
+
+void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+       unsigned short val)
+{
+       pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
+
+       if (sport_handle->tx_run) {
+               enqueue_cmd(ac97, (reg << 8), val); /* write */
+               enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */
+       } else {
+               struct ac97_frame frame;
+               memset(&frame, 0, sizeof(struct ac97_frame));
+               frame.ac97_tag = TAG_VALID | TAG_CMD;
+               frame.ac97_addr = (reg << 8);
+               frame.ac97_data = val;
+               sport_send_and_recv(sport_handle, (unsigned char *)&frame, \
+                               NULL, sizeof(struct ac97_frame));
+       }
+}
+
+static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
+ (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
+
+#define CONCAT(a, b, c) a ## b ## c
+#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
+
+       u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
+       u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+
+       pr_debug("%s enter\n", __func__);
+
+       peripheral_free(per);
+       gpio_request(gpio, "bf5xx-ac97");
+       gpio_direction_output(gpio, 1);
+       udelay(2);
+       gpio_set_value(gpio, 0);
+       udelay(1);
+       gpio_free(gpio);
+       peripheral_request(per, "soc-audio");
+#else
+       pr_info("%s: Not implemented\n", __func__);
+#endif
+}
+
+static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+       pr_debug("%s enter\n", __func__);
+
+       /* It is specified for bf548-ezkit */
+       gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0);
+       /* Keep reset pin low for 1 ms */
+       mdelay(1);
+       gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
+       /* Wait for bit clock recover */
+       mdelay(1);
+#else
+       pr_info("%s: Not implemented\n", __func__);
+#endif
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read   = bf5xx_ac97_read,
+       .write  = bf5xx_ac97_write,
+       .warm_reset     = bf5xx_ac97_warm_reset,
+       .reset  = bf5xx_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+#ifdef CONFIG_PM
+static int bf5xx_ac97_suspend(struct platform_device *pdev,
+       struct snd_soc_dai *dai)
+{
+       struct sport_device *sport =
+               (struct sport_device *)dai->private_data;
+
+       pr_debug("%s : sport %d\n", __func__, dai->id);
+       if (!dai->active)
+               return 0;
+       if (dai->capture.active)
+               sport_rx_stop(sport);
+       if (dai->playback.active)
+               sport_tx_stop(sport);
+       return 0;
+}
+
+static int bf5xx_ac97_resume(struct platform_device *pdev,
+       struct snd_soc_dai *dai)
+{
+       int ret;
+       struct sport_device *sport =
+               (struct sport_device *)dai->private_data;
+
+       pr_debug("%s : sport %d\n", __func__, dai->id);
+       if (!dai->active)
+               return 0;
+
+       ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               return -EBUSY;
+       }
+
+       ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               return -EBUSY;
+       }
+
+       ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               return -EBUSY;
+       }
+
+       if (dai->capture.active)
+               sport_rx_start(sport);
+       if (dai->playback.active)
+               sport_tx_start(sport);
+       return 0;
+}
+
+#else
+#define bf5xx_ac97_suspend     NULL
+#define bf5xx_ac97_resume      NULL
+#endif
+
+static int bf5xx_ac97_probe(struct platform_device *pdev,
+                           struct snd_soc_dai *dai)
+{
+       int ret;
+#if defined(CONFIG_BF54x)
+       u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
+                                PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
+#else
+       u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1};
+#endif
+       cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
+       if (cmd_count == NULL)
+               return -ENOMEM;
+
+       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+               pr_err("Requesting Peripherals failed\n");
+               return -EFAULT;
+               }
+
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+       /* Request PB3 as reset pin */
+       if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
+               pr_err("Failed to request GPIO_%d for reset\n",
+                               CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+               peripheral_free_list(&sport_req[sport_num][0]);
+               return -1;
+       }
+       gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
+#endif
+       sport_handle = sport_init(&sport_params[sport_num], 2, \
+                       sizeof(struct ac97_frame), NULL);
+       if (!sport_handle) {
+               peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+               return -ENODEV;
+       }
+       /*SPORT works in TDM mode to simulate AC97 transfers*/
+       ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               kfree(sport_handle);
+               peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+               return -EBUSY;
+       }
+
+       ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               kfree(sport_handle);
+               peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+               return -EBUSY;
+       }
+
+       ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               kfree(sport_handle);
+               peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static void bf5xx_ac97_remove(struct platform_device *pdev,
+                             struct snd_soc_dai *dai)
+{
+       free_page((unsigned long)cmd_count);
+       cmd_count = NULL;
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+       gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+}
+
+struct snd_soc_dai bfin_ac97_dai = {
+       .name = "bf5xx-ac97",
+       .id = 0,
+       .type = SND_SOC_DAI_AC97,
+       .probe = bf5xx_ac97_probe,
+       .remove = bf5xx_ac97_remove,
+       .suspend = bf5xx_ac97_suspend,
+       .resume = bf5xx_ac97_resume,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(bfin_ac97_dai);
+
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
new file mode 100644 (file)
index 0000000..3f77cc5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/sound/arm/bf5xx-ac97.h
+ *
+ * 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 _BF5XX_AC97_H
+#define _BF5XX_AC97_H
+
+extern struct snd_ac97_bus_ops bf5xx_ac97_ops;
+extern struct snd_ac97 *ac97;
+/* Frame format in memory, only support stereo currently */
+struct ac97_frame {
+       u16 ac97_tag;           /* slot 0 */
+       u16 ac97_addr;          /* slot 1 */
+       u16 ac97_data;          /* slot 2 */
+       u32 ac97_pcm;           /* slot 3 and 4: left and right pcm data */
+} __attribute__ ((packed));
+
+#define TAG_VALID              0x8000
+#define TAG_CMD                        0x6000
+#define TAG_PCM_LEFT           0x1000
+#define TAG_PCM_RIGHT          0x0800
+#define TAG_PCM                        (TAG_PCM_LEFT | TAG_PCM_RIGHT)
+
+extern struct snd_soc_dai bfin_ac97_dai;
+
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
+               size_t count);
+
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+               size_t count);
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
new file mode 100644 (file)
index 0000000..124425d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ad1980.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Board driver for AD1980/1 audio codec
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <asm/dma.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <linux/gpio.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad1980.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-ac97-pcm.h"
+#include "bf5xx-ac97.h"
+
+static struct snd_soc_machine bf5xx_board;
+
+static int bf5xx_board_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+       pr_debug("%s enter\n", __func__);
+       cpu_dai->private_data = sport_handle;
+       return 0;
+}
+
+static struct snd_soc_ops bf5xx_board_ops = {
+       .startup = bf5xx_board_startup,
+};
+
+static struct snd_soc_dai_link bf5xx_board_dai = {
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &bfin_ac97_dai,
+       .codec_dai = &ad1980_dai,
+       .ops = &bf5xx_board_ops,
+};
+
+static struct snd_soc_machine bf5xx_board = {
+       .name = "bf5xx-board",
+       .dai_link = &bf5xx_board_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_board_snd_devdata = {
+       .machine = &bf5xx_board,
+       .platform = &bf5xx_ac97_soc_platform,
+       .codec_dev = &soc_codec_dev_ad1980,
+};
+
+static struct platform_device *bf5xx_board_snd_device;
+
+static int __init bf5xx_board_init(void)
+{
+       int ret;
+
+       bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!bf5xx_board_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
+       bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+       ret = platform_device_add(bf5xx_board_snd_device);
+
+       if (ret)
+               platform_device_put(bf5xx_board_snd_device);
+
+       return ret;
+}
+
+static void __exit bf5xx_board_exit(void)
+{
+       platform_device_unregister(bf5xx_board_snd_device);
+}
+
+module_init(bf5xx_board_init);
+module_exit(bf5xx_board_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
new file mode 100644 (file)
index 0000000..61fccf9
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-i2s-pcm.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  DMA driver for i2s codec
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+#include "bf5xx-sport.h"
+
+static void bf5xx_dma_irq(void *data)
+{
+       struct snd_pcm_substream *pcm = data;
+       snd_pcm_period_elapsed(pcm);
+}
+
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_MMAP_VALID |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE |
+                                  SNDRV_PCM_FMTBIT_S32_LE,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 0x10000,
+       .periods_min            = 1,
+       .periods_max            = PAGE_SIZE/32,
+       .buffer_bytes_max       = 0x20000, /* 128 kbytes */
+       .fifo_size              = 16,
+};
+
+static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+       snd_pcm_lib_malloc_pages(substream, size);
+
+       return 0;
+}
+
+static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+
+       return 0;
+}
+
+static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       int period_bytes = frames_to_bytes(runtime, runtime->period_size);
+
+       pr_debug("%s enter\n", __func__);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+               sport_config_tx_dma(sport, runtime->dma_area,
+                       runtime->periods, period_bytes);
+       } else {
+               sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+               sport_config_rx_dma(sport, runtime->dma_area,
+                       runtime->periods, period_bytes);
+       }
+
+       return 0;
+}
+
+static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       int ret = 0;
+
+       pr_debug("%s enter\n", __func__);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_tx_start(sport);
+               else
+                       sport_rx_start(sport);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_tx_stop(sport);
+               else
+                       sport_rx_stop(sport);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+       unsigned int diff;
+       snd_pcm_uframes_t frames;
+       pr_debug("%s enter\n", __func__);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               diff = sport_curr_offset_tx(sport);
+               frames = bytes_to_frames(substream->runtime, diff);
+       } else {
+               diff = sport_curr_offset_rx(sport);
+               frames = bytes_to_frames(substream->runtime, diff);
+       }
+       return frames;
+}
+
+static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime, \
+                       SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               goto out;
+
+       if (sport_handle != NULL)
+               runtime->private_data = sport_handle;
+       else {
+               pr_err("sport_handle is NULL\n");
+               return -1;
+       }
+       return 0;
+
+ out:
+       return ret;
+}
+
+static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       size_t size = vma->vm_end - vma->vm_start;
+       vma->vm_start = (unsigned long)runtime->dma_area;
+       vma->vm_end = vma->vm_start + size;
+       vma->vm_flags |=  VM_SHARED;
+
+       return 0 ;
+}
+
+struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
+       .open           = bf5xx_pcm_open,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = bf5xx_pcm_hw_params,
+       .hw_free        = bf5xx_pcm_hw_free,
+       .prepare        = bf5xx_pcm_prepare,
+       .trigger        = bf5xx_pcm_trigger,
+       .pointer        = bf5xx_pcm_pointer,
+       .mmap           = bf5xx_pcm_mmap,
+};
+
+static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_coherent(pcm->card->dev, size,
+                       &buf->addr, GFP_KERNEL);
+       if (!buf->area) {
+               pr_err("Failed to allocate dma memory \
+                       Please increase uncached DMA memory region\n");
+               return -ENOMEM;
+       }
+       buf->bytes = size;
+
+       pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
+               buf->area, buf->bytes);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               sport_handle->tx_buf = buf->area;
+       else
+               sport_handle->rx_buf = buf->area;
+
+       return 0;
+}
+
+static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+               dma_free_coherent(NULL, buf->bytes, buf->area, 0);
+               buf->area = NULL;
+       }
+       if (sport_handle)
+               sport_done(sport_handle);
+}
+
+static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
+       struct snd_pcm *pcm)
+{
+       int ret = 0;
+
+       pr_debug("%s enter\n", __func__);
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &bf5xx_pcm_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+       if (dai->playback.channels_min) {
+               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (dai->capture.channels_min) {
+               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+ out:
+       return ret;
+}
+
+struct snd_soc_platform bf5xx_i2s_soc_platform = {
+       .name           = "bf5xx-audio",
+       .pcm_ops        = &bf5xx_pcm_i2s_ops,
+       .pcm_new        = bf5xx_pcm_i2s_new,
+       .pcm_free       = bf5xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h
new file mode 100644 (file)
index 0000000..4d4609a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/bf5xx-i2s-pcm.h -- ALSA PCM interface for the Blackfin
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * 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 _BF5XX_I2S_PCM_H
+#define _BF5XX_I2S_PCM_H
+
+struct bf5xx_pcm_dma_params {
+       char *name;                     /* stream identifier */
+};
+
+struct bf5xx_gpio {
+       u32 sys;
+       u32 rx;
+       u32 tx;
+       u32 clk;
+       u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform bf5xx_i2s_soc_platform;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
new file mode 100644 (file)
index 0000000..43a4092
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-i2s.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Blackfin I2S CPU DAI driver
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <asm/portmux.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s.h"
+
+struct bf5xx_i2s_port {
+       u16 tcr1;
+       u16 rcr1;
+       u16 tcr2;
+       u16 rcr2;
+       int counter;
+};
+
+static struct bf5xx_i2s_port bf5xx_i2s;
+static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+static struct sport_param sport_params[2] = {
+       {
+               .dma_rx_chan    = CH_SPORT0_RX,
+               .dma_tx_chan    = CH_SPORT0_TX,
+               .err_irq        = IRQ_SPORT0_ERROR,
+               .regs           = (struct sport_register *)SPORT0_TCR1,
+       },
+       {
+               .dma_rx_chan    = CH_SPORT1_RX,
+               .dma_tx_chan    = CH_SPORT1_TX,
+               .err_irq        = IRQ_SPORT1_ERROR,
+               .regs           = (struct sport_register *)SPORT1_TCR1,
+       }
+};
+
+static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+               unsigned int fmt)
+{
+       int ret = 0;
+
+       /* interface format:support I2S,slave mode */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ret = -EINVAL;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               ret = -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               ret = -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               ret = -EINVAL;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int bf5xx_i2s_startup(struct snd_pcm_substream *substream)
+{
+       pr_debug("%s enter\n", __func__);
+
+       /*this counter is used for counting how many pcm streams are opened*/
+       bf5xx_i2s.counter++;
+       return 0;
+}
+
+static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       int ret = 0;
+
+       bf5xx_i2s.tcr2 &= ~0x1f;
+       bf5xx_i2s.rcr2 &= ~0x1f;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bf5xx_i2s.tcr2 |= 15;
+               bf5xx_i2s.rcr2 |= 15;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               bf5xx_i2s.tcr2 |= 23;
+               bf5xx_i2s.rcr2 |= 23;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               bf5xx_i2s.tcr2 |= 31;
+               bf5xx_i2s.rcr2 |= 31;
+               break;
+       }
+
+       if (bf5xx_i2s.counter == 1) {
+               /*
+                * TX and RX are not independent,they are enabled at the
+                * same time, even if only one side is running. So, we
+                * need to configure both of them at the time when the first
+                * stream is opened.
+                *
+                * CPU DAI format:I2S, slave mode.
+                */
+               ret = sport_config_rx(sport_handle, RFSR | RCKFE,
+                                     RSFSE|bf5xx_i2s.rcr2, 0, 0);
+               if (ret) {
+                       pr_err("SPORT is busy!\n");
+                       return -EBUSY;
+               }
+
+               ret = sport_config_tx(sport_handle, TFSR | TCKFE,
+                                     TSFSE|bf5xx_i2s.tcr2, 0, 0);
+               if (ret) {
+                       pr_err("SPORT is busy!\n");
+                       return -EBUSY;
+               }
+       }
+
+       return 0;
+}
+
+static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+       pr_debug("%s enter\n", __func__);
+       bf5xx_i2s.counter--;
+}
+
+static int bf5xx_i2s_probe(struct platform_device *pdev,
+                          struct snd_soc_dai *dai)
+{
+       u16 sport_req[][7] = {
+               { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+                 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
+               { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+                 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
+       };
+
+       pr_debug("%s enter\n", __func__);
+       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+               pr_err("Requesting Peripherals failed\n");
+               return -EFAULT;
+       }
+
+       /* request DMA for SPORT */
+       sport_handle = sport_init(&sport_params[sport_num], 4, \
+                       2 * sizeof(u32), NULL);
+       if (!sport_handle) {
+               peripheral_free_list(&sport_req[sport_num][0]);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int bf5xx_i2s_suspend(struct platform_device *dev,
+                            struct snd_soc_dai *dai)
+{
+       struct sport_device *sport =
+               (struct sport_device *)dai->private_data;
+
+       pr_debug("%s : sport %d\n", __func__, dai->id);
+       if (!dai->active)
+               return 0;
+       if (dai->capture.active)
+               sport_rx_stop(sport);
+       if (dai->playback.active)
+               sport_tx_stop(sport);
+       return 0;
+}
+
+static int bf5xx_i2s_resume(struct platform_device *pdev,
+                           struct snd_soc_dai *dai)
+{
+       int ret;
+       struct sport_device *sport =
+               (struct sport_device *)dai->private_data;
+
+       pr_debug("%s : sport %d\n", __func__, dai->id);
+       if (!dai->active)
+               return 0;
+
+       ret = sport_config_rx(sport_handle, RFSR | RCKFE, RSFSE|0x1f, 0, 0);
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               return -EBUSY;
+       }
+
+       ret = sport_config_tx(sport_handle, TFSR | TCKFE, TSFSE|0x1f, 0, 0);
+       if (ret) {
+               pr_err("SPORT is busy!\n");
+               return -EBUSY;
+       }
+
+       if (dai->capture.active)
+               sport_rx_start(sport);
+       if (dai->playback.active)
+               sport_tx_start(sport);
+       return 0;
+}
+
+#else
+#define bf5xx_i2s_suspend      NULL
+#define bf5xx_i2s_resume       NULL
+#endif
+
+#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+               SNDRV_PCM_RATE_96000)
+
+#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+       SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai bf5xx_i2s_dai = {
+       .name = "bf5xx-i2s",
+       .id = 0,
+       .type = SND_SOC_DAI_I2S,
+       .probe = bf5xx_i2s_probe,
+       .suspend = bf5xx_i2s_suspend,
+       .resume = bf5xx_i2s_resume,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = BF5XX_I2S_RATES,
+               .formats = BF5XX_I2S_FORMATS,},
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = BF5XX_I2S_RATES,
+               .formats = BF5XX_I2S_FORMATS,},
+       .ops = {
+               .startup   = bf5xx_i2s_startup,
+               .shutdown  = bf5xx_i2s_shutdown,
+               .hw_params = bf5xx_i2s_hw_params,},
+       .dai_ops = {
+               .set_fmt = bf5xx_i2s_set_dai_fmt,
+       },
+};
+EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("I2S driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h
new file mode 100644 (file)
index 0000000..7107d1a
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * linux/sound/arm/bf5xx-i2s.h
+ *
+ * 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 _BF5XX_I2S_H
+#define _BF5XX_I2S_H
+
+extern struct snd_soc_dai bf5xx_i2s_dai;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
new file mode 100644 (file)
index 0000000..3b99e48
--- /dev/null
@@ -0,0 +1,1032 @@
+/*
+ * File:         bf5xx_sport.c
+ * Based on:
+ * Author:       Roy Huang <roy.huang@analog.com>
+ *
+ * Created:      Tue Sep 21 10:52:42 CEST 2004
+ * Description:
+ *               Blackfin SPORT Driver
+ *
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <linux/bug.h>
+#include <asm/portmux.h>
+#include <asm/dma.h>
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+
+#include "bf5xx-sport.h"
+/* delay between frame sync pulse and first data bit in multichannel mode */
+#define FRAME_DELAY (1<<12)
+
+struct sport_device *sport_handle;
+EXPORT_SYMBOL(sport_handle);
+/* note: multichannel is in units of 8 channels,
+ * tdm_count is # channels NOT / 8 ! */
+int sport_set_multichannel(struct sport_device *sport,
+               int tdm_count, u32 mask, int packed)
+{
+       pr_debug("%s tdm_count=%d mask:0x%08x packed=%d\n", __func__,
+                       tdm_count, mask, packed);
+
+       if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
+               return -EBUSY;
+
+       if (tdm_count & 0x7)
+               return -EINVAL;
+
+       if (tdm_count > 32)
+               return -EINVAL; /* Only support less than 32 channels now */
+
+       if (tdm_count) {
+               sport->regs->mcmc1 = ((tdm_count>>3)-1) << 12;
+               sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \
+                               (packed ? (MCDTXPE|MCDRXPE) : 0);
+
+               sport->regs->mtcs0 = mask;
+               sport->regs->mrcs0 = mask;
+               sport->regs->mtcs1 = 0;
+               sport->regs->mrcs1 = 0;
+               sport->regs->mtcs2 = 0;
+               sport->regs->mrcs2 = 0;
+               sport->regs->mtcs3 = 0;
+               sport->regs->mrcs3 = 0;
+       } else {
+               sport->regs->mcmc1 = 0;
+               sport->regs->mcmc2 = 0;
+
+               sport->regs->mtcs0 = 0;
+               sport->regs->mrcs0 = 0;
+       }
+
+       sport->regs->mtcs1 = 0; sport->regs->mtcs2 = 0; sport->regs->mtcs3 = 0;
+       sport->regs->mrcs1 = 0; sport->regs->mrcs2 = 0; sport->regs->mrcs3 = 0;
+
+       SSYNC();
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_set_multichannel);
+
+int sport_config_rx(struct sport_device *sport, unsigned int rcr1,
+               unsigned int rcr2, unsigned int clkdiv, unsigned int fsdiv)
+{
+       if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
+               return -EBUSY;
+
+       sport->regs->rcr1 = rcr1;
+       sport->regs->rcr2 = rcr2;
+       sport->regs->rclkdiv = clkdiv;
+       sport->regs->rfsdiv = fsdiv;
+
+       SSYNC();
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_config_rx);
+
+int sport_config_tx(struct sport_device *sport, unsigned int tcr1,
+               unsigned int tcr2, unsigned int clkdiv, unsigned int fsdiv)
+{
+       if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
+               return -EBUSY;
+
+       sport->regs->tcr1 = tcr1;
+       sport->regs->tcr2 = tcr2;
+       sport->regs->tclkdiv = clkdiv;
+       sport->regs->tfsdiv = fsdiv;
+
+       SSYNC();
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_config_tx);
+
+static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
+               size_t fragsize, unsigned int cfg,
+               unsigned int x_count, unsigned int ycount, size_t wdsize)
+{
+
+       int i;
+
+       for (i = 0; i < fragcount; ++i) {
+               desc[i].next_desc_addr  = (unsigned long)&(desc[i + 1]);
+               desc[i].start_addr = (unsigned long)buf + i*fragsize;
+               desc[i].cfg = cfg;
+               desc[i].x_count = x_count;
+               desc[i].x_modify = wdsize;
+               desc[i].y_count = ycount;
+               desc[i].y_modify = wdsize;
+       }
+
+       /* make circular */
+       desc[fragcount-1].next_desc_addr = (unsigned long)desc;
+
+       pr_debug("setup desc: desc0=%p, next0=%lx, desc1=%p,"
+               "next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
+               &(desc[0]), desc[0].next_desc_addr,
+               &(desc[1]), desc[1].next_desc_addr,
+               desc[0].x_count, desc[0].y_count,
+               desc[0].start_addr, desc[0].cfg);
+}
+
+static int sport_start(struct sport_device *sport)
+{
+       enable_dma(sport->dma_rx_chan);
+       enable_dma(sport->dma_tx_chan);
+       sport->regs->rcr1 |= RSPEN;
+       sport->regs->tcr1 |= TSPEN;
+       SSYNC();
+
+       return 0;
+}
+
+static int sport_stop(struct sport_device *sport)
+{
+       sport->regs->tcr1 &= ~TSPEN;
+       sport->regs->rcr1 &= ~RSPEN;
+       SSYNC();
+
+       disable_dma(sport->dma_rx_chan);
+       disable_dma(sport->dma_tx_chan);
+       return 0;
+}
+
+static inline int sport_hook_rx_dummy(struct sport_device *sport)
+{
+       struct dmasg *desc, temp_desc;
+       unsigned long flags;
+
+       BUG_ON(sport->dummy_rx_desc == NULL);
+       BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc);
+
+       /* Maybe the dummy buffer descriptor ring is damaged */
+       sport->dummy_rx_desc->next_desc_addr = \
+                       (unsigned long)(sport->dummy_rx_desc+1);
+
+       local_irq_save(flags);
+       desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_rx_chan);
+       /* Copy the descriptor which will be damaged to backup */
+       temp_desc = *desc;
+       desc->x_count = 0xa;
+       desc->y_count = 0;
+       desc->next_desc_addr = (unsigned long)(sport->dummy_rx_desc);
+       local_irq_restore(flags);
+       /* Waiting for dummy buffer descriptor is already hooked*/
+       while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
+                       sizeof(struct dmasg)) !=
+                       (unsigned long)sport->dummy_rx_desc)
+               ;
+       sport->curr_rx_desc = sport->dummy_rx_desc;
+       /* Restore the damaged descriptor */
+       *desc = temp_desc;
+
+       return 0;
+}
+
+static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
+{
+       if (dummy) {
+               sport->dummy_rx_desc->next_desc_addr = \
+                               (unsigned long) sport->dummy_rx_desc;
+               sport->curr_rx_desc = sport->dummy_rx_desc;
+       } else
+               sport->curr_rx_desc = sport->dma_rx_desc;
+
+       set_dma_next_desc_addr(sport->dma_rx_chan, \
+                       (unsigned long)(sport->curr_rx_desc));
+       set_dma_x_count(sport->dma_rx_chan, 0);
+       set_dma_x_modify(sport->dma_rx_chan, 0);
+       set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \
+                               WDSIZE_32 | WNR));
+       set_dma_curr_addr(sport->dma_rx_chan, sport->curr_rx_desc->start_addr);
+       SSYNC();
+
+       return 0;
+}
+
+static inline int sport_tx_dma_start(struct sport_device *sport, int dummy)
+{
+       if (dummy) {
+               sport->dummy_tx_desc->next_desc_addr = \
+                               (unsigned long) sport->dummy_tx_desc;
+               sport->curr_tx_desc = sport->dummy_tx_desc;
+       } else
+               sport->curr_tx_desc = sport->dma_tx_desc;
+
+       set_dma_next_desc_addr(sport->dma_tx_chan, \
+                       (unsigned long)(sport->curr_tx_desc));
+       set_dma_x_count(sport->dma_tx_chan, 0);
+       set_dma_x_modify(sport->dma_tx_chan, 0);
+       set_dma_config(sport->dma_tx_chan,
+                       (DMAFLOW_LARGE | NDSIZE_9 | WDSIZE_32));
+       set_dma_curr_addr(sport->dma_tx_chan, sport->curr_tx_desc->start_addr);
+       SSYNC();
+
+       return 0;
+}
+
+int sport_rx_start(struct sport_device *sport)
+{
+       unsigned long flags;
+       pr_debug("%s enter\n", __func__);
+       if (sport->rx_run)
+               return -EBUSY;
+       if (sport->tx_run) {
+               /* tx is running, rx is not running */
+               BUG_ON(sport->dma_rx_desc == NULL);
+               BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc);
+               local_irq_save(flags);
+               while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
+                       sizeof(struct dmasg)) !=
+                       (unsigned long)sport->dummy_rx_desc)
+                       ;
+               sport->dummy_rx_desc->next_desc_addr =
+                               (unsigned long)(sport->dma_rx_desc);
+               local_irq_restore(flags);
+               sport->curr_rx_desc = sport->dma_rx_desc;
+       } else {
+               sport_tx_dma_start(sport, 1);
+               sport_rx_dma_start(sport, 0);
+               sport_start(sport);
+       }
+
+       sport->rx_run = 1;
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_rx_start);
+
+int sport_rx_stop(struct sport_device *sport)
+{
+       pr_debug("%s enter\n", __func__);
+
+       if (!sport->rx_run)
+               return 0;
+       if (sport->tx_run) {
+               /* TX dma is still running, hook the dummy buffer */
+               sport_hook_rx_dummy(sport);
+       } else {
+               /* Both rx and tx dma will be stopped */
+               sport_stop(sport);
+               sport->curr_rx_desc = NULL;
+               sport->curr_tx_desc = NULL;
+       }
+
+       sport->rx_run = 0;
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_rx_stop);
+
+static inline int sport_hook_tx_dummy(struct sport_device *sport)
+{
+       struct dmasg *desc, temp_desc;
+       unsigned long flags;
+
+       BUG_ON(sport->dummy_tx_desc == NULL);
+       BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc);
+
+       sport->dummy_tx_desc->next_desc_addr = \
+                       (unsigned long)(sport->dummy_tx_desc+1);
+
+       /* Shorten the time on last normal descriptor */
+       local_irq_save(flags);
+       desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_tx_chan);
+       /* Store the descriptor which will be damaged */
+       temp_desc = *desc;
+       desc->x_count = 0xa;
+       desc->y_count = 0;
+       desc->next_desc_addr = (unsigned long)(sport->dummy_tx_desc);
+       local_irq_restore(flags);
+       /* Waiting for dummy buffer descriptor is already hooked*/
+       while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \
+                       sizeof(struct dmasg)) != \
+                       (unsigned long)sport->dummy_tx_desc)
+               ;
+       sport->curr_tx_desc = sport->dummy_tx_desc;
+       /* Restore the damaged descriptor */
+       *desc = temp_desc;
+
+       return 0;
+}
+
+int sport_tx_start(struct sport_device *sport)
+{
+       unsigned flags;
+       pr_debug("%s: tx_run:%d, rx_run:%d\n", __func__,
+                       sport->tx_run, sport->rx_run);
+       if (sport->tx_run)
+               return -EBUSY;
+       if (sport->rx_run) {
+               BUG_ON(sport->dma_tx_desc == NULL);
+               BUG_ON(sport->curr_tx_desc != sport->dummy_tx_desc);
+               /* Hook the normal buffer descriptor */
+               local_irq_save(flags);
+               while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) -
+                       sizeof(struct dmasg)) !=
+                       (unsigned long)sport->dummy_tx_desc)
+                       ;
+               sport->dummy_tx_desc->next_desc_addr =
+                               (unsigned long)(sport->dma_tx_desc);
+               local_irq_restore(flags);
+               sport->curr_tx_desc = sport->dma_tx_desc;
+       } else {
+
+               sport_tx_dma_start(sport, 0);
+               /* Let rx dma run the dummy buffer */
+               sport_rx_dma_start(sport, 1);
+               sport_start(sport);
+       }
+       sport->tx_run = 1;
+       return 0;
+}
+EXPORT_SYMBOL(sport_tx_start);
+
+int sport_tx_stop(struct sport_device *sport)
+{
+       if (!sport->tx_run)
+               return 0;
+       if (sport->rx_run) {
+               /* RX is still running, hook the dummy buffer */
+               sport_hook_tx_dummy(sport);
+       } else {
+               /* Both rx and tx dma stopped */
+               sport_stop(sport);
+               sport->curr_rx_desc = NULL;
+               sport->curr_tx_desc = NULL;
+       }
+
+       sport->tx_run = 0;
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_tx_stop);
+
+static inline int compute_wdsize(size_t wdsize)
+{
+       switch (wdsize) {
+       case 1:
+               return WDSIZE_8;
+       case 2:
+               return WDSIZE_16;
+       case 4:
+       default:
+               return WDSIZE_32;
+       }
+}
+
+int sport_config_rx_dma(struct sport_device *sport, void *buf,
+               int fragcount, size_t fragsize)
+{
+       unsigned int x_count;
+       unsigned int y_count;
+       unsigned int cfg;
+       dma_addr_t addr;
+
+       pr_debug("%s buf:%p, frag:%d, fragsize:0x%lx\n", __func__, \
+                       buf, fragcount, fragsize);
+
+       x_count = fragsize / sport->wdsize;
+       y_count = 0;
+
+       /* for fragments larger than 64k words we use 2d dma,
+        * denote fragecount as two numbers' mutliply and both of them
+        * are less than 64k.*/
+       if (x_count >= 0x10000) {
+               int i, count = x_count;
+
+               for (i = 16; i > 0; i--) {
+                       x_count = 1 << i;
+                       if ((count & (x_count - 1)) == 0) {
+                               y_count = count >> i;
+                               if (y_count < 0x10000)
+                                       break;
+                       }
+               }
+               if (i == 0)
+                       return -EINVAL;
+       }
+       pr_debug("%s(x_count:0x%x, y_count:0x%x)\n", __func__,
+                       x_count, y_count);
+
+       if (sport->dma_rx_desc)
+               dma_free_coherent(NULL, sport->rx_desc_bytes,
+                                       sport->dma_rx_desc, 0);
+
+       /* Allocate a new descritor ring as current one. */
+       sport->dma_rx_desc = dma_alloc_coherent(NULL, \
+                       fragcount * sizeof(struct dmasg), &addr, 0);
+       sport->rx_desc_bytes = fragcount * sizeof(struct dmasg);
+
+       if (!sport->dma_rx_desc) {
+               pr_err("Failed to allocate memory for rx desc\n");
+               return -ENOMEM;
+       }
+
+       sport->rx_buf = buf;
+       sport->rx_fragsize = fragsize;
+       sport->rx_frags = fragcount;
+
+       cfg     = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | WNR | \
+                 (DESC_ELEMENT_COUNT << 8); /* large descriptor mode */
+
+       if (y_count != 0)
+               cfg |= DMA2D;
+
+       setup_desc(sport->dma_rx_desc, buf, fragcount, fragsize,
+                       cfg|DMAEN, x_count, y_count, sport->wdsize);
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_config_rx_dma);
+
+int sport_config_tx_dma(struct sport_device *sport, void *buf, \
+               int fragcount, size_t fragsize)
+{
+       unsigned int x_count;
+       unsigned int y_count;
+       unsigned int cfg;
+       dma_addr_t addr;
+
+       pr_debug("%s buf:%p, fragcount:%d, fragsize:0x%lx\n",
+                       __func__, buf, fragcount, fragsize);
+
+       x_count = fragsize/sport->wdsize;
+       y_count = 0;
+
+       /* for fragments larger than 64k words we use 2d dma,
+        * denote fragecount as two numbers' mutliply and both of them
+        * are less than 64k.*/
+       if (x_count >= 0x10000) {
+               int i, count = x_count;
+
+               for (i = 16; i > 0; i--) {
+                       x_count = 1 << i;
+                       if ((count & (x_count - 1)) == 0) {
+                               y_count = count >> i;
+                               if (y_count < 0x10000)
+                                       break;
+                       }
+               }
+               if (i == 0)
+                       return -EINVAL;
+       }
+       pr_debug("%s x_count:0x%x, y_count:0x%x\n", __func__,
+                       x_count, y_count);
+
+
+       if (sport->dma_tx_desc) {
+               dma_free_coherent(NULL, sport->tx_desc_bytes, \
+                               sport->dma_tx_desc, 0);
+       }
+
+       sport->dma_tx_desc = dma_alloc_coherent(NULL, \
+                       fragcount * sizeof(struct dmasg), &addr, 0);
+       sport->tx_desc_bytes = fragcount * sizeof(struct dmasg);
+       if (!sport->dma_tx_desc) {
+               pr_err("Failed to allocate memory for tx desc\n");
+               return -ENOMEM;
+       }
+
+       sport->tx_buf = buf;
+       sport->tx_fragsize = fragsize;
+       sport->tx_frags = fragcount;
+       cfg     = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | \
+                 (DESC_ELEMENT_COUNT << 8); /* large descriptor mode */
+
+       if (y_count != 0)
+               cfg |= DMA2D;
+
+       setup_desc(sport->dma_tx_desc, buf, fragcount, fragsize,
+                       cfg|DMAEN, x_count, y_count, sport->wdsize);
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_config_tx_dma);
+
+/* setup dummy dma descriptor ring, which don't generate interrupts,
+ * the x_modify is set to 0 */
+static int sport_config_rx_dummy(struct sport_device *sport)
+{
+       struct dmasg *desc;
+       unsigned config;
+
+       pr_debug("%s entered\n", __func__);
+#if L1_DATA_A_LENGTH != 0
+       desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
+#else
+       {
+               dma_addr_t addr;
+               desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+       }
+#endif
+       if (desc == NULL) {
+               pr_err("Failed to allocate memory for dummy rx desc\n");
+               return -ENOMEM;
+       }
+       memset(desc, 0, 2 * sizeof(*desc));
+       sport->dummy_rx_desc = desc;
+       desc->start_addr = (unsigned long)sport->dummy_buf;
+       config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize)
+                | WNR | DMAEN;
+       desc->cfg = config;
+       desc->x_count = sport->dummy_count/sport->wdsize;
+       desc->x_modify = sport->wdsize;
+       desc->y_count = 0;
+       desc->y_modify = 0;
+       memcpy(desc+1, desc, sizeof(*desc));
+       desc->next_desc_addr = (unsigned long)(desc+1);
+       desc[1].next_desc_addr = (unsigned long)desc;
+       return 0;
+}
+
+static int sport_config_tx_dummy(struct sport_device *sport)
+{
+       struct dmasg *desc;
+       unsigned int config;
+
+       pr_debug("%s entered\n", __func__);
+
+#if L1_DATA_A_LENGTH != 0
+       desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
+#else
+       {
+               dma_addr_t addr;
+               desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+       }
+#endif
+       if (!desc) {
+               pr_err("Failed to allocate memory for dummy tx desc\n");
+               return -ENOMEM;
+       }
+       memset(desc, 0, 2 * sizeof(*desc));
+       sport->dummy_tx_desc = desc;
+       desc->start_addr = (unsigned long)sport->dummy_buf + \
+               sport->dummy_count;
+       config = DMAFLOW_LARGE | NDSIZE_9 |
+                compute_wdsize(sport->wdsize) | DMAEN;
+       desc->cfg = config;
+       desc->x_count = sport->dummy_count/sport->wdsize;
+       desc->x_modify = sport->wdsize;
+       desc->y_count = 0;
+       desc->y_modify = 0;
+       memcpy(desc+1, desc, sizeof(*desc));
+       desc->next_desc_addr = (unsigned long)(desc+1);
+       desc[1].next_desc_addr = (unsigned long)desc;
+       return 0;
+}
+
+unsigned long sport_curr_offset_rx(struct sport_device *sport)
+{
+       unsigned long curr = get_dma_curr_addr(sport->dma_rx_chan);
+
+       return (unsigned char *)curr - sport->rx_buf;
+}
+EXPORT_SYMBOL(sport_curr_offset_rx);
+
+unsigned long sport_curr_offset_tx(struct sport_device *sport)
+{
+       unsigned long curr = get_dma_curr_addr(sport->dma_tx_chan);
+
+       return (unsigned char *)curr - sport->tx_buf;
+}
+EXPORT_SYMBOL(sport_curr_offset_tx);
+
+void sport_incfrag(struct sport_device *sport, int *frag, int tx)
+{
+       ++(*frag);
+       if (tx == 1 && *frag == sport->tx_frags)
+               *frag = 0;
+
+       if (tx == 0 && *frag == sport->rx_frags)
+               *frag = 0;
+}
+EXPORT_SYMBOL(sport_incfrag);
+
+void sport_decfrag(struct sport_device *sport, int *frag, int tx)
+{
+       --(*frag);
+       if (tx == 1 && *frag == 0)
+               *frag = sport->tx_frags;
+
+       if (tx == 0 && *frag == 0)
+               *frag = sport->rx_frags;
+}
+EXPORT_SYMBOL(sport_decfrag);
+
+static int sport_check_status(struct sport_device *sport,
+               unsigned int *sport_stat,
+               unsigned int *rx_stat,
+               unsigned int *tx_stat)
+{
+       int status = 0;
+
+       if (sport_stat) {
+               SSYNC();
+               status = sport->regs->stat;
+               if (status & (TOVF|TUVF|ROVF|RUVF))
+                       sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF));
+               SSYNC();
+               *sport_stat = status;
+       }
+
+       if (rx_stat) {
+               SSYNC();
+               status = get_dma_curr_irqstat(sport->dma_rx_chan);
+               if (status & (DMA_DONE|DMA_ERR))
+                       clear_dma_irqstat(sport->dma_rx_chan);
+               SSYNC();
+               *rx_stat = status;
+       }
+
+       if (tx_stat) {
+               SSYNC();
+               status = get_dma_curr_irqstat(sport->dma_tx_chan);
+               if (status & (DMA_DONE|DMA_ERR))
+                       clear_dma_irqstat(sport->dma_tx_chan);
+               SSYNC();
+               *tx_stat = status;
+       }
+
+       return 0;
+}
+
+int  sport_dump_stat(struct sport_device *sport, char *buf, size_t len)
+{
+       int ret;
+
+       ret = snprintf(buf, len,
+                       "sts: 0x%04x\n"
+                       "rx dma %d sts: 0x%04x tx dma %d sts: 0x%04x\n",
+                       sport->regs->stat,
+                       sport->dma_rx_chan,
+                       get_dma_curr_irqstat(sport->dma_rx_chan),
+                       sport->dma_tx_chan,
+                       get_dma_curr_irqstat(sport->dma_tx_chan));
+       buf += ret;
+       len -= ret;
+
+       ret += snprintf(buf, len,
+                       "curr_rx_desc:0x%p, curr_tx_desc:0x%p\n"
+                       "dma_rx_desc:0x%p, dma_tx_desc:0x%p\n"
+                       "dummy_rx_desc:0x%p, dummy_tx_desc:0x%p\n",
+                       sport->curr_rx_desc, sport->curr_tx_desc,
+                       sport->dma_rx_desc, sport->dma_tx_desc,
+                       sport->dummy_rx_desc, sport->dummy_tx_desc);
+
+       return ret;
+}
+
+static irqreturn_t rx_handler(int irq, void *dev_id)
+{
+       unsigned int rx_stat;
+       struct sport_device *sport = dev_id;
+
+       pr_debug("%s enter\n", __func__);
+       sport_check_status(sport, NULL, &rx_stat, NULL);
+       if (!(rx_stat & DMA_DONE))
+               pr_err("rx dma is already stopped\n");
+
+       if (sport->rx_callback) {
+               sport->rx_callback(sport->rx_data);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t tx_handler(int irq, void *dev_id)
+{
+       unsigned int tx_stat;
+       struct sport_device *sport = dev_id;
+       pr_debug("%s enter\n", __func__);
+       sport_check_status(sport, NULL, NULL, &tx_stat);
+       if (!(tx_stat & DMA_DONE)) {
+               pr_err("tx dma is already stopped\n");
+               return IRQ_HANDLED;
+       }
+       if (sport->tx_callback) {
+               sport->tx_callback(sport->tx_data);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t err_handler(int irq, void *dev_id)
+{
+       unsigned int status = 0;
+       struct sport_device *sport = dev_id;
+
+       pr_debug("%s\n", __func__);
+       if (sport_check_status(sport, &status, NULL, NULL)) {
+               pr_err("error checking status ??");
+               return IRQ_NONE;
+       }
+
+       if (status & (TOVF|TUVF|ROVF|RUVF)) {
+               pr_info("sport status error:%s%s%s%s\n",
+                               status & TOVF ? " TOVF" : "",
+                               status & TUVF ? " TUVF" : "",
+                               status & ROVF ? " ROVF" : "",
+                               status & RUVF ? " RUVF" : "");
+               if (status & TOVF || status & TUVF) {
+                       disable_dma(sport->dma_tx_chan);
+                       if (sport->tx_run)
+                               sport_tx_dma_start(sport, 0);
+                       else
+                               sport_tx_dma_start(sport, 1);
+                       enable_dma(sport->dma_tx_chan);
+               } else {
+                       disable_dma(sport->dma_rx_chan);
+                       if (sport->rx_run)
+                               sport_rx_dma_start(sport, 0);
+                       else
+                               sport_rx_dma_start(sport, 1);
+                       enable_dma(sport->dma_rx_chan);
+               }
+       }
+       status = sport->regs->stat;
+       if (status & (TOVF|TUVF|ROVF|RUVF))
+               sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF));
+       SSYNC();
+
+       if (sport->err_callback)
+               sport->err_callback(sport->err_data);
+
+       return IRQ_HANDLED;
+}
+
+int sport_set_rx_callback(struct sport_device *sport,
+                      void (*rx_callback)(void *), void *rx_data)
+{
+       BUG_ON(rx_callback == NULL);
+       sport->rx_callback = rx_callback;
+       sport->rx_data = rx_data;
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_set_rx_callback);
+
+int sport_set_tx_callback(struct sport_device *sport,
+               void (*tx_callback)(void *), void *tx_data)
+{
+       BUG_ON(tx_callback == NULL);
+       sport->tx_callback = tx_callback;
+       sport->tx_data = tx_data;
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_set_tx_callback);
+
+int sport_set_err_callback(struct sport_device *sport,
+               void (*err_callback)(void *), void *err_data)
+{
+       BUG_ON(err_callback == NULL);
+       sport->err_callback = err_callback;
+       sport->err_data = err_data;
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_set_err_callback);
+
+struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
+               unsigned dummy_count, void *private_data)
+{
+       int ret;
+       struct sport_device *sport;
+       pr_debug("%s enter\n", __func__);
+       BUG_ON(param == NULL);
+       BUG_ON(wdsize == 0 || dummy_count == 0);
+       sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
+       if (!sport) {
+               pr_err("Failed to allocate for sport device\n");
+               return NULL;
+       }
+
+       memset(sport, 0, sizeof(struct sport_device));
+       sport->dma_rx_chan = param->dma_rx_chan;
+       sport->dma_tx_chan = param->dma_tx_chan;
+       sport->err_irq = param->err_irq;
+       sport->regs = param->regs;
+       sport->private_data = private_data;
+
+       if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
+               pr_err("Failed to request RX dma %d\n", \
+                               sport->dma_rx_chan);
+               goto __init_err1;
+       }
+       if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
+               pr_err("Failed to request RX irq %d\n", \
+                               sport->dma_rx_chan);
+               goto __init_err2;
+       }
+
+       if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
+               pr_err("Failed to request TX dma %d\n", \
+                               sport->dma_tx_chan);
+               goto __init_err2;
+       }
+
+       if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
+               pr_err("Failed to request TX irq %d\n", \
+                               sport->dma_tx_chan);
+               goto __init_err3;
+       }
+
+       if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
+                       sport) < 0) {
+               pr_err("Failed to request err irq:%d\n", \
+                               sport->err_irq);
+               goto __init_err3;
+       }
+
+       pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+                       sport->dma_rx_chan, sport->dma_tx_chan,
+                       sport->err_irq, sport->regs);
+
+       sport->wdsize = wdsize;
+       sport->dummy_count = dummy_count;
+
+#if L1_DATA_A_LENGTH != 0
+       sport->dummy_buf = l1_data_sram_alloc(dummy_count * 2);
+#else
+       sport->dummy_buf = kmalloc(dummy_count * 2, GFP_KERNEL);
+#endif
+       if (sport->dummy_buf == NULL) {
+               pr_err("Failed to allocate dummy buffer\n");
+               goto __error;
+       }
+
+       memset(sport->dummy_buf, 0, dummy_count * 2);
+       ret = sport_config_rx_dummy(sport);
+       if (ret) {
+               pr_err("Failed to config rx dummy ring\n");
+               goto __error;
+       }
+       ret = sport_config_tx_dummy(sport);
+       if (ret) {
+               pr_err("Failed to config tx dummy ring\n");
+               goto __error;
+       }
+
+       return sport;
+__error:
+       free_irq(sport->err_irq, sport);
+__init_err3:
+       free_dma(sport->dma_tx_chan);
+__init_err2:
+       free_dma(sport->dma_rx_chan);
+__init_err1:
+       kfree(sport);
+       return NULL;
+}
+EXPORT_SYMBOL(sport_init);
+
+void sport_done(struct sport_device *sport)
+{
+       if (sport == NULL)
+               return;
+
+       sport_stop(sport);
+       if (sport->dma_rx_desc)
+               dma_free_coherent(NULL, sport->rx_desc_bytes,
+                       sport->dma_rx_desc, 0);
+       if (sport->dma_tx_desc)
+               dma_free_coherent(NULL, sport->tx_desc_bytes,
+                       sport->dma_tx_desc, 0);
+
+#if L1_DATA_A_LENGTH != 0
+       l1_data_sram_free(sport->dummy_rx_desc);
+       l1_data_sram_free(sport->dummy_tx_desc);
+       l1_data_sram_free(sport->dummy_buf);
+#else
+       dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+               sport->dummy_rx_desc, 0);
+       dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+               sport->dummy_tx_desc, 0);
+       kfree(sport->dummy_buf);
+#endif
+       free_dma(sport->dma_rx_chan);
+       free_dma(sport->dma_tx_chan);
+       free_irq(sport->err_irq, sport);
+
+       kfree(sport);
+               sport = NULL;
+}
+EXPORT_SYMBOL(sport_done);
+/*
+* It is only used to send several bytes when dma is not enabled
+ * sport controller is configured but not enabled.
+ * Multichannel cannot works with pio mode */
+/* Used by ac97 to write and read codec register */
+int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
+               u8 *in_data, int len)
+{
+       unsigned short dma_config;
+       unsigned short status;
+       unsigned long flags;
+       unsigned long wait = 0;
+
+       pr_debug("%s enter, out_data:%p, in_data:%p len:%d\n", \
+                       __func__, out_data, in_data, len);
+       pr_debug("tcr1:0x%04x, tcr2:0x%04x, tclkdiv:0x%04x, tfsdiv:0x%04x\n"
+                       "mcmc1:0x%04x, mcmc2:0x%04x\n",
+                       sport->regs->tcr1, sport->regs->tcr2,
+                       sport->regs->tclkdiv, sport->regs->tfsdiv,
+                       sport->regs->mcmc1, sport->regs->mcmc2);
+       flush_dcache_range((unsigned)out_data, (unsigned)(out_data + len));
+
+       /* Enable tx dma */
+       dma_config = (RESTART | WDSIZE_16 | DI_EN);
+       set_dma_start_addr(sport->dma_tx_chan, (unsigned long)out_data);
+       set_dma_x_count(sport->dma_tx_chan, len/2);
+       set_dma_x_modify(sport->dma_tx_chan, 2);
+       set_dma_config(sport->dma_tx_chan, dma_config);
+       enable_dma(sport->dma_tx_chan);
+
+       if (in_data != NULL) {
+               invalidate_dcache_range((unsigned)in_data, \
+                               (unsigned)(in_data + len));
+               /* Enable rx dma */
+               dma_config = (RESTART | WDSIZE_16 | WNR | DI_EN);
+               set_dma_start_addr(sport->dma_rx_chan, (unsigned long)in_data);
+               set_dma_x_count(sport->dma_rx_chan, len/2);
+               set_dma_x_modify(sport->dma_rx_chan, 2);
+               set_dma_config(sport->dma_rx_chan, dma_config);
+               enable_dma(sport->dma_rx_chan);
+       }
+
+       local_irq_save(flags);
+       sport->regs->tcr1 |= TSPEN;
+       sport->regs->rcr1 |= RSPEN;
+       SSYNC();
+
+       status = get_dma_curr_irqstat(sport->dma_tx_chan);
+       while (status & DMA_RUN) {
+               udelay(1);
+               status = get_dma_curr_irqstat(sport->dma_tx_chan);
+               pr_debug("DMA status:0x%04x\n", status);
+               if (wait++ > 100)
+                       goto __over;
+       }
+       status = sport->regs->stat;
+       wait = 0;
+
+       while (!(status & TXHRE)) {
+               pr_debug("sport status:0x%04x\n", status);
+               udelay(1);
+               status = *(unsigned short *)&sport->regs->stat;
+               if (wait++ > 1000)
+                       goto __over;
+       }
+       /* Wait for the last byte sent out */
+       udelay(20);
+       pr_debug("sport status:0x%04x\n", status);
+
+__over:
+       sport->regs->tcr1 &= ~TSPEN;
+       sport->regs->rcr1 &= ~RSPEN;
+       SSYNC();
+       disable_dma(sport->dma_tx_chan);
+       /* Clear the status */
+       clear_dma_irqstat(sport->dma_tx_chan);
+       if (in_data != NULL) {
+               disable_dma(sport->dma_rx_chan);
+               clear_dma_irqstat(sport->dma_rx_chan);
+       }
+       SSYNC();
+       local_irq_restore(flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(sport_send_and_recv);
+
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("SPORT driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
new file mode 100644 (file)
index 0000000..4c16345
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * File:         bf5xx_ac97_sport.h
+ * Based on:
+ * Author:       Roy Huang <roy.huang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#ifndef __BF5XX_SPORT_H__
+#define __BF5XX_SPORT_H__
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <asm/dma.h>
+
+struct sport_register {
+       u16 tcr1;       u16 reserved0;
+       u16 tcr2;       u16 reserved1;
+       u16 tclkdiv;    u16 reserved2;
+       u16 tfsdiv;     u16 reserved3;
+       u32 tx;
+       u32 reserved_l0;
+       u32 rx;
+       u32 reserved_l1;
+       u16 rcr1;       u16 reserved4;
+       u16 rcr2;       u16 reserved5;
+       u16 rclkdiv;    u16 reserved6;
+       u16 rfsdiv;     u16 reserved7;
+       u16 stat;       u16 reserved8;
+       u16 chnl;       u16 reserved9;
+       u16 mcmc1;      u16 reserved10;
+       u16 mcmc2;      u16 reserved11;
+       u32 mtcs0;
+       u32 mtcs1;
+       u32 mtcs2;
+       u32 mtcs3;
+       u32 mrcs0;
+       u32 mrcs1;
+       u32 mrcs2;
+       u32 mrcs3;
+};
+
+#define DESC_ELEMENT_COUNT 9
+
+struct sport_device {
+       int dma_rx_chan;
+       int dma_tx_chan;
+       int err_irq;
+       struct sport_register *regs;
+
+       unsigned char *rx_buf;
+       unsigned char *tx_buf;
+       unsigned int rx_fragsize;
+       unsigned int tx_fragsize;
+       unsigned int rx_frags;
+       unsigned int tx_frags;
+       unsigned int wdsize;
+
+       /* for dummy dma transfer */
+       void *dummy_buf;
+       unsigned int dummy_count;
+
+       /* DMA descriptor ring head of current audio stream*/
+       struct dmasg *dma_rx_desc;
+       struct dmasg *dma_tx_desc;
+       unsigned int rx_desc_bytes;
+       unsigned int tx_desc_bytes;
+
+       unsigned int rx_run:1; /* rx is running */
+       unsigned int tx_run:1; /* tx is running */
+
+       struct dmasg *dummy_rx_desc;
+       struct dmasg *dummy_tx_desc;
+
+       struct dmasg *curr_rx_desc;
+       struct dmasg *curr_tx_desc;
+
+       int rx_curr_frag;
+       int tx_curr_frag;
+
+       unsigned int rcr1;
+       unsigned int rcr2;
+       int rx_tdm_count;
+
+       unsigned int tcr1;
+       unsigned int tcr2;
+       int tx_tdm_count;
+
+       void (*rx_callback)(void *data);
+       void *rx_data;
+       void (*tx_callback)(void *data);
+       void *tx_data;
+       void (*err_callback)(void *data);
+       void *err_data;
+       unsigned char *tx_dma_buf;
+       unsigned char *rx_dma_buf;
+#ifdef CONFIG_SND_MMAP_SUPPORT
+       dma_addr_t tx_dma_phy;
+       dma_addr_t rx_dma_phy;
+       int tx_pos;/*pcm sample count*/
+       int rx_pos;
+       unsigned int tx_buffer_size;
+       unsigned int rx_buffer_size;
+#endif
+       void *private_data;
+};
+
+extern struct sport_device *sport_handle;
+
+struct sport_param {
+       int dma_rx_chan;
+       int dma_tx_chan;
+       int err_irq;
+       struct sport_register *regs;
+};
+
+struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
+               unsigned dummy_count, void *private_data);
+
+void sport_done(struct sport_device *sport);
+
+/* first use these ...*/
+
+/* note: multichannel is in units of 8 channels, tdm_count is number of channels
+ *  NOT / 8 ! all channels are enabled by default */
+int sport_set_multichannel(struct sport_device *sport, int tdm_count,
+               u32 mask, int packed);
+
+int sport_config_rx(struct sport_device *sport,
+               unsigned int rcr1, unsigned int rcr2,
+               unsigned int clkdiv, unsigned int fsdiv);
+
+int sport_config_tx(struct sport_device *sport,
+               unsigned int tcr1, unsigned int tcr2,
+               unsigned int clkdiv, unsigned int fsdiv);
+
+/* ... then these: */
+
+/* buffer size (in bytes) == fragcount * fragsize_bytes */
+
+/* this is not a very general api, it sets the dma to 2d autobuffer mode */
+
+int sport_config_rx_dma(struct sport_device *sport, void *buf,
+               int fragcount, size_t fragsize_bytes);
+
+int sport_config_tx_dma(struct sport_device *sport, void *buf,
+               int fragcount, size_t fragsize_bytes);
+
+int sport_tx_start(struct sport_device *sport);
+int sport_tx_stop(struct sport_device *sport);
+int sport_rx_start(struct sport_device *sport);
+int sport_rx_stop(struct sport_device *sport);
+
+/* for use in interrupt handler */
+unsigned long sport_curr_offset_rx(struct sport_device *sport);
+unsigned long sport_curr_offset_tx(struct sport_device *sport);
+
+void sport_incfrag(struct sport_device *sport, int *frag, int tx);
+void sport_decfrag(struct sport_device *sport, int *frag, int tx);
+
+int sport_set_rx_callback(struct sport_device *sport,
+                      void (*rx_callback)(void *), void *rx_data);
+int sport_set_tx_callback(struct sport_device *sport,
+                      void (*tx_callback)(void *), void *tx_data);
+int sport_set_err_callback(struct sport_device *sport,
+                      void (*err_callback)(void *), void *err_data);
+
+int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
+               u8 *in_data, int len);
+#endif /* BF53X_SPORT_H */
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
new file mode 100644 (file)
index 0000000..e15f67f
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ssm2602.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  board driver for SSM2602 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/dma.h>
+#include <asm/portmux.h>
+#include <linux/gpio.h>
+#include "../codecs/ssm2602.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+static struct snd_soc_machine bf5xx_ssm2602;
+
+static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+       pr_debug("%s enter\n", __func__);
+       cpu_dai->private_data = sport_handle;
+       return 0;
+}
+
+static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       unsigned int clk = 0;
+       int ret = 0;
+
+       pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+               params_format(params));
+       /*
+        * If you are using a crystal source which frequency is not 12MHz
+        * then modify the below case statement with frequency of the crystal.
+        *
+        * If you are using the SPORT to generate clocking then this is
+        * where to do it.
+        */
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 48000:
+       case 96000:
+       case 11025:
+       case 22050:
+       case 44100:
+               clk = 12000000;
+               break;
+       }
+
+       /*
+        * CODEC is master for BCLK and LRC in this configuration.
+        */
+
+       /* set codec DAI configuration */
+       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+       /* set cpu DAI configuration */
+       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops bf5xx_ssm2602_ops = {
+       .startup = bf5xx_ssm2602_startup,
+       .hw_params = bf5xx_ssm2602_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
+       .name = "ssm2602",
+       .stream_name = "SSM2602",
+       .cpu_dai = &bf5xx_i2s_dai,
+       .codec_dai = &ssm2602_dai,
+       .ops = &bf5xx_ssm2602_ops,
+};
+
+/*
+ * SSM2602 2 wire address is determined by CSB
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+
+static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
+       .i2c_bus = 0,
+       .i2c_address = 0x1b,
+};
+
+static struct snd_soc_machine bf5xx_ssm2602 = {
+       .name = "bf5xx_ssm2602",
+       .dai_link = &bf5xx_ssm2602_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
+       .machine = &bf5xx_ssm2602,
+       .platform = &bf5xx_i2s_soc_platform,
+       .codec_dev = &soc_codec_dev_ssm2602,
+       .codec_data = &bf5xx_ssm2602_setup,
+};
+
+static struct platform_device *bf52x_ssm2602_snd_device;
+
+static int __init bf5xx_ssm2602_init(void)
+{
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!bf52x_ssm2602_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(bf52x_ssm2602_snd_device,
+                               &bf5xx_ssm2602_snd_devdata);
+       bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev;
+       ret = platform_device_add(bf52x_ssm2602_snd_device);
+
+       if (ret)
+               platform_device_put(bf52x_ssm2602_snd_device);
+
+       return ret;
+}
+
+static void __exit bf5xx_ssm2602_exit(void)
+{
+       pr_debug("%s enter\n", __func__);
+       platform_device_unregister(bf52x_ssm2602_snd_device);
+}
+
+module_init(bf5xx_ssm2602_init);
+module_exit(bf5xx_ssm2602_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC SSM2602 BF527-EZKIT");
+MODULE_LICENSE("GPL");
+
index 1db04a28a53d46c7732401a2375ea904db158af6..e0b9869df0f107ed2876a2a8b9c8893ff8740cd5 100644 (file)
@@ -1,16 +1,80 @@
+config SND_SOC_ALL_CODECS
+       tristate "Build all ASoC CODEC drivers"
+       depends on I2C
+       select SPI
+       select SPI_MASTER
+       select SND_SOC_AK4535
+       select SND_SOC_CS4270
+       select SND_SOC_SSM2602
+       select SND_SOC_TLV320AIC26
+       select SND_SOC_TLV320AIC3X
+       select SND_SOC_UDA1380
+       select SND_SOC_WM8510
+       select SND_SOC_WM8580
+       select SND_SOC_WM8731
+       select SND_SOC_WM8750
+       select SND_SOC_WM8753
+       select SND_SOC_WM8900
+       select SND_SOC_WM8903
+       select SND_SOC_WM8971
+       select SND_SOC_WM8990
+        help
+          Normally ASoC codec drivers are only built if a machine driver which
+          uses them is also built since they are only usable with a machine
+          driver.  Selecting this option will allow these drivers to be built
+          without an explicit machine driver for test and development purposes.
+
+          If unsure select "N".
+
+
 config SND_SOC_AC97_CODEC
        tristate
        select SND_AC97_CODEC
 
+config SND_SOC_AD1980
+       tristate
+
 config SND_SOC_AK4535
        tristate
 
+# Cirrus Logic CS4270 Codec
+config SND_SOC_CS4270
+       tristate
+
+# Cirrus Logic CS4270 Codec Hardware Mute Support
+# Select if you have external muting circuitry attached to your CS4270.
+config SND_SOC_CS4270_HWMUTE
+       bool
+       depends on SND_SOC_CS4270
+
+# Cirrus Logic CS4270 Codec VD = 3.3V Errata
+# Select if you are affected by the errata where the part will not function
+# if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
+# not select any sample rates that require MCLK to be divided by 1.5.
+config SND_SOC_CS4270_VD33_ERRATA
+       bool
+       depends on SND_SOC_CS4270
+
+config SND_SOC_SSM2602
+       tristate
+
+config SND_SOC_TLV320AIC26
+       tristate "TI TLV320AIC26 Codec support"
+       depends on SND_SOC && SPI
+
+config SND_SOC_TLV320AIC3X
+       tristate
+       depends on I2C
+
 config SND_SOC_UDA1380
         tristate
 
 config SND_SOC_WM8510
        tristate
 
+config SND_SOC_WM8580
+       tristate
+
 config SND_SOC_WM8731
        tristate
 
@@ -20,33 +84,20 @@ config SND_SOC_WM8750
 config SND_SOC_WM8753
        tristate
 
-config SND_SOC_WM8990
+config SND_SOC_WM8900
        tristate
 
-config SND_SOC_WM9712
+config SND_SOC_WM8903
        tristate
 
-config SND_SOC_WM9713
+config SND_SOC_WM8971
        tristate
 
-# Cirrus Logic CS4270 Codec
-config SND_SOC_CS4270
+config SND_SOC_WM8990
        tristate
 
-# Cirrus Logic CS4270 Codec Hardware Mute Support
-# Select if you have external muting circuitry attached to your CS4270.
-config SND_SOC_CS4270_HWMUTE
-       bool
-       depends on SND_SOC_CS4270
-
-# Cirrus Logic CS4270 Codec VD = 3.3V Errata
-# Select if you are affected by the errata where the part will not function
-# if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
-# not select any sample rates that require MCLK to be divided by 1.5.
-config SND_SOC_CS4270_VD33_ERRATA
-       bool
-       depends on SND_SOC_CS4270
+config SND_SOC_WM9712
+       tristate
 
-config SND_SOC_TLV320AIC3X
+config SND_SOC_WM9713
        tristate
-       depends on I2C
index d7b97abcf7291cea11e2ea29a3c687551f241b4f..f977978a3409e2c19584f1819ddde1989bd9aeef 100644 (file)
@@ -1,25 +1,39 @@
 snd-soc-ac97-objs := ac97.o
+snd-soc-ad1980-objs := ad1980.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-cs4270-objs := cs4270.o
+snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-tlv320aic26-objs := tlv320aic26.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8510-objs := wm8510.o
+snd-soc-wm8580-objs := wm8580.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
+snd-soc-wm8900-objs := wm8900.o
+snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
-snd-soc-cs4270-objs := cs4270.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
+obj-$(CONFIG_SND_SOC_WM8580)   += snd-soc-wm8580.o
 obj-$(CONFIG_SND_SOC_WM8731)   += snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)   += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
+obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
+obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
+obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
-obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
-obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
new file mode 100644 (file)
index 0000000..4e09c1f
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * ad1980.c  --  ALSA Soc AD1980 codec support
+ *
+ * Copyright:  Analog Device Inc.
+ * Author:     Roy Huang <roy.huang@analog.com>
+ *             Cliff Cai <cliff.cai@analog.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "ad1980.h"
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+       unsigned int reg);
+static int ac97_write(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int val);
+
+/*
+ * AD1980 register cache
+ */
+static const u16 ad1980_reg[] = {
+       0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6  */
+       0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e  */
+       0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
+       0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
+       0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
+       0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
+       0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
+       0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+       0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+       0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+       0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+       0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
+       0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
+       0x0000, 0x0000, 0x4144, 0x5370  /* 78 - 7e */
+};
+
+static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
+               "Stereo Mix", "Mono Mix", "Phone"};
+
+static const struct soc_enum ad1980_cap_src =
+       SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel);
+
+static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
+SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
+
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+
+SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
+
+SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0),
+SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1),
+SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1),
+
+SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1),
+SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
+
+SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0),
+SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0),
+
+SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
+
+SOC_ENUM("Capture Source", ad1980_cap_src),
+
+SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
+};
+
+/* add non dapm controls */
+static int ad1980_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) {
+               err = snd_ctl_add(codec->card, snd_soc_cnew(
+                               &ad1980_snd_ac97_controls[i], codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       switch (reg) {
+       case AC97_RESET:
+       case AC97_INT_PAGING:
+       case AC97_POWERDOWN:
+       case AC97_EXTENDED_STATUS:
+       case AC97_VENDOR_ID1:
+       case AC97_VENDOR_ID2:
+               return soc_ac97_ops.read(codec->ac97, reg);
+       default:
+               reg = reg >> 1;
+
+               if (reg >= (ARRAY_SIZE(ad1980_reg)))
+                       return -EINVAL;
+
+               return cache[reg];
+       }
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int val)
+{
+       u16 *cache = codec->reg_cache;
+
+       soc_ac97_ops.write(codec->ac97, reg, val);
+       reg = reg >> 1;
+       if (reg < (ARRAY_SIZE(ad1980_reg)))
+               cache[reg] = val;
+
+       return 0;
+}
+
+struct snd_soc_dai ad1980_dai = {
+       .name = "AC97",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad1980_dai);
+
+static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
+{
+       u16 retry_cnt = 0;
+
+retry:
+       if (try_warm && soc_ac97_ops.warm_reset) {
+               soc_ac97_ops.warm_reset(codec->ac97);
+               if (ac97_read(codec, AC97_RESET) == 0x0090)
+                       return 1;
+       }
+
+       soc_ac97_ops.reset(codec->ac97);
+       /* Set bit 16slot in register 74h, then every slot will has only 16
+        * bits. This command is sent out in 20bit mode, in which case the
+        * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
+       ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
+
+       if (ac97_read(codec, AC97_RESET)  != 0x0090)
+               goto err;
+       return 0;
+
+err:
+       while (retry_cnt++ < 10)
+               goto retry;
+
+       printk(KERN_ERR "AD1980 AC97 reset failed\n");
+       return -EIO;
+}
+
+static int ad1980_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+       u16 vendor_id2;
+
+       printk(KERN_INFO "AD1980 SoC Audio Codec\n");
+
+       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (socdev->codec == NULL)
+               return -ENOMEM;
+       codec = socdev->codec;
+       mutex_init(&codec->mutex);
+
+       codec->reg_cache =
+               kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               ret = -ENOMEM;
+               goto cache_err;
+       }
+       memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
+                       ARRAY_SIZE(ad1980_reg));
+       codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
+       codec->reg_cache_step = 2;
+       codec->name = "AD1980";
+       codec->owner = THIS_MODULE;
+       codec->dai = &ad1980_dai;
+       codec->num_dai = 1;
+       codec->write = ac97_write;
+       codec->read = ac97_read;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       if (ret < 0) {
+               printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
+               goto codec_err;
+       }
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0)
+               goto pcm_err;
+
+
+       ret = ad1980_reset(codec, 0);
+       if (ret < 0) {
+               printk(KERN_ERR "AC97 link error\n");
+               goto reset_err;
+       }
+
+       /* Read out vendor ID to make sure it is ad1980 */
+       if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144)
+               goto reset_err;
+
+       vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
+
+       if (vendor_id2 != 0x5370) {
+               if (vendor_id2 != 0x5374)
+                       goto reset_err;
+               else
+                       printk(KERN_WARNING "ad1980: "
+                               "Found AD1981 - only 2/2 IN/OUT Channels "
+                               "supported\n");
+       }
+
+       ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */
+       ac97_write(codec, AC97_PCM, 0x0000);    /* unmute PCM out volume */
+       ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */
+
+       ad1980_add_controls(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "ad1980: failed to register card\n");
+               goto reset_err;
+       }
+
+       return 0;
+
+reset_err:
+       snd_soc_free_pcms(socdev);
+
+pcm_err:
+       snd_soc_free_ac97_codec(codec);
+
+codec_err:
+       kfree(codec->reg_cache);
+
+cache_err:
+       kfree(socdev->codec);
+       socdev->codec = NULL;
+       return ret;
+}
+
+static int ad1980_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec == NULL)
+               return 0;
+
+       snd_soc_dapm_free(socdev);
+       snd_soc_free_pcms(socdev);
+       snd_soc_free_ac97_codec(codec);
+       kfree(codec->reg_cache);
+       kfree(codec);
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+       .probe =        ad1980_soc_probe,
+       .remove =       ad1980_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+MODULE_DESCRIPTION("ASoC ad1980 driver");
+MODULE_AUTHOR("Roy Huang, Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h
new file mode 100644 (file)
index 0000000..db6c850
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * ad1980.h  --  ad1980 Soc Audio driver
+ */
+
+#ifndef _AD1980_H
+#define _AD1980_H
+/* Bit definition of Power-Down Control/Status Register */
+#define ADC            0x0001
+#define DAC            0x0002
+#define ANL            0x0004
+#define REF            0x0008
+#define PR0            0x0100
+#define PR1            0x0200
+#define PR2            0x0400
+#define PR3            0x0800
+#define PR4            0x1000
+#define PR5            0x2000
+#define PR6            0x4000
+
+extern struct snd_soc_dai ad1980_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad1980;
+
+#endif
index 7da9f467b7b83f06d4fdf02a44e05ba4ff530b97..088cf99277203ff4d729d722629ed8cf222f2cb0 100644 (file)
@@ -535,87 +535,85 @@ static struct snd_soc_device *ak4535_socdev;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
-#define I2C_DRIVERID_AK4535 0xfefe /* liam -  need a proper id */
-
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver ak4535_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int ak4535_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = ak4535_socdev;
-       struct ak4535_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               printk(KERN_ERR "failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = ak4535_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                printk(KERN_ERR "failed to initialise AK4535\n");
-               goto err;
-       }
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int ak4535_i2c_detach(struct i2c_client *client)
+static int ak4535_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int ak4535_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, ak4535_codec_probe);
-}
+static const struct i2c_device_id ak4535_i2c_id[] = {
+       { "ak4535", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver ak4535_i2c_driver = {
        .driver = {
                .name = "AK4535 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_AK4535,
-       .attach_adapter = ak4535_i2c_attach,
-       .detach_client =  ak4535_i2c_detach,
-       .command =        NULL,
+       .probe =    ak4535_i2c_probe,
+       .remove =   ak4535_i2c_remove,
+       .id_table = ak4535_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "AK4535",
-       .driver = &ak4535_i2c_driver,
-};
+static int ak4535_add_i2c_device(struct platform_device *pdev,
+                                const struct ak4535_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&ak4535_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&ak4535_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int ak4535_probe(struct platform_device *pdev)
@@ -624,7 +622,7 @@ static int ak4535_probe(struct platform_device *pdev)
        struct ak4535_setup_data *setup;
        struct snd_soc_codec *codec;
        struct ak4535_priv *ak4535;
-       int ret = 0;
+       int ret;
 
        printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
 
@@ -646,17 +644,14 @@ static int ak4535_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        ak4535_socdev = socdev;
+       ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
                codec->hw_read = (hw_read_t)i2c_master_recv;
-               ret = i2c_add_driver(&ak4535_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = ak4535_add_i2c_device(pdev, setup);
        }
-#else
-       /* Add other interfaces here */
 #endif
 
        if (ret != 0) {
@@ -678,6 +673,7 @@ static int ak4535_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&ak4535_i2c_driver);
 #endif
        kfree(codec->private_data);
index e9fe30e2c05613f3f500aeea1d98115f9b29e508..c7a58703ea394ccd30c79a359d4be1401b438710 100644 (file)
@@ -37,6 +37,7 @@
 #define AK4535_CACHEREGNUM     0x10
 
 struct ak4535_setup_data {
+       int            i2c_bus;
        unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
new file mode 100644 (file)
index 0000000..940ce1c
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ * File:         sound/soc/codecs/ssm2602.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Driver for ssm2602 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "ssm2602.h"
+
+#define AUDIO_NAME "ssm2602"
+#define SSM2602_VERSION "0.1"
+
+struct snd_soc_codec_device soc_codec_dev_ssm2602;
+
+/* codec private data */
+struct ssm2602_priv {
+       unsigned int sysclk;
+       struct snd_pcm_substream *master_substream;
+       struct snd_pcm_substream *slave_substream;
+};
+
+/*
+ * ssm2602 register cache
+ * We can't read the ssm2602 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
+       0x0017, 0x0017, 0x0079, 0x0079,
+       0x0000, 0x0000, 0x0000, 0x000a,
+       0x0000, 0x0000
+};
+
+/*
+ * read ssm2602 register cache
+ */
+static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg == SSM2602_RESET)
+               return 0;
+       if (reg >= SSM2602_CACHEREGNUM)
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write ssm2602 register cache
+ */
+static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
+       u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= SSM2602_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the ssm2602 register space
+ */
+static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D9 ssm2602 register offset
+        *   D8...D0 register data
+        */
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
+
+       ssm2602_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define ssm2602_reset(c)       ssm2602_write(c, SSM2602_RESET, 0)
+
+/*Appending several "None"s just for OSS mixer use*/
+static const char *ssm2602_input_select[] = {
+       "Line", "Mic", "None", "None", "None",
+       "None", "None", "None",
+};
+
+static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum ssm2602_enum[] = {
+       SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select),
+       SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
+};
+
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+
+SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+       0, 127, 0),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+       7, 1, 0),
+
+SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+
+SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Capture Source", ssm2602_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
+};
+
+/* add non dapm controls */
+static int ssm2602_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                       snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Output Mixer */
+static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new ssm2602_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+       &ssm2602_output_mixer_controls[0],
+       ARRAY_SIZE(ssm2602_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route audio_conn[] = {
+       /* output mixer */
+       {"Output Mixer", "Line Bypass Switch", "Line Input"},
+       {"Output Mixer", "HiFi Playback Switch", "DAC"},
+       {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+       /* outputs */
+       {"RHPOUT", NULL, "Output Mixer"},
+       {"ROUT", NULL, "Output Mixer"},
+       {"LHPOUT", NULL, "Output Mixer"},
+       {"LOUT", NULL, "Output Mixer"},
+
+       /* input mux */
+       {"Input Mux", "Line", "Line Input"},
+       {"Input Mux", "Mic", "Mic Bias"},
+       {"ADC", NULL, "Input Mux"},
+
+       /* inputs */
+       {"Line Input", NULL, "LLINEIN"},
+       {"Line Input", NULL, "RLINEIN"},
+       {"Mic Bias", NULL, "MICIN"},
+};
+
+static int ssm2602_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets,
+                                 ARRAY_SIZE(ssm2602_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+struct _coeff_div {
+       u32 mclk;
+       u32 rate;
+       u16 fs;
+       u8 sr:4;
+       u8 bosr:1;
+       u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+       /* 48k */
+       {12288000, 48000, 256, 0x0, 0x0, 0x0},
+       {18432000, 48000, 384, 0x0, 0x1, 0x0},
+       {12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+       /* 32k */
+       {12288000, 32000, 384, 0x6, 0x0, 0x0},
+       {18432000, 32000, 576, 0x6, 0x1, 0x0},
+       {12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+       /* 8k */
+       {12288000, 8000, 1536, 0x3, 0x0, 0x0},
+       {18432000, 8000, 2304, 0x3, 0x1, 0x0},
+       {11289600, 8000, 1408, 0xb, 0x0, 0x0},
+       {16934400, 8000, 2112, 0xb, 0x1, 0x0},
+       {12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+       /* 96k */
+       {12288000, 96000, 128, 0x7, 0x0, 0x0},
+       {18432000, 96000, 192, 0x7, 0x1, 0x0},
+       {12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+       /* 44.1k */
+       {11289600, 44100, 256, 0x8, 0x0, 0x0},
+       {16934400, 44100, 384, 0x8, 0x1, 0x0},
+       {12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+       /* 88.2k */
+       {11289600, 88200, 128, 0xf, 0x0, 0x0},
+       {16934400, 88200, 192, 0xf, 0x1, 0x0},
+       {12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+                       return i;
+       }
+       return i;
+}
+
+static int ssm2602_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       u16 srate;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct ssm2602_priv *ssm2602 = codec->private_data;
+       u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
+       int i = get_coeff(ssm2602->sysclk, params_rate(params));
+
+       /*no match is found*/
+       if (i == ARRAY_SIZE(coeff_div))
+               return -EINVAL;
+
+       srate = (coeff_div[i].sr << 2) |
+               (coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+       ssm2602_write(codec, SSM2602_ACTIVE, 0);
+       ssm2602_write(codec, SSM2602_SRATE, srate);
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= 0x0004;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= 0x0008;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= 0x000c;
+               break;
+       }
+       ssm2602_write(codec, SSM2602_IFACE, iface);
+       ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+       return 0;
+}
+
+static int ssm2602_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct ssm2602_priv *ssm2602 = codec->private_data;
+       struct snd_pcm_runtime *master_runtime;
+
+       /* The DAI has shared clocks so if we already have a playback or
+        * capture going then constrain this substream to match it.
+        */
+       if (ssm2602->master_substream) {
+               master_runtime = ssm2602->master_substream->runtime;
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_RATE,
+                                            master_runtime->rate,
+                                            master_runtime->rate);
+
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                            master_runtime->sample_bits,
+                                            master_runtime->sample_bits);
+
+               ssm2602->slave_substream = substream;
+       } else
+               ssm2602->master_substream = substream;
+
+       return 0;
+}
+
+static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       /* set active */
+       ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+
+       return 0;
+}
+
+static void ssm2602_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       /* deactivate */
+       if (!codec->active)
+               ssm2602_write(codec, SSM2602_ACTIVE, 0);
+}
+
+static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+       if (mute)
+               ssm2602_write(codec, SSM2602_APDIGI,
+                               mute_reg | APDIGI_ENABLE_DAC_MUTE);
+       else
+               ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
+       return 0;
+}
+
+static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct ssm2602_priv *ssm2602 = codec->private_data;
+       switch (freq) {
+       case 11289600:
+       case 12000000:
+       case 12288000:
+       case 16934400:
+       case 18432000:
+               ssm2602->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = 0;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface |= 0x0040;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= 0x0002;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= 0x0001;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= 0x0003;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface |= 0x0013;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= 0x0090;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= 0x0080;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= 0x0010;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set iface */
+       ssm2602_write(codec, SSM2602_IFACE, iface);
+       return 0;
+}
+
+static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* vref/mid, osc on, dac unmute */
+               ssm2602_write(codec, SSM2602_PWR, reg);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* everything off except vref/vmid, */
+               ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* everything off, dac mute, inactive */
+               ssm2602_write(codec, SSM2602_ACTIVE, 0);
+               ssm2602_write(codec, SSM2602_PWR, 0xffff);
+               break;
+
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+               SNDRV_PCM_RATE_96000)
+
+struct snd_soc_dai ssm2602_dai = {
+       .name = "SSM2602",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SSM2602_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SSM2602_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
+       .ops = {
+               .startup = ssm2602_startup,
+               .prepare = ssm2602_pcm_prepare,
+               .hw_params = ssm2602_hw_params,
+               .shutdown = ssm2602_shutdown,
+       },
+       .dai_ops = {
+               .digital_mute = ssm2602_mute,
+               .set_sysclk = ssm2602_set_dai_sysclk,
+               .set_fmt = ssm2602_set_dai_fmt,
+       }
+};
+EXPORT_SYMBOL_GPL(ssm2602_dai);
+
+static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int ssm2602_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u8 data[2];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+       ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       ssm2602_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+/*
+ * initialise the ssm2602 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int ssm2602_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int reg, ret = 0;
+
+       codec->name = "SSM2602";
+       codec->owner = THIS_MODULE;
+       codec->read = ssm2602_read_reg_cache;
+       codec->write = ssm2602_write;
+       codec->set_bias_level = ssm2602_set_bias_level;
+       codec->dai = &ssm2602_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = sizeof(ssm2602_reg);
+       codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
+                                       GFP_KERNEL);
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       ssm2602_reset(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               pr_err("ssm2602: failed to create pcms\n");
+               goto pcm_err;
+       }
+       /*power on device*/
+       ssm2602_write(codec, SSM2602_ACTIVE, 0);
+       /* set the update bits */
+       reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
+       ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
+       reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
+       ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
+       reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
+       ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+       reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
+       ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+       /*select Line in as default input*/
+       ssm2602_write(codec, SSM2602_APANA,
+                       APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC |
+                       APANA_ENABLE_MIC_BOOST);
+       ssm2602_write(codec, SSM2602_PWR, 0);
+
+       ssm2602_add_controls(codec);
+       ssm2602_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               pr_err("ssm2602: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+static struct snd_soc_device *ssm2602_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * ssm2602 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int ssm2602_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct snd_soc_device *socdev = ssm2602_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = ssm2602_init(socdev);
+       if (ret < 0)
+               pr_err("failed to initialise SSM2602\n");
+
+       return ret;
+}
+
+static int ssm2602_i2c_remove(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       kfree(codec->reg_cache);
+       return 0;
+}
+
+static const struct i2c_device_id ssm2602_i2c_id[] = {
+       { "ssm2602", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+/* corgi i2c codec control layer */
+static struct i2c_driver ssm2602_i2c_driver = {
+       .driver = {
+               .name = "SSM2602 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = ssm2602_i2c_probe,
+       .remove = ssm2602_i2c_remove,
+       .id_table = ssm2602_i2c_id,
+};
+
+static int ssm2602_add_i2c_device(struct platform_device *pdev,
+                                 const struct ssm2602_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&ssm2602_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+               setup->i2c_bus);
+               goto err_driver;
+       }
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+               (unsigned int)info.addr);
+               goto err_driver;
+       }
+       return 0;
+err_driver:
+       i2c_del_driver(&ssm2602_i2c_driver);
+       return -ENODEV;
+}
+#endif
+
+static int ssm2602_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct ssm2602_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct ssm2602_priv *ssm2602;
+       int ret = 0;
+
+       pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+       if (ssm2602 == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = ssm2602;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       ssm2602_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = ssm2602_add_i2c_device(pdev, setup);
+       }
+#else
+       /* other interfaces */
+#endif
+       return ret;
+}
+
+/* remove everything here */
+static int ssm2602_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
+       i2c_del_driver(&ssm2602_i2c_driver);
+#endif
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
+       .probe =        ssm2602_probe,
+       .remove =       ssm2602_remove,
+       .suspend =      ssm2602_suspend,
+       .resume =       ssm2602_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
+
+MODULE_DESCRIPTION("ASoC ssm2602 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
new file mode 100644 (file)
index 0000000..f344e6d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * File:         sound/soc/codecs/ssm2602.h
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SSM2602_H
+#define _SSM2602_H
+
+/* SSM2602 Codec Register definitions */
+
+#define SSM2602_LINVOL   0x00
+#define SSM2602_RINVOL   0x01
+#define SSM2602_LOUT1V   0x02
+#define SSM2602_ROUT1V   0x03
+#define SSM2602_APANA    0x04
+#define SSM2602_APDIGI   0x05
+#define SSM2602_PWR      0x06
+#define SSM2602_IFACE    0x07
+#define SSM2602_SRATE    0x08
+#define SSM2602_ACTIVE   0x09
+#define SSM2602_RESET   0x0f
+
+/*SSM2602 Codec Register Field definitions
+ *(Mask value to extract the corresponding Register field)
+ */
+
+/*Left ADC Volume Control (SSM2602_REG_LEFT_ADC_VOL)*/
+#define     LINVOL_LIN_VOL                0x01F   /* Left Channel PGA Volume control                      */
+#define     LINVOL_LIN_ENABLE_MUTE        0x080   /* Left Channel Input Mute                              */
+#define     LINVOL_LRIN_BOTH              0x100   /* Left Channel Line Input Volume update                */
+
+/*Right ADC Volume Control (SSM2602_REG_RIGHT_ADC_VOL)*/
+#define     RINVOL_RIN_VOL                0x01F   /* Right Channel PGA Volume control                     */
+#define     RINVOL_RIN_ENABLE_MUTE        0x080   /* Right Channel Input Mute                             */
+#define     RINVOL_RLIN_BOTH              0x100   /* Right Channel Line Input Volume update               */
+
+/*Left DAC Volume Control (SSM2602_REG_LEFT_DAC_VOL)*/
+#define     LOUT1V_LHP_VOL                0x07F   /* Left Channel Headphone volume control                */
+#define     LOUT1V_ENABLE_LZC             0x080   /* Left Channel Zero cross detect enable                */
+#define     LOUT1V_LRHP_BOTH              0x100   /* Left Channel Headphone volume update                 */
+
+/*Right DAC Volume Control (SSM2602_REG_RIGHT_DAC_VOL)*/
+#define     ROUT1V_RHP_VOL                0x07F   /* Right Channel Headphone volume control               */
+#define     ROUT1V_ENABLE_RZC             0x080   /* Right Channel Zero cross detect enable               */
+#define     ROUT1V_RLHP_BOTH              0x100   /* Right Channel Headphone volume update                */
+
+/*Analogue Audio Path Control (SSM2602_REG_ANALOGUE_PATH)*/
+#define     APANA_ENABLE_MIC_BOOST       0x001   /* Primary Microphone Amplifier gain booster control    */
+#define     APANA_ENABLE_MIC_MUTE        0x002   /* Microphone Mute Control                              */
+#define     APANA_ADC_IN_SELECT          0x004   /* Microphone/Line IN select to ADC (1=MIC, 0=Line In)  */
+#define     APANA_ENABLE_BYPASS          0x008   /* Line input bypass to line output                     */
+#define     APANA_SELECT_DAC             0x010   /* Select DAC (1=Select DAC, 0=Don't Select DAC)        */
+#define     APANA_ENABLE_SIDETONE        0x020   /* Enable/Disable Side Tone                             */
+#define     APANA_SIDETONE_ATTN          0x0C0   /* Side Tone Attenuation                                */
+#define     APANA_ENABLE_MIC_BOOST2      0x100   /* Secondary Microphone Amplifier gain booster control  */
+
+/*Digital Audio Path Control (SSM2602_REG_DIGITAL_PATH)*/
+#define     APDIGI_ENABLE_ADC_HPF         0x001   /* Enable/Disable ADC Highpass Filter                   */
+#define     APDIGI_DE_EMPHASIS            0x006   /* De-Emphasis Control                                  */
+#define     APDIGI_ENABLE_DAC_MUTE        0x008   /* DAC Mute Control                                     */
+#define     APDIGI_STORE_OFFSET           0x010   /* Store/Clear DC offset when HPF is disabled           */
+
+/*Power Down Control (SSM2602_REG_POWER)
+ *(1=Enable PowerDown, 0=Disable PowerDown)
+ */
+#define     PWR_LINE_IN_PDN            0x001   /* Line Input Power Down                                */
+#define     PWR_MIC_PDN                0x002   /* Microphone Input & Bias Power Down                   */
+#define     PWR_ADC_PDN                0x004   /* ADC Power Down                                       */
+#define     PWR_DAC_PDN                0x008   /* DAC Power Down                                       */
+#define     PWR_OUT_PDN                0x010   /* Outputs Power Down                                   */
+#define     PWR_OSC_PDN                0x020   /* Oscillator Power Down                                */
+#define     PWR_CLK_OUT_PDN            0x040   /* CLKOUT Power Down                                    */
+#define     PWR_POWER_OFF              0x080   /* POWEROFF Mode                                        */
+
+/*Digital Audio Interface Format (SSM2602_REG_DIGITAL_IFACE)*/
+#define     IFACE_IFACE_FORMAT           0x003   /* Digital Audio input format control                   */
+#define     IFACE_AUDIO_DATA_LEN         0x00C   /* Audio Data word length control                       */
+#define     IFACE_DAC_LR_POLARITY        0x010   /* Polarity Control for clocks in RJ,LJ and I2S modes   */
+#define     IFACE_DAC_LR_SWAP            0x020   /* Swap DAC data control                                */
+#define     IFACE_ENABLE_MASTER          0x040   /* Enable/Disable Master Mode                           */
+#define     IFACE_BCLK_INVERT            0x080   /* Bit Clock Inversion control                          */
+
+/*Sampling Control (SSM2602_REG_SAMPLING_CTRL)*/
+#define     SRATE_ENABLE_USB_MODE        0x001   /* Enable/Disable USB Mode                              */
+#define     SRATE_BOS_RATE               0x002   /* Base Over-Sampling rate                              */
+#define     SRATE_SAMPLE_RATE            0x03C   /* Clock setting condition (Sampling rate control)      */
+#define     SRATE_CORECLK_DIV2           0x040   /* Core Clock divider select                            */
+#define     SRATE_CLKOUT_DIV2            0x080   /* Clock Out divider select                             */
+
+/*Active Control (SSM2602_REG_ACTIVE_CTRL)*/
+#define     ACTIVE_ACTIVATE_CODEC         0x001   /* Activate Codec Digital Audio Interface               */
+
+/*********************************************************************/
+
+#define SSM2602_CACHEREGNUM    10
+
+#define SSM2602_SYSCLK 0
+#define SSM2602_DAI            0
+
+struct ssm2602_setup_data {
+       int i2c_bus;
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai ssm2602_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
new file mode 100644 (file)
index 0000000..bed8a9e
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * ALSA SoC CODEC driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-of-simple.h>
+#include <sound/initval.h>
+
+#include "tlv320aic26.h"
+
+MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver");
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+
+/* AIC26 driver private data */
+struct aic26 {
+       struct spi_device *spi;
+       struct snd_soc_codec codec;
+       u16 reg_cache[AIC26_NUM_REGS];  /* shadow registers */
+       int master;
+       int datfm;
+       int mclk;
+
+       /* Keyclick parameters */
+       int keyclick_amplitude;
+       int keyclick_freq;
+       int keyclick_len;
+};
+
+/* ---------------------------------------------------------------------
+ * Register access routines
+ */
+static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
+                                  unsigned int reg)
+{
+       struct aic26 *aic26 = codec->private_data;
+       u16 *cache = codec->reg_cache;
+       u16 cmd, value;
+       u8 buffer[2];
+       int rc;
+
+       if (reg >= AIC26_NUM_REGS) {
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+
+       /* Do SPI transfer; first 16bits are command; remaining is
+        * register contents */
+       cmd = AIC26_READ_COMMAND_WORD(reg);
+       buffer[0] = (cmd >> 8) & 0xff;
+       buffer[1] = cmd & 0xff;
+       rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2);
+       if (rc) {
+               dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+               return -EIO;
+       }
+       value = (buffer[0] << 8) | buffer[1];
+
+       /* Update the cache before returning with the value */
+       cache[reg] = value;
+       return value;
+}
+
+static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
+                                        unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       if (reg >= AIC26_NUM_REGS) {
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+
+       return cache[reg];
+}
+
+static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
+                          unsigned int value)
+{
+       struct aic26 *aic26 = codec->private_data;
+       u16 *cache = codec->reg_cache;
+       u16 cmd;
+       u8 buffer[4];
+       int rc;
+
+       if (reg >= AIC26_NUM_REGS) {
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+
+       /* Do SPI transfer; first 16bits are command; remaining is data
+        * to write into register */
+       cmd = AIC26_WRITE_COMMAND_WORD(reg);
+       buffer[0] = (cmd >> 8) & 0xff;
+       buffer[1] = cmd & 0xff;
+       buffer[2] = value >> 8;
+       buffer[3] = value;
+       rc = spi_write(aic26->spi, buffer, 4);
+       if (rc) {
+               dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+               return -EIO;
+       }
+
+       /* update cache before returning */
+       cache[reg] = value;
+       return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Operations
+ */
+static int aic26_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct aic26 *aic26 = codec->private_data;
+       int fsref, divisor, wlen, pval, jval, dval, qval;
+       u16 reg;
+
+       dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n",
+               substream, params);
+       dev_dbg(&aic26->spi->dev, "rate=%i format=%i\n", params_rate(params),
+               params_format(params));
+
+       switch (params_rate(params)) {
+       case 8000:  fsref = 48000; divisor = AIC26_DIV_6; break;
+       case 11025: fsref = 44100; divisor = AIC26_DIV_4; break;
+       case 12000: fsref = 48000; divisor = AIC26_DIV_4; break;
+       case 16000: fsref = 48000; divisor = AIC26_DIV_3; break;
+       case 22050: fsref = 44100; divisor = AIC26_DIV_2; break;
+       case 24000: fsref = 48000; divisor = AIC26_DIV_2; break;
+       case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break;
+       case 44100: fsref = 44100; divisor = AIC26_DIV_1; break;
+       case 48000: fsref = 48000; divisor = AIC26_DIV_1; break;
+       default:
+               dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL;
+       }
+
+       /* select data word length */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:     wlen = AIC26_WLEN_16; break;
+       case SNDRV_PCM_FORMAT_S16_BE: wlen = AIC26_WLEN_16; break;
+       case SNDRV_PCM_FORMAT_S24_BE: wlen = AIC26_WLEN_24; break;
+       case SNDRV_PCM_FORMAT_S32_BE: wlen = AIC26_WLEN_32; break;
+       default:
+               dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+       }
+
+       /* Configure PLL */
+       pval = 1;
+       jval = (fsref == 44100) ? 7 : 8;
+       dval = (fsref == 44100) ? 5264 : 1920;
+       qval = 0;
+       reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
+       aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
+       reg = dval << 2;
+       aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
+
+       /* Audio Control 3 (master mode, fsref rate) */
+       reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
+       reg &= ~0xf800;
+       if (aic26->master)
+               reg |= 0x0800;
+       if (fsref == 48000)
+               reg |= 0x2000;
+       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+       /* Audio Control 1 (FSref divisor) */
+       reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
+       reg &= ~0x0fff;
+       reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
+       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+
+       return 0;
+}
+
+/**
+ * aic26_mute - Mute control to reduce noise when changing audio format
+ */
+static int aic26_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct aic26 *aic26 = codec->private_data;
+       u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
+
+       dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
+               dai, mute);
+
+       if (mute)
+               reg |= 0x8080;
+       else
+               reg &= ~0x8080;
+       aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg);
+
+       return 0;
+}
+
+static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
+                           int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic26 *aic26 = codec->private_data;
+
+       dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
+               " freq=%i, dir=%i)\n",
+               codec_dai, clk_id, freq, dir);
+
+       /* MCLK needs to fall between 2MHz and 50 MHz */
+       if ((freq < 2000000) || (freq > 50000000))
+               return -EINVAL;
+
+       aic26->mclk = freq;
+       return 0;
+}
+
+static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic26 *aic26 = codec->private_data;
+
+       dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
+               codec_dai, fmt);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
+       case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+       default:
+               dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:     aic26->datfm = AIC26_DATFM_I2S; break;
+       case SND_SOC_DAIFMT_DSP_A:   aic26->datfm = AIC26_DATFM_DSP; break;
+       case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
+       case SND_SOC_DAIFMT_LEFT_J:  aic26->datfm = AIC26_DATFM_LEFTJ; break;
+       default:
+               dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Definition
+ */
+#define AIC26_RATES    (SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 |\
+                        SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+                        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+                        SNDRV_PCM_RATE_48000)
+#define AIC26_FORMATS  (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_BE |\
+                        SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+struct snd_soc_dai aic26_dai = {
+       .name = "tlv320aic26",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = AIC26_RATES,
+               .formats = AIC26_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = AIC26_RATES,
+               .formats = AIC26_FORMATS,
+       },
+       .ops = {
+               .hw_params = aic26_hw_params,
+       },
+       .dai_ops = {
+               .digital_mute = aic26_mute,
+               .set_sysclk = aic26_set_sysclk,
+               .set_fmt = aic26_set_fmt,
+       },
+};
+EXPORT_SYMBOL_GPL(aic26_dai);
+
+/* ---------------------------------------------------------------------
+ * ALSA controls
+ */
+static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
+static const struct soc_enum aic26_capture_src_enum =
+       SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text);
+
+static const struct snd_kcontrol_new aic26_snd_controls[] = {
+       /* Output */
+       SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1),
+       SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1),
+       SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0),
+       SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1),
+       SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
+       SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
+       SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
+       SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
+       SOC_ENUM("Capture Source", aic26_capture_src_enum),
+};
+
+/* ---------------------------------------------------------------------
+ * SoC CODEC portion of driver: probe and release routines
+ */
+static int aic26_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       struct snd_kcontrol *kcontrol;
+       struct aic26 *aic26;
+       int i, ret, err;
+
+       dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
+       dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
+       dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
+
+       /* Fetch the relevant aic26 private data here (it's already been
+        * stored in the .codec pointer) */
+       aic26 = socdev->codec_data;
+       if (aic26 == NULL) {
+               dev_err(&pdev->dev, "aic26: missing codec pointer\n");
+               return -ENODEV;
+       }
+       codec = &aic26->codec;
+       socdev->codec = codec;
+
+       dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
+               &pdev->dev, socdev->dev);
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "aic26: failed to create pcms\n");
+               return -ENODEV;
+       }
+
+       /* register controls */
+       dev_dbg(&pdev->dev, "Registering controls\n");
+       for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) {
+               kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL);
+               err = snd_ctl_add(codec->card, kcontrol);
+               WARN_ON(err < 0);
+       }
+
+       /* CODEC is setup, we can register the card now */
+       dev_dbg(&pdev->dev, "Registering card\n");
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "aic26: failed to register card\n");
+               goto card_err;
+       }
+       return 0;
+
+ card_err:
+       snd_soc_free_pcms(socdev);
+       return ret;
+}
+
+static int aic26_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       snd_soc_free_pcms(socdev);
+       return 0;
+}
+
+struct snd_soc_codec_device aic26_soc_codec_dev = {
+       .probe = aic26_probe,
+       .remove = aic26_remove,
+};
+EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: sysfs files for debugging
+ */
+
+static ssize_t aic26_keyclick_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct aic26 *aic26 = dev_get_drvdata(dev);
+       int val, amp, freq, len;
+
+       val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+       amp = (val >> 12) & 0x7;
+       freq = (125 << ((val >> 8) & 0x7)) >> 1;
+       len = 2 * (1 + ((val >> 4) & 0xf));
+
+       return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
+}
+
+/* Any write to the keyclick attribute will trigger the keyclick event */
+static ssize_t aic26_keyclick_set(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct aic26 *aic26 = dev_get_drvdata(dev);
+       int val;
+
+       val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+       val |= 0x8000;
+       aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+
+       return count;
+}
+
+static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ *                              driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
+{
+       struct aic26 *aic26;
+       int rc, i, reg;
+
+       dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+       /* Allocate driver data */
+       aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+       if (!aic26)
+               return -ENOMEM;
+
+       /* Initialize the driver data */
+       aic26->spi = spi;
+       dev_set_drvdata(&spi->dev, aic26);
+
+       /* Setup what we can in the codec structure so that the register
+        * access functions will work as expected.  More will be filled
+        * out when it is probed by the SoC CODEC part of this driver */
+       aic26->codec.private_data = aic26;
+       aic26->codec.name = "aic26";
+       aic26->codec.owner = THIS_MODULE;
+       aic26->codec.dai = &aic26_dai;
+       aic26->codec.num_dai = 1;
+       aic26->codec.read = aic26_reg_read;
+       aic26->codec.write = aic26_reg_write;
+       aic26->master = 1;
+       mutex_init(&aic26->codec.mutex);
+       INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
+       INIT_LIST_HEAD(&aic26->codec.dapm_paths);
+       aic26->codec.reg_cache_size = AIC26_NUM_REGS;
+       aic26->codec.reg_cache = aic26->reg_cache;
+
+       /* Reset the codec to power on defaults */
+       aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+
+       /* Power up CODEC */
+       aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+
+       /* Audio Control 3 (master mode, fsref rate) */
+       reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+       reg &= ~0xf800;
+       reg |= 0x0800; /* set master mode */
+       aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+       /* Fill register cache */
+       for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
+               aic26_reg_read(&aic26->codec, i);
+
+       /* Register the sysfs files for debugging */
+       /* Create SysFS files */
+       rc = device_create_file(&spi->dev, &dev_attr_keyclick);
+       if (rc)
+               dev_info(&spi->dev, "error creating sysfs files\n");
+
+#if defined(CONFIG_SND_SOC_OF_SIMPLE)
+       /* Tell the of_soc helper about this codec */
+       of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
+                                 spi->dev.archdata.of_node);
+#endif
+
+       dev_dbg(&spi->dev, "SPI device initialized\n");
+       return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+       struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+
+       kfree(aic26);
+
+       return 0;
+}
+
+static struct spi_driver aic26_spi = {
+       .driver = {
+               .name = "tlv320aic26",
+               .owner = THIS_MODULE,
+       },
+       .probe = aic26_spi_probe,
+       .remove = aic26_spi_remove,
+};
+
+static int __init aic26_init(void)
+{
+       return spi_register_driver(&aic26_spi);
+}
+module_init(aic26_init);
+
+static void __exit aic26_exit(void)
+{
+       spi_unregister_driver(&aic26_spi);
+}
+module_exit(aic26_exit);
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
new file mode 100644 (file)
index 0000000..786ba16
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * register definitions
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#ifndef _TLV320AIC16_H_
+#define _TLV320AIC16_H_
+
+/* AIC26 Registers */
+#define AIC26_READ_COMMAND_WORD(addr)  ((1 << 15) | (addr << 5))
+#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
+#define AIC26_PAGE_ADDR(page, offset)  ((page << 6) | offset)
+#define AIC26_NUM_REGS                 AIC26_PAGE_ADDR(3, 0)
+
+/* Page 0: Auxillary data registers */
+#define AIC26_REG_BAT1                 AIC26_PAGE_ADDR(0, 0x05)
+#define AIC26_REG_BAT2                 AIC26_PAGE_ADDR(0, 0x06)
+#define AIC26_REG_AUX                  AIC26_PAGE_ADDR(0, 0x07)
+#define AIC26_REG_TEMP1                        AIC26_PAGE_ADDR(0, 0x09)
+#define AIC26_REG_TEMP2                        AIC26_PAGE_ADDR(0, 0x0A)
+
+/* Page 1: Auxillary control registers */
+#define AIC26_REG_AUX_ADC              AIC26_PAGE_ADDR(1, 0x00)
+#define AIC26_REG_STATUS               AIC26_PAGE_ADDR(1, 0x01)
+#define AIC26_REG_REFERENCE            AIC26_PAGE_ADDR(1, 0x03)
+#define AIC26_REG_RESET                        AIC26_PAGE_ADDR(1, 0x04)
+
+/* Page 2: Audio control registers */
+#define AIC26_REG_AUDIO_CTRL1          AIC26_PAGE_ADDR(2, 0x00)
+#define AIC26_REG_ADC_GAIN             AIC26_PAGE_ADDR(2, 0x01)
+#define AIC26_REG_DAC_GAIN             AIC26_PAGE_ADDR(2, 0x02)
+#define AIC26_REG_SIDETONE             AIC26_PAGE_ADDR(2, 0x03)
+#define AIC26_REG_AUDIO_CTRL2          AIC26_PAGE_ADDR(2, 0x04)
+#define AIC26_REG_POWER_CTRL           AIC26_PAGE_ADDR(2, 0x05)
+#define AIC26_REG_AUDIO_CTRL3          AIC26_PAGE_ADDR(2, 0x06)
+
+#define AIC26_REG_FILTER_COEFF_L_N0    AIC26_PAGE_ADDR(2, 0x07)
+#define AIC26_REG_FILTER_COEFF_L_N1    AIC26_PAGE_ADDR(2, 0x08)
+#define AIC26_REG_FILTER_COEFF_L_N2    AIC26_PAGE_ADDR(2, 0x09)
+#define AIC26_REG_FILTER_COEFF_L_N3    AIC26_PAGE_ADDR(2, 0x0A)
+#define AIC26_REG_FILTER_COEFF_L_N4    AIC26_PAGE_ADDR(2, 0x0B)
+#define AIC26_REG_FILTER_COEFF_L_N5    AIC26_PAGE_ADDR(2, 0x0C)
+#define AIC26_REG_FILTER_COEFF_L_D1    AIC26_PAGE_ADDR(2, 0x0D)
+#define AIC26_REG_FILTER_COEFF_L_D2    AIC26_PAGE_ADDR(2, 0x0E)
+#define AIC26_REG_FILTER_COEFF_L_D4    AIC26_PAGE_ADDR(2, 0x0F)
+#define AIC26_REG_FILTER_COEFF_L_D5    AIC26_PAGE_ADDR(2, 0x10)
+#define AIC26_REG_FILTER_COEFF_R_N0    AIC26_PAGE_ADDR(2, 0x11)
+#define AIC26_REG_FILTER_COEFF_R_N1    AIC26_PAGE_ADDR(2, 0x12)
+#define AIC26_REG_FILTER_COEFF_R_N2    AIC26_PAGE_ADDR(2, 0x13)
+#define AIC26_REG_FILTER_COEFF_R_N3    AIC26_PAGE_ADDR(2, 0x14)
+#define AIC26_REG_FILTER_COEFF_R_N4    AIC26_PAGE_ADDR(2, 0x15)
+#define AIC26_REG_FILTER_COEFF_R_N5    AIC26_PAGE_ADDR(2, 0x16)
+#define AIC26_REG_FILTER_COEFF_R_D1    AIC26_PAGE_ADDR(2, 0x17)
+#define AIC26_REG_FILTER_COEFF_R_D2    AIC26_PAGE_ADDR(2, 0x18)
+#define AIC26_REG_FILTER_COEFF_R_D4    AIC26_PAGE_ADDR(2, 0x19)
+#define AIC26_REG_FILTER_COEFF_R_D5    AIC26_PAGE_ADDR(2, 0x1A)
+
+#define AIC26_REG_PLL_PROG1            AIC26_PAGE_ADDR(2, 0x1B)
+#define AIC26_REG_PLL_PROG2            AIC26_PAGE_ADDR(2, 0x1C)
+#define AIC26_REG_AUDIO_CTRL4          AIC26_PAGE_ADDR(2, 0x1D)
+#define AIC26_REG_AUDIO_CTRL5          AIC26_PAGE_ADDR(2, 0x1E)
+
+/* fsref dividers; used in register 'Audio Control 1' */
+enum aic26_divisors {
+       AIC26_DIV_1     = 0,
+       AIC26_DIV_1_5   = 1,
+       AIC26_DIV_2     = 2,
+       AIC26_DIV_3     = 3,
+       AIC26_DIV_4     = 4,
+       AIC26_DIV_5     = 5,
+       AIC26_DIV_5_5   = 6,
+       AIC26_DIV_6     = 7,
+};
+
+/* Digital data format */
+enum aic26_datfm {
+       AIC26_DATFM_I2S         = 0 << 8,
+       AIC26_DATFM_DSP         = 1 << 8,
+       AIC26_DATFM_RIGHTJ      = 2 << 8, /* right justified */
+       AIC26_DATFM_LEFTJ       = 3 << 8, /* left justified */
+};
+
+/* Sample word length in bits; used in register 'Audio Control 1' */
+enum aic26_wlen {
+       AIC26_WLEN_16   = 0 << 10,
+       AIC26_WLEN_20   = 1 << 10,
+       AIC26_WLEN_24   = 2 << 10,
+       AIC26_WLEN_32   = 3 << 10,
+};
+
+extern struct snd_soc_dai aic26_dai;
+extern struct snd_soc_codec_device aic26_soc_codec_dev;
+
+#endif /* _TLV320AIC16_H_ */
index 5f9abb199435b35e82d99d7603e11f2338556080..566a427c928f18085101add5e5990736101850dc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC TLV320AIC3X codec driver
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
@@ -1172,71 +1172,39 @@ static struct snd_soc_device *aic3x_socdev;
  * AIC3X 2 wire address can be up to 4 devices with device addresses
  * 0x18, 0x19, 0x1A, 0x1B
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver aic3x_i2c_driver;
-static struct i2c_client client_template;
 
 /*
  * If the i2c layer weren't so broken, we could pass this kind of data
  * around
  */
-static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int aic3x_i2c_probe(struct i2c_client *i2c,
+                          const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = aic3x_socdev;
-       struct aic3x_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n",
-                      addr);
-               goto err;
-       }
-
        ret = aic3x_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                printk(KERN_ERR "aic3x: failed to initialise AIC3X\n");
-               goto err;
-       }
-       return ret;
-
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int aic3x_i2c_detach(struct i2c_client *client)
+static int aic3x_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int aic3x_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, aic3x_codec_probe);
-}
+static const struct i2c_device_id aic3x_i2c_id[] = {
+       { "tlv320aic3x", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
 
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
@@ -1244,13 +1212,9 @@ static struct i2c_driver aic3x_i2c_driver = {
                .name = "aic3x I2C Codec",
                .owner = THIS_MODULE,
        },
-       .attach_adapter = aic3x_i2c_attach,
-       .detach_client = aic3x_i2c_detach,
-};
-
-static struct i2c_client client_template = {
-       .name = "AIC3X",
-       .driver = &aic3x_i2c_driver,
+       .probe = aic3x_i2c_probe,
+       .remove = aic3x_i2c_remove,
+       .id_table = aic3x_i2c_id,
 };
 
 static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
@@ -1258,6 +1222,46 @@ static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
        value[0] = i2c_smbus_read_byte_data(client, value[0]);
        return (len == 1);
 }
+
+static int aic3x_add_i2c_device(struct platform_device *pdev,
+                                const struct aic3x_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&aic3x_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&aic3x_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int aic3x_probe(struct platform_device *pdev)
@@ -1290,12 +1294,9 @@ static int aic3x_probe(struct platform_device *pdev)
        aic3x_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t) i2c_master_send;
                codec->hw_read = (hw_read_t) aic3x_i2c_read;
-               ret = i2c_add_driver(&aic3x_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = aic3x_add_i2c_device(pdev, setup);
        }
 #else
        /* Add other interfaces here */
@@ -1320,6 +1321,7 @@ static int aic3x_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&aic3x_i2c_driver);
 #endif
        kfree(codec->private_data);
index d76c079b86e7b52f148b3a35a49ff0ea2f9a7b8d..00a195aa02e4e2321d9437f964688f532cf0fde8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC TLV320AIC3X codec driver
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -224,6 +224,7 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
 int aic3x_headset_detected(struct snd_soc_codec *codec);
 
 struct aic3x_setup_data {
+       int i2c_bus;
        unsigned short i2c_address;
        unsigned int gpio_func[2];
 };
index 807318fbdc8f182a96df656f3918770887a65e31..d206d7f892b68b8c0103bc5337b27e5b460b62d2 100644 (file)
@@ -701,87 +701,86 @@ static struct snd_soc_device *uda1380_socdev;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
-#define I2C_DRIVERID_UDA1380 0xfefe /* liam -  need a proper id */
-
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver uda1380_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-
-static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int uda1380_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = uda1380_socdev;
        struct uda1380_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               pr_err("uda1380: failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = uda1380_init(socdev, setup->dac_clk);
-       if (ret < 0) {
+       if (ret < 0)
                pr_err("uda1380: failed to initialise UDA1380\n");
-               goto err;
-       }
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int uda1380_i2c_detach(struct i2c_client *client)
+static int uda1380_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int uda1380_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, uda1380_codec_probe);
-}
+static const struct i2c_device_id uda1380_i2c_id[] = {
+       { "uda1380", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
 
 static struct i2c_driver uda1380_i2c_driver = {
        .driver = {
                .name =  "UDA1380 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_UDA1380,
-       .attach_adapter = uda1380_i2c_attach,
-       .detach_client =  uda1380_i2c_detach,
-       .command =        NULL,
+       .probe =    uda1380_i2c_probe,
+       .remove =   uda1380_i2c_remove,
+       .id_table = uda1380_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "UDA1380",
-       .driver = &uda1380_i2c_driver,
-};
+static int uda1380_add_i2c_device(struct platform_device *pdev,
+                                 const struct uda1380_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&uda1380_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "uda1380", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&uda1380_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int uda1380_probe(struct platform_device *pdev)
@@ -789,7 +788,7 @@ static int uda1380_probe(struct platform_device *pdev)
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct uda1380_setup_data *setup;
        struct snd_soc_codec *codec;
-       int ret = 0;
+       int ret;
 
        pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION);
 
@@ -804,16 +803,13 @@ static int uda1380_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        uda1380_socdev = socdev;
+       ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&uda1380_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = uda1380_add_i2c_device(pdev, setup);
        }
-#else
-       /* Add other interfaces here */
 #endif
 
        if (ret != 0)
@@ -833,6 +829,7 @@ static int uda1380_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&uda1380_i2c_driver);
 #endif
        kfree(codec);
index 50c603e2c9f271a2a83f42136eaca9d1bf970e79..c55c17a52a1205a17454e0c0b575b881ea44b71d 100644 (file)
@@ -73,6 +73,7 @@
 #define R23_AGC_EN     0x0001
 
 struct uda1380_setup_data {
+       int            i2c_bus;
        unsigned short i2c_address;
        int            dac_clk;
 #define UDA1380_DAC_CLK_SYSCLK 0
index 3d998e6a997e5270838a4532c425e154fb8f2bd6..9a37c8d95ed2475892f75cbef7a6ca43fc3e1533 100644 (file)
@@ -199,7 +199,7 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new wm8510_boost_controls[] = {
-SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 0),
+SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 1),
 SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0),
 SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0),
 };
@@ -665,88 +665,86 @@ static struct snd_soc_device *wm8510_socdev;
 /*
  * WM8510 2 wire address is 0x1a
  */
-#define I2C_DRIVERID_WM8510 0xfefe /* liam -  need a proper id */
 
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8510_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-
-static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8510_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8510_socdev;
-       struct wm8510_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               pr_err("failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = wm8510_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                pr_err("failed to initialise WM8510\n");
-               goto err;
-       }
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int wm8510_i2c_detach(struct i2c_client *client)
+static int wm8510_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int wm8510_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, wm8510_codec_probe);
-}
+static const struct i2c_device_id wm8510_i2c_id[] = {
+       { "wm8510", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8510_i2c_driver = {
        .driver = {
                .name = "WM8510 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_WM8510,
-       .attach_adapter = wm8510_i2c_attach,
-       .detach_client =  wm8510_i2c_detach,
-       .command =        NULL,
+       .probe =    wm8510_i2c_probe,
+       .remove =   wm8510_i2c_remove,
+       .id_table = wm8510_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "WM8510",
-       .driver = &wm8510_i2c_driver,
-};
+static int wm8510_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8510_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8510_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8510_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int wm8510_probe(struct platform_device *pdev)
@@ -771,11 +769,8 @@ static int wm8510_probe(struct platform_device *pdev)
        wm8510_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&wm8510_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = wm8510_add_i2c_device(pdev, setup);
        }
 #else
        /* Add other interfaces here */
@@ -798,6 +793,7 @@ static int wm8510_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8510_i2c_driver);
 #endif
        kfree(codec);
index f5d2e42eb3f491730dc8fb2b46f4f7764dacc6c9..c53683960456ad2a568c3ae44eea7c9095e7723b 100644 (file)
@@ -94,6 +94,7 @@
 #define WM8510_MCLKDIV_12      (7 << 5)
 
 struct wm8510_setup_data {
+       int i2c_bus;
        unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
new file mode 100644 (file)
index 0000000..df1ffbe
--- /dev/null
@@ -0,0 +1,1055 @@
+/*
+ * wm8580.c  --  WM8580 ALSA Soc Audio driver
+ *
+ * Copyright 2008 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * Notes:
+ *  The WM8580 is a multichannel codec with S/PDIF support, featuring six
+ *  DAC channels and two ADC channels.
+ *
+ *  Currently only the primary audio interface is supported - S/PDIF and
+ *  the secondary audio interfaces are not.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+
+#include "wm8580.h"
+
+#define AUDIO_NAME "wm8580"
+#define WM8580_VERSION "0.1"
+
+struct pll_state {
+       unsigned int in;
+       unsigned int out;
+};
+
+/* codec private data */
+struct wm8580_priv {
+       struct pll_state a;
+       struct pll_state b;
+};
+
+/* WM8580 register space */
+#define WM8580_PLLA1                         0x00
+#define WM8580_PLLA2                         0x01
+#define WM8580_PLLA3                         0x02
+#define WM8580_PLLA4                         0x03
+#define WM8580_PLLB1                         0x04
+#define WM8580_PLLB2                         0x05
+#define WM8580_PLLB3                         0x06
+#define WM8580_PLLB4                         0x07
+#define WM8580_CLKSEL                        0x08
+#define WM8580_PAIF1                         0x09
+#define WM8580_PAIF2                         0x0A
+#define WM8580_SAIF1                         0x0B
+#define WM8580_PAIF3                         0x0C
+#define WM8580_PAIF4                         0x0D
+#define WM8580_SAIF2                         0x0E
+#define WM8580_DAC_CONTROL1                  0x0F
+#define WM8580_DAC_CONTROL2                  0x10
+#define WM8580_DAC_CONTROL3                  0x11
+#define WM8580_DAC_CONTROL4                  0x12
+#define WM8580_DAC_CONTROL5                  0x13
+#define WM8580_DIGITAL_ATTENUATION_DACL1     0x14
+#define WM8580_DIGITAL_ATTENUATION_DACR1     0x15
+#define WM8580_DIGITAL_ATTENUATION_DACL2     0x16
+#define WM8580_DIGITAL_ATTENUATION_DACR2     0x17
+#define WM8580_DIGITAL_ATTENUATION_DACL3     0x18
+#define WM8580_DIGITAL_ATTENUATION_DACR3     0x19
+#define WM8580_MASTER_DIGITAL_ATTENUATION    0x1C
+#define WM8580_ADC_CONTROL1                  0x1D
+#define WM8580_SPDTXCHAN0                    0x1E
+#define WM8580_SPDTXCHAN1                    0x1F
+#define WM8580_SPDTXCHAN2                    0x20
+#define WM8580_SPDTXCHAN3                    0x21
+#define WM8580_SPDTXCHAN4                    0x22
+#define WM8580_SPDTXCHAN5                    0x23
+#define WM8580_SPDMODE                       0x24
+#define WM8580_INTMASK                       0x25
+#define WM8580_GPO1                          0x26
+#define WM8580_GPO2                          0x27
+#define WM8580_GPO3                          0x28
+#define WM8580_GPO4                          0x29
+#define WM8580_GPO5                          0x2A
+#define WM8580_INTSTAT                       0x2B
+#define WM8580_SPDRXCHAN1                    0x2C
+#define WM8580_SPDRXCHAN2                    0x2D
+#define WM8580_SPDRXCHAN3                    0x2E
+#define WM8580_SPDRXCHAN4                    0x2F
+#define WM8580_SPDRXCHAN5                    0x30
+#define WM8580_SPDSTAT                       0x31
+#define WM8580_PWRDN1                        0x32
+#define WM8580_PWRDN2                        0x33
+#define WM8580_READBACK                      0x34
+#define WM8580_RESET                         0x35
+
+/* PLLB4 (register 7h) */
+#define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
+#define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
+#define WM8580_PLLB4_MCLKOUTSRC_PLLB   0x40
+#define WM8580_PLLB4_MCLKOUTSRC_OSC    0x60
+
+#define WM8580_PLLB4_CLKOUTSRC_MASK    0x180
+#define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080
+#define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100
+#define WM8580_PLLB4_CLKOUTSRC_OSCCLK  0x180
+
+/* CLKSEL (register 8h) */
+#define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03
+#define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01
+#define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02
+
+/* AIF control 1 (registers 9h-bh) */
+#define WM8580_AIF_RATE_MASK       0x7
+#define WM8580_AIF_RATE_128        0x0
+#define WM8580_AIF_RATE_192        0x1
+#define WM8580_AIF_RATE_256        0x2
+#define WM8580_AIF_RATE_384        0x3
+#define WM8580_AIF_RATE_512        0x4
+#define WM8580_AIF_RATE_768        0x5
+#define WM8580_AIF_RATE_1152       0x6
+
+#define WM8580_AIF_BCLKSEL_MASK   0x18
+#define WM8580_AIF_BCLKSEL_64     0x00
+#define WM8580_AIF_BCLKSEL_128    0x08
+#define WM8580_AIF_BCLKSEL_256    0x10
+#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
+
+#define WM8580_AIF_MS             0x20
+
+#define WM8580_AIF_CLKSRC_MASK    0xc0
+#define WM8580_AIF_CLKSRC_PLLA    0x40
+#define WM8580_AIF_CLKSRC_PLLB    0x40
+#define WM8580_AIF_CLKSRC_MCLK    0xc0
+
+/* AIF control 2 (registers ch-eh) */
+#define WM8580_AIF_FMT_MASK    0x03
+#define WM8580_AIF_FMT_RIGHTJ  0x00
+#define WM8580_AIF_FMT_LEFTJ   0x01
+#define WM8580_AIF_FMT_I2S     0x02
+#define WM8580_AIF_FMT_DSP     0x03
+
+#define WM8580_AIF_LENGTH_MASK   0x0c
+#define WM8580_AIF_LENGTH_16     0x00
+#define WM8580_AIF_LENGTH_20     0x04
+#define WM8580_AIF_LENGTH_24     0x08
+#define WM8580_AIF_LENGTH_32     0x0c
+
+#define WM8580_AIF_LRP         0x10
+#define WM8580_AIF_BCP         0x20
+
+/* Powerdown Register 1 (register 32h) */
+#define WM8580_PWRDN1_PWDN     0x001
+#define WM8580_PWRDN1_ALLDACPD 0x040
+
+/* Powerdown Register 2 (register 33h) */
+#define WM8580_PWRDN2_OSSCPD   0x001
+#define WM8580_PWRDN2_PLLAPD   0x002
+#define WM8580_PWRDN2_PLLBPD   0x004
+#define WM8580_PWRDN2_SPDIFPD  0x008
+#define WM8580_PWRDN2_SPDIFTXD 0x010
+#define WM8580_PWRDN2_SPDIFRXD 0x020
+
+#define WM8580_DAC_CONTROL5_MUTEALL 0x10
+
+/*
+ * wm8580 register cache
+ * We can't read the WM8580 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8580_reg[] = {
+       0x0121, 0x017e, 0x007d, 0x0014, /*R3*/
+       0x0121, 0x017e, 0x007d, 0x0194, /*R7*/
+       0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/
+       0x0182, 0x0082, 0x000a, 0x0024, /*R15*/
+       0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/
+       0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/
+       0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/
+       0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/
+       0x0000, 0x0000, 0x0031, 0x000b, /*R35*/
+       0x0039, 0x0000, 0x0010, 0x0032, /*R39*/
+       0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/
+       0x0000, 0x0000, 0x0000, 0x0000, /*R47*/
+       0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/
+       0x0000, 0x0000 /*R53*/
+};
+
+/*
+ * read wm8580 register cache
+ */
+static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+       return cache[reg];
+}
+
+/*
+ * write wm8580 register cache
+ */
+static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+
+       cache[reg] = value;
+}
+
+/*
+ * write to the WM8580 register space
+ */
+static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+
+       /* Registers are 9 bits wide */
+       value &= 0x1ff;
+
+       switch (reg) {
+       case WM8580_RESET:
+               /* Uncached */
+               break;
+       default:
+               if (value == wm8580_read_reg_cache(codec, reg))
+                       return 0;
+       }
+
+       /* data is
+        *   D15..D9 WM8580 register offset
+        *   D8...D0 register data
+        */
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
+
+       wm8580_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+static inline unsigned int wm8580_read(struct snd_soc_codec *codec,
+                                      unsigned int reg)
+{
+       switch (reg) {
+       default:
+               return wm8580_read_reg_cache(codec, reg);
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+
+static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int reg = kcontrol->private_value & 0xff;
+       int reg2 = (kcontrol->private_value >> 24) & 0xff;
+       int ret;
+       u16 val;
+
+       /* Clear the register cache so we write without VU set */
+       wm8580_write_reg_cache(codec, reg, 0);
+       wm8580_write_reg_cache(codec, reg2, 0);
+
+       ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+       if (ret < 0)
+               return ret;
+
+       /* Now write again with the volume update bit set */
+       val = wm8580_read_reg_cache(codec, reg);
+       wm8580_write(codec, reg, val | 0x0100);
+
+       val = wm8580_read_reg_cache(codec, reg2);
+       wm8580_write(codec, reg2, val | 0x0100);
+
+       return 0;
+}
+
+#define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+               SNDRV_CTL_ELEM_ACCESS_READWRITE,  \
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw_2r, \
+       .get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \
+       .private_value = (reg_left) | ((shift) << 8)  |         \
+               ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+
+static const struct snd_kcontrol_new wm8580_snd_controls[] = {
+SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume",
+                           WM8580_DIGITAL_ATTENUATION_DACL1,
+                           WM8580_DIGITAL_ATTENUATION_DACR1,
+                           0, 0xff, 0, dac_tlv),
+SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume",
+                           WM8580_DIGITAL_ATTENUATION_DACL2,
+                           WM8580_DIGITAL_ATTENUATION_DACR2,
+                           0, 0xff, 0, dac_tlv),
+SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume",
+                           WM8580_DIGITAL_ATTENUATION_DACL3,
+                           WM8580_DIGITAL_ATTENUATION_DACR3,
+                           0, 0xff, 0, dac_tlv),
+
+SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0),
+SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0),
+SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0),
+
+SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4,  0, 1, 1, 0),
+SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4,  2, 3, 1, 0),
+SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4,  4, 5, 1, 0),
+
+SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0),
+SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0),
+SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0),
+SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0),
+
+SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
+SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+};
+
+/* Add non-DAPM controls */
+static int wm8580_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&wm8580_snd_controls[i],
+                                              codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
+SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
+SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1),
+
+SND_SOC_DAPM_OUTPUT("VOUT1L"),
+SND_SOC_DAPM_OUTPUT("VOUT1R"),
+SND_SOC_DAPM_OUTPUT("VOUT2L"),
+SND_SOC_DAPM_OUTPUT("VOUT2R"),
+SND_SOC_DAPM_OUTPUT("VOUT3L"),
+SND_SOC_DAPM_OUTPUT("VOUT3R"),
+
+SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1),
+
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "VOUT1L", NULL, "DAC1" },
+       { "VOUT1R", NULL, "DAC1" },
+
+       { "VOUT2L", NULL, "DAC2" },
+       { "VOUT2R", NULL, "DAC2" },
+
+       { "VOUT3L", NULL, "DAC3" },
+       { "VOUT3R", NULL, "DAC3" },
+
+       { "ADC", NULL, "AINL" },
+       { "ADC", NULL, "AINR" },
+};
+
+static int wm8580_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets,
+                                 ARRAY_SIZE(wm8580_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+       u32 prescale:1;
+       u32 postscale:1;
+       u32 freqmode:2;
+       u32 n:4;
+       u32 k:24;
+};
+
+/* The size in bits of the pll divide */
+#define FIXED_PLL_SIZE (1 << 22)
+
+/* PLL rate to output rate divisions */
+static struct {
+       unsigned int div;
+       unsigned int freqmode;
+       unsigned int postscale;
+} post_table[] = {
+       {  2,  0, 0 },
+       {  4,  0, 1 },
+       {  4,  1, 0 },
+       {  8,  1, 1 },
+       {  8,  2, 0 },
+       { 16,  2, 1 },
+       { 12,  3, 0 },
+       { 24,  3, 1 }
+};
+
+static int pll_factors(struct _pll_div *pll_div, unsigned int target,
+                      unsigned int source)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod;
+       int i;
+
+       pr_debug("wm8580: PLL %dHz->%dHz\n", source, target);
+
+       /* Scale the output frequency up; the PLL should run in the
+        * region of 90-100MHz.
+        */
+       for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+               if (target * post_table[i].div >=  90000000 &&
+                   target * post_table[i].div <= 100000000) {
+                       pll_div->freqmode = post_table[i].freqmode;
+                       pll_div->postscale = post_table[i].postscale;
+                       target *= post_table[i].div;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(post_table)) {
+               printk(KERN_ERR "wm8580: Unable to scale output frequency "
+                      "%u\n", target);
+               return -EINVAL;
+       }
+
+       Ndiv = target / source;
+
+       if (Ndiv < 5) {
+               source /= 2;
+               pll_div->prescale = 1;
+               Ndiv = target / source;
+       } else
+               pll_div->prescale = 0;
+
+       if ((Ndiv < 5) || (Ndiv > 13)) {
+               printk(KERN_ERR
+                       "WM8580 N=%d outside supported range\n", Ndiv);
+               return -EINVAL;
+       }
+
+       pll_div->n = Ndiv;
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       pll_div->k = K;
+
+       pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n",
+                pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode,
+                pll_div->postscale);
+
+       return 0;
+}
+
+static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       int offset;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8580_priv *wm8580 = codec->private_data;
+       struct pll_state *state;
+       struct _pll_div pll_div;
+       unsigned int reg;
+       unsigned int pwr_mask;
+       int ret;
+
+       /* GCC isn't able to work out the ifs below for initialising/using
+        * pll_div so suppress warnings.
+        */
+       memset(&pll_div, 0, sizeof(pll_div));
+
+       switch (pll_id) {
+       case WM8580_PLLA:
+               state = &wm8580->a;
+               offset = 0;
+               pwr_mask = WM8580_PWRDN2_PLLAPD;
+               break;
+       case WM8580_PLLB:
+               state = &wm8580->b;
+               offset = 4;
+               pwr_mask = WM8580_PWRDN2_PLLBPD;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       if (freq_in && freq_out) {
+               ret = pll_factors(&pll_div, freq_out, freq_in);
+               if (ret != 0)
+                       return ret;
+       }
+
+       state->in = freq_in;
+       state->out = freq_out;
+
+       /* Always disable the PLL - it is not safe to leave it running
+        * while reprogramming it.
+        */
+       reg = wm8580_read(codec, WM8580_PWRDN2);
+       wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask);
+
+       if (!freq_in || !freq_out)
+               return 0;
+
+       wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
+       wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff);
+       wm8580_write(codec, WM8580_PLLA3 + offset,
+                    (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
+
+       reg = wm8580_read(codec, WM8580_PLLA4 + offset);
+       reg &= ~0x3f;
+       reg |= pll_div.prescale | pll_div.postscale << 1 |
+               pll_div.freqmode << 4;
+
+       wm8580_write(codec, WM8580_PLLA4 + offset, reg);
+
+       /* All done, turn it on */
+       reg = wm8580_read(codec, WM8580_PWRDN2);
+       wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
+
+       return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai_link *dai = rtd->dai;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id);
+
+       paifb &= ~WM8580_AIF_LENGTH_MASK;
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               paifb |= WM8580_AIF_LENGTH_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               paifb |= WM8580_AIF_LENGTH_24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               paifb |= WM8580_AIF_LENGTH_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb);
+       return 0;
+}
+
+static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
+                                     unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int aifa;
+       unsigned int aifb;
+       int can_invert_lrclk;
+
+       aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id);
+       aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id);
+
+       aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               aifa &= ~WM8580_AIF_MS;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aifa |= WM8580_AIF_MS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               can_invert_lrclk = 1;
+               aifb |= WM8580_AIF_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               can_invert_lrclk = 1;
+               aifb |= WM8580_AIF_FMT_RIGHTJ;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               can_invert_lrclk = 1;
+               aifb |= WM8580_AIF_FMT_LEFTJ;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               can_invert_lrclk = 0;
+               aifb |= WM8580_AIF_FMT_DSP;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               can_invert_lrclk = 0;
+               aifb |= WM8580_AIF_FMT_DSP;
+               aifb |= WM8580_AIF_LRP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+
+       case SND_SOC_DAIFMT_IB_IF:
+               if (!can_invert_lrclk)
+                       return -EINVAL;
+               aifb |= WM8580_AIF_BCP;
+               aifb |= WM8580_AIF_LRP;
+               break;
+
+       case SND_SOC_DAIFMT_IB_NF:
+               aifb |= WM8580_AIF_BCP;
+               break;
+
+       case SND_SOC_DAIFMT_NB_IF:
+               if (!can_invert_lrclk)
+                       return -EINVAL;
+               aifb |= WM8580_AIF_LRP;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
+       wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+
+       return 0;
+}
+
+static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+                                int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int reg;
+
+       switch (div_id) {
+       case WM8580_MCLK:
+               reg = wm8580_read(codec, WM8580_PLLB4);
+               reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
+
+               switch (div) {
+               case WM8580_CLKSRC_MCLK:
+                       /* Input */
+                       break;
+
+               case WM8580_CLKSRC_PLLA:
+                       reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA;
+                       break;
+               case WM8580_CLKSRC_PLLB:
+                       reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB;
+                       break;
+
+               case WM8580_CLKSRC_OSC:
+                       reg |= WM8580_PLLB4_MCLKOUTSRC_OSC;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+               wm8580_write(codec, WM8580_PLLB4, reg);
+               break;
+
+       case WM8580_DAC_CLKSEL:
+               reg = wm8580_read(codec, WM8580_CLKSEL);
+               reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
+
+               switch (div) {
+               case WM8580_CLKSRC_MCLK:
+                       break;
+
+               case WM8580_CLKSRC_PLLA:
+                       reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA;
+                       break;
+
+               case WM8580_CLKSRC_PLLB:
+                       reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+               wm8580_write(codec, WM8580_CLKSEL, reg);
+               break;
+
+       case WM8580_CLKOUTSRC:
+               reg = wm8580_read(codec, WM8580_PLLB4);
+               reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
+
+               switch (div) {
+               case WM8580_CLKSRC_NONE:
+                       break;
+
+               case WM8580_CLKSRC_PLLA:
+                       reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK;
+                       break;
+
+               case WM8580_CLKSRC_PLLB:
+                       reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK;
+                       break;
+
+               case WM8580_CLKSRC_OSC:
+                       reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+               wm8580_write(codec, WM8580_PLLB4, reg);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int reg;
+
+       reg = wm8580_read(codec, WM8580_DAC_CONTROL5);
+
+       if (mute)
+               reg |= WM8580_DAC_CONTROL5_MUTEALL;
+       else
+               reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
+
+       wm8580_write(codec, WM8580_DAC_CONTROL5, reg);
+
+       return 0;
+}
+
+static int wm8580_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       u16 reg;
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       case SND_SOC_BIAS_OFF:
+               reg = wm8580_read(codec, WM8580_PWRDN1);
+               wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai wm8580_dai[] = {
+       {
+               .name = "WM8580 PAIFRX",
+               .id = 0,
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = WM8580_FORMATS,
+               },
+               .ops = {
+                        .hw_params = wm8580_paif_hw_params,
+                },
+               .dai_ops = {
+                        .set_fmt = wm8580_set_paif_dai_fmt,
+                        .set_clkdiv = wm8580_set_dai_clkdiv,
+                        .set_pll = wm8580_set_dai_pll,
+                        .digital_mute = wm8580_digital_mute,
+                },
+       },
+       {
+               .name = "WM8580 PAIFTX",
+               .id = 1,
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = WM8580_FORMATS,
+               },
+               .ops = {
+                        .hw_params = wm8580_paif_hw_params,
+                },
+               .dai_ops = {
+                        .set_fmt = wm8580_set_paif_dai_fmt,
+                        .set_clkdiv = wm8580_set_dai_clkdiv,
+                        .set_pll = wm8580_set_dai_pll,
+                },
+       },
+};
+EXPORT_SYMBOL_GPL(wm8580_dai);
+
+/*
+ * initialise the WM8580 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8580_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+
+       codec->name = "WM8580";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8580_read_reg_cache;
+       codec->write = wm8580_write;
+       codec->set_bias_level = wm8580_set_bias_level;
+       codec->dai = wm8580_dai;
+       codec->num_dai = ARRAY_SIZE(wm8580_dai);
+       codec->reg_cache_size = ARRAY_SIZE(wm8580_reg);
+       codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg),
+                                  GFP_KERNEL);
+
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       /* Get the codec into a known state */
+       wm8580_write(codec, WM8580_RESET, 0);
+
+       /* Power up and get individual control of the DACs */
+       wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) &
+                    ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD));
+
+       /* Make VMID high impedence */
+       wm8580_write(codec, WM8580_ADC_CONTROL1,
+                    wm8580_read(codec,  WM8580_ADC_CONTROL1) & ~0x100);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,
+                              SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8580: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       wm8580_add_controls(codec);
+       wm8580_add_widgets(codec);
+
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8580: failed to register card\n");
+               goto card_err;
+       }
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8580_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+/*
+ * WM8580 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8580_i2c_driver;
+static struct i2c_client client_template;
+
+static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = wm8580_socdev;
+       struct wm8580_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr);
+               goto err;
+       }
+
+       ret = wm8580_init(socdev);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "failed to initialise WM8580\n");
+               goto err;
+       }
+
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int wm8580_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int wm8580_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, wm8580_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8580_i2c_driver = {
+       .driver = {
+               .name = "WM8580 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .attach_adapter = wm8580_i2c_attach,
+       .detach_client =  wm8580_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "WM8580",
+       .driver = &wm8580_i2c_driver,
+};
+#endif
+
+static int wm8580_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct wm8580_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct wm8580_priv *wm8580;
+       int ret = 0;
+
+       pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
+       if (wm8580 == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = wm8580;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+       wm8580_socdev = socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = i2c_add_driver(&wm8580_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+               /* Add other interfaces here */
+#endif
+       return ret;
+}
+
+/* power down chip */
+static int wm8580_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8580_i2c_driver);
+#endif
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8580 = {
+       .probe =        wm8580_probe,
+       .remove =       wm8580_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
+
+MODULE_DESCRIPTION("ASoC WM8580 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
new file mode 100644 (file)
index 0000000..589ddab
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * wm8580.h  --  audio driver for WM8580
+ *
+ * Copyright 2008 Samsung Electronics.
+ * Author: Ryu Euiyoul
+ *         ryu.real@gmail.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.
+ *
+ */
+
+#ifndef _WM8580_H
+#define _WM8580_H
+
+#define WM8580_PLLA  1
+#define WM8580_PLLB  2
+
+#define WM8580_MCLK       1
+#define WM8580_DAC_CLKSEL 2
+#define WM8580_CLKOUTSRC  3
+
+#define WM8580_CLKSRC_MCLK 1
+#define WM8580_CLKSRC_PLLA 2
+#define WM8580_CLKSRC_PLLB 3
+#define WM8580_CLKSRC_OSC  4
+#define WM8580_CLKSRC_NONE 5
+
+struct wm8580_setup_data {
+       unsigned short i2c_address;
+};
+
+#define WM8580_DAI_PAIFRX 0
+#define WM8580_DAI_PAIFTX 1
+
+extern struct snd_soc_dai wm8580_dai[];
+extern struct snd_soc_codec_device soc_codec_dev_wm8580;
+
+#endif
+
index 9402fcaf04fa50b0c1c71bf2f3026e3aa0985ec8..7b64d9a7ff76408092520d614c1601dbb901c7be 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -570,88 +571,144 @@ static struct snd_soc_device *wm8731_socdev;
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8731_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-
-static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8731_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8731_socdev;
-       struct wm8731_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               pr_err("failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = wm8731_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                pr_err("failed to initialise WM8731\n");
-               goto err;
-       }
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int wm8731_i2c_detach(struct i2c_client *client)
+static int wm8731_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int wm8731_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, wm8731_codec_probe);
-}
+static const struct i2c_device_id wm8731_i2c_id[] = {
+       { "wm8731", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8731_i2c_driver = {
        .driver = {
                .name = "WM8731 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_WM8731,
-       .attach_adapter = wm8731_i2c_attach,
-       .detach_client =  wm8731_i2c_detach,
-       .command =        NULL,
+       .probe =    wm8731_i2c_probe,
+       .remove =   wm8731_i2c_remove,
+       .id_table = wm8731_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "WM8731",
-       .driver = &wm8731_i2c_driver,
-};
+static int wm8731_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8731_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8731_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8731_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8731_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_device *socdev = wm8731_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       codec->control_data = spi;
+
+       ret = wm8731_init(socdev);
+       if (ret < 0)
+               dev_err(&spi->dev, "failed to initialise WM8731\n");
+
+       return ret;
+}
+
+static int __devexit wm8731_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver wm8731_spi_driver = {
+       .driver = {
+               .name   = "wm8731",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8731_spi_probe,
+       .remove         = __devexit_p(wm8731_spi_remove),
+};
+
+static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
 static int wm8731_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -680,16 +737,21 @@ static int wm8731_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        wm8731_socdev = socdev;
+       ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&wm8731_i2c_driver);
+               ret = wm8731_add_i2c_device(pdev, setup);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       if (setup->spi) {
+               codec->hw_write = (hw_write_t)wm8731_spi_write;
+               ret = spi_register_driver(&wm8731_spi_driver);
                if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+                       printk(KERN_ERR "can't add spi driver");
        }
-#else
-       /* Add other interfaces here */
 #endif
 
        if (ret != 0) {
@@ -711,7 +773,11 @@ static int wm8731_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8731_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8731_spi_driver);
 #endif
        kfree(codec->private_data);
        kfree(codec);
index 99f2e3c60e3331c6802318b636ff709fc4796518..95190e9c0c145f32c2a0e9a1bd681d86e84e4181 100644 (file)
@@ -35,6 +35,8 @@
 #define WM8731_DAI             0
 
 struct wm8731_setup_data {
+       int            spi;
+       int            i2c_bus;
        unsigned short i2c_address;
 };
 
index dd1f55404b29d073a2eb5a74beb3a468882a8bd8..4892e398a5982fa89b87ecbd1d2ceaa6fdc3af53 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -841,88 +842,147 @@ static struct snd_soc_device *wm8750_socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
 /*
- * WM8731 2 wire address is determined by GPIO5
+ * WM8750 2 wire address is determined by GPIO5
  * state during powerup.
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8750_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8750_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8750_socdev;
-       struct wm8750_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               pr_err("failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = wm8750_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                pr_err("failed to initialise WM8750\n");
-               goto err;
-       }
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int wm8750_i2c_detach(struct i2c_client *client)
+static int wm8750_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int wm8750_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, wm8750_codec_probe);
-}
+static const struct i2c_device_id wm8750_i2c_id[] = {
+       { "wm8750", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8750_i2c_driver = {
        .driver = {
                .name = "WM8750 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_WM8750,
-       .attach_adapter = wm8750_i2c_attach,
-       .detach_client =  wm8750_i2c_detach,
-       .command =        NULL,
+       .probe =    wm8750_i2c_probe,
+       .remove =   wm8750_i2c_remove,
+       .id_table = wm8750_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "WM8750",
-       .driver = &wm8750_i2c_driver,
+static int wm8750_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8750_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8750_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8750", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8750_i2c_driver);
+       return -ENODEV;
+}
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8750_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_device *socdev = wm8750_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       codec->control_data = spi;
+
+       ret = wm8750_init(socdev);
+       if (ret < 0)
+               dev_err(&spi->dev, "failed to initialise WM8750\n");
+
+       return ret;
+}
+
+static int __devexit wm8750_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver wm8750_spi_driver = {
+       .driver = {
+               .name   = "wm8750",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8750_spi_probe,
+       .remove         = __devexit_p(wm8750_spi_remove),
 };
+
+static int wm8750_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
 #endif
 
 static int wm8750_probe(struct platform_device *pdev)
@@ -931,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev)
        struct wm8750_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec;
        struct wm8750_priv *wm8750;
-       int ret = 0;
+       int ret;
 
        pr_info("WM8750 Audio Codec %s", WM8750_VERSION);
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
@@ -952,16 +1012,21 @@ static int wm8750_probe(struct platform_device *pdev)
        wm8750_socdev = socdev;
        INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work);
 
+       ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&wm8750_i2c_driver);
+               ret = wm8750_add_i2c_device(pdev, setup);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       if (setup->spi) {
+               codec->hw_write = (hw_write_t)wm8750_spi_write;
+               ret = spi_register_driver(&wm8750_spi_driver);
                if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+                       printk(KERN_ERR "can't add spi driver");
        }
-#else
-               /* Add other interfaces here */
 #endif
 
        if (ret != 0) {
@@ -1002,7 +1067,11 @@ static int wm8750_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8750_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8750_spi_driver);
 #endif
        kfree(codec->private_data);
        kfree(codec);
index 8ef30e628b21963a35d10668747f7b76874a4192..1dc100e19cfe3076019a4c564999f4e061844b4d 100644 (file)
@@ -58,6 +58,8 @@
 #define WM8750_SYSCLK  0
 
 struct wm8750_setup_data {
+       int spi;
+       int i2c_bus;
        unsigned short i2c_address;
 };
 
index e873414840c854231899d5bdd1b83316f08de4d8..8c4df44f334582b2fa23a8be42a0ecdea472c1c0 100644 (file)
@@ -1637,84 +1637,86 @@ static struct snd_soc_device *wm8753_socdev;
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8753_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8753_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8753_socdev;
-       struct wm8753_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (!i2c)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               pr_err("failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = wm8753_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                pr_err("failed to initialise WM8753\n");
-               goto err;
-       }
-
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int wm8753_i2c_detach(struct i2c_client *client)
+static int wm8753_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int wm8753_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, wm8753_codec_probe);
-}
+static const struct i2c_device_id wm8753_i2c_id[] = {
+       { "wm8753", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8753_i2c_driver = {
        .driver = {
                .name = "WM8753 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_WM8753,
-       .attach_adapter = wm8753_i2c_attach,
-       .detach_client =  wm8753_i2c_detach,
-       .command =        NULL,
+       .probe =    wm8753_i2c_probe,
+       .remove =   wm8753_i2c_remove,
+       .id_table = wm8753_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "WM8753",
-       .driver = &wm8753_i2c_driver,
-};
+static int wm8753_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8753_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8753_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8753", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8753_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int wm8753_probe(struct platform_device *pdev)
@@ -1748,11 +1750,8 @@ static int wm8753_probe(struct platform_device *pdev)
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&wm8753_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = wm8753_add_i2c_device(pdev, setup);
        }
 #else
                /* Add other interfaces here */
@@ -1796,6 +1795,7 @@ static int wm8753_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8753_i2c_driver);
 #endif
        kfree(codec->private_data);
index 44f5f1ff0cc7080bfb920c0c5fbb345901896e8a..7defde069f1df92793c254f49c305351db3d8b86 100644 (file)
@@ -79,6 +79,7 @@
 #define WM8753_ADCTL2          0x3f
 
 struct wm8753_setup_data {
+       int i2c_bus;
        unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
new file mode 100644 (file)
index 0000000..0b8c6d3
--- /dev/null
@@ -0,0 +1,1542 @@
+/*
+ * wm8900.c  --  WM8900 ALSA Soc Audio driver
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * 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.
+ *
+ * TODO:
+ *  - Tristating.
+ *  - TDM.
+ *  - Jack detect.
+ *  - FLL source configuration, currently only MCLK is supported.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8900.h"
+
+/* WM8900 register space */
+#define WM8900_REG_RESET       0x0
+#define WM8900_REG_ID          0x0
+#define WM8900_REG_POWER1      0x1
+#define WM8900_REG_POWER2      0x2
+#define WM8900_REG_POWER3      0x3
+#define WM8900_REG_AUDIO1      0x4
+#define WM8900_REG_AUDIO2      0x5
+#define WM8900_REG_CLOCKING1    0x6
+#define WM8900_REG_CLOCKING2    0x7
+#define WM8900_REG_AUDIO3       0x8
+#define WM8900_REG_AUDIO4       0x9
+#define WM8900_REG_DACCTRL      0xa
+#define WM8900_REG_LDAC_DV      0xb
+#define WM8900_REG_RDAC_DV      0xc
+#define WM8900_REG_SIDETONE     0xd
+#define WM8900_REG_ADCCTRL      0xe
+#define WM8900_REG_LADC_DV     0xf
+#define WM8900_REG_RADC_DV      0x10
+#define WM8900_REG_GPIO         0x12
+#define WM8900_REG_INCTL       0x15
+#define WM8900_REG_LINVOL      0x16
+#define WM8900_REG_RINVOL      0x17
+#define WM8900_REG_INBOOSTMIX1  0x18
+#define WM8900_REG_INBOOSTMIX2  0x19
+#define WM8900_REG_ADCPATH     0x1a
+#define WM8900_REG_AUXBOOST    0x1b
+#define WM8900_REG_ADDCTL       0x1e
+#define WM8900_REG_FLLCTL1      0x24
+#define WM8900_REG_FLLCTL2      0x25
+#define WM8900_REG_FLLCTL3      0x26
+#define WM8900_REG_FLLCTL4      0x27
+#define WM8900_REG_FLLCTL5      0x28
+#define WM8900_REG_FLLCTL6      0x29
+#define WM8900_REG_LOUTMIXCTL1  0x2c
+#define WM8900_REG_ROUTMIXCTL1  0x2d
+#define WM8900_REG_BYPASS1     0x2e
+#define WM8900_REG_BYPASS2     0x2f
+#define WM8900_REG_AUXOUT_CTL   0x30
+#define WM8900_REG_LOUT1CTL     0x33
+#define WM8900_REG_ROUT1CTL     0x34
+#define WM8900_REG_LOUT2CTL    0x35
+#define WM8900_REG_ROUT2CTL    0x36
+#define WM8900_REG_HPCTL1      0x3a
+#define WM8900_REG_OUTBIASCTL   0x73
+
+#define WM8900_MAXREG          0x80
+
+#define WM8900_REG_ADDCTL_OUT1_DIS    0x80
+#define WM8900_REG_ADDCTL_OUT2_DIS    0x40
+#define WM8900_REG_ADDCTL_VMID_DIS    0x20
+#define WM8900_REG_ADDCTL_BIAS_SRC    0x10
+#define WM8900_REG_ADDCTL_VMID_SOFTST 0x04
+#define WM8900_REG_ADDCTL_TEMP_SD     0x02
+
+#define WM8900_REG_GPIO_TEMP_ENA   0x2
+
+#define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100
+#define WM8900_REG_POWER1_BIAS_ENA         0x0008
+#define WM8900_REG_POWER1_VMID_BUF_ENA     0x0004
+#define WM8900_REG_POWER1_FLL_ENA          0x0040
+
+#define WM8900_REG_POWER2_SYSCLK_ENA  0x8000
+#define WM8900_REG_POWER2_ADCL_ENA    0x0002
+#define WM8900_REG_POWER2_ADCR_ENA    0x0001
+
+#define WM8900_REG_POWER3_DACL_ENA    0x0002
+#define WM8900_REG_POWER3_DACR_ENA    0x0001
+
+#define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018
+#define WM8900_REG_AUDIO1_LRCLK_INV    0x0080
+#define WM8900_REG_AUDIO1_BCLK_INV     0x0100
+
+#define WM8900_REG_CLOCKING1_BCLK_DIR   0x1
+#define WM8900_REG_CLOCKING1_MCLK_SRC   0x100
+#define WM8900_REG_CLOCKING1_BCLK_MASK  (~0x01e)
+#define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000)
+
+#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0
+#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
+
+#define WM8900_REG_DACCTRL_MUTE          0x004
+#define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400
+
+#define WM8900_REG_AUDIO3_ADCLRC_DIR    0x0800
+
+#define WM8900_REG_AUDIO4_DACLRC_DIR    0x0800
+
+#define WM8900_REG_FLLCTL1_OSC_ENA    0x100
+
+#define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100
+
+#define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80
+#define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40
+#define WM8900_REG_HPCTL1_HP_CLAMP_IP    0x20
+#define WM8900_REG_HPCTL1_HP_CLAMP_OP    0x10
+#define WM8900_REG_HPCTL1_HP_SHORT       0x08
+#define WM8900_REG_HPCTL1_HP_SHORT2      0x04
+
+#define WM8900_LRC_MASK 0xfc00
+
+struct snd_soc_codec_device soc_codec_dev_wm8900;
+
+struct wm8900_priv {
+       u32 fll_in; /* FLL input frequency */
+       u32 fll_out; /* FLL output frequency */
+};
+
+/*
+ * wm8900 register cache.  We can't read the entire register space and we
+ * have slow control buses so we cache the registers.
+ */
+static const u16 wm8900_reg_defaults[WM8900_MAXREG] = {
+       0x8900, 0x0000,
+       0xc000, 0x0000,
+       0x4050, 0x4000,
+       0x0008, 0x0000,
+       0x0040, 0x0040,
+       0x1004, 0x00c0,
+       0x00c0, 0x0000,
+       0x0100, 0x00c0,
+       0x00c0, 0x0000,
+       0xb001, 0x0000,
+       0x0000, 0x0044,
+       0x004c, 0x004c,
+       0x0044, 0x0044,
+       0x0000, 0x0044,
+       0x0000, 0x0000,
+       0x0002, 0x0000,
+       0x0000, 0x0000,
+       0x0000, 0x0000,
+       0x0008, 0x0000,
+       0x0000, 0x0008,
+       0x0097, 0x0100,
+       0x0000, 0x0000,
+       0x0050, 0x0050,
+       0x0055, 0x0055,
+       0x0055, 0x0000,
+       0x0000, 0x0079,
+       0x0079, 0x0079,
+       0x0079, 0x0000,
+       /* Remaining registers all zero */
+};
+
+/*
+ * read wm8900 register cache
+ */
+static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       BUG_ON(reg >= WM8900_MAXREG);
+
+       if (reg == WM8900_REG_ID)
+               return 0;
+
+       return cache[reg];
+}
+
+/*
+ * write wm8900 register cache
+ */
+static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec,
+       u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+
+       BUG_ON(reg >= WM8900_MAXREG);
+
+       cache[reg] = value;
+}
+
+/*
+ * write to the WM8900 register space
+ */
+static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg,
+                       unsigned int value)
+{
+       u8 data[3];
+
+       if (value == wm8900_read_reg_cache(codec, reg))
+               return 0;
+
+       /* data is
+        *   D15..D9 WM8900 register offset
+        *   D8...D0 register data
+        */
+       data[0] = reg;
+       data[1] = value >> 8;
+       data[2] = value & 0x00ff;
+
+       wm8900_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 3) == 3)
+               return 0;
+       else
+               return -EIO;
+}
+
+/*
+ * Read from the wm8900.
+ */
+static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg)
+{
+       struct i2c_msg xfer[2];
+       u16 data;
+       int ret;
+       struct i2c_client *client = codec->control_data;
+
+       BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1);
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 2;
+       xfer[1].buf = (u8 *)&data;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret != 2) {
+               printk(KERN_CRIT "i2c_transfer returned %d\n", ret);
+               return 0;
+       }
+
+       return (data >> 8) | ((data & 0xff) << 8);
+}
+
+/*
+ * Read from the WM8900 register space.  Most registers can't be read
+ * and are therefore supplied from cache.
+ */
+static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       switch (reg) {
+       case WM8900_REG_ID:
+               return wm8900_chip_read(codec, reg);
+       default:
+               return wm8900_read_reg_cache(codec, reg);
+       }
+}
+
+static void wm8900_reset(struct snd_soc_codec *codec)
+{
+       wm8900_write(codec, WM8900_REG_RESET, 0);
+
+       memcpy(codec->reg_cache, wm8900_reg_defaults,
+              sizeof(codec->reg_cache));
+}
+
+static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Clamp headphone outputs */
+               hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
+                       WM8900_REG_HPCTL1_HP_CLAMP_OP;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               /* Enable the input stage */
+               hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP;
+               hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
+                       WM8900_REG_HPCTL1_HP_SHORT2 |
+                       WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+               msleep(400);
+
+               /* Enable the output stage */
+               hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
+               hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+               /* Remove the shorts */
+               hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+               hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Short the output */
+               hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+               /* Disable the output stage */
+               hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+
+               /* Clamp the outputs and power down input */
+               hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
+                       WM8900_REG_HPCTL1_HP_CLAMP_OP;
+               hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
+               wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               /* Disable everything */
+               wm8900_write(codec, WM8900_REG_HPCTL1, 0);
+               break;
+
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
+
+static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0);
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
+
+static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
+
+static const struct soc_enum mic_bias_level =
+SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt);
+
+static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
+
+static const struct soc_enum dac_mute_rate =
+SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt);
+
+static const char *dac_deemphasis_txt[] = {
+       "Disabled", "32kHz", "44.1kHz", "48kHz"
+};
+
+static const struct soc_enum dac_deemphasis =
+SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt);
+
+static const char *adc_hpf_cut_txt[] = {
+       "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
+};
+
+static const struct soc_enum adc_hpf_cut =
+SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt);
+
+static const char *lr_txt[] = {
+       "Left", "Right"
+};
+
+static const struct soc_enum aifl_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt);
+
+static const struct soc_enum aifr_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt);
+
+static const struct soc_enum dacl_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt);
+
+static const struct soc_enum dacr_src =
+SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt);
+
+static const char *sidetone_txt[] = {
+       "Disabled", "Left ADC", "Right ADC"
+};
+
+static const struct soc_enum dacl_sidetone =
+SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt);
+
+static const struct soc_enum dacr_sidetone =
+SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt);
+
+static const struct snd_kcontrol_new wm8900_snd_controls[] = {
+SOC_ENUM("Mic Bias Level", mic_bias_level),
+
+SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0,
+              in_pga_tlv),
+SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1),
+SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0),
+
+SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0,
+              in_pga_tlv),
+SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1),
+SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1),
+SOC_ENUM("DAC Mute Rate", dac_mute_rate),
+SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0),
+SOC_ENUM("DAC Deemphasis", dac_deemphasis),
+SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0),
+SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL,
+          12, 1, 0),
+
+SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0),
+SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut),
+SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0),
+SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0,
+              adc_svol_tlv),
+SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0,
+              adc_svol_tlv),
+SOC_ENUM("Left Digital Audio Source", aifl_src),
+SOC_ENUM("Right Digital Audio Source", aifr_src),
+
+SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0,
+              dac_boost_tlv),
+SOC_ENUM("Left DAC Source", dacl_src),
+SOC_ENUM("Right DAC Source", dacr_src),
+SOC_ENUM("Left DAC Sidetone", dacl_sidetone),
+SOC_ENUM("Right DAC Sidetone", dacr_sidetone),
+SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume",
+                WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV,
+                1, 96, 0, dac_tlv),
+SOC_DOUBLE_R_TLV("Digital Capture Volume",
+                WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv),
+
+SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0,
+              out_mix_tlv),
+SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0,
+              out_mix_tlv),
+SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0,
+              out_mix_tlv),
+SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0,
+              out_mix_tlv),
+
+SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0,
+              out_mix_tlv),
+SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0,
+              out_mix_tlv),
+SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0,
+              out_mix_tlv),
+SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0,
+              out_mix_tlv),
+
+SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0,
+              in_boost_tlv),
+SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0,
+              in_boost_tlv),
+SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0,
+              in_boost_tlv),
+SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0,
+              in_boost_tlv),
+SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0,
+              in_boost_tlv),
+SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0,
+              in_boost_tlv),
+
+SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+              0, 63, 0, out_pga_tlv),
+SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+            6, 1, 1),
+SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+            7, 1, 0),
+
+SOC_DOUBLE_R_TLV("LINEOUT2 Volume",
+                WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL,
+                0, 63, 0, out_pga_tlv),
+SOC_DOUBLE_R("LINEOUT2 Switch",
+            WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1),
+SOC_DOUBLE_R("LINEOUT2 ZC Switch",
+            WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0),
+SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
+          0, 1, 1),
+
+};
+
+/* add non dapm controls */
+static int wm8900_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&wm8900_snd_controls[i],
+                                              codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm8900_dapm_loutput2_control =
+SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0);
+
+static const struct snd_kcontrol_new wm8900_dapm_routput2_control =
+SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0);
+
+static const struct snd_kcontrol_new wm8900_loutmix_controls[] = {
+SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0),
+SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0),
+SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0),
+SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_routmix_controls[] = {
+SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0),
+SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0),
+SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0),
+SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_linmix_controls[] = {
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1),
+SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1),
+SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_rinmix_controls[] = {
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1),
+SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1),
+SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_linpga_controls[] = {
+SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0),
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_rinpga_controls[] = {
+SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0),
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
+};
+
+static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" };
+
+static const struct soc_enum wm8900_lineout2_lp_mux =
+SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux);
+
+static const struct snd_kcontrol_new wm8900_lineout2_lp =
+SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
+
+static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = {
+
+/* Externally visible pins */
+SND_SOC_DAPM_OUTPUT("LINEOUT1L"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1R"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2L"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2R"),
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_VMID("VMID"),
+
+/* Input */
+SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0,
+                  wm8900_linpga_controls,
+                  ARRAY_SIZE(wm8900_linpga_controls)),
+SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0,
+                  wm8900_rinpga_controls,
+                  ARRAY_SIZE(wm8900_rinpga_controls)),
+
+SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0,
+                  wm8900_linmix_controls,
+                  ARRAY_SIZE(wm8900_linmix_controls)),
+SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0,
+                  wm8900_rinmix_controls,
+                  ARRAY_SIZE(wm8900_rinmix_controls)),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0),
+
+/* Output */
+SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0),
+SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0),
+
+SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0,
+                  wm8900_hp_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp),
+SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0,
+                  wm8900_loutmix_controls,
+                  ARRAY_SIZE(wm8900_loutmix_controls)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0,
+                  wm8900_routmix_controls,
+                  ARRAY_SIZE(wm8900_routmix_controls)),
+};
+
+/* Target, Path, Source */
+static const struct snd_soc_dapm_route audio_map[] = {
+/* Inputs */
+{"Left Input PGA", "LINPUT1 Switch", "LINPUT1"},
+{"Left Input PGA", "LINPUT2 Switch", "LINPUT2"},
+{"Left Input PGA", "LINPUT3 Switch", "LINPUT3"},
+
+{"Right Input PGA", "RINPUT1 Switch", "RINPUT1"},
+{"Right Input PGA", "RINPUT2 Switch", "RINPUT2"},
+{"Right Input PGA", "RINPUT3 Switch", "RINPUT3"},
+
+{"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"},
+{"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"},
+{"Left Input Mixer", "AUX Switch", "AUX"},
+{"Left Input Mixer", "Input PGA Switch", "Left Input PGA"},
+
+{"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"},
+{"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"},
+{"Right Input Mixer", "AUX Switch", "AUX"},
+{"Right Input Mixer", "Input PGA Switch", "Right Input PGA"},
+
+{"ADCL", NULL, "Left Input Mixer"},
+{"ADCR", NULL, "Right Input Mixer"},
+
+/* Outputs */
+{"LINEOUT1L", NULL, "LINEOUT1L PGA"},
+{"LINEOUT1L PGA", NULL, "Left Output Mixer"},
+{"LINEOUT1R", NULL, "LINEOUT1R PGA"},
+{"LINEOUT1R PGA", NULL, "Right Output Mixer"},
+
+{"LINEOUT2L PGA", NULL, "Left Output Mixer"},
+{"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"},
+{"LINEOUT2 LP", "Enabled", "Left Output Mixer"},
+{"LINEOUT2L", NULL, "LINEOUT2 LP"},
+
+{"LINEOUT2R PGA", NULL, "Right Output Mixer"},
+{"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"},
+{"LINEOUT2 LP", "Enabled", "Right Output Mixer"},
+{"LINEOUT2R", NULL, "LINEOUT2 LP"},
+
+{"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"},
+{"Left Output Mixer", "AUX Bypass Switch", "AUX"},
+{"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
+{"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
+{"Left Output Mixer", "DACL Switch", "DACL"},
+
+{"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"},
+{"Right Output Mixer", "AUX Bypass Switch", "AUX"},
+{"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
+{"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
+{"Right Output Mixer", "DACR Switch", "DACR"},
+
+/* Note that the headphone output stage needs to be connected
+ * externally to LINEOUT2 via DC blocking capacitors.  Other
+ * configurations are not supported.
+ *
+ * Note also that left and right headphone paths are treated as a
+ * mono path.
+ */
+{"Headphone Amplifier", NULL, "LINEOUT2 LP"},
+{"Headphone Amplifier", NULL, "LINEOUT2 LP"},
+{"HP_L", NULL, "Headphone Amplifier"},
+{"HP_R", NULL, "Headphone Amplifier"},
+};
+
+static int wm8900_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets,
+                                 ARRAY_SIZE(wm8900_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+
+       return 0;
+}
+
+static int wm8900_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 reg;
+
+       reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               reg |= 0x20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               reg |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               reg |= 0x60;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8900_write(codec, WM8900_REG_AUDIO1, reg);
+
+       return 0;
+}
+
+/* FLL divisors */
+struct _fll_div {
+       u16 fll_ratio;
+       u16 fllclk_div;
+       u16 fll_slow_lock_ref;
+       u16 n;
+       u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod, target;
+       unsigned int div;
+
+       BUG_ON(!Fout);
+
+       /* The FLL must run at 90-100MHz which is then scaled down to
+        * the output value by FLLCLK_DIV. */
+       target = Fout;
+       div = 1;
+       while (target < 90000000) {
+               div *= 2;
+               target *= 2;
+       }
+
+       if (target > 100000000)
+               printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d"
+                      " Fout=%d\n", target, Fref, Fout);
+       if (div > 32) {
+               printk(KERN_ERR "wm8900: Invalid FLL division rate %u, "
+                      "Fref=%d, Fout=%d, target=%d\n",
+                      div, Fref, Fout, target);
+               return -EINVAL;
+       }
+
+       fll_div->fllclk_div = div >> 2;
+
+       if (Fref < 48000)
+               fll_div->fll_slow_lock_ref = 1;
+       else
+               fll_div->fll_slow_lock_ref = 0;
+
+       Ndiv = target / Fref;
+
+       if (Fref < 1000000)
+               fll_div->fll_ratio = 8;
+       else
+               fll_div->fll_ratio = 1;
+
+       fll_div->n = Ndiv / fll_div->fll_ratio;
+       Nmod = (target / fll_div->fll_ratio) % Fref;
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, Fref);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       fll_div->k = K / 10;
+
+       BUG_ON(target != Fout * (fll_div->fllclk_div << 2));
+       BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n);
+
+       return 0;
+}
+
+static int wm8900_set_fll(struct snd_soc_codec *codec,
+       int fll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       struct wm8900_priv *wm8900 = codec->private_data;
+       struct _fll_div fll_div;
+       unsigned int reg;
+
+       if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
+               return 0;
+
+       /* The digital side should be disabled during any change. */
+       reg = wm8900_read(codec, WM8900_REG_POWER1);
+       wm8900_write(codec, WM8900_REG_POWER1,
+                    reg & (~WM8900_REG_POWER1_FLL_ENA));
+
+       /* Disable the FLL? */
+       if (!freq_in || !freq_out) {
+               reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+               wm8900_write(codec, WM8900_REG_CLOCKING1,
+                            reg & (~WM8900_REG_CLOCKING1_MCLK_SRC));
+
+               reg = wm8900_read(codec, WM8900_REG_FLLCTL1);
+               wm8900_write(codec, WM8900_REG_FLLCTL1,
+                            reg & (~WM8900_REG_FLLCTL1_OSC_ENA));
+
+               wm8900->fll_in = freq_in;
+               wm8900->fll_out = freq_out;
+
+               return 0;
+       }
+
+       if (fll_factors(&fll_div, freq_in, freq_out) != 0)
+               goto reenable;
+
+       wm8900->fll_in = freq_in;
+       wm8900->fll_out = freq_out;
+
+       /* The osclilator *MUST* be enabled before we enable the
+        * digital circuit. */
+       wm8900_write(codec, WM8900_REG_FLLCTL1,
+                    fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
+
+       wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5);
+       wm8900_write(codec, WM8900_REG_FLLCTL5,
+                    (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
+
+       if (fll_div.k) {
+               wm8900_write(codec, WM8900_REG_FLLCTL2,
+                            (fll_div.k >> 8) | 0x100);
+               wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
+       } else
+               wm8900_write(codec, WM8900_REG_FLLCTL2, 0);
+
+       if (fll_div.fll_slow_lock_ref)
+               wm8900_write(codec, WM8900_REG_FLLCTL6,
+                            WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
+       else
+               wm8900_write(codec, WM8900_REG_FLLCTL6, 0);
+
+       reg = wm8900_read(codec, WM8900_REG_POWER1);
+       wm8900_write(codec, WM8900_REG_POWER1,
+                    reg | WM8900_REG_POWER1_FLL_ENA);
+
+reenable:
+       reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+       wm8900_write(codec, WM8900_REG_CLOCKING1,
+                    reg | WM8900_REG_CLOCKING1_MCLK_SRC);
+
+       return 0;
+}
+
+static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out);
+}
+
+static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+                                int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int reg;
+
+       switch (div_id) {
+       case WM8900_BCLK_DIV:
+               reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+               wm8900_write(codec, WM8900_REG_CLOCKING1,
+                            div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK));
+               break;
+       case WM8900_OPCLK_DIV:
+               reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
+               wm8900_write(codec, WM8900_REG_CLOCKING1,
+                            div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK));
+               break;
+       case WM8900_DAC_LRCLK:
+               reg = wm8900_read(codec, WM8900_REG_AUDIO4);
+               wm8900_write(codec, WM8900_REG_AUDIO4,
+                            div | (reg & WM8900_LRC_MASK));
+               break;
+       case WM8900_ADC_LRCLK:
+               reg = wm8900_read(codec, WM8900_REG_AUDIO3);
+               wm8900_write(codec, WM8900_REG_AUDIO3,
+                            div | (reg & WM8900_LRC_MASK));
+               break;
+       case WM8900_DAC_CLKDIV:
+               reg = wm8900_read(codec, WM8900_REG_CLOCKING2);
+               wm8900_write(codec, WM8900_REG_CLOCKING2,
+                            div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV));
+               break;
+       case WM8900_ADC_CLKDIV:
+               reg = wm8900_read(codec, WM8900_REG_CLOCKING2);
+               wm8900_write(codec, WM8900_REG_CLOCKING2,
+                            div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV));
+               break;
+       case WM8900_LRCLK_MODE:
+               reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+               wm8900_write(codec, WM8900_REG_DACCTRL,
+                            div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int clocking1, aif1, aif3, aif4;
+
+       clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1);
+       aif1 = wm8900_read(codec, WM8900_REG_AUDIO1);
+       aif3 = wm8900_read(codec, WM8900_REG_AUDIO3);
+       aif4 = wm8900_read(codec, WM8900_REG_AUDIO4);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
+               aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
+               aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
+               aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
+               aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
+               aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
+               aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
+               aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
+               aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
+               aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
+               aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+               aif1 |= 0x10;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+               aif1 |= 0x8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+                       aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+                       aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+                       aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+                       aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1);
+       wm8900_write(codec, WM8900_REG_AUDIO1, aif1);
+       wm8900_write(codec, WM8900_REG_AUDIO3, aif3);
+       wm8900_write(codec, WM8900_REG_AUDIO4, aif4);
+
+       return 0;
+}
+
+static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+
+       if (mute)
+               reg |= WM8900_REG_DACCTRL_MUTE;
+       else
+               reg &= ~WM8900_REG_DACCTRL_MUTE;
+
+       wm8900_write(codec, WM8900_REG_DACCTRL, reg);
+
+       return 0;
+}
+
+#define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+                     SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+                     SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define WM8900_PCM_FORMATS \
+       (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
+        SNDRV_PCM_FORMAT_S24_LE)
+
+struct snd_soc_dai wm8900_dai = {
+       .name = "WM8900 HiFi",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8900_RATES,
+               .formats = WM8900_PCM_FORMATS,
+       },
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8900_RATES,
+               .formats = WM8900_PCM_FORMATS,
+        },
+       .ops = {
+               .hw_params = wm8900_hw_params,
+        },
+       .dai_ops = {
+                .set_clkdiv = wm8900_set_dai_clkdiv,
+                .set_pll = wm8900_set_dai_pll,
+                .set_fmt = wm8900_set_dai_fmt,
+                .digital_mute = wm8900_digital_mute,
+        },
+};
+EXPORT_SYMBOL_GPL(wm8900_dai);
+
+static int wm8900_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u16 reg;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* Enable thermal shutdown */
+               reg = wm8900_read(codec, WM8900_REG_GPIO);
+               wm8900_write(codec, WM8900_REG_GPIO,
+                            reg | WM8900_REG_GPIO_TEMP_ENA);
+               reg = wm8900_read(codec, WM8900_REG_ADDCTL);
+               wm8900_write(codec, WM8900_REG_ADDCTL,
+                            reg | WM8900_REG_ADDCTL_TEMP_SD);
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               /* Charge capacitors if initial power up */
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* STARTUP_BIAS_ENA on */
+                       wm8900_write(codec, WM8900_REG_POWER1,
+                                    WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+
+                       /* Startup bias mode */
+                       wm8900_write(codec, WM8900_REG_ADDCTL,
+                                    WM8900_REG_ADDCTL_BIAS_SRC |
+                                    WM8900_REG_ADDCTL_VMID_SOFTST);
+
+                       /* VMID 2x50k */
+                       wm8900_write(codec, WM8900_REG_POWER1,
+                                    WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
+
+                       /* Allow capacitors to charge */
+                       schedule_timeout_interruptible(msecs_to_jiffies(400));
+
+                       /* Enable bias */
+                       wm8900_write(codec, WM8900_REG_POWER1,
+                                    WM8900_REG_POWER1_STARTUP_BIAS_ENA |
+                                    WM8900_REG_POWER1_BIAS_ENA | 0x1);
+
+                       wm8900_write(codec, WM8900_REG_ADDCTL, 0);
+
+                       wm8900_write(codec, WM8900_REG_POWER1,
+                                    WM8900_REG_POWER1_BIAS_ENA | 0x1);
+               }
+
+               reg = wm8900_read(codec, WM8900_REG_POWER1);
+               wm8900_write(codec, WM8900_REG_POWER1,
+                            (reg & WM8900_REG_POWER1_FLL_ENA) |
+                            WM8900_REG_POWER1_BIAS_ENA | 0x1);
+               wm8900_write(codec, WM8900_REG_POWER2,
+                            WM8900_REG_POWER2_SYSCLK_ENA);
+               wm8900_write(codec, WM8900_REG_POWER3, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Startup bias enable */
+               reg = wm8900_read(codec, WM8900_REG_POWER1);
+               wm8900_write(codec, WM8900_REG_POWER1,
+                            reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+               wm8900_write(codec, WM8900_REG_ADDCTL,
+                            WM8900_REG_ADDCTL_BIAS_SRC |
+                            WM8900_REG_ADDCTL_VMID_SOFTST);
+
+               /* Discharge caps */
+               wm8900_write(codec, WM8900_REG_POWER1,
+                            WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+               schedule_timeout_interruptible(msecs_to_jiffies(500));
+
+               /* Remove clamp */
+               wm8900_write(codec, WM8900_REG_HPCTL1, 0);
+
+               /* Power down */
+               wm8900_write(codec, WM8900_REG_ADDCTL, 0);
+               wm8900_write(codec, WM8900_REG_POWER1, 0);
+               wm8900_write(codec, WM8900_REG_POWER2, 0);
+               wm8900_write(codec, WM8900_REG_POWER3, 0);
+
+               /* Need to let things settle before stopping the clock
+                * to ensure that restart works, see "Stopping the
+                * master clock" in the datasheet. */
+               schedule_timeout_interruptible(msecs_to_jiffies(1));
+               wm8900_write(codec, WM8900_REG_POWER2,
+                            WM8900_REG_POWER2_SYSCLK_ENA);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8900_priv *wm8900 = codec->private_data;
+       int fll_out = wm8900->fll_out;
+       int fll_in  = wm8900->fll_in;
+       int ret;
+
+       /* Stop the FLL in an orderly fashion */
+       ret = wm8900_set_fll(codec, 0, 0, 0);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to stop FLL\n");
+               return ret;
+       }
+
+       wm8900->fll_out = fll_out;
+       wm8900->fll_in = fll_in;
+
+       wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8900_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8900_priv *wm8900 = codec->private_data;
+       u16 *cache;
+       int i, ret;
+
+       cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults),
+                       GFP_KERNEL);
+
+       wm8900_reset(codec);
+       wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Restart the FLL? */
+       if (wm8900->fll_out) {
+               int fll_out = wm8900->fll_out;
+               int fll_in  = wm8900->fll_in;
+
+               wm8900->fll_in = 0;
+               wm8900->fll_out = 0;
+
+               ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
+               if (ret != 0) {
+                       dev_err(&pdev->dev, "Failed to restart FLL\n");
+                       return ret;
+               }
+       }
+
+       if (cache) {
+               for (i = 0; i < WM8900_MAXREG; i++)
+                       wm8900_write(codec, i, cache[i]);
+               kfree(cache);
+       } else
+               dev_err(&pdev->dev, "Unable to allocate register cache\n");
+
+       return 0;
+}
+
+/*
+ * initialise the WM8900 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8900_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+       unsigned int reg;
+       struct i2c_client *i2c_client = socdev->codec->control_data;
+
+       codec->name = "WM8900";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8900_read;
+       codec->write = wm8900_write;
+       codec->dai = &wm8900_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = WM8900_MAXREG;
+       codec->reg_cache = kmemdup(wm8900_reg_defaults,
+                                  sizeof(wm8900_reg_defaults), GFP_KERNEL);
+
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       reg = wm8900_read(codec, WM8900_REG_ID);
+       if (reg != 0x8900) {
+               dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n",
+                       reg);
+               return -ENODEV;
+       }
+
+       codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       if (codec->private_data == NULL) {
+               ret = -ENOMEM;
+               goto priv_err;
+       }
+
+       /* Read back from the chip */
+       reg = wm8900_chip_read(codec, WM8900_REG_POWER1);
+       reg = (reg >> 12) & 0xf;
+       dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg);
+
+       wm8900_reset(codec);
+
+       /* Latch the volume update bits */
+       wm8900_write(codec, WM8900_REG_LINVOL,
+                    wm8900_read(codec, WM8900_REG_LINVOL) | 0x100);
+       wm8900_write(codec, WM8900_REG_RINVOL,
+                    wm8900_read(codec, WM8900_REG_RINVOL) | 0x100);
+       wm8900_write(codec, WM8900_REG_LOUT1CTL,
+                    wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100);
+       wm8900_write(codec, WM8900_REG_ROUT1CTL,
+                    wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100);
+       wm8900_write(codec, WM8900_REG_LOUT2CTL,
+                    wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100);
+       wm8900_write(codec, WM8900_REG_ROUT2CTL,
+                    wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
+       wm8900_write(codec, WM8900_REG_LDAC_DV,
+                    wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100);
+       wm8900_write(codec, WM8900_REG_RDAC_DV,
+                    wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100);
+       wm8900_write(codec, WM8900_REG_LADC_DV,
+                    wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100);
+       wm8900_write(codec, WM8900_REG_RADC_DV,
+                    wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100);
+
+       /* Set the DAC and mixer output bias */
+       wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
+
+       /* Register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Failed to register new PCMs\n");
+               goto pcm_err;
+       }
+
+       /* Turn the chip on */
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       wm8900_add_controls(codec);
+       wm8900_add_widgets(codec);
+
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Failed to register card\n");
+               goto card_err;
+       }
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+priv_err:
+       kfree(codec->private_data);
+       return ret;
+}
+
+static struct snd_soc_device *wm8900_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8900_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = wm8900_socdev;
+       struct wm8900_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       dev_err(&adap->dev, "Probe on %x\n", addr);
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               dev_err(&adap->dev,
+                       "failed to attach codec at addr %x\n", addr);
+               goto err;
+       }
+
+       ret = wm8900_init(socdev);
+       if (ret < 0) {
+               dev_err(&adap->dev, "failed to initialise WM8900\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int wm8900_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int wm8900_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, wm8900_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8900_i2c_driver = {
+       .driver = {
+               .name = "WM8900 I2C codec",
+               .owner = THIS_MODULE,
+       },
+       .attach_adapter = wm8900_i2c_attach,
+       .detach_client =  wm8900_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "WM8900",
+       .driver = &wm8900_i2c_driver,
+};
+#endif
+
+static int wm8900_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct wm8900_setup_data *setup;
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       dev_info(&pdev->dev, "WM8900 Audio Codec\n");
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       socdev->codec = codec;
+
+       codec->set_bias_level = wm8900_set_bias_level;
+
+       wm8900_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = i2c_add_driver(&wm8900_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+#error Non-I2C interfaces not yet supported
+#endif
+       return ret;
+}
+
+/* power down chip */
+static int wm8900_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8900_i2c_driver);
+#endif
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8900 = {
+       .probe =        wm8900_probe,
+       .remove =       wm8900_remove,
+       .suspend =      wm8900_suspend,
+       .resume =       wm8900_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
+
+MODULE_DESCRIPTION("ASoC WM8900 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h
new file mode 100644 (file)
index 0000000..ba450d9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * wm8900.h  --  WM890 Soc Audio driver
+ *
+ * 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 _WM8900_H
+#define _WM8900_H
+
+#define WM8900_FLL 1
+
+#define WM8900_BCLK_DIV   1
+#define WM8900_ADC_CLKDIV 2
+#define WM8900_DAC_CLKDIV 3
+#define WM8900_ADC_LRCLK  4
+#define WM8900_DAC_LRCLK  5
+#define WM8900_OPCLK_DIV  6
+#define WM8900_LRCLK_MODE 7
+
+#define WM8900_BCLK_DIV_1   0x00
+#define WM8900_BCLK_DIV_1_5 0x02
+#define WM8900_BCLK_DIV_2   0x04
+#define WM8900_BCLK_DIV_3   0x06
+#define WM8900_BCLK_DIV_4   0x08
+#define WM8900_BCLK_DIV_5_5 0x0a
+#define WM8900_BCLK_DIV_6   0x0c
+#define WM8900_BCLK_DIV_8   0x0e
+#define WM8900_BCLK_DIV_11  0x10
+#define WM8900_BCLK_DIV_12  0x12
+#define WM8900_BCLK_DIV_16  0x14
+#define WM8900_BCLK_DIV_22  0x16
+#define WM8900_BCLK_DIV_24  0x18
+#define WM8900_BCLK_DIV_32  0x1a
+#define WM8900_BCLK_DIV_44  0x1c
+#define WM8900_BCLK_DIV_48  0x1e
+
+#define WM8900_ADC_CLKDIV_1   0x00
+#define WM8900_ADC_CLKDIV_1_5 0x20
+#define WM8900_ADC_CLKDIV_2   0x40
+#define WM8900_ADC_CLKDIV_3   0x60
+#define WM8900_ADC_CLKDIV_4   0x80
+#define WM8900_ADC_CLKDIV_5_5 0xa0
+#define WM8900_ADC_CLKDIV_6   0xc0
+
+#define WM8900_DAC_CLKDIV_1   0x00
+#define WM8900_DAC_CLKDIV_1_5 0x04
+#define WM8900_DAC_CLKDIV_2   0x08
+#define WM8900_DAC_CLKDIV_3   0x0c
+#define WM8900_DAC_CLKDIV_4   0x10
+#define WM8900_DAC_CLKDIV_5_5 0x14
+#define WM8900_DAC_CLKDIV_6   0x18
+
+#define WM8900_
+
+struct wm8900_setup_data {
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8900_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8900;
+
+#endif
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
new file mode 100644 (file)
index 0000000..a3f54ec
--- /dev/null
@@ -0,0 +1,1813 @@
+/*
+ * wm8903.c  --  WM8903 ALSA SoC Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * 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.
+ *
+ * TODO:
+ *  - TDM mode configuration.
+ *  - Mic detect.
+ *  - Digital microphone support.
+ *  - Interrupt support (mic detect and sequencer).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8903.h"
+
+struct wm8903_priv {
+       int sysclk;
+
+       /* Reference counts */
+       int charge_pump_users;
+       int class_w_users;
+       int playback_active;
+       int capture_active;
+
+       struct snd_pcm_substream *master_substream;
+       struct snd_pcm_substream *slave_substream;
+};
+
+/* Register defaults at reset */
+static u16 wm8903_reg_defaults[] = {
+       0x8903,     /* R0   - SW Reset and ID */
+       0x0000,     /* R1   - Revision Number */
+       0x0000,     /* R2 */
+       0x0000,     /* R3 */
+       0x0018,     /* R4   - Bias Control 0 */
+       0x0000,     /* R5   - VMID Control 0 */
+       0x0000,     /* R6   - Mic Bias Control 0 */
+       0x0000,     /* R7 */
+       0x0001,     /* R8   - Analogue DAC 0 */
+       0x0000,     /* R9 */
+       0x0001,     /* R10  - Analogue ADC 0 */
+       0x0000,     /* R11 */
+       0x0000,     /* R12  - Power Management 0 */
+       0x0000,     /* R13  - Power Management 1 */
+       0x0000,     /* R14  - Power Management 2 */
+       0x0000,     /* R15  - Power Management 3 */
+       0x0000,     /* R16  - Power Management 4 */
+       0x0000,     /* R17  - Power Management 5 */
+       0x0000,     /* R18  - Power Management 6 */
+       0x0000,     /* R19 */
+       0x0400,     /* R20  - Clock Rates 0 */
+       0x0D07,     /* R21  - Clock Rates 1 */
+       0x0000,     /* R22  - Clock Rates 2 */
+       0x0000,     /* R23 */
+       0x0050,     /* R24  - Audio Interface 0 */
+       0x0242,     /* R25  - Audio Interface 1 */
+       0x0008,     /* R26  - Audio Interface 2 */
+       0x0022,     /* R27  - Audio Interface 3 */
+       0x0000,     /* R28 */
+       0x0000,     /* R29 */
+       0x00C0,     /* R30  - DAC Digital Volume Left */
+       0x00C0,     /* R31  - DAC Digital Volume Right */
+       0x0000,     /* R32  - DAC Digital 0 */
+       0x0000,     /* R33  - DAC Digital 1 */
+       0x0000,     /* R34 */
+       0x0000,     /* R35 */
+       0x00C0,     /* R36  - ADC Digital Volume Left */
+       0x00C0,     /* R37  - ADC Digital Volume Right */
+       0x0000,     /* R38  - ADC Digital 0 */
+       0x0073,     /* R39  - Digital Microphone 0 */
+       0x09BF,     /* R40  - DRC 0 */
+       0x3241,     /* R41  - DRC 1 */
+       0x0020,     /* R42  - DRC 2 */
+       0x0000,     /* R43  - DRC 3 */
+       0x0085,     /* R44  - Analogue Left Input 0 */
+       0x0085,     /* R45  - Analogue Right Input 0 */
+       0x0044,     /* R46  - Analogue Left Input 1 */
+       0x0044,     /* R47  - Analogue Right Input 1 */
+       0x0000,     /* R48 */
+       0x0000,     /* R49 */
+       0x0008,     /* R50  - Analogue Left Mix 0 */
+       0x0004,     /* R51  - Analogue Right Mix 0 */
+       0x0000,     /* R52  - Analogue Spk Mix Left 0 */
+       0x0000,     /* R53  - Analogue Spk Mix Left 1 */
+       0x0000,     /* R54  - Analogue Spk Mix Right 0 */
+       0x0000,     /* R55  - Analogue Spk Mix Right 1 */
+       0x0000,     /* R56 */
+       0x002D,     /* R57  - Analogue OUT1 Left */
+       0x002D,     /* R58  - Analogue OUT1 Right */
+       0x0039,     /* R59  - Analogue OUT2 Left */
+       0x0039,     /* R60  - Analogue OUT2 Right */
+       0x0100,     /* R61 */
+       0x0139,     /* R62  - Analogue OUT3 Left */
+       0x0139,     /* R63  - Analogue OUT3 Right */
+       0x0000,     /* R64 */
+       0x0000,     /* R65  - Analogue SPK Output Control 0 */
+       0x0000,     /* R66 */
+       0x0010,     /* R67  - DC Servo 0 */
+       0x0100,     /* R68 */
+       0x00A4,     /* R69  - DC Servo 2 */
+       0x0807,     /* R70 */
+       0x0000,     /* R71 */
+       0x0000,     /* R72 */
+       0x0000,     /* R73 */
+       0x0000,     /* R74 */
+       0x0000,     /* R75 */
+       0x0000,     /* R76 */
+       0x0000,     /* R77 */
+       0x0000,     /* R78 */
+       0x000E,     /* R79 */
+       0x0000,     /* R80 */
+       0x0000,     /* R81 */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0006,     /* R87 */
+       0x0000,     /* R88 */
+       0x0000,     /* R89 */
+       0x0000,     /* R90  - Analogue HP 0 */
+       0x0060,     /* R91 */
+       0x0000,     /* R92 */
+       0x0000,     /* R93 */
+       0x0000,     /* R94  - Analogue Lineout 0 */
+       0x0060,     /* R95 */
+       0x0000,     /* R96 */
+       0x0000,     /* R97 */
+       0x0000,     /* R98  - Charge Pump 0 */
+       0x1F25,     /* R99 */
+       0x2B19,     /* R100 */
+       0x01C0,     /* R101 */
+       0x01EF,     /* R102 */
+       0x2B00,     /* R103 */
+       0x0000,     /* R104 - Class W 0 */
+       0x01C0,     /* R105 */
+       0x1C10,     /* R106 */
+       0x0000,     /* R107 */
+       0x0000,     /* R108 - Write Sequencer 0 */
+       0x0000,     /* R109 - Write Sequencer 1 */
+       0x0000,     /* R110 - Write Sequencer 2 */
+       0x0000,     /* R111 - Write Sequencer 3 */
+       0x0000,     /* R112 - Write Sequencer 4 */
+       0x0000,     /* R113 */
+       0x0000,     /* R114 - Control Interface */
+       0x0000,     /* R115 */
+       0x00A8,     /* R116 - GPIO Control 1 */
+       0x00A8,     /* R117 - GPIO Control 2 */
+       0x00A8,     /* R118 - GPIO Control 3 */
+       0x0220,     /* R119 - GPIO Control 4 */
+       0x01A0,     /* R120 - GPIO Control 5 */
+       0x0000,     /* R121 - Interrupt Status 1 */
+       0xFFFF,     /* R122 - Interrupt Status 1 Mask */
+       0x0000,     /* R123 - Interrupt Polarity 1 */
+       0x0000,     /* R124 */
+       0x0003,     /* R125 */
+       0x0000,     /* R126 - Interrupt Control */
+       0x0000,     /* R127 */
+       0x0005,     /* R128 */
+       0x0000,     /* R129 - Control Interface Test 1 */
+       0x0000,     /* R130 */
+       0x0000,     /* R131 */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 */
+       0x0000,     /* R134 */
+       0x03FF,     /* R135 */
+       0x0007,     /* R136 */
+       0x0040,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0000,     /* R140 */
+       0x0000,     /* R141 */
+       0x0000,     /* R142 */
+       0x0000,     /* R143 */
+       0x0000,     /* R144 */
+       0x0000,     /* R145 */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x4000,     /* R148 */
+       0x6810,     /* R149 - Charge Pump Test 1 */
+       0x0004,     /* R150 */
+       0x0000,     /* R151 */
+       0x0000,     /* R152 */
+       0x0000,     /* R153 */
+       0x0000,     /* R154 */
+       0x0000,     /* R155 */
+       0x0000,     /* R156 */
+       0x0000,     /* R157 */
+       0x0000,     /* R158 */
+       0x0000,     /* R159 */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 */
+       0x0028,     /* R164 - Clock Rate Test 4 */
+       0x0004,     /* R165 */
+       0x0000,     /* R166 */
+       0x0060,     /* R167 */
+       0x0000,     /* R168 */
+       0x0000,     /* R169 */
+       0x0000,     /* R170 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Analogue Output Bias 0 */
+};
+
+static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec,
+                                                unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
+
+       return cache[reg];
+}
+
+static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg)
+{
+       struct i2c_msg xfer[2];
+       u16 data;
+       int ret;
+       struct i2c_client *client = codec->control_data;
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 2;
+       xfer[1].buf = (u8 *)&data;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret != 2) {
+               pr_err("i2c_transfer returned %d\n", ret);
+               return 0;
+       }
+
+       return (data >> 8) | ((data & 0xff) << 8);
+}
+
+static unsigned int wm8903_read(struct snd_soc_codec *codec,
+                               unsigned int reg)
+{
+       switch (reg) {
+       case WM8903_SW_RESET_AND_ID:
+       case WM8903_REVISION_NUMBER:
+       case WM8903_INTERRUPT_STATUS_1:
+       case WM8903_WRITE_SEQUENCER_4:
+               return wm8903_hw_read(codec, reg);
+
+       default:
+               return wm8903_read_reg_cache(codec, reg);
+       }
+}
+
+static void wm8903_write_reg_cache(struct snd_soc_codec *codec,
+                                  u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+
+       BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
+
+       switch (reg) {
+       case WM8903_SW_RESET_AND_ID:
+       case WM8903_REVISION_NUMBER:
+               break;
+
+       default:
+               cache[reg] = value;
+               break;
+       }
+}
+
+static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg,
+                       unsigned int value)
+{
+       u8 data[3];
+
+       wm8903_write_reg_cache(codec, reg, value);
+
+       /* Data format is 1 byte of address followed by 2 bytes of data */
+       data[0] = reg;
+       data[1] = (value >> 8) & 0xff;
+       data[2] = value & 0xff;
+
+       if (codec->hw_write(codec->control_data, data, 3) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
+{
+       u16 reg[5];
+       struct i2c_client *i2c = codec->control_data;
+
+       BUG_ON(start > 48);
+
+       /* Enable the sequencer */
+       reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0);
+       reg[0] |= WM8903_WSEQ_ENA;
+       wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
+
+       dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
+
+       wm8903_write(codec, WM8903_WRITE_SEQUENCER_3,
+                    start | WM8903_WSEQ_START);
+
+       /* Wait for it to complete.  If we have the interrupt wired up then
+        * we could block waiting for an interrupt, though polling may still
+        * be desirable for diagnostic purposes.
+        */
+       do {
+               msleep(10);
+
+               reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4);
+       } while (reg[4] & WM8903_WSEQ_BUSY);
+
+       dev_dbg(&i2c->dev, "Sequence complete\n");
+
+       /* Disable the sequencer again */
+       wm8903_write(codec, WM8903_WRITE_SEQUENCER_0,
+                    reg[0] & ~WM8903_WSEQ_ENA);
+
+       return 0;
+}
+
+static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache)
+{
+       int i;
+
+       /* There really ought to be something better we can do here :/ */
+       for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
+               cache[i] = wm8903_hw_read(codec, i);
+}
+
+static void wm8903_reset(struct snd_soc_codec *codec)
+{
+       wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0);
+}
+
+#define WM8903_OUTPUT_SHORT 0x8
+#define WM8903_OUTPUT_OUT   0x4
+#define WM8903_OUTPUT_INT   0x2
+#define WM8903_OUTPUT_IN    0x1
+
+/*
+ * Event for headphone and line out amplifier power changes.  Special
+ * power up/down sequences are required in order to maximise pop/click
+ * performance.
+ */
+static int wm8903_output_event(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8903_priv *wm8903 = codec->private_data;
+       struct i2c_client *i2c = codec->control_data;
+       u16 val;
+       u16 reg;
+       int shift;
+       u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0);
+
+       switch (w->reg) {
+       case WM8903_POWER_MANAGEMENT_2:
+               reg = WM8903_ANALOGUE_HP_0;
+               break;
+       case WM8903_POWER_MANAGEMENT_3:
+               reg = WM8903_ANALOGUE_LINEOUT_0;
+               break;
+       default:
+               BUG();
+       }
+
+       switch (w->shift) {
+       case 0:
+               shift = 0;
+               break;
+       case 1:
+               shift = 4;
+               break;
+       default:
+               BUG();
+       }
+
+       if (event & SND_SOC_DAPM_PRE_PMU) {
+               val = wm8903_read(codec, reg);
+
+               /* Short the output */
+               val &= ~(WM8903_OUTPUT_SHORT << shift);
+               wm8903_write(codec, reg, val);
+
+               wm8903->charge_pump_users++;
+
+               dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
+                       wm8903->charge_pump_users);
+
+               if (wm8903->charge_pump_users == 1) {
+                       dev_dbg(&i2c->dev, "Enabling charge pump\n");
+                       wm8903_write(codec, WM8903_CHARGE_PUMP_0,
+                                    cp_reg | WM8903_CP_ENA);
+                       mdelay(4);
+               }
+       }
+
+       if (event & SND_SOC_DAPM_POST_PMU) {
+               val = wm8903_read(codec, reg);
+
+               val |= (WM8903_OUTPUT_IN << shift);
+               wm8903_write(codec, reg, val);
+
+               val |= (WM8903_OUTPUT_INT << shift);
+               wm8903_write(codec, reg, val);
+
+               /* Turn on the output ENA_OUTP */
+               val |= (WM8903_OUTPUT_OUT << shift);
+               wm8903_write(codec, reg, val);
+
+               /* Remove the short */
+               val |= (WM8903_OUTPUT_SHORT << shift);
+               wm8903_write(codec, reg, val);
+       }
+
+       if (event & SND_SOC_DAPM_PRE_PMD) {
+               val = wm8903_read(codec, reg);
+
+               /* Short the output */
+               val &= ~(WM8903_OUTPUT_SHORT << shift);
+               wm8903_write(codec, reg, val);
+
+               /* Then disable the intermediate and output stages */
+               val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
+                         WM8903_OUTPUT_IN) << shift);
+               wm8903_write(codec, reg, val);
+       }
+
+       if (event & SND_SOC_DAPM_POST_PMD) {
+               wm8903->charge_pump_users--;
+
+               dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
+                       wm8903->charge_pump_users);
+
+               if (wm8903->charge_pump_users == 0) {
+                       dev_dbg(&i2c->dev, "Disabling charge pump\n");
+                       wm8903_write(codec, WM8903_CHARGE_PUMP_0,
+                                    cp_reg & ~WM8903_CP_ENA);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * When used with DAC outputs only the WM8903 charge pump supports
+ * operation in class W mode, providing very low power consumption
+ * when used with digital sources.  Enable and disable this mode
+ * automatically depending on the mixer configuration.
+ *
+ * All the relevant controls are simple switches.
+ */
+static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = widget->codec;
+       struct wm8903_priv *wm8903 = codec->private_data;
+       struct i2c_client *i2c = codec->control_data;
+       u16 reg;
+       int ret;
+
+       reg = wm8903_read(codec, WM8903_CLASS_W_0);
+
+       /* Turn it off if we're about to enable bypass */
+       if (ucontrol->value.integer.value[0]) {
+               if (wm8903->class_w_users == 0) {
+                       dev_dbg(&i2c->dev, "Disabling Class W\n");
+                       wm8903_write(codec, WM8903_CLASS_W_0, reg &
+                                    ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
+               }
+               wm8903->class_w_users++;
+       }
+
+       /* Implement the change */
+       ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+       /* If we've just disabled the last bypass path turn Class W on */
+       if (!ucontrol->value.integer.value[0]) {
+               if (wm8903->class_w_users == 1) {
+                       dev_dbg(&i2c->dev, "Enabling Class W\n");
+                       wm8903_write(codec, WM8903_CLASS_W_0, reg |
+                                    WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
+               }
+               wm8903->class_w_users--;
+       }
+
+       dev_dbg(&i2c->dev, "Bypass use count now %d\n",
+               wm8903->class_w_users);
+
+       return ret;
+}
+
+#define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+
+/* ALSA can only do steps of .01dB */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_amp, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0);
+
+static const char *drc_slope_text[] = {
+       "1", "1/2", "1/4", "1/8", "1/16", "0"
+};
+
+static const struct soc_enum drc_slope_r0 =
+       SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text);
+
+static const struct soc_enum drc_slope_r1 =
+       SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text);
+
+static const char *drc_attack_text[] = {
+       "instantaneous",
+       "363us", "762us", "1.45ms", "2.9ms", "5.8ms", "11.6ms", "23.2ms",
+       "46.4ms", "92.8ms", "185.6ms"
+};
+
+static const struct soc_enum drc_attack =
+       SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text);
+
+static const char *drc_decay_text[] = {
+       "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
+       "23.87s", "47.56s"
+};
+
+static const struct soc_enum drc_decay =
+       SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text);
+
+static const char *drc_ff_delay_text[] = {
+       "5 samples", "9 samples"
+};
+
+static const struct soc_enum drc_ff_delay =
+       SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text);
+
+static const char *drc_qr_decay_text[] = {
+       "0.725ms", "1.45ms", "5.8ms"
+};
+
+static const struct soc_enum drc_qr_decay =
+       SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text);
+
+static const char *drc_smoothing_text[] = {
+       "Low", "Medium", "High"
+};
+
+static const struct soc_enum drc_smoothing =
+       SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text);
+
+static const char *soft_mute_text[] = {
+       "Fast (fs/2)", "Slow (fs/32)"
+};
+
+static const struct soc_enum soft_mute =
+       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text);
+
+static const char *mute_mode_text[] = {
+       "Hard", "Soft"
+};
+
+static const struct soc_enum mute_mode =
+       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
+
+static const char *dac_deemphasis_text[] = {
+       "Disabled", "32kHz", "44.1kHz", "48kHz"
+};
+
+static const struct soc_enum dac_deemphasis =
+       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text);
+
+static const char *companding_text[] = {
+       "ulaw", "alaw"
+};
+
+static const struct soc_enum dac_companding =
+       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text);
+
+static const struct soc_enum adc_companding =
+       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text);
+
+static const char *input_mode_text[] = {
+       "Single-Ended", "Differential Line", "Differential Mic"
+};
+
+static const struct soc_enum linput_mode_enum =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+
+static const struct soc_enum rinput_mode_enum =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+
+static const char *linput_mux_text[] = {
+       "IN1L", "IN2L", "IN3L"
+};
+
+static const struct soc_enum linput_enum =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text);
+
+static const struct soc_enum linput_inv_enum =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text);
+
+static const char *rinput_mux_text[] = {
+       "IN1R", "IN2R", "IN3R"
+};
+
+static const struct soc_enum rinput_enum =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text);
+
+static const struct soc_enum rinput_inv_enum =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
+
+
+static const struct snd_kcontrol_new wm8903_snd_controls[] = {
+
+/* Input PGAs - No TLV since the scale depends on PGA mode */
+SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
+          7, 1, 0),
+SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
+          0, 31, 0),
+SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
+          6, 1, 0),
+
+SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
+          7, 1, 0),
+SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
+          0, 31, 0),
+SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
+          6, 1, 0),
+
+/* ADCs */
+SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0),
+SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0),
+SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1),
+SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1,
+              drc_tlv_thresh),
+SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp),
+SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min),
+SOC_SINGLE_TLV("DRC Maximum Gain Volume", WM8903_DRC_1, 0, 3, 0, drc_tlv_max),
+SOC_ENUM("DRC Attack Rate", drc_attack),
+SOC_ENUM("DRC Decay Rate", drc_decay),
+SOC_ENUM("DRC FF Delay", drc_ff_delay),
+SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0),
+SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0),
+SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max),
+SOC_ENUM("DRC QR Decay Rate", drc_qr_decay),
+SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0),
+SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0),
+SOC_ENUM("DRC Smoothing Threashold", drc_smoothing),
+SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
+                WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+SOC_ENUM("ADC Companding Mode", adc_companding),
+SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
+
+/* DAC */
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
+                WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
+SOC_ENUM("DAC Soft Mute Rate", soft_mute),
+SOC_ENUM("DAC Mute Mode", mute_mode),
+SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
+SOC_ENUM("DAC De-emphasis", dac_deemphasis),
+SOC_SINGLE("DAC Sloping Stopband Filter Switch",
+          WM8903_DAC_DIGITAL_1, 11, 1, 0),
+SOC_ENUM("DAC Companding Mode", dac_companding),
+SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+
+/* Headphones */
+SOC_DOUBLE_R("Headphone Switch",
+            WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+            8, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch",
+            WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+            6, 1, 0),
+SOC_DOUBLE_R_TLV("Headphone Volume",
+                WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+                0, 63, 0, out_tlv),
+
+/* Line out */
+SOC_DOUBLE_R("Line Out Switch",
+            WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+            8, 1, 1),
+SOC_DOUBLE_R("Line Out ZC Switch",
+            WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+            6, 1, 0),
+SOC_DOUBLE_R_TLV("Line Out Volume",
+                WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+                0, 63, 0, out_tlv),
+
+/* Speaker */
+SOC_DOUBLE_R("Speaker Switch",
+            WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch",
+            WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 6, 1, 0),
+SOC_DOUBLE_R_TLV("Speaker Volume",
+                WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT,
+                0, 63, 0, out_tlv),
+};
+
+static int wm8903_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&wm8903_snd_controls[i],
+                                              codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new linput_mode_mux =
+       SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum);
+
+static const struct snd_kcontrol_new rinput_mode_mux =
+       SOC_DAPM_ENUM("Right Input Mode Mux", rinput_mode_enum);
+
+static const struct snd_kcontrol_new linput_mux =
+       SOC_DAPM_ENUM("Left Input Mux", linput_enum);
+
+static const struct snd_kcontrol_new linput_inv_mux =
+       SOC_DAPM_ENUM("Left Inverting Input Mux", linput_inv_enum);
+
+static const struct snd_kcontrol_new rinput_mux =
+       SOC_DAPM_ENUM("Right Input Mux", rinput_enum);
+
+static const struct snd_kcontrol_new rinput_inv_mux =
+       SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
+
+static const struct snd_kcontrol_new left_output_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
+SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0),
+SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0,
+               1, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
+               1, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
+               1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8903_MIC_BIAS_CONTROL_0, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux),
+SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0,
+                &linput_inv_mux),
+SND_SOC_DAPM_MUX("Left Input Mode Mux", SND_SOC_NOPM, 0, 0, &linput_mode_mux),
+
+SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &rinput_mux),
+SND_SOC_DAPM_MUX("Right Input Inverting Mux", SND_SOC_NOPM, 0, 0,
+                &rinput_inv_mux),
+SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
+
+SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0,
+                  left_output_mixer, ARRAY_SIZE(left_output_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8903_POWER_MANAGEMENT_1, 0, 0,
+                  right_output_mixer, ARRAY_SIZE(right_output_mixer)),
+
+SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
+                  left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
+                  right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+
+SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
+                  1, 0, NULL, 0, wm8903_output_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
+                  0, 0, NULL, 0, wm8903_output_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0,
+                  NULL, 0, wm8903_output_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0,
+                  NULL, 0, wm8903_output_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
+                NULL, 0),
+
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+
+       { "Left Input Mux", "IN1L", "IN1L" },
+       { "Left Input Mux", "IN2L", "IN2L" },
+       { "Left Input Mux", "IN3L", "IN3L" },
+
+       { "Left Input Inverting Mux", "IN1L", "IN1L" },
+       { "Left Input Inverting Mux", "IN2L", "IN2L" },
+       { "Left Input Inverting Mux", "IN3L", "IN3L" },
+
+       { "Right Input Mux", "IN1R", "IN1R" },
+       { "Right Input Mux", "IN2R", "IN2R" },
+       { "Right Input Mux", "IN3R", "IN3R" },
+
+       { "Right Input Inverting Mux", "IN1R", "IN1R" },
+       { "Right Input Inverting Mux", "IN2R", "IN2R" },
+       { "Right Input Inverting Mux", "IN3R", "IN3R" },
+
+       { "Left Input Mode Mux", "Single-Ended", "Left Input Inverting Mux" },
+       { "Left Input Mode Mux", "Differential Line",
+         "Left Input Mux" },
+       { "Left Input Mode Mux", "Differential Line",
+         "Left Input Inverting Mux" },
+       { "Left Input Mode Mux", "Differential Mic",
+         "Left Input Mux" },
+       { "Left Input Mode Mux", "Differential Mic",
+         "Left Input Inverting Mux" },
+
+       { "Right Input Mode Mux", "Single-Ended",
+         "Right Input Inverting Mux" },
+       { "Right Input Mode Mux", "Differential Line",
+         "Right Input Mux" },
+       { "Right Input Mode Mux", "Differential Line",
+         "Right Input Inverting Mux" },
+       { "Right Input Mode Mux", "Differential Mic",
+         "Right Input Mux" },
+       { "Right Input Mode Mux", "Differential Mic",
+         "Right Input Inverting Mux" },
+
+       { "Left Input PGA", NULL, "Left Input Mode Mux" },
+       { "Right Input PGA", NULL, "Right Input Mode Mux" },
+
+       { "ADCL", NULL, "Left Input PGA" },
+       { "ADCR", NULL, "Right Input PGA" },
+
+       { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
+       { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
+       { "Left Output Mixer", "DACL Switch", "DACL" },
+       { "Left Output Mixer", "DACR Switch", "DACR" },
+
+       { "Right Output Mixer", "Left Bypass Switch", "Left Input PGA" },
+       { "Right Output Mixer", "Right Bypass Switch", "Right Input PGA" },
+       { "Right Output Mixer", "DACL Switch", "DACL" },
+       { "Right Output Mixer", "DACR Switch", "DACR" },
+
+       { "Left Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
+       { "Left Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
+       { "Left Speaker Mixer", "DACL Switch", "DACL" },
+       { "Left Speaker Mixer", "DACR Switch", "DACR" },
+
+       { "Right Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
+       { "Right Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
+       { "Right Speaker Mixer", "DACL Switch", "DACL" },
+       { "Right Speaker Mixer", "DACR Switch", "DACR" },
+
+       { "Left Line Output PGA", NULL, "Left Output Mixer" },
+       { "Right Line Output PGA", NULL, "Right Output Mixer" },
+
+       { "Left Headphone Output PGA", NULL, "Left Output Mixer" },
+       { "Right Headphone Output PGA", NULL, "Right Output Mixer" },
+
+       { "Left Speaker PGA", NULL, "Left Speaker Mixer" },
+       { "Right Speaker PGA", NULL, "Right Speaker Mixer" },
+
+       { "HPOUTL", NULL, "Left Headphone Output PGA" },
+       { "HPOUTR", NULL, "Right Headphone Output PGA" },
+
+       { "LINEOUTL", NULL, "Left Line Output PGA" },
+       { "LINEOUTR", NULL, "Right Line Output PGA" },
+
+       { "LOP", NULL, "Left Speaker PGA" },
+       { "LON", NULL, "Left Speaker PGA" },
+
+       { "ROP", NULL, "Right Speaker PGA" },
+       { "RON", NULL, "Right Speaker PGA" },
+};
+
+static int wm8903_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8903_dapm_widgets,
+                                 ARRAY_SIZE(wm8903_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       snd_soc_dapm_new_widgets(codec);
+
+       return 0;
+}
+
+static int wm8903_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct i2c_client *i2c = codec->control_data;
+       u16 reg, reg2;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               reg = wm8903_read(codec, WM8903_VMID_CONTROL_0);
+               reg &= ~(WM8903_VMID_RES_MASK);
+               reg |= WM8903_VMID_RES_50K;
+               wm8903_write(codec, WM8903_VMID_CONTROL_0, reg);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       wm8903_run_sequence(codec, 0);
+                       wm8903_sync_reg_cache(codec, codec->reg_cache);
+
+                       /* Enable low impedence charge pump output */
+                       reg = wm8903_read(codec,
+                                         WM8903_CONTROL_INTERFACE_TEST_1);
+                       wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
+                                    reg | WM8903_TEST_KEY);
+                       reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1);
+                       wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1,
+                                    reg2 | WM8903_CP_SW_KELVIN_MODE_MASK);
+                       wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
+                                    reg);
+
+                       /* By default no bypass paths are enabled so
+                        * enable Class W support.
+                        */
+                       dev_dbg(&i2c->dev, "Enabling Class W\n");
+                       wm8903_write(codec, WM8903_CLASS_W_0, reg |
+                                    WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
+               }
+
+               reg = wm8903_read(codec, WM8903_VMID_CONTROL_0);
+               reg &= ~(WM8903_VMID_RES_MASK);
+               reg |= WM8903_VMID_RES_250K;
+               wm8903_write(codec, WM8903_VMID_CONTROL_0, reg);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               wm8903_run_sequence(codec, 32);
+               break;
+       }
+
+       codec->bias_level = level;
+
+       return 0;
+}
+
+static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8903_priv *wm8903 = codec->private_data;
+
+       wm8903->sysclk = freq;
+
+       return 0;
+}
+
+static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1);
+
+       aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
+                 WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               aif1 |= WM8903_LRCLK_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               aif1 |= WM8903_BCLK_DIR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               aif1 |= 0x3;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aif1 |= 0x3 | WM8903_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif1 |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               aif1 |= 0x1;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8903_AIF_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif1 |= WM8903_AIF_BCLK_INV | WM8903_AIF_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8903_AIF_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif1 |= WM8903_AIF_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+
+       return 0;
+}
+
+static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+
+       if (mute)
+               reg |= WM8903_DAC_MUTE;
+       else
+               reg &= ~WM8903_DAC_MUTE;
+
+       wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg);
+
+       return 0;
+}
+
+/* Lookup table for CLK_SYS/fs ratio.  256fs or more is recommended
+ * for optimal performance so we list the lower rates first and match
+ * on the last match we find. */
+static struct {
+       int div;
+       int rate;
+       int mode;
+       int mclk_div;
+} clk_sys_ratios[] = {
+       {   64, 0x0, 0x0, 1 },
+       {   68, 0x0, 0x1, 1 },
+       {  125, 0x0, 0x2, 1 },
+       {  128, 0x1, 0x0, 1 },
+       {  136, 0x1, 0x1, 1 },
+       {  192, 0x2, 0x0, 1 },
+       {  204, 0x2, 0x1, 1 },
+
+       {   64, 0x0, 0x0, 2 },
+       {   68, 0x0, 0x1, 2 },
+       {  125, 0x0, 0x2, 2 },
+       {  128, 0x1, 0x0, 2 },
+       {  136, 0x1, 0x1, 2 },
+       {  192, 0x2, 0x0, 2 },
+       {  204, 0x2, 0x1, 2 },
+
+       {  250, 0x2, 0x2, 1 },
+       {  256, 0x3, 0x0, 1 },
+       {  272, 0x3, 0x1, 1 },
+       {  384, 0x4, 0x0, 1 },
+       {  408, 0x4, 0x1, 1 },
+       {  375, 0x4, 0x2, 1 },
+       {  512, 0x5, 0x0, 1 },
+       {  544, 0x5, 0x1, 1 },
+       {  500, 0x5, 0x2, 1 },
+       {  768, 0x6, 0x0, 1 },
+       {  816, 0x6, 0x1, 1 },
+       {  750, 0x6, 0x2, 1 },
+       { 1024, 0x7, 0x0, 1 },
+       { 1088, 0x7, 0x1, 1 },
+       { 1000, 0x7, 0x2, 1 },
+       { 1408, 0x8, 0x0, 1 },
+       { 1496, 0x8, 0x1, 1 },
+       { 1536, 0x9, 0x0, 1 },
+       { 1632, 0x9, 0x1, 1 },
+       { 1500, 0x9, 0x2, 1 },
+
+       {  250, 0x2, 0x2, 2 },
+       {  256, 0x3, 0x0, 2 },
+       {  272, 0x3, 0x1, 2 },
+       {  384, 0x4, 0x0, 2 },
+       {  408, 0x4, 0x1, 2 },
+       {  375, 0x4, 0x2, 2 },
+       {  512, 0x5, 0x0, 2 },
+       {  544, 0x5, 0x1, 2 },
+       {  500, 0x5, 0x2, 2 },
+       {  768, 0x6, 0x0, 2 },
+       {  816, 0x6, 0x1, 2 },
+       {  750, 0x6, 0x2, 2 },
+       { 1024, 0x7, 0x0, 2 },
+       { 1088, 0x7, 0x1, 2 },
+       { 1000, 0x7, 0x2, 2 },
+       { 1408, 0x8, 0x0, 2 },
+       { 1496, 0x8, 0x1, 2 },
+       { 1536, 0x9, 0x0, 2 },
+       { 1632, 0x9, 0x1, 2 },
+       { 1500, 0x9, 0x2, 2 },
+};
+
+/* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */
+static struct {
+       int ratio;
+       int div;
+} bclk_divs[] = {
+       {  10,  0 },
+       {  15,  1 },
+       {  20,  2 },
+       {  30,  3 },
+       {  40,  4 },
+       {  50,  5 },
+       {  55,  6 },
+       {  60,  7 },
+       {  80,  8 },
+       { 100,  9 },
+       { 110, 10 },
+       { 120, 11 },
+       { 160, 12 },
+       { 200, 13 },
+       { 220, 14 },
+       { 240, 15 },
+       { 250, 16 },
+       { 300, 17 },
+       { 320, 18 },
+       { 440, 19 },
+       { 480, 20 },
+};
+
+/* Sample rates for DSP */
+static struct {
+       int rate;
+       int value;
+} sample_rates[] = {
+       {  8000,  0 },
+       { 11025,  1 },
+       { 12000,  2 },
+       { 16000,  3 },
+       { 22050,  4 },
+       { 24000,  5 },
+       { 32000,  6 },
+       { 44100,  7 },
+       { 48000,  8 },
+       { 88200,  9 },
+       { 96000, 10 },
+       { 0,      0 },
+};
+
+static int wm8903_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8903_priv *wm8903 = codec->private_data;
+       struct i2c_client *i2c = codec->control_data;
+       struct snd_pcm_runtime *master_runtime;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               wm8903->playback_active++;
+       else
+               wm8903->capture_active++;
+
+       /* The DAI has shared clocks so if we already have a playback or
+        * capture going then constrain this substream to match it.
+        */
+       if (wm8903->master_substream) {
+               master_runtime = wm8903->master_substream->runtime;
+
+               dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
+                       master_runtime->sample_bits,
+                       master_runtime->rate);
+
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_RATE,
+                                            master_runtime->rate,
+                                            master_runtime->rate);
+
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                            master_runtime->sample_bits,
+                                            master_runtime->sample_bits);
+
+               wm8903->slave_substream = substream;
+       } else
+               wm8903->master_substream = substream;
+
+       return 0;
+}
+
+static void wm8903_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8903_priv *wm8903 = codec->private_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               wm8903->playback_active--;
+       else
+               wm8903->capture_active--;
+
+       if (wm8903->master_substream == substream)
+               wm8903->master_substream = wm8903->slave_substream;
+
+       wm8903->slave_substream = NULL;
+}
+
+static int wm8903_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8903_priv *wm8903 = codec->private_data;
+       struct i2c_client *i2c = codec->control_data;
+       int fs = params_rate(params);
+       int bclk;
+       int bclk_div;
+       int i;
+       int dsp_config;
+       int clk_config;
+       int best_val;
+       int cur_val;
+       int clk_sys;
+
+       u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1);
+       u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2);
+       u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3);
+       u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0);
+       u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1);
+
+       if (substream == wm8903->slave_substream) {
+               dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+               return 0;
+       }
+
+       /* Configure sample rate logic for DSP - choose nearest rate */
+       dsp_config = 0;
+       best_val = abs(sample_rates[dsp_config].rate - fs);
+       for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+               cur_val = abs(sample_rates[i].rate - fs);
+               if (cur_val <= best_val) {
+                       dsp_config = i;
+                       best_val = cur_val;
+               }
+       }
+
+       /* Constraints should stop us hitting this but let's make sure */
+       if (wm8903->capture_active)
+               switch (sample_rates[dsp_config].rate) {
+               case 88200:
+               case 96000:
+                       dev_err(&i2c->dev, "%dHz unsupported by ADC\n",
+                               fs);
+                       return -EINVAL;
+
+               default:
+                       break;
+               }
+
+       dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+       clock1 &= ~WM8903_SAMPLE_RATE_MASK;
+       clock1 |= sample_rates[dsp_config].value;
+
+       aif1 &= ~WM8903_AIF_WL_MASK;
+       bclk = 2 * fs;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bclk *= 16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               bclk *= 20;
+               aif1 |= 0x4;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               bclk *= 24;
+               aif1 |= 0x8;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               bclk *= 32;
+               aif1 |= 0xc;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+               wm8903->sysclk, fs);
+
+       /* We may not have an MCLK which allows us to generate exactly
+        * the clock we want, particularly with USB derived inputs, so
+        * approximate.
+        */
+       clk_config = 0;
+       best_val = abs((wm8903->sysclk /
+                       (clk_sys_ratios[0].mclk_div *
+                        clk_sys_ratios[0].div)) - fs);
+       for (i = 1; i < ARRAY_SIZE(clk_sys_ratios); i++) {
+               cur_val = abs((wm8903->sysclk /
+                              (clk_sys_ratios[i].mclk_div *
+                               clk_sys_ratios[i].div)) - fs);
+
+               if (cur_val <= best_val) {
+                       clk_config = i;
+                       best_val = cur_val;
+               }
+       }
+
+       if (clk_sys_ratios[clk_config].mclk_div == 2) {
+               clock0 |= WM8903_MCLKDIV2;
+               clk_sys = wm8903->sysclk / 2;
+       } else {
+               clock0 &= ~WM8903_MCLKDIV2;
+               clk_sys = wm8903->sysclk;
+       }
+
+       clock1 &= ~(WM8903_CLK_SYS_RATE_MASK |
+                   WM8903_CLK_SYS_MODE_MASK);
+       clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
+       clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
+
+       dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+               clk_sys_ratios[clk_config].rate,
+               clk_sys_ratios[clk_config].mode,
+               clk_sys_ratios[clk_config].div);
+
+       dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+
+       /* We may not get quite the right frequency if using
+        * approximate clocks so look for the closest match that is
+        * higher than the target (we need to ensure that there enough
+        * BCLKs to clock out the samples).
+        */
+       bclk_div = 0;
+       best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk;
+       i = 1;
+       while (i < ARRAY_SIZE(bclk_divs)) {
+               cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk;
+               if (cur_val < 0) /* BCLK table is sorted */
+                       break;
+               bclk_div = i;
+               best_val = cur_val;
+               i++;
+       }
+
+       aif2 &= ~WM8903_BCLK_DIV_MASK;
+       aif3 &= ~WM8903_LRCLK_RATE_MASK;
+
+       dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+               bclk_divs[bclk_div].ratio / 10, bclk,
+               (clk_sys * 10) / bclk_divs[bclk_div].ratio);
+
+       aif2 |= bclk_divs[bclk_div].div;
+       aif3 |= bclk / fs;
+
+       wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0);
+       wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1);
+       wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+       wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
+       wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
+
+       return 0;
+}
+
+#define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
+                              SNDRV_PCM_RATE_11025 |   \
+                              SNDRV_PCM_RATE_16000 |   \
+                              SNDRV_PCM_RATE_22050 |   \
+                              SNDRV_PCM_RATE_32000 |   \
+                              SNDRV_PCM_RATE_44100 |   \
+                              SNDRV_PCM_RATE_48000 |   \
+                              SNDRV_PCM_RATE_88200 |   \
+                              SNDRV_PCM_RATE_96000)
+
+#define WM8903_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+                             SNDRV_PCM_RATE_11025 |    \
+                             SNDRV_PCM_RATE_16000 |    \
+                             SNDRV_PCM_RATE_22050 |    \
+                             SNDRV_PCM_RATE_32000 |    \
+                             SNDRV_PCM_RATE_44100 |    \
+                             SNDRV_PCM_RATE_48000)
+
+#define WM8903_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8903_dai = {
+       .name = "WM8903",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8903_PLAYBACK_RATES,
+               .formats = WM8903_FORMATS,
+       },
+       .capture = {
+                .stream_name = "Capture",
+                .channels_min = 2,
+                .channels_max = 2,
+                .rates = WM8903_CAPTURE_RATES,
+                .formats = WM8903_FORMATS,
+        },
+       .ops = {
+                .startup = wm8903_startup,
+                .shutdown = wm8903_shutdown,
+                .hw_params = wm8903_hw_params,
+       },
+       .dai_ops = {
+                .digital_mute = wm8903_digital_mute,
+                .set_fmt = wm8903_set_dai_fmt,
+                .set_sysclk = wm8903_set_dai_sysclk
+       }
+};
+EXPORT_SYMBOL_GPL(wm8903_dai);
+
+static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8903_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c = codec->control_data;
+       int i;
+       u16 *reg_cache = codec->reg_cache;
+       u16 *tmp_cache = kmemdup(codec->reg_cache, sizeof(wm8903_reg_defaults),
+                                GFP_KERNEL);
+
+       /* Bring the codec back up to standby first to minimise pop/clicks */
+       wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8903_set_bias_level(codec, codec->suspend_bias_level);
+
+       /* Sync back everything else */
+       if (tmp_cache) {
+               for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
+                       if (tmp_cache[i] != reg_cache[i])
+                               wm8903_write(codec, i, tmp_cache[i]);
+       } else {
+               dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
+       }
+
+       return 0;
+}
+
+/*
+ * initialise the WM8903 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8903_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c = codec->control_data;
+       int ret = 0;
+       u16 val;
+
+       val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID);
+       if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %x is not a WM8903\n", val);
+               return -ENODEV;
+       }
+
+       codec->name = "WM8903";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8903_read;
+       codec->write = wm8903_write;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8903_set_bias_level;
+       codec->dai = &wm8903_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults);
+       codec->reg_cache = kmemdup(wm8903_reg_defaults,
+                                  sizeof(wm8903_reg_defaults),
+                                  GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               dev_err(&i2c->dev, "Failed to allocate register cache\n");
+               return -ENOMEM;
+       }
+
+       val = wm8903_read(codec, WM8903_REVISION_NUMBER);
+       dev_info(&i2c->dev, "WM8903 revision %d\n",
+                val & WM8903_CHIP_REV_MASK);
+
+       wm8903_reset(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* SYSCLK is required for pretty much anything */
+       wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA);
+
+       /* power on device */
+       wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch volume update bits */
+       val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
+       val |= WM8903_ADCVU;
+       wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
+       wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
+
+       val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
+       val |= WM8903_DACVU;
+       wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
+       wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
+
+       val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
+       val |= WM8903_HPOUTVU;
+       wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
+       wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
+
+       val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
+       val |= WM8903_LINEOUTVU;
+       wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
+       wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
+
+       val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
+       val |= WM8903_SPKVU;
+       wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
+       wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
+
+       /* Enable DAC soft mute by default */
+       val = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+       val |= WM8903_DAC_MUTEMODE;
+       wm8903_write(codec, WM8903_DAC_DIGITAL_1, val);
+
+       wm8903_add_controls(codec);
+       wm8903_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "wm8903: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+static struct snd_soc_device *wm8903_socdev;
+
+static int wm8903_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct snd_soc_device *socdev = wm8903_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = wm8903_init(socdev);
+       if (ret < 0)
+               dev_err(&i2c->dev, "Device initialisation failed\n");
+
+       return ret;
+}
+
+static int wm8903_i2c_remove(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       kfree(codec->reg_cache);
+       return 0;
+}
+
+/* i2c codec control layer */
+static const struct i2c_device_id wm8903_i2c_id[] = {
+       { "wm8903", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
+
+static struct i2c_driver wm8903_i2c_driver = {
+       .driver = {
+               .name = "WM8903",
+               .owner = THIS_MODULE,
+       },
+       .probe    = wm8903_i2c_probe,
+       .remove   = wm8903_i2c_remove,
+       .id_table = wm8903_i2c_id,
+};
+
+static int wm8903_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct wm8903_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct wm8903_priv *wm8903;
+       struct i2c_board_info board_info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *i2c_client;
+       int ret = 0;
+
+       setup = socdev->codec_data;
+
+       if (!setup->i2c_address) {
+               dev_err(&pdev->dev, "No codec address provided\n");
+               return -ENODEV;
+       }
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+       if (wm8903 == NULL) {
+               ret = -ENOMEM;
+               goto err_codec;
+       }
+
+       codec->private_data = wm8903;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       wm8903_socdev = socdev;
+
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       ret = i2c_add_driver(&wm8903_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               goto err_priv;
+       } else {
+               memset(&board_info, 0, sizeof(board_info));
+               strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE);
+               board_info.addr = setup->i2c_address;
+
+               adapter = i2c_get_adapter(setup->i2c_bus);
+               if (!adapter) {
+                       dev_err(&pdev->dev, "Can't get I2C bus %d\n",
+                               setup->i2c_bus);
+                       ret = -ENODEV;
+                       goto err_adapter;
+               }
+
+               i2c_client = i2c_new_device(adapter, &board_info);
+               i2c_put_adapter(adapter);
+               if (i2c_client == NULL) {
+                       dev_err(&pdev->dev,
+                               "I2C driver registration failed\n");
+                       ret = -ENODEV;
+                       goto err_adapter;
+               }
+       }
+
+       return ret;
+
+err_adapter:
+       i2c_del_driver(&wm8903_i2c_driver);
+err_priv:
+       kfree(codec->private_data);
+err_codec:
+       kfree(codec);
+       return ret;
+}
+
+/* power down chip */
+static int wm8903_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+       i2c_unregister_device(socdev->codec->control_data);
+       i2c_del_driver(&wm8903_i2c_driver);
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8903 = {
+       .probe =        wm8903_probe,
+       .remove =       wm8903_remove,
+       .suspend =      wm8903_suspend,
+       .resume =       wm8903_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
+
+MODULE_DESCRIPTION("ASoC WM8903 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
new file mode 100644 (file)
index 0000000..cec622f
--- /dev/null
@@ -0,0 +1,1463 @@
+/*
+ * wm8903.h - WM8903 audio codec interface
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ */
+
+#ifndef _WM8903_H
+#define _WM8903_H
+
+#include <linux/i2c.h>
+
+extern struct snd_soc_dai wm8903_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8903;
+
+struct wm8903_setup_data {
+       int i2c_bus;
+       int i2c_address;
+};
+
+#define WM8903_MCLK_DIV_2 1
+#define WM8903_CLK_SYS    2
+#define WM8903_BCLK       3
+#define WM8903_LRCLK      4
+
+/*
+ * Register values.
+ */
+#define WM8903_SW_RESET_AND_ID                  0x00
+#define WM8903_REVISION_NUMBER                  0x01
+#define WM8903_BIAS_CONTROL_0                   0x04
+#define WM8903_VMID_CONTROL_0                   0x05
+#define WM8903_MIC_BIAS_CONTROL_0               0x06
+#define WM8903_ANALOGUE_DAC_0                   0x08
+#define WM8903_ANALOGUE_ADC_0                   0x0A
+#define WM8903_POWER_MANAGEMENT_0               0x0C
+#define WM8903_POWER_MANAGEMENT_1               0x0D
+#define WM8903_POWER_MANAGEMENT_2               0x0E
+#define WM8903_POWER_MANAGEMENT_3               0x0F
+#define WM8903_POWER_MANAGEMENT_4               0x10
+#define WM8903_POWER_MANAGEMENT_5               0x11
+#define WM8903_POWER_MANAGEMENT_6               0x12
+#define WM8903_CLOCK_RATES_0                    0x14
+#define WM8903_CLOCK_RATES_1                    0x15
+#define WM8903_CLOCK_RATES_2                    0x16
+#define WM8903_AUDIO_INTERFACE_0                0x18
+#define WM8903_AUDIO_INTERFACE_1                0x19
+#define WM8903_AUDIO_INTERFACE_2                0x1A
+#define WM8903_AUDIO_INTERFACE_3                0x1B
+#define WM8903_DAC_DIGITAL_VOLUME_LEFT          0x1E
+#define WM8903_DAC_DIGITAL_VOLUME_RIGHT         0x1F
+#define WM8903_DAC_DIGITAL_0                    0x20
+#define WM8903_DAC_DIGITAL_1                    0x21
+#define WM8903_ADC_DIGITAL_VOLUME_LEFT          0x24
+#define WM8903_ADC_DIGITAL_VOLUME_RIGHT         0x25
+#define WM8903_ADC_DIGITAL_0                    0x26
+#define WM8903_DIGITAL_MICROPHONE_0             0x27
+#define WM8903_DRC_0                            0x28
+#define WM8903_DRC_1                            0x29
+#define WM8903_DRC_2                            0x2A
+#define WM8903_DRC_3                            0x2B
+#define WM8903_ANALOGUE_LEFT_INPUT_0            0x2C
+#define WM8903_ANALOGUE_RIGHT_INPUT_0           0x2D
+#define WM8903_ANALOGUE_LEFT_INPUT_1            0x2E
+#define WM8903_ANALOGUE_RIGHT_INPUT_1           0x2F
+#define WM8903_ANALOGUE_LEFT_MIX_0              0x32
+#define WM8903_ANALOGUE_RIGHT_MIX_0             0x33
+#define WM8903_ANALOGUE_SPK_MIX_LEFT_0          0x34
+#define WM8903_ANALOGUE_SPK_MIX_LEFT_1          0x35
+#define WM8903_ANALOGUE_SPK_MIX_RIGHT_0         0x36
+#define WM8903_ANALOGUE_SPK_MIX_RIGHT_1         0x37
+#define WM8903_ANALOGUE_OUT1_LEFT               0x39
+#define WM8903_ANALOGUE_OUT1_RIGHT              0x3A
+#define WM8903_ANALOGUE_OUT2_LEFT               0x3B
+#define WM8903_ANALOGUE_OUT2_RIGHT              0x3C
+#define WM8903_ANALOGUE_OUT3_LEFT               0x3E
+#define WM8903_ANALOGUE_OUT3_RIGHT              0x3F
+#define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0    0x41
+#define WM8903_DC_SERVO_0                       0x43
+#define WM8903_DC_SERVO_2                       0x45
+#define WM8903_ANALOGUE_HP_0                    0x5A
+#define WM8903_ANALOGUE_LINEOUT_0               0x5E
+#define WM8903_CHARGE_PUMP_0                    0x62
+#define WM8903_CLASS_W_0                        0x68
+#define WM8903_WRITE_SEQUENCER_0                0x6C
+#define WM8903_WRITE_SEQUENCER_1                0x6D
+#define WM8903_WRITE_SEQUENCER_2                0x6E
+#define WM8903_WRITE_SEQUENCER_3                0x6F
+#define WM8903_WRITE_SEQUENCER_4                0x70
+#define WM8903_CONTROL_INTERFACE                0x72
+#define WM8903_GPIO_CONTROL_1                   0x74
+#define WM8903_GPIO_CONTROL_2                   0x75
+#define WM8903_GPIO_CONTROL_3                   0x76
+#define WM8903_GPIO_CONTROL_4                   0x77
+#define WM8903_GPIO_CONTROL_5                   0x78
+#define WM8903_INTERRUPT_STATUS_1               0x79
+#define WM8903_INTERRUPT_STATUS_1_MASK          0x7A
+#define WM8903_INTERRUPT_POLARITY_1             0x7B
+#define WM8903_INTERRUPT_CONTROL                0x7E
+#define WM8903_CONTROL_INTERFACE_TEST_1         0x81
+#define WM8903_CHARGE_PUMP_TEST_1               0x95
+#define WM8903_CLOCK_RATE_TEST_4                0xA4
+#define WM8903_ANALOGUE_OUTPUT_BIAS_0           0xAC
+
+#define WM8903_REGISTER_COUNT                   75
+#define WM8903_MAX_REGISTER                     0xAC
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - SW Reset and ID
+ */
+#define WM8903_SW_RESET_DEV_ID1_MASK            0xFFFF  /* SW_RESET_DEV_ID1 - [15:0] */
+#define WM8903_SW_RESET_DEV_ID1_SHIFT                0  /* SW_RESET_DEV_ID1 - [15:0] */
+#define WM8903_SW_RESET_DEV_ID1_WIDTH               16  /* SW_RESET_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Revision Number
+ */
+#define WM8903_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8903_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8903_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R4 (0x04) - Bias Control 0
+ */
+#define WM8903_POBCTRL                          0x0010  /* POBCTRL */
+#define WM8903_POBCTRL_MASK                     0x0010  /* POBCTRL */
+#define WM8903_POBCTRL_SHIFT                         4  /* POBCTRL */
+#define WM8903_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8903_ISEL_MASK                        0x000C  /* ISEL - [3:2] */
+#define WM8903_ISEL_SHIFT                            2  /* ISEL - [3:2] */
+#define WM8903_ISEL_WIDTH                            2  /* ISEL - [3:2] */
+#define WM8903_STARTUP_BIAS_ENA                 0x0002  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_MASK            0x0002  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_SHIFT                1  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8903_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R5 (0x05) - VMID Control 0
+ */
+#define WM8903_VMID_TIE_ENA                     0x0080  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_MASK                0x0080  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_SHIFT                    7  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_WIDTH                    1  /* VMID_TIE_ENA */
+#define WM8903_BUFIO_ENA                        0x0040  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_MASK                   0x0040  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_SHIFT                       6  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_WIDTH                       1  /* BUFIO_ENA */
+#define WM8903_VMID_IO_ENA                      0x0020  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_MASK                 0x0020  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_SHIFT                     5  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_WIDTH                     1  /* VMID_IO_ENA */
+#define WM8903_VMID_SOFT_MASK                   0x0018  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_SOFT_SHIFT                       3  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_SOFT_WIDTH                       2  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM8903_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM8903_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM8903_VMID_BUF_ENA                     0x0001  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_MASK                0x0001  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_SHIFT                    0  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+
+#define WM8903_VMID_RES_50K                          2
+#define WM8903_VMID_RES_250K                         3
+#define WM8903_VMID_RES_5K                           4
+
+/*
+ * R6 (0x06) - Mic Bias Control 0
+ */
+#define WM8903_MICDET_HYST_ENA                  0x0080  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_MASK             0x0080  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_SHIFT                 7  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_WIDTH                 1  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8903_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICDET_ENA                       0x0002  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_MASK                  0x0002  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_SHIFT                      1  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8903_MICBIAS_ENA                      0x0001  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_MASK                 0x0001  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_SHIFT                     0  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R8 (0x08) - Analogue DAC 0
+ */
+#define WM8903_DACBIAS_SEL_MASK                 0x0018  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACBIAS_SEL_SHIFT                     3  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACBIAS_SEL_WIDTH                     2  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACVMID_BIAS_SEL_MASK            0x0006  /* DACVMID_BIAS_SEL - [2:1] */
+#define WM8903_DACVMID_BIAS_SEL_SHIFT                1  /* DACVMID_BIAS_SEL - [2:1] */
+#define WM8903_DACVMID_BIAS_SEL_WIDTH                2  /* DACVMID_BIAS_SEL - [2:1] */
+
+/*
+ * R10 (0x0A) - Analogue ADC 0
+ */
+#define WM8903_ADC_OSR128                       0x0001  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_MASK                  0x0001  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_SHIFT                      0  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+
+/*
+ * R12 (0x0C) - Power Management 0
+ */
+#define WM8903_INL_ENA                          0x0002  /* INL_ENA */
+#define WM8903_INL_ENA_MASK                     0x0002  /* INL_ENA */
+#define WM8903_INL_ENA_SHIFT                         1  /* INL_ENA */
+#define WM8903_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8903_INR_ENA                          0x0001  /* INR_ENA */
+#define WM8903_INR_ENA_MASK                     0x0001  /* INR_ENA */
+#define WM8903_INR_ENA_SHIFT                         0  /* INR_ENA */
+#define WM8903_INR_ENA_WIDTH                         1  /* INR_ENA */
+
+/*
+ * R13 (0x0D) - Power Management 1
+ */
+#define WM8903_MIXOUTL_ENA                      0x0002  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_MASK                 0x0002  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_SHIFT                     1  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_WIDTH                     1  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTR_ENA                      0x0001  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_MASK                 0x0001  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_SHIFT                     0  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_WIDTH                     1  /* MIXOUTR_ENA */
+
+/*
+ * R14 (0x0E) - Power Management 2
+ */
+#define WM8903_HPL_PGA_ENA                      0x0002  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_MASK                 0x0002  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_SHIFT                     1  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_WIDTH                     1  /* HPL_PGA_ENA */
+#define WM8903_HPR_PGA_ENA                      0x0001  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_MASK                 0x0001  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_SHIFT                     0  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_WIDTH                     1  /* HPR_PGA_ENA */
+
+/*
+ * R15 (0x0F) - Power Management 3
+ */
+#define WM8903_LINEOUTL_PGA_ENA                 0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_MASK            0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_SHIFT                1  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_WIDTH                1  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA                 0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_MASK            0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_SHIFT                0  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_WIDTH                1  /* LINEOUTR_PGA_ENA */
+
+/*
+ * R16 (0x10) - Power Management 4
+ */
+#define WM8903_MIXSPKL_ENA                      0x0002  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_MASK                 0x0002  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_SHIFT                     1  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_WIDTH                     1  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKR_ENA                      0x0001  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_MASK                 0x0001  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_SHIFT                     0  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_WIDTH                     1  /* MIXSPKR_ENA */
+
+/*
+ * R17 (0x11) - Power Management 5
+ */
+#define WM8903_SPKL_ENA                         0x0002  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_MASK                    0x0002  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_SHIFT                        1  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8903_SPKR_ENA                         0x0001  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_MASK                    0x0001  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_SHIFT                        0  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+
+/*
+ * R18 (0x12) - Power Management 6
+ */
+#define WM8903_DACL_ENA                         0x0008  /* DACL_ENA */
+#define WM8903_DACL_ENA_MASK                    0x0008  /* DACL_ENA */
+#define WM8903_DACL_ENA_SHIFT                        3  /* DACL_ENA */
+#define WM8903_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8903_DACR_ENA                         0x0004  /* DACR_ENA */
+#define WM8903_DACR_ENA_MASK                    0x0004  /* DACR_ENA */
+#define WM8903_DACR_ENA_SHIFT                        2  /* DACR_ENA */
+#define WM8903_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8903_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8903_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R20 (0x14) - Clock Rates 0
+ */
+#define WM8903_MCLKDIV2                         0x0001  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_MASK                    0x0001  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_SHIFT                        0  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+
+/*
+ * R21 (0x15) - Clock Rates 1
+ */
+#define WM8903_CLK_SYS_RATE_MASK                0x3C00  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_RATE_SHIFT                   10  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_MODE_MASK                0x0300  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_CLK_SYS_MODE_SHIFT                    8  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_CLK_SYS_MODE_WIDTH                    2  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_SAMPLE_RATE_MASK                 0x000F  /* SAMPLE_RATE - [3:0] */
+#define WM8903_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [3:0] */
+#define WM8903_SAMPLE_RATE_WIDTH                     4  /* SAMPLE_RATE - [3:0] */
+
+/*
+ * R22 (0x16) - Clock Rates 2
+ */
+#define WM8903_CLK_SYS_ENA                      0x0004  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_MASK                 0x0004  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_SHIFT                     2  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8903_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8903_TO_ENA                           0x0001  /* TO_ENA */
+#define WM8903_TO_ENA_MASK                      0x0001  /* TO_ENA */
+#define WM8903_TO_ENA_SHIFT                          0  /* TO_ENA */
+#define WM8903_TO_ENA_WIDTH                          1  /* TO_ENA */
+
+/*
+ * R24 (0x18) - Audio Interface 0
+ */
+#define WM8903_DACL_DATINV                      0x1000  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_MASK                 0x1000  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_SHIFT                    12  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8903_DACR_DATINV                      0x0800  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_MASK                 0x0800  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_SHIFT                    11  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+#define WM8903_DAC_BOOST_MASK                   0x0600  /* DAC_BOOST - [10:9] */
+#define WM8903_DAC_BOOST_SHIFT                       9  /* DAC_BOOST - [10:9] */
+#define WM8903_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [10:9] */
+#define WM8903_LOOPBACK                         0x0100  /* LOOPBACK */
+#define WM8903_LOOPBACK_MASK                    0x0100  /* LOOPBACK */
+#define WM8903_LOOPBACK_SHIFT                        8  /* LOOPBACK */
+#define WM8903_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+#define WM8903_AIFADCL_SRC                      0x0080  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_MASK                 0x0080  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_SHIFT                     7  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8903_AIFADCR_SRC                      0x0040  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_MASK                 0x0040  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_SHIFT                     6  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8903_AIFDACL_SRC                      0x0020  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_MASK                 0x0020  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_SHIFT                     5  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8903_AIFDACR_SRC                      0x0010  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_MASK                 0x0010  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_SHIFT                     4  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8903_ADC_COMP                         0x0008  /* ADC_COMP */
+#define WM8903_ADC_COMP_MASK                    0x0008  /* ADC_COMP */
+#define WM8903_ADC_COMP_SHIFT                        3  /* ADC_COMP */
+#define WM8903_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8903_ADC_COMPMODE                     0x0004  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_MASK                0x0004  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_SHIFT                    2  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8903_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM8903_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM8903_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM8903_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8903_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R25 (0x19) - Audio Interface 1
+ */
+#define WM8903_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFADC_TDM                       0x0800  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_MASK                  0x0800  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_SHIFT                     11  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_CHAN                  0x0400  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_MASK             0x0400  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_SHIFT                10  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8903_LRCLK_DIR                        0x0200  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_MASK                   0x0200  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_SHIFT                       9  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8903_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8903_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8903_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8903_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM8903_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM8903_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM8903_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM8903_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM8903_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R26 (0x1A) - Audio Interface 2
+ */
+#define WM8903_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM8903_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM8903_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R27 (0x1B) - Audio Interface 3
+ */
+#define WM8903_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8903_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8903_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R30 (0x1E) - DAC Digital Volume Left
+ */
+#define WM8903_DACVU                            0x0100  /* DACVU */
+#define WM8903_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8903_DACVU_SHIFT                           8  /* DACVU */
+#define WM8903_DACVU_WIDTH                           1  /* DACVU */
+#define WM8903_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8903_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8903_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital Volume Right
+ */
+#define WM8903_DACVU                            0x0100  /* DACVU */
+#define WM8903_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8903_DACVU_SHIFT                           8  /* DACVU */
+#define WM8903_DACVU_WIDTH                           1  /* DACVU */
+#define WM8903_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8903_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8903_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R32 (0x20) - DAC Digital 0
+ */
+#define WM8903_ADCL_DAC_SVOL_MASK               0x0F00  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCL_DAC_SVOL_SHIFT                   8  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8903_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8903_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R33 (0x21) - DAC Digital 1
+ */
+#define WM8903_DAC_MONO                         0x1000  /* DAC_MONO */
+#define WM8903_DAC_MONO_MASK                    0x1000  /* DAC_MONO */
+#define WM8903_DAC_MONO_SHIFT                       12  /* DAC_MONO */
+#define WM8903_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8903_DAC_SB_FILT                      0x0800  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_MASK                 0x0800  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_SHIFT                    11  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8903_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTEMODE                     0x0200  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_MASK                0x0200  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_SHIFT                    9  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8903_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8903_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8903_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R36 (0x24) - ADC Digital Volume Left
+ */
+#define WM8903_ADCVU                            0x0100  /* ADCVU */
+#define WM8903_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8903_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8903_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8903_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8903_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8903_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R37 (0x25) - ADC Digital Volume Right
+ */
+#define WM8903_ADCVU                            0x0100  /* ADCVU */
+#define WM8903_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8903_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8903_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8903_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8903_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8903_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R38 (0x26) - ADC Digital 0
+ */
+#define WM8903_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_ENA                      0x0010  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_MASK                 0x0010  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_SHIFT                     4  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_WIDTH                     1  /* ADC_HPF_ENA */
+#define WM8903_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8903_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R39 (0x27) - Digital Microphone 0
+ */
+#define WM8903_DIGMIC_MODE_SEL                  0x0100  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_MASK             0x0100  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_SHIFT                 8  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_WIDTH                 1  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_CLK_SEL_L_MASK            0x00C0  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_L_SHIFT                6  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_L_WIDTH                2  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_R_MASK            0x0030  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_R_SHIFT                4  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_R_WIDTH                2  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_RT_MASK           0x000C  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_RT_SHIFT               2  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_RT_WIDTH               2  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_MASK              0x0003  /* DIGMIC_CLK_SEL - [1:0] */
+#define WM8903_DIGMIC_CLK_SEL_SHIFT                  0  /* DIGMIC_CLK_SEL - [1:0] */
+#define WM8903_DIGMIC_CLK_SEL_WIDTH                  2  /* DIGMIC_CLK_SEL - [1:0] */
+
+/*
+ * R40 (0x28) - DRC 0
+ */
+#define WM8903_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8903_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8903_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8903_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8903_DRC_THRESH_HYST_MASK             0x1800  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_THRESH_HYST_SHIFT                11  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_THRESH_HYST_WIDTH                 2  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_FF_DELAY                     0x0020  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_MASK                0x0020  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_SHIFT                    5  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8903_DRC_SMOOTH_ENA                   0x0008  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_MASK              0x0008  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_SHIFT                  3  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_WIDTH                  1  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_QR_ENA                       0x0004  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_MASK                  0x0004  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_SHIFT                      2  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_WIDTH                      1  /* DRC_QR_ENA */
+#define WM8903_DRC_ANTICLIP_ENA                 0x0002  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_MASK            0x0002  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_SHIFT                1  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_WIDTH                1  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_HYST_ENA                     0x0001  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_MASK                0x0001  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_SHIFT                    0  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_WIDTH                    1  /* DRC_HYST_ENA */
+
+/*
+ * R41 (0x29) - DRC 1
+ */
+#define WM8903_DRC_ATTACK_RATE_MASK             0xF000  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_ATTACK_RATE_SHIFT                12  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_ATTACK_RATE_WIDTH                 4  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_DECAY_RATE_MASK              0x0F00  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_DECAY_RATE_SHIFT                  8  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_DECAY_RATE_WIDTH                  4  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_THRESH_QR_MASK               0x00C0  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_THRESH_QR_SHIFT                   6  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_THRESH_QR_WIDTH                   2  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_RATE_QR_MASK                 0x0030  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_RATE_QR_SHIFT                     4  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_RATE_QR_WIDTH                     2  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8903_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8903_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R42 (0x2A) - DRC 2
+ */
+#define WM8903_DRC_R0_SLOPE_COMP_MASK           0x0038  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R0_SLOPE_COMP_SHIFT               3  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R0_SLOPE_COMP_WIDTH               3  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R1_SLOPE_COMP_MASK           0x0007  /* DRC_R1_SLOPE_COMP - [2:0] */
+#define WM8903_DRC_R1_SLOPE_COMP_SHIFT               0  /* DRC_R1_SLOPE_COMP - [2:0] */
+#define WM8903_DRC_R1_SLOPE_COMP_WIDTH               3  /* DRC_R1_SLOPE_COMP - [2:0] */
+
+/*
+ * R43 (0x2B) - DRC 3
+ */
+#define WM8903_DRC_THRESH_COMP_MASK             0x07E0  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_THRESH_COMP_SHIFT                 5  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_THRESH_COMP_WIDTH                 6  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_AMP_COMP_MASK                0x001F  /* DRC_AMP_COMP - [4:0] */
+#define WM8903_DRC_AMP_COMP_SHIFT                    0  /* DRC_AMP_COMP - [4:0] */
+#define WM8903_DRC_AMP_COMP_WIDTH                    5  /* DRC_AMP_COMP - [4:0] */
+
+/*
+ * R44 (0x2C) - Analogue Left Input 0
+ */
+#define WM8903_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8903_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8903_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8903_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8903_LIN_VOL_MASK                     0x001F  /* LIN_VOL - [4:0] */
+#define WM8903_LIN_VOL_SHIFT                         0  /* LIN_VOL - [4:0] */
+#define WM8903_LIN_VOL_WIDTH                         5  /* LIN_VOL - [4:0] */
+
+/*
+ * R45 (0x2D) - Analogue Right Input 0
+ */
+#define WM8903_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8903_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8903_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8903_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8903_RIN_VOL_MASK                     0x001F  /* RIN_VOL - [4:0] */
+#define WM8903_RIN_VOL_SHIFT                         0  /* RIN_VOL - [4:0] */
+#define WM8903_RIN_VOL_WIDTH                         5  /* RIN_VOL - [4:0] */
+
+/*
+ * R46 (0x2E) - Analogue Left Input 1
+ */
+#define WM8903_INL_CM_ENA                       0x0040  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_MASK                  0x0040  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_SHIFT                      6  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_WIDTH                      1  /* INL_CM_ENA */
+#define WM8903_L_IP_SEL_N_MASK                  0x0030  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_N_SHIFT                      4  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_N_WIDTH                      2  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_P_MASK                  0x000C  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_IP_SEL_P_SHIFT                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_IP_SEL_P_WIDTH                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_MODE_MASK                      0x0003  /* L_MODE - [1:0] */
+#define WM8903_L_MODE_SHIFT                          0  /* L_MODE - [1:0] */
+#define WM8903_L_MODE_WIDTH                          2  /* L_MODE - [1:0] */
+
+/*
+ * R47 (0x2F) - Analogue Right Input 1
+ */
+#define WM8903_INR_CM_ENA                       0x0040  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_MASK                  0x0040  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_SHIFT                      6  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_WIDTH                      1  /* INR_CM_ENA */
+#define WM8903_R_IP_SEL_N_MASK                  0x0030  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_N_SHIFT                      4  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_N_WIDTH                      2  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_P_MASK                  0x000C  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_IP_SEL_P_SHIFT                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_IP_SEL_P_WIDTH                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_MODE_MASK                      0x0003  /* R_MODE - [1:0] */
+#define WM8903_R_MODE_SHIFT                          0  /* R_MODE - [1:0] */
+#define WM8903_R_MODE_WIDTH                          2  /* R_MODE - [1:0] */
+
+/*
+ * R50 (0x32) - Analogue Left Mix 0
+ */
+#define WM8903_DACL_TO_MIXOUTL                  0x0008  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_MASK             0x0008  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_SHIFT                 3  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_WIDTH                 1  /* DACL_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL                  0x0004  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_MASK             0x0004  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_SHIFT                 2  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_WIDTH                 1  /* DACR_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL               0x0002  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_MASK          0x0002  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_SHIFT              1  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_WIDTH              1  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL               0x0001  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_MASK          0x0001  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_SHIFT              0  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_WIDTH              1  /* BYPASSR_TO_MIXOUTL */
+
+/*
+ * R51 (0x33) - Analogue Right Mix 0
+ */
+#define WM8903_DACL_TO_MIXOUTR                  0x0008  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_MASK             0x0008  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_SHIFT                 3  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_WIDTH                 1  /* DACL_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR                  0x0004  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_MASK             0x0004  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_SHIFT                 2  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_WIDTH                 1  /* DACR_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR               0x0002  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_MASK          0x0002  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_SHIFT              1  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_WIDTH              1  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR               0x0001  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_MASK          0x0001  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_SHIFT              0  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_WIDTH              1  /* BYPASSR_TO_MIXOUTR */
+
+/*
+ * R52 (0x34) - Analogue Spk Mix Left 0
+ */
+#define WM8903_DACL_TO_MIXSPKL                  0x0008  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_MASK             0x0008  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_SHIFT                 3  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_WIDTH                 1  /* DACL_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL                  0x0004  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_MASK             0x0004  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_SHIFT                 2  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_WIDTH                 1  /* DACR_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL               0x0002  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_MASK          0x0002  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_SHIFT              1  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_WIDTH              1  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL               0x0001  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_MASK          0x0001  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_SHIFT              0  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_WIDTH              1  /* BYPASSR_TO_MIXSPKL */
+
+/*
+ * R53 (0x35) - Analogue Spk Mix Left 1
+ */
+#define WM8903_DACL_MIXSPKL_VOL                 0x0008  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_MASK            0x0008  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_SHIFT                3  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_WIDTH                1  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL                 0x0004  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_MASK            0x0004  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_SHIFT                2  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_WIDTH                1  /* DACR_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL              0x0002  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_MASK         0x0002  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_SHIFT             1  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_WIDTH             1  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL              0x0001  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_MASK         0x0001  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_SHIFT             0  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_WIDTH             1  /* BYPASSR_MIXSPKL_VOL */
+
+/*
+ * R54 (0x36) - Analogue Spk Mix Right 0
+ */
+#define WM8903_DACL_TO_MIXSPKR                  0x0008  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_MASK             0x0008  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_SHIFT                 3  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_WIDTH                 1  /* DACL_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR                  0x0004  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_MASK             0x0004  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_SHIFT                 2  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_WIDTH                 1  /* DACR_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR               0x0002  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_MASK          0x0002  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_SHIFT              1  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_WIDTH              1  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR               0x0001  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_MASK          0x0001  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_SHIFT              0  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_WIDTH              1  /* BYPASSR_TO_MIXSPKR */
+
+/*
+ * R55 (0x37) - Analogue Spk Mix Right 1
+ */
+#define WM8903_DACL_MIXSPKR_VOL                 0x0008  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_MASK            0x0008  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_SHIFT                3  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_WIDTH                1  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL                 0x0004  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_MASK            0x0004  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_SHIFT                2  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_WIDTH                1  /* DACR_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL              0x0002  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_MASK         0x0002  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_SHIFT             1  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_WIDTH             1  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL              0x0001  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_MASK         0x0001  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_SHIFT             0  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_WIDTH             1  /* BYPASSR_MIXSPKR_VOL */
+
+/*
+ * R57 (0x39) - Analogue OUT1 Left
+ */
+#define WM8903_HPL_MUTE                         0x0100  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_MASK                    0x0100  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_SHIFT                        8  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_WIDTH                        1  /* HPL_MUTE */
+#define WM8903_HPOUTVU                          0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_MASK                     0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_SHIFT                         7  /* HPOUTVU */
+#define WM8903_HPOUTVU_WIDTH                         1  /* HPOUTVU */
+#define WM8903_HPOUTLZC                         0x0040  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_MASK                    0x0040  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_SHIFT                        6  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_WIDTH                        1  /* HPOUTLZC */
+#define WM8903_HPOUTL_VOL_MASK                  0x003F  /* HPOUTL_VOL - [5:0] */
+#define WM8903_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [5:0] */
+#define WM8903_HPOUTL_VOL_WIDTH                      6  /* HPOUTL_VOL - [5:0] */
+
+/*
+ * R58 (0x3A) - Analogue OUT1 Right
+ */
+#define WM8903_HPR_MUTE                         0x0100  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_MASK                    0x0100  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_SHIFT                        8  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_WIDTH                        1  /* HPR_MUTE */
+#define WM8903_HPOUTVU                          0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_MASK                     0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_SHIFT                         7  /* HPOUTVU */
+#define WM8903_HPOUTVU_WIDTH                         1  /* HPOUTVU */
+#define WM8903_HPOUTRZC                         0x0040  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_MASK                    0x0040  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_SHIFT                        6  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_WIDTH                        1  /* HPOUTRZC */
+#define WM8903_HPOUTR_VOL_MASK                  0x003F  /* HPOUTR_VOL - [5:0] */
+#define WM8903_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [5:0] */
+#define WM8903_HPOUTR_VOL_WIDTH                      6  /* HPOUTR_VOL - [5:0] */
+
+/*
+ * R59 (0x3B) - Analogue OUT2 Left
+ */
+#define WM8903_LINEOUTL_MUTE                    0x0100  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_MASK               0x0100  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_SHIFT                   8  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_WIDTH                   1  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTVU                        0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_MASK                   0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_SHIFT                       7  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_WIDTH                       1  /* LINEOUTVU */
+#define WM8903_LINEOUTLZC                       0x0040  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_MASK                  0x0040  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_SHIFT                      6  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_WIDTH                      1  /* LINEOUTLZC */
+#define WM8903_LINEOUTL_VOL_MASK                0x003F  /* LINEOUTL_VOL - [5:0] */
+#define WM8903_LINEOUTL_VOL_SHIFT                    0  /* LINEOUTL_VOL - [5:0] */
+#define WM8903_LINEOUTL_VOL_WIDTH                    6  /* LINEOUTL_VOL - [5:0] */
+
+/*
+ * R60 (0x3C) - Analogue OUT2 Right
+ */
+#define WM8903_LINEOUTR_MUTE                    0x0100  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_MASK               0x0100  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_SHIFT                   8  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_WIDTH                   1  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTVU                        0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_MASK                   0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_SHIFT                       7  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_WIDTH                       1  /* LINEOUTVU */
+#define WM8903_LINEOUTRZC                       0x0040  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_MASK                  0x0040  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_SHIFT                      6  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_WIDTH                      1  /* LINEOUTRZC */
+#define WM8903_LINEOUTR_VOL_MASK                0x003F  /* LINEOUTR_VOL - [5:0] */
+#define WM8903_LINEOUTR_VOL_SHIFT                    0  /* LINEOUTR_VOL - [5:0] */
+#define WM8903_LINEOUTR_VOL_WIDTH                    6  /* LINEOUTR_VOL - [5:0] */
+
+/*
+ * R62 (0x3E) - Analogue OUT3 Left
+ */
+#define WM8903_SPKL_MUTE                        0x0100  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_MASK                   0x0100  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_SHIFT                       8  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8903_SPKVU                            0x0080  /* SPKVU */
+#define WM8903_SPKVU_MASK                       0x0080  /* SPKVU */
+#define WM8903_SPKVU_SHIFT                           7  /* SPKVU */
+#define WM8903_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8903_SPKLZC                           0x0040  /* SPKLZC */
+#define WM8903_SPKLZC_MASK                      0x0040  /* SPKLZC */
+#define WM8903_SPKLZC_SHIFT                          6  /* SPKLZC */
+#define WM8903_SPKLZC_WIDTH                          1  /* SPKLZC */
+#define WM8903_SPKL_VOL_MASK                    0x003F  /* SPKL_VOL - [5:0] */
+#define WM8903_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [5:0] */
+#define WM8903_SPKL_VOL_WIDTH                        6  /* SPKL_VOL - [5:0] */
+
+/*
+ * R63 (0x3F) - Analogue OUT3 Right
+ */
+#define WM8903_SPKR_MUTE                        0x0100  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_MASK                   0x0100  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_SHIFT                       8  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8903_SPKVU                            0x0080  /* SPKVU */
+#define WM8903_SPKVU_MASK                       0x0080  /* SPKVU */
+#define WM8903_SPKVU_SHIFT                           7  /* SPKVU */
+#define WM8903_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8903_SPKRZC                           0x0040  /* SPKRZC */
+#define WM8903_SPKRZC_MASK                      0x0040  /* SPKRZC */
+#define WM8903_SPKRZC_SHIFT                          6  /* SPKRZC */
+#define WM8903_SPKRZC_WIDTH                          1  /* SPKRZC */
+#define WM8903_SPKR_VOL_MASK                    0x003F  /* SPKR_VOL - [5:0] */
+#define WM8903_SPKR_VOL_SHIFT                        0  /* SPKR_VOL - [5:0] */
+#define WM8903_SPKR_VOL_WIDTH                        6  /* SPKR_VOL - [5:0] */
+
+/*
+ * R65 (0x41) - Analogue SPK Output Control 0
+ */
+#define WM8903_SPK_DISCHARGE                    0x0002  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_MASK               0x0002  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_SHIFT                   1  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_WIDTH                   1  /* SPK_DISCHARGE */
+#define WM8903_VROI                             0x0001  /* VROI */
+#define WM8903_VROI_MASK                        0x0001  /* VROI */
+#define WM8903_VROI_SHIFT                            0  /* VROI */
+#define WM8903_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R67 (0x43) - DC Servo 0
+ */
+#define WM8903_DCS_MASTER_ENA                   0x0010  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_MASK              0x0010  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_SHIFT                  4  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_WIDTH                  1  /* DCS_MASTER_ENA */
+#define WM8903_DCS_ENA_MASK                     0x000F  /* DCS_ENA - [3:0] */
+#define WM8903_DCS_ENA_SHIFT                         0  /* DCS_ENA - [3:0] */
+#define WM8903_DCS_ENA_WIDTH                         4  /* DCS_ENA - [3:0] */
+
+/*
+ * R69 (0x45) - DC Servo 2
+ */
+#define WM8903_DCS_MODE_MASK                    0x0003  /* DCS_MODE - [1:0] */
+#define WM8903_DCS_MODE_SHIFT                        0  /* DCS_MODE - [1:0] */
+#define WM8903_DCS_MODE_WIDTH                        2  /* DCS_MODE - [1:0] */
+
+/*
+ * R90 (0x5A) - Analogue HP 0
+ */
+#define WM8903_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8903_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8903_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8903_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8903_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8903_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8903_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8903_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8903_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8903_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R94 (0x5E) - Analogue Lineout 0
+ */
+#define WM8903_LINEOUTL_RMV_SHORT               0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_MASK          0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_SHIFT              7  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_WIDTH              1  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_ENA_OUTP                0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_MASK           0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_SHIFT               6  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_WIDTH               1  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_DLY                 0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_MASK            0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_SHIFT                5  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_WIDTH                1  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA                     0x0010  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_MASK                0x0010  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_SHIFT                    4  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_WIDTH                    1  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTR_RMV_SHORT               0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_MASK          0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_SHIFT              3  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_WIDTH              1  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_ENA_OUTP                0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_MASK           0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_SHIFT               2  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_WIDTH               1  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_DLY                 0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_MASK            0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_SHIFT                1  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_WIDTH                1  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA                     0x0001  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_MASK                0x0001  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_SHIFT                    0  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_WIDTH                    1  /* LINEOUTR_ENA */
+
+/*
+ * R98 (0x62) - Charge Pump 0
+ */
+#define WM8903_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8903_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8903_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8903_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R104 (0x68) - Class W 0
+ */
+#define WM8903_CP_DYN_FREQ                      0x0002  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_MASK                 0x0002  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_SHIFT                     1  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_WIDTH                     1  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_V                         0x0001  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_MASK                    0x0001  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_SHIFT                        0  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_WIDTH                        1  /* CP_DYN_V */
+
+/*
+ * R108 (0x6C) - Write Sequencer 0
+ */
+#define WM8903_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8903_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8903_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8903_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R109 (0x6D) - Write Sequencer 1
+ */
+#define WM8903_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8903_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8903_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R110 (0x6E) - Write Sequencer 2
+ */
+#define WM8903_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8903_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8903_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8903_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R111 (0x6F) - Write Sequencer 3
+ */
+#define WM8903_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8903_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8903_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8903_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8903_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8903_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8903_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8903_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R112 (0x70) - Write Sequencer 4
+ */
+#define WM8903_WSEQ_CURRENT_INDEX_MASK          0x03F0  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R114 (0x72) - Control Interface
+ */
+#define WM8903_MASK_WRITE_ENA                   0x0001  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_MASK              0x0001  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_SHIFT                  0  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_WIDTH                  1  /* MASK_WRITE_ENA */
+
+/*
+ * R116 (0x74) - GPIO Control 1
+ */
+#define WM8903_GP1_FN_MASK                      0x1F00  /* GP1_FN - [12:8] */
+#define WM8903_GP1_FN_SHIFT                          8  /* GP1_FN - [12:8] */
+#define WM8903_GP1_FN_WIDTH                          5  /* GP1_FN - [12:8] */
+#define WM8903_GP1_DIR                          0x0080  /* GP1_DIR */
+#define WM8903_GP1_DIR_MASK                     0x0080  /* GP1_DIR */
+#define WM8903_GP1_DIR_SHIFT                         7  /* GP1_DIR */
+#define WM8903_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8903_GP1_OP_CFG                       0x0040  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_MASK                  0x0040  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_SHIFT                      6  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8903_GP1_IP_CFG                       0x0020  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_MASK                  0x0020  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_SHIFT                      5  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_WIDTH                      1  /* GP1_IP_CFG */
+#define WM8903_GP1_LVL                          0x0010  /* GP1_LVL */
+#define WM8903_GP1_LVL_MASK                     0x0010  /* GP1_LVL */
+#define WM8903_GP1_LVL_SHIFT                         4  /* GP1_LVL */
+#define WM8903_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8903_GP1_PD                           0x0008  /* GP1_PD */
+#define WM8903_GP1_PD_MASK                      0x0008  /* GP1_PD */
+#define WM8903_GP1_PD_SHIFT                          3  /* GP1_PD */
+#define WM8903_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8903_GP1_PU                           0x0004  /* GP1_PU */
+#define WM8903_GP1_PU_MASK                      0x0004  /* GP1_PU */
+#define WM8903_GP1_PU_SHIFT                          2  /* GP1_PU */
+#define WM8903_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8903_GP1_INTMODE                      0x0002  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_MASK                 0x0002  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_SHIFT                     1  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_WIDTH                     1  /* GP1_INTMODE */
+#define WM8903_GP1_DB                           0x0001  /* GP1_DB */
+#define WM8903_GP1_DB_MASK                      0x0001  /* GP1_DB */
+#define WM8903_GP1_DB_SHIFT                          0  /* GP1_DB */
+#define WM8903_GP1_DB_WIDTH                          1  /* GP1_DB */
+
+/*
+ * R117 (0x75) - GPIO Control 2
+ */
+#define WM8903_GP2_FN_MASK                      0x1F00  /* GP2_FN - [12:8] */
+#define WM8903_GP2_FN_SHIFT                          8  /* GP2_FN - [12:8] */
+#define WM8903_GP2_FN_WIDTH                          5  /* GP2_FN - [12:8] */
+#define WM8903_GP2_DIR                          0x0080  /* GP2_DIR */
+#define WM8903_GP2_DIR_MASK                     0x0080  /* GP2_DIR */
+#define WM8903_GP2_DIR_SHIFT                         7  /* GP2_DIR */
+#define WM8903_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8903_GP2_OP_CFG                       0x0040  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_MASK                  0x0040  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_SHIFT                      6  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8903_GP2_IP_CFG                       0x0020  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_MASK                  0x0020  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_SHIFT                      5  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_WIDTH                      1  /* GP2_IP_CFG */
+#define WM8903_GP2_LVL                          0x0010  /* GP2_LVL */
+#define WM8903_GP2_LVL_MASK                     0x0010  /* GP2_LVL */
+#define WM8903_GP2_LVL_SHIFT                         4  /* GP2_LVL */
+#define WM8903_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8903_GP2_PD                           0x0008  /* GP2_PD */
+#define WM8903_GP2_PD_MASK                      0x0008  /* GP2_PD */
+#define WM8903_GP2_PD_SHIFT                          3  /* GP2_PD */
+#define WM8903_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8903_GP2_PU                           0x0004  /* GP2_PU */
+#define WM8903_GP2_PU_MASK                      0x0004  /* GP2_PU */
+#define WM8903_GP2_PU_SHIFT                          2  /* GP2_PU */
+#define WM8903_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8903_GP2_INTMODE                      0x0002  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_MASK                 0x0002  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_SHIFT                     1  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_WIDTH                     1  /* GP2_INTMODE */
+#define WM8903_GP2_DB                           0x0001  /* GP2_DB */
+#define WM8903_GP2_DB_MASK                      0x0001  /* GP2_DB */
+#define WM8903_GP2_DB_SHIFT                          0  /* GP2_DB */
+#define WM8903_GP2_DB_WIDTH                          1  /* GP2_DB */
+
+/*
+ * R118 (0x76) - GPIO Control 3
+ */
+#define WM8903_GP3_FN_MASK                      0x1F00  /* GP3_FN - [12:8] */
+#define WM8903_GP3_FN_SHIFT                          8  /* GP3_FN - [12:8] */
+#define WM8903_GP3_FN_WIDTH                          5  /* GP3_FN - [12:8] */
+#define WM8903_GP3_DIR                          0x0080  /* GP3_DIR */
+#define WM8903_GP3_DIR_MASK                     0x0080  /* GP3_DIR */
+#define WM8903_GP3_DIR_SHIFT                         7  /* GP3_DIR */
+#define WM8903_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8903_GP3_OP_CFG                       0x0040  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_MASK                  0x0040  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_SHIFT                      6  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8903_GP3_IP_CFG                       0x0020  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_MASK                  0x0020  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_SHIFT                      5  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_WIDTH                      1  /* GP3_IP_CFG */
+#define WM8903_GP3_LVL                          0x0010  /* GP3_LVL */
+#define WM8903_GP3_LVL_MASK                     0x0010  /* GP3_LVL */
+#define WM8903_GP3_LVL_SHIFT                         4  /* GP3_LVL */
+#define WM8903_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8903_GP3_PD                           0x0008  /* GP3_PD */
+#define WM8903_GP3_PD_MASK                      0x0008  /* GP3_PD */
+#define WM8903_GP3_PD_SHIFT                          3  /* GP3_PD */
+#define WM8903_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8903_GP3_PU                           0x0004  /* GP3_PU */
+#define WM8903_GP3_PU_MASK                      0x0004  /* GP3_PU */
+#define WM8903_GP3_PU_SHIFT                          2  /* GP3_PU */
+#define WM8903_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8903_GP3_INTMODE                      0x0002  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_MASK                 0x0002  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_SHIFT                     1  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_WIDTH                     1  /* GP3_INTMODE */
+#define WM8903_GP3_DB                           0x0001  /* GP3_DB */
+#define WM8903_GP3_DB_MASK                      0x0001  /* GP3_DB */
+#define WM8903_GP3_DB_SHIFT                          0  /* GP3_DB */
+#define WM8903_GP3_DB_WIDTH                          1  /* GP3_DB */
+
+/*
+ * R119 (0x77) - GPIO Control 4
+ */
+#define WM8903_GP4_FN_MASK                      0x1F00  /* GP4_FN - [12:8] */
+#define WM8903_GP4_FN_SHIFT                          8  /* GP4_FN - [12:8] */
+#define WM8903_GP4_FN_WIDTH                          5  /* GP4_FN - [12:8] */
+#define WM8903_GP4_DIR                          0x0080  /* GP4_DIR */
+#define WM8903_GP4_DIR_MASK                     0x0080  /* GP4_DIR */
+#define WM8903_GP4_DIR_SHIFT                         7  /* GP4_DIR */
+#define WM8903_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8903_GP4_OP_CFG                       0x0040  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_MASK                  0x0040  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_SHIFT                      6  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8903_GP4_IP_CFG                       0x0020  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_MASK                  0x0020  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_SHIFT                      5  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_WIDTH                      1  /* GP4_IP_CFG */
+#define WM8903_GP4_LVL                          0x0010  /* GP4_LVL */
+#define WM8903_GP4_LVL_MASK                     0x0010  /* GP4_LVL */
+#define WM8903_GP4_LVL_SHIFT                         4  /* GP4_LVL */
+#define WM8903_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8903_GP4_PD                           0x0008  /* GP4_PD */
+#define WM8903_GP4_PD_MASK                      0x0008  /* GP4_PD */
+#define WM8903_GP4_PD_SHIFT                          3  /* GP4_PD */
+#define WM8903_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8903_GP4_PU                           0x0004  /* GP4_PU */
+#define WM8903_GP4_PU_MASK                      0x0004  /* GP4_PU */
+#define WM8903_GP4_PU_SHIFT                          2  /* GP4_PU */
+#define WM8903_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8903_GP4_INTMODE                      0x0002  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_MASK                 0x0002  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_SHIFT                     1  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_WIDTH                     1  /* GP4_INTMODE */
+#define WM8903_GP4_DB                           0x0001  /* GP4_DB */
+#define WM8903_GP4_DB_MASK                      0x0001  /* GP4_DB */
+#define WM8903_GP4_DB_SHIFT                          0  /* GP4_DB */
+#define WM8903_GP4_DB_WIDTH                          1  /* GP4_DB */
+
+/*
+ * R120 (0x78) - GPIO Control 5
+ */
+#define WM8903_GP5_FN_MASK                      0x1F00  /* GP5_FN - [12:8] */
+#define WM8903_GP5_FN_SHIFT                          8  /* GP5_FN - [12:8] */
+#define WM8903_GP5_FN_WIDTH                          5  /* GP5_FN - [12:8] */
+#define WM8903_GP5_DIR                          0x0080  /* GP5_DIR */
+#define WM8903_GP5_DIR_MASK                     0x0080  /* GP5_DIR */
+#define WM8903_GP5_DIR_SHIFT                         7  /* GP5_DIR */
+#define WM8903_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8903_GP5_OP_CFG                       0x0040  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_MASK                  0x0040  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_SHIFT                      6  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8903_GP5_IP_CFG                       0x0020  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_MASK                  0x0020  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_SHIFT                      5  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_WIDTH                      1  /* GP5_IP_CFG */
+#define WM8903_GP5_LVL                          0x0010  /* GP5_LVL */
+#define WM8903_GP5_LVL_MASK                     0x0010  /* GP5_LVL */
+#define WM8903_GP5_LVL_SHIFT                         4  /* GP5_LVL */
+#define WM8903_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8903_GP5_PD                           0x0008  /* GP5_PD */
+#define WM8903_GP5_PD_MASK                      0x0008  /* GP5_PD */
+#define WM8903_GP5_PD_SHIFT                          3  /* GP5_PD */
+#define WM8903_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8903_GP5_PU                           0x0004  /* GP5_PU */
+#define WM8903_GP5_PU_MASK                      0x0004  /* GP5_PU */
+#define WM8903_GP5_PU_SHIFT                          2  /* GP5_PU */
+#define WM8903_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8903_GP5_INTMODE                      0x0002  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_MASK                 0x0002  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_SHIFT                     1  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_WIDTH                     1  /* GP5_INTMODE */
+#define WM8903_GP5_DB                           0x0001  /* GP5_DB */
+#define WM8903_GP5_DB_MASK                      0x0001  /* GP5_DB */
+#define WM8903_GP5_DB_SHIFT                          0  /* GP5_DB */
+#define WM8903_GP5_DB_WIDTH                          1  /* GP5_DB */
+
+/*
+ * R121 (0x79) - Interrupt Status 1
+ */
+#define WM8903_MICSHRT_EINT                     0x8000  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_MASK                0x8000  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_SHIFT                   15  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_WIDTH                    1  /* MICSHRT_EINT */
+#define WM8903_MICDET_EINT                      0x4000  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_MASK                 0x4000  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_SHIFT                    14  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_WIDTH                     1  /* MICDET_EINT */
+#define WM8903_WSEQ_BUSY_EINT                   0x2000  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_MASK              0x2000  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_SHIFT                 13  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM8903_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8903_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8903_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8903_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8903_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8903_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8903_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8903_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8903_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8903_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8903_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8903_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8903_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8903_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8903_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8903_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8903_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8903_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8903_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8903_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R122 (0x7A) - Interrupt Status 1 Mask
+ */
+#define WM8903_IM_MICSHRT_EINT                  0x8000  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_MASK             0x8000  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_SHIFT                15  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_WIDTH                 1  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICDET_EINT                   0x4000  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_MASK              0x4000  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_SHIFT                 14  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_WIDTH                  1  /* IM_MICDET_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT                0x2000  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_MASK           0x2000  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_SHIFT              13  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8903_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8903_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8903_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8903_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R123 (0x7B) - Interrupt Polarity 1
+ */
+#define WM8903_MICSHRT_INV                      0x8000  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_MASK                 0x8000  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_SHIFT                    15  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_WIDTH                     1  /* MICSHRT_INV */
+#define WM8903_MICDET_INV                       0x4000  /* MICDET_INV */
+#define WM8903_MICDET_INV_MASK                  0x4000  /* MICDET_INV */
+#define WM8903_MICDET_INV_SHIFT                     14  /* MICDET_INV */
+#define WM8903_MICDET_INV_WIDTH                      1  /* MICDET_INV */
+
+/*
+ * R126 (0x7E) - Interrupt Control
+ */
+#define WM8903_IRQ_POL                          0x0001  /* IRQ_POL */
+#define WM8903_IRQ_POL_MASK                     0x0001  /* IRQ_POL */
+#define WM8903_IRQ_POL_SHIFT                         0  /* IRQ_POL */
+#define WM8903_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+
+/*
+ * R129 (0x81) - Control Interface Test 1
+ */
+#define WM8903_USER_KEY                         0x0002  /* USER_KEY */
+#define WM8903_USER_KEY_MASK                    0x0002  /* USER_KEY */
+#define WM8903_USER_KEY_SHIFT                        1  /* USER_KEY */
+#define WM8903_USER_KEY_WIDTH                        1  /* USER_KEY */
+#define WM8903_TEST_KEY                         0x0001  /* TEST_KEY */
+#define WM8903_TEST_KEY_MASK                    0x0001  /* TEST_KEY */
+#define WM8903_TEST_KEY_SHIFT                        0  /* TEST_KEY */
+#define WM8903_TEST_KEY_WIDTH                        1  /* TEST_KEY */
+
+/*
+ * R149 (0x95) - Charge Pump Test 1
+ */
+#define WM8903_CP_SW_KELVIN_MODE_MASK           0x0006  /* CP_SW_KELVIN_MODE - [2:1] */
+#define WM8903_CP_SW_KELVIN_MODE_SHIFT               1  /* CP_SW_KELVIN_MODE - [2:1] */
+#define WM8903_CP_SW_KELVIN_MODE_WIDTH               2  /* CP_SW_KELVIN_MODE - [2:1] */
+
+/*
+ * R164 (0xA4) - Clock Rate Test 4
+ */
+#define WM8903_ADC_DIG_MIC                      0x0200  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_MASK                 0x0200  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_SHIFT                     9  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_WIDTH                     1  /* ADC_DIG_MIC */
+
+/*
+ * R172 (0xAC) - Analogue Output Bias 0
+ */
+#define WM8903_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
+#define WM8903_PGA_BIAS_SHIFT                        4  /* PGA_BIAS - [6:4] */
+#define WM8903_PGA_BIAS_WIDTH                        3  /* PGA_BIAS - [6:4] */
+
+#endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
new file mode 100644 (file)
index 0000000..974a4cd
--- /dev/null
@@ -0,0 +1,942 @@
+/*
+ * wm8971.c  --  WM8971 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Lab126, Inc.
+ *
+ * Author: Kenneth Kiraly <kiraly@lab126.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8971.h"
+
+#define AUDIO_NAME "wm8971"
+#define WM8971_VERSION "0.9"
+
+#define        WM8971_REG_COUNT                43
+
+static struct workqueue_struct *wm8971_workq = NULL;
+
+/* codec private data */
+struct wm8971_priv {
+       unsigned int sysclk;
+};
+
+/*
+ * wm8971 register cache
+ * We can't read the WM8971 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8971_reg[] = {
+       0x0097, 0x0097, 0x0079, 0x0079,  /*  0 */
+       0x0000, 0x0008, 0x0000, 0x000a,  /*  4 */
+       0x0000, 0x0000, 0x00ff, 0x00ff,  /*  8 */
+       0x000f, 0x000f, 0x0000, 0x0000,  /* 12 */
+       0x0000, 0x007b, 0x0000, 0x0032,  /* 16 */
+       0x0000, 0x00c3, 0x00c3, 0x00c0,  /* 20 */
+       0x0000, 0x0000, 0x0000, 0x0000,  /* 24 */
+       0x0000, 0x0000, 0x0000, 0x0000,  /* 28 */
+       0x0000, 0x0000, 0x0050, 0x0050,  /* 32 */
+       0x0050, 0x0050, 0x0050, 0x0050,  /* 36 */
+       0x0079, 0x0079, 0x0079,          /* 40 */
+};
+
+static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg < WM8971_REG_COUNT)
+               return cache[reg];
+
+       return -1;
+}
+
+static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg < WM8971_REG_COUNT)
+               cache[reg] = value;
+}
+
+static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D9 WM8753 register offset
+        *   D8...D0 register data
+        */
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
+
+       wm8971_write_reg_cache (codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define wm8971_reset(c)        wm8971_write(c, WM8971_RESET, 0)
+
+/* WM8971 Controls */
+static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
+static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz",
+       "200Hz @ 48kHz" };
+static const char *wm8971_treble[] = { "8kHz", "4kHz" };
+static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" };
+static const char *wm8971_ng_type[] = { "Constant PGA Gain",
+       "Mute ADC Output" };
+static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)",
+       "Mono (Right)", "Digital Mono"};
+static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" };
+static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA",
+       "Differential"};
+static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA",
+       "Differential"};
+static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"};
+static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"};
+static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert",
+       "L + R Invert"};
+
+static const struct soc_enum wm8971_enum[] = {
+       SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass),        /* 0 */
+       SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter),
+       SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble),
+       SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func),
+       SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type),    /* 4 */
+       SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp),
+       SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux),
+       SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase),
+       SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */
+       SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux),
+       SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel),
+       SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel),
+       SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol),    /* 12 */
+       SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux),
+};
+
+static const struct snd_kcontrol_new wm8971_snd_controls[] = {
+       SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0),
+       SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL,
+                    6, 1, 0),
+       SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1),
+
+       SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V,
+               WM8971_ROUT1V, 7, 1, 0),
+       SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V,
+               WM8971_ROUT2V, 7, 1, 0),
+       SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
+
+       SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0),
+
+       SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1,
+               WM8971_LOUTM2, 4, 7, 1),
+       SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1,
+               WM8971_ROUTM2, 4, 7, 1),
+       SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1,
+               WM8971_MOUTM2, 4, 7, 1),
+
+       SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V,
+               WM8971_ROUT1V, 0, 127, 0),
+       SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V,
+               WM8971_ROUT2V, 0, 127, 0),
+
+       SOC_ENUM("Bass Boost", wm8971_enum[0]),
+       SOC_ENUM("Bass Filter", wm8971_enum[1]),
+       SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1),
+
+       SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0),
+       SOC_ENUM("Treble Cut-off", wm8971_enum[2]),
+
+       SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1),
+
+       SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0),
+       SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0),
+
+       SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0),
+       SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0),
+       SOC_ENUM("ALC Capture Function", wm8971_enum[3]),
+       SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0),
+       SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0),
+       SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0),
+       SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0),
+       SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0),
+       SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]),
+       SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0),
+
+       SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0),
+       SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0),
+
+       SOC_ENUM("Playback De-emphasis", wm8971_enum[5]),
+       SOC_ENUM("Playback Function", wm8971_enum[6]),
+       SOC_ENUM("Playback Phase", wm8971_enum[7]),
+
+       SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0),
+};
+
+/* add non-DAPM controls */
+static int wm8971_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                               snd_soc_cnew(&wm8971_snd_controls[i],
+                                            codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8971_left_line_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[8]);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8971_right_line_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[9]);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8971_left_pga_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[10]);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8971_right_pga_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[11]);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8971_monomux_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[13]);
+
+static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = {
+       SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+               &wm8971_left_mixer_controls[0],
+               ARRAY_SIZE(wm8971_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+               &wm8971_right_mixer_controls[0],
+               ARRAY_SIZE(wm8971_right_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0,
+               &wm8971_mono_mixer_controls[0],
+               ARRAY_SIZE(wm8971_mono_mixer_controls)),
+
+       SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0),
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0),
+       SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
+
+       SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0,
+               &wm8971_left_pga_controls),
+       SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0,
+               &wm8971_right_pga_controls),
+       SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+               &wm8971_left_line_controls),
+       SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+               &wm8971_right_line_controls),
+
+       SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+               &wm8971_monomux_controls),
+       SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+               &wm8971_monomux_controls),
+
+       SND_SOC_DAPM_OUTPUT("LOUT1"),
+       SND_SOC_DAPM_OUTPUT("ROUT1"),
+       SND_SOC_DAPM_OUTPUT("LOUT2"),
+       SND_SOC_DAPM_OUTPUT("ROUT2"),
+       SND_SOC_DAPM_OUTPUT("MONO"),
+
+       SND_SOC_DAPM_INPUT("LINPUT1"),
+       SND_SOC_DAPM_INPUT("RINPUT1"),
+       SND_SOC_DAPM_INPUT("MIC"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* left mixer */
+       {"Left Mixer", "Playback Switch", "Left DAC"},
+       {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+       {"Left Mixer", "Right Playback Switch", "Right DAC"},
+       {"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+       /* right mixer */
+       {"Right Mixer", "Left Playback Switch", "Left DAC"},
+       {"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+       {"Right Mixer", "Playback Switch", "Right DAC"},
+       {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+       /* left out 1 */
+       {"Left Out 1", NULL, "Left Mixer"},
+       {"LOUT1", NULL, "Left Out 1"},
+
+       /* left out 2 */
+       {"Left Out 2", NULL, "Left Mixer"},
+       {"LOUT2", NULL, "Left Out 2"},
+
+       /* right out 1 */
+       {"Right Out 1", NULL, "Right Mixer"},
+       {"ROUT1", NULL, "Right Out 1"},
+
+       /* right out 2 */
+       {"Right Out 2", NULL, "Right Mixer"},
+       {"ROUT2", NULL, "Right Out 2"},
+
+       /* mono mixer */
+       {"Mono Mixer", "Left Playback Switch", "Left DAC"},
+       {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+       {"Mono Mixer", "Right Playback Switch", "Right DAC"},
+       {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+       /* mono out */
+       {"Mono Out", NULL, "Mono Mixer"},
+       {"MONO1", NULL, "Mono Out"},
+
+       /* Left Line Mux */
+       {"Left Line Mux", "Line", "LINPUT1"},
+       {"Left Line Mux", "PGA", "Left PGA Mux"},
+       {"Left Line Mux", "Differential", "Differential Mux"},
+
+       /* Right Line Mux */
+       {"Right Line Mux", "Line", "RINPUT1"},
+       {"Right Line Mux", "Mic", "MIC"},
+       {"Right Line Mux", "PGA", "Right PGA Mux"},
+       {"Right Line Mux", "Differential", "Differential Mux"},
+
+       /* Left PGA Mux */
+       {"Left PGA Mux", "Line", "LINPUT1"},
+       {"Left PGA Mux", "Differential", "Differential Mux"},
+
+       /* Right PGA Mux */
+       {"Right PGA Mux", "Line", "RINPUT1"},
+       {"Right PGA Mux", "Differential", "Differential Mux"},
+
+       /* Differential Mux */
+       {"Differential Mux", "Line", "LINPUT1"},
+       {"Differential Mux", "Line", "RINPUT1"},
+
+       /* Left ADC Mux */
+       {"Left ADC Mux", "Stereo", "Left PGA Mux"},
+       {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+       {"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+       /* Right ADC Mux */
+       {"Right ADC Mux", "Stereo", "Right PGA Mux"},
+       {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+       {"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+       /* ADC */
+       {"Left ADC", NULL, "Left ADC Mux"},
+       {"Right ADC", NULL, "Right ADC Mux"},
+};
+
+static int wm8971_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets,
+                                 ARRAY_SIZE(wm8971_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+
+       return 0;
+}
+
+struct _coeff_div {
+       u32 mclk;
+       u32 rate;
+       u16 fs;
+       u8 sr:5;
+       u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+       /* 8k */
+       {12288000, 8000, 1536, 0x6, 0x0},
+       {11289600, 8000, 1408, 0x16, 0x0},
+       {18432000, 8000, 2304, 0x7, 0x0},
+       {16934400, 8000, 2112, 0x17, 0x0},
+       {12000000, 8000, 1500, 0x6, 0x1},
+
+       /* 11.025k */
+       {11289600, 11025, 1024, 0x18, 0x0},
+       {16934400, 11025, 1536, 0x19, 0x0},
+       {12000000, 11025, 1088, 0x19, 0x1},
+
+       /* 16k */
+       {12288000, 16000, 768, 0xa, 0x0},
+       {18432000, 16000, 1152, 0xb, 0x0},
+       {12000000, 16000, 750, 0xa, 0x1},
+
+       /* 22.05k */
+       {11289600, 22050, 512, 0x1a, 0x0},
+       {16934400, 22050, 768, 0x1b, 0x0},
+       {12000000, 22050, 544, 0x1b, 0x1},
+
+       /* 32k */
+       {12288000, 32000, 384, 0xc, 0x0},
+       {18432000, 32000, 576, 0xd, 0x0},
+       {12000000, 32000, 375, 0xa, 0x1},
+
+       /* 44.1k */
+       {11289600, 44100, 256, 0x10, 0x0},
+       {16934400, 44100, 384, 0x11, 0x0},
+       {12000000, 44100, 272, 0x11, 0x1},
+
+       /* 48k */
+       {12288000, 48000, 256, 0x0, 0x0},
+       {18432000, 48000, 384, 0x1, 0x0},
+       {12000000, 48000, 250, 0x0, 0x1},
+
+       /* 88.2k */
+       {11289600, 88200, 128, 0x1e, 0x0},
+       {16934400, 88200, 192, 0x1f, 0x0},
+       {12000000, 88200, 136, 0x1f, 0x1},
+
+       /* 96k */
+       {12288000, 96000, 128, 0xe, 0x0},
+       {18432000, 96000, 192, 0xf, 0x0},
+       {12000000, 96000, 125, 0xe, 0x1},
+};
+
+static int get_coeff(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8971_priv *wm8971 = codec->private_data;
+
+       switch (freq) {
+       case 11289600:
+       case 12000000:
+       case 12288000:
+       case 16934400:
+       case 18432000:
+               wm8971->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = 0;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface = 0x0040;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= 0x0002;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= 0x0001;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= 0x0003;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface |= 0x0013;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= 0x0090;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= 0x0080;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= 0x0010;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8971_write(codec, WM8971_IFACE, iface);
+       return 0;
+}
+
+static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8971_priv *wm8971 = codec->private_data;
+       u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3;
+       u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0;
+       int coeff = get_coeff(wm8971->sysclk, params_rate(params));
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= 0x0004;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= 0x0008;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= 0x000c;
+               break;
+       }
+
+       /* set iface & srate */
+       wm8971_write(codec, WM8971_IFACE, iface);
+       if (coeff >= 0)
+               wm8971_write(codec, WM8971_SRATE, srate |
+                       (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+       return 0;
+}
+
+static int wm8971_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7;
+
+       if (mute)
+               wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
+       else
+               wm8971_write(codec, WM8971_ADCDAC, mute_reg);
+       return 0;
+}
+
+static int wm8971_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* set vmid to 50k and unmute dac */
+               wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* mute dac and set vmid to 500k, enable VREF */
+               wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
+               break;
+       case SND_SOC_BIAS_OFF:
+               wm8971_write(codec, WM8971_PWR1, 0x0001);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8971_dai = {
+       .name = "WM8971",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8971_RATES,
+               .formats = WM8971_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8971_RATES,
+               .formats = WM8971_FORMATS,},
+       .ops = {
+               .hw_params = wm8971_pcm_hw_params,
+       },
+       .dai_ops = {
+               .digital_mute = wm8971_mute,
+               .set_fmt = wm8971_set_dai_fmt,
+               .set_sysclk = wm8971_set_dai_sysclk,
+       },
+};
+EXPORT_SYMBOL_GPL(wm8971_dai);
+
+static void wm8971_work(struct work_struct *work)
+{
+       struct snd_soc_codec *codec =
+               container_of(work, struct snd_soc_codec, delayed_work.work);
+       wm8971_set_bias_level(codec, codec->bias_level);
+}
+
+static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8971_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u8 data[2];
+       u16 *cache = codec->reg_cache;
+       u16 reg;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) {
+               if (i + 1 == WM8971_RESET)
+                       continue;
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+
+       wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* charge wm8971 caps */
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+               reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+               wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
+               codec->bias_level = SND_SOC_BIAS_ON;
+               queue_delayed_work(wm8971_workq, &codec->delayed_work,
+                       msecs_to_jiffies(1000));
+       }
+
+       return 0;
+}
+
+static int wm8971_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int reg, ret = 0;
+
+       codec->name = "WM8971";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8971_read_reg_cache;
+       codec->write = wm8971_write;
+       codec->set_bias_level = wm8971_set_bias_level;
+       codec->dai = &wm8971_dai;
+       codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
+       codec->num_dai = 1;
+       codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
+
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       wm8971_reset(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8971: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* charge output caps - set vmid to 5k for quick power up */
+       reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+       wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
+       codec->bias_level = SND_SOC_BIAS_STANDBY;
+       queue_delayed_work(wm8971_workq, &codec->delayed_work,
+               msecs_to_jiffies(1000));
+
+       /* set the update bits */
+       reg = wm8971_read_reg_cache(codec, WM8971_LDAC);
+       wm8971_write(codec, WM8971_LDAC, reg | 0x0100);
+       reg = wm8971_read_reg_cache(codec, WM8971_RDAC);
+       wm8971_write(codec, WM8971_RDAC, reg | 0x0100);
+
+       reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V);
+       wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100);
+       reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V);
+       wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100);
+
+       reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V);
+       wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100);
+       reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V);
+       wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100);
+
+       reg = wm8971_read_reg_cache(codec, WM8971_LINVOL);
+       wm8971_write(codec, WM8971_LINVOL, reg | 0x0100);
+       reg = wm8971_read_reg_cache(codec, WM8971_RINVOL);
+       wm8971_write(codec, WM8971_RINVOL, reg | 0x0100);
+
+       wm8971_add_controls(codec);
+       wm8971_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8971: failed to register card\n");
+               goto card_err;
+       }
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8971_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+static int wm8971_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct snd_soc_device *socdev = wm8971_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       i2c_set_clientdata(i2c, codec);
+
+       codec->control_data = i2c;
+
+       ret = wm8971_init(socdev);
+       if (ret < 0)
+               pr_err("failed to initialise WM8971\n");
+
+       return ret;
+}
+
+static int wm8971_i2c_remove(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       kfree(codec->reg_cache);
+       return 0;
+}
+
+static const struct i2c_device_id wm8971_i2c_id[] = {
+       { "wm8971", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
+
+static struct i2c_driver wm8971_i2c_driver = {
+       .driver = {
+               .name = "WM8971 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe    = wm8971_i2c_probe,
+       .remove   = wm8971_i2c_remove,
+       .id_table = wm8971_i2c_id,
+};
+
+static int wm8971_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8971_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8971_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8971_i2c_driver);
+       return -ENODEV;
+}
+
+#endif
+
+static int wm8971_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct wm8971_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct wm8971_priv *wm8971;
+       int ret = 0;
+
+       pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+       if (wm8971 == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = wm8971;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+       wm8971_socdev = socdev;
+
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+       wm8971_workq = create_workqueue("wm8971");
+       if (wm8971_workq == NULL) {
+               kfree(codec->private_data);
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = wm8971_add_i2c_device(pdev, setup);
+       }
+#endif
+       /* Add other interfaces here */
+
+       if (ret != 0) {
+               destroy_workqueue(wm8971_workq);
+               kfree(codec->private_data);
+               kfree(codec);
+       }
+
+       return ret;
+}
+
+/* power down chip */
+static int wm8971_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       if (wm8971_workq)
+               destroy_workqueue(wm8971_workq);
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
+       i2c_del_driver(&wm8971_i2c_driver);
+#endif
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8971 = {
+       .probe =        wm8971_probe,
+       .remove =       wm8971_remove,
+       .suspend =      wm8971_suspend,
+       .resume =       wm8971_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
+
+MODULE_DESCRIPTION("ASoC WM8971 driver");
+MODULE_AUTHOR("Lab126");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h
new file mode 100644 (file)
index 0000000..ef4f08f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * wm8971.h  --  audio driver for WM8971
+ *
+ * Copyright 2005 Lab126, Inc.
+ *
+ * Author: Kenneth Kiraly <kiraly@lab126.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.
+ *
+ */
+
+#ifndef _WM8971_H
+#define _WM8971_H
+
+#define WM8971_LINVOL  0x00
+#define WM8971_RINVOL  0x01
+#define WM8971_LOUT1V  0x02
+#define WM8971_ROUT1V  0x03
+#define WM8971_ADCDAC  0x05
+#define WM8971_IFACE   0x07
+#define WM8971_SRATE   0x08
+#define WM8971_LDAC            0x0a
+#define WM8971_RDAC            0x0b
+#define WM8971_BASS            0x0c
+#define WM8971_TREBLE  0x0d
+#define WM8971_RESET   0x0f
+#define WM8971_ALC1            0x11
+#define        WM8971_ALC2             0x12
+#define        WM8971_ALC3             0x13
+#define WM8971_NGATE   0x14
+#define WM8971_LADC            0x15
+#define WM8971_RADC            0x16
+#define        WM8971_ADCTL1   0x17
+#define        WM8971_ADCTL2   0x18
+#define WM8971_PWR1            0x19
+#define WM8971_PWR2            0x1a
+#define        WM8971_ADCTL3   0x1b
+#define WM8971_ADCIN   0x1f
+#define        WM8971_LADCIN   0x20
+#define        WM8971_RADCIN   0x21
+#define WM8971_LOUTM1  0x22
+#define WM8971_LOUTM2  0x23
+#define WM8971_ROUTM1  0x24
+#define WM8971_ROUTM2  0x25
+#define WM8971_MOUTM1  0x26
+#define WM8971_MOUTM2  0x27
+#define WM8971_LOUT2V  0x28
+#define WM8971_ROUT2V  0x29
+#define WM8971_MOUTV   0x2A
+
+#define WM8971_SYSCLK  0
+
+struct wm8971_setup_data {
+       int i2c_bus;
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8971_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8971;
+
+#endif
index dd995ef448b44452dcab76cdb2f3aa0f48a1b55c..63410d7b5efb3623c8e92585ac51fb9ff8737606 100644 (file)
@@ -1477,81 +1477,86 @@ static struct snd_soc_device *wm8990_socdev;
  *    low  = 0x34
  *    high = 0x36
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8990_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8990_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8990_socdev;
-       struct wm8990_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               pr_err("failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = wm8990_init(socdev);
-       if (ret < 0) {
+       if (ret < 0)
                pr_err("failed to initialise WM8990\n");
-               goto err;
-       }
-       return ret;
 
-err:
-       kfree(i2c);
        return ret;
 }
 
-static int wm8990_i2c_detach(struct i2c_client *client)
+static int wm8990_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int wm8990_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, wm8990_codec_probe);
-}
+static const struct i2c_device_id wm8990_i2c_id[] = {
+       { "wm8990", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
 
 static struct i2c_driver wm8990_i2c_driver = {
        .driver = {
                .name = "WM8990 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .attach_adapter = wm8990_i2c_attach,
-       .detach_client =  wm8990_i2c_detach,
-       .command =        NULL,
+       .probe =    wm8990_i2c_probe,
+       .remove =   wm8990_i2c_remove,
+       .id_table = wm8990_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "WM8990",
-       .driver = &wm8990_i2c_driver,
-};
+static int wm8990_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8990_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8990_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8990_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int wm8990_probe(struct platform_device *pdev)
@@ -1560,7 +1565,7 @@ static int wm8990_probe(struct platform_device *pdev)
        struct wm8990_setup_data *setup;
        struct snd_soc_codec *codec;
        struct wm8990_priv *wm8990;
-       int ret = 0;
+       int ret;
 
        pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
 
@@ -1582,16 +1587,13 @@ static int wm8990_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&codec->dapm_paths);
        wm8990_socdev = socdev;
 
+       ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&wm8990_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = wm8990_add_i2c_device(pdev, setup);
        }
-#else
-               /* Add other interfaces here */
 #endif
 
        if (ret != 0) {
@@ -1612,6 +1614,7 @@ static int wm8990_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8990_i2c_driver);
 #endif
        kfree(codec->private_data);
index 0a08325d54430819ac0d3a7552384881eea095ca..0e192f3b07882a44cb7950486c3f8bacafa4a09f 100644 (file)
 #define WM8990_AINRMUX_PWR_BIT                 3
 
 struct wm8990_setup_data {
+       unsigned i2c_bus;
        unsigned short i2c_address;
 };
 
index 38d1fe0971fc7faf328c6a19ca0f6f6516f42577..441d0580db1f75adf212ee40a882cd4ca47fb4c0 100644 (file)
@@ -419,8 +419,12 @@ SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1),
 SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1),
-SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_EXTENDED_MID, 5, 1),
-SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_EXTENDED_MID, 4, 1),
+SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0),
+SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Left Voice ADC", "Left Voice Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Right Voice ADC", "Right Voice Capture", SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0),
@@ -583,9 +587,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
        /* left ADC */
        {"Left ADC", NULL, "Left Capture Source"},
+       {"Left Voice ADC", NULL, "Left ADC"},
+       {"Left HiFi ADC", NULL, "Left ADC"},
 
        /* right ADC */
        {"Right ADC", NULL, "Right Capture Source"},
+       {"Right Voice ADC", NULL, "Right ADC"},
+       {"Right HiFi ADC", NULL, "Right ADC"},
 
        /* mic */
        {"Mic A Pre Amp", NULL, "Mic A Source"},
@@ -949,17 +957,17 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static void wm9713_voiceshutdown(struct snd_pcm_substream *substream)
 {
-    struct snd_soc_pcm_runtime *rtd = substream->private_data;
-    struct snd_soc_device *socdev = rtd->socdev;
-    struct snd_soc_codec *codec = socdev->codec;
-    u16 status;
-
-    /* Gracefully shut down the voice interface. */
-    status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
-    ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
-    schedule_timeout_interruptible(msecs_to_jiffies(1));
-    ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
-    ac97_write(codec, AC97_EXTENDED_MID, status);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 status;
+
+       /* Gracefully shut down the voice interface. */
+       status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
+       ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
+       ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
+       ac97_write(codec, AC97_EXTENDED_MID, status);
 }
 
 static int ac97_hifi_prepare(struct snd_pcm_substream *substream)
index 65fdbd81a379c022589697eda8445dd62380bf83..9e6062cd6b59957f6df964470a52b8756f7f9398 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ASoC driver for TI DAVINCI EVM platform
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -136,6 +136,7 @@ static struct snd_soc_machine snd_soc_machine_evm = {
 
 /* evm audio private data */
 static struct aic3x_setup_data evm_aic3x_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1b,
 };
 
index 5ebf1ff71c4cbce6451ecd63dbe080586ac531ea..abb5fedb0b1e0952ecb17fedb7592ab966c0ffda 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -256,7 +256,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
                break;
        default:
-               printk(KERN_WARNING "davinci-i2s: unsupported PCM format");
+               printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
                return -EINVAL;
        }
 
index c5b091807eecf891bb71baa1a208933da3c62a17..241648ce8873014cd6e8a2f52ec6bf11c08b3028 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
index 6a5e56a782bb2f9a13551aa3365a6b2b7db85e4a..76feaa657375e3579cee33db8528a3d6e57f4da6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA PCM interface for the TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
index 8d6a45e75a6ef06be50c840bfbdcf7279dbb3c27..62cb4eb07e34404121f7075a2c6de05c28fe40bb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA PCM interface for the TI DAVINCI processor
  *
- * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or modify
index 3368ace60977eac389f1b57254e3fcb6c832ab4d..bba9546ba5f5c30d076cb7962359d9405f1cc0fa 100644 (file)
@@ -1,3 +1,6 @@
+config SND_SOC_OF_SIMPLE
+       tristate
+
 config SND_SOC_MPC8610
        bool "ALSA SoC support for the MPC8610 SOC"
        depends on MPC8610_HPCD
@@ -14,3 +17,10 @@ config SND_SOC_MPC8610_HPCD
        default y if MPC8610_HPCD
        help
          Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
+
+config SND_SOC_MPC5200_I2S
+       tristate "Freescale MPC5200 PSC in I2S mode driver"
+       select SND_SOC_OF_SIMPLE
+       depends on SND_SOC && PPC_MPC52xx
+       help
+         Say Y here to support the MPC5200 PSCs in I2S mode.
index 62f680a4a7766e9d2d6e305fda697be006311d0b..035da4afec34bb8961dfbd86a5ffd23164bb0ce2 100644 (file)
@@ -1,6 +1,11 @@
+# Simple machine driver that extracts configuration from the OF device tree
+obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
+
 # MPC8610 HPCD Machine Support
 obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
 
 # MPC8610 Platform Support
 obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
 
+obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
new file mode 100644 (file)
index 0000000..8692329
--- /dev/null
@@ -0,0 +1,884 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/gen_bd.h>
+#include <asm/mpc52xx_psc.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
+
+/**
+ * PSC_I2S_RATES: sample rates supported by the I2S
+ *
+ * This driver currently only supports the PSC running in I2S slave mode,
+ * which means the codec determines the sample rate.  Therefore, we tell
+ * ALSA that we support all rates and let the codec driver decide what rates
+ * are really supported.
+ */
+#define PSC_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
+                       SNDRV_PCM_RATE_CONTINUOUS)
+
+/**
+ * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
+ */
+#define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+                        SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
+                        SNDRV_PCM_FMTBIT_S32_BE)
+
+/**
+ * psc_i2s_stream - Data specific to a single stream (playback or capture)
+ * @active:            flag indicating if the stream is active
+ * @psc_i2s:           pointer back to parent psc_i2s data structure
+ * @bcom_task:         bestcomm task structure
+ * @irq:               irq number for bestcomm task
+ * @period_start:      physical address of start of DMA region
+ * @period_end:                physical address of end of DMA region
+ * @period_next_pt:    physical address of next DMA buffer to enqueue
+ * @period_bytes:      size of DMA period in bytes
+ */
+struct psc_i2s_stream {
+       int active;
+       struct psc_i2s *psc_i2s;
+       struct bcom_task *bcom_task;
+       int irq;
+       struct snd_pcm_substream *stream;
+       dma_addr_t period_start;
+       dma_addr_t period_end;
+       dma_addr_t period_next_pt;
+       dma_addr_t period_current_pt;
+       int period_bytes;
+};
+
+/**
+ * psc_i2s - Private driver data
+ * @name: short name for this device ("PSC0", "PSC1", etc)
+ * @psc_regs: pointer to the PSC's registers
+ * @fifo_regs: pointer to the PSC's FIFO registers
+ * @irq: IRQ of this PSC
+ * @dev: struct device pointer
+ * @dai: the CPU DAI for this device
+ * @sicr: Base value used in serial interface control register; mode is ORed
+ *        with this value.
+ * @playback: Playback stream context data
+ * @capture: Capture stream context data
+ */
+struct psc_i2s {
+       char name[32];
+       struct mpc52xx_psc __iomem *psc_regs;
+       struct mpc52xx_psc_fifo __iomem *fifo_regs;
+       unsigned int irq;
+       struct device *dev;
+       struct snd_soc_dai dai;
+       spinlock_t lock;
+       u32 sicr;
+
+       /* per-stream data */
+       struct psc_i2s_stream playback;
+       struct psc_i2s_stream capture;
+
+       /* Statistics */
+       struct {
+               int overrun_count;
+               int underrun_count;
+       } stats;
+};
+
+/*
+ * Interrupt handlers
+ */
+static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
+{
+       struct psc_i2s *psc_i2s = _psc_i2s;
+       struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+       u16 isr;
+
+       isr = in_be16(&regs->mpc52xx_psc_isr);
+
+       /* Playback underrun error */
+       if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
+               psc_i2s->stats.underrun_count++;
+
+       /* Capture overrun error */
+       if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
+               psc_i2s->stats.overrun_count++;
+
+       out_8(&regs->command, 4 << 4);  /* reset the error status */
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
+ * @s: pointer to stream private data structure
+ *
+ * Enqueues another audio period buffer into the bestcomm queue.
+ *
+ * Note: The routine must only be called when there is space available in
+ * the queue.  Otherwise the enqueue will fail and the audio ring buffer
+ * will get out of sync
+ */
+static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
+{
+       struct bcom_bd *bd;
+
+       /* Prepare and enqueue the next buffer descriptor */
+       bd = bcom_prepare_next_buffer(s->bcom_task);
+       bd->status = s->period_bytes;
+       bd->data[0] = s->period_next_pt;
+       bcom_submit_next_buffer(s->bcom_task, NULL);
+
+       /* Update for next period */
+       s->period_next_pt += s->period_bytes;
+       if (s->period_next_pt >= s->period_end)
+               s->period_next_pt = s->period_start;
+}
+
+/* Bestcomm DMA irq handler */
+static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
+{
+       struct psc_i2s_stream *s = _psc_i2s_stream;
+
+       /* For each finished period, dequeue the completed period buffer
+        * and enqueue a new one in it's place. */
+       while (bcom_buffer_done(s->bcom_task)) {
+               bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+               s->period_current_pt += s->period_bytes;
+               if (s->period_current_pt >= s->period_end)
+                       s->period_current_pt = s->period_start;
+               psc_i2s_bcom_enqueue_next_buffer(s);
+               bcom_enable(s->bcom_task);
+       }
+
+       /* If the stream is active, then also inform the PCM middle layer
+        * of the period finished event. */
+       if (s->active)
+               snd_pcm_period_elapsed(s->stream);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * psc_i2s_startup: create a new substream
+ *
+ * This is the first function called when a stream is opened.
+ *
+ * If this is the first stream open, then grab the IRQ and program most of
+ * the PSC registers.
+ */
+static int psc_i2s_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       int rc;
+
+       dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream);
+
+       if (!psc_i2s->playback.active &&
+           !psc_i2s->capture.active) {
+               /* Setup the IRQs */
+               rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED,
+                                "psc-i2s-status", psc_i2s);
+               rc |= request_irq(psc_i2s->capture.irq,
+                                 &psc_i2s_bcom_irq, IRQF_SHARED,
+                                 "psc-i2s-capture", &psc_i2s->capture);
+               rc |= request_irq(psc_i2s->playback.irq,
+                                 &psc_i2s_bcom_irq, IRQF_SHARED,
+                                 "psc-i2s-playback", &psc_i2s->playback);
+               if (rc) {
+                       free_irq(psc_i2s->irq, psc_i2s);
+                       free_irq(psc_i2s->capture.irq,
+                                &psc_i2s->capture);
+                       free_irq(psc_i2s->playback.irq,
+                                &psc_i2s->playback);
+                       return -ENODEV;
+               }
+       }
+
+       return 0;
+}
+
+static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       u32 mode;
+
+       dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+               " periods=%i buffer_size=%i  buffer_bytes=%i\n",
+               __func__, substream, params_period_size(params),
+               params_period_bytes(params), params_periods(params),
+               params_buffer_size(params), params_buffer_bytes(params));
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               mode = MPC52xx_PSC_SICR_SIM_CODEC_8;
+               break;
+       case SNDRV_PCM_FORMAT_S16_BE:
+               mode = MPC52xx_PSC_SICR_SIM_CODEC_16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_BE:
+               mode = MPC52xx_PSC_SICR_SIM_CODEC_24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_BE:
+               mode = MPC52xx_PSC_SICR_SIM_CODEC_32;
+               break;
+       default:
+               dev_dbg(psc_i2s->dev, "invalid format\n");
+               return -EINVAL;
+       }
+       out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode);
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       return 0;
+}
+
+static int psc_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_set_runtime_buffer(substream, NULL);
+       return 0;
+}
+
+/**
+ * psc_i2s_trigger: start and stop the DMA transfer.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the DMA
+ * transfer of data.
+ */
+static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct psc_i2s_stream *s;
+       struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+       u16 imr;
+       u8 psc_cmd;
+       long flags;
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_i2s->capture;
+       else
+               s = &psc_i2s->playback;
+
+       dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)"
+               " stream_id=%i\n",
+               substream, cmd, substream->pstr->stream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               s->period_bytes = frames_to_bytes(runtime,
+                                                 runtime->period_size);
+               s->period_start = virt_to_phys(runtime->dma_area);
+               s->period_end = s->period_start +
+                               (s->period_bytes * runtime->periods);
+               s->period_next_pt = s->period_start;
+               s->period_current_pt = s->period_start;
+               s->active = 1;
+
+               /* First; reset everything */
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       out_8(&regs->command, MPC52xx_PSC_RST_RX);
+                       out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+               } else {
+                       out_8(&regs->command, MPC52xx_PSC_RST_TX);
+                       out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+               }
+
+               /* Next, fill up the bestcomm bd queue and enable DMA.
+                * This will begin filling the PSC's fifo. */
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       bcom_gen_bd_rx_reset(s->bcom_task);
+               else
+                       bcom_gen_bd_tx_reset(s->bcom_task);
+               while (!bcom_queue_full(s->bcom_task))
+                       psc_i2s_bcom_enqueue_next_buffer(s);
+               bcom_enable(s->bcom_task);
+
+               /* Due to errata in the i2s mode; need to line up enabling
+                * the transmitter with a transition on the frame sync
+                * line */
+
+               spin_lock_irqsave(&psc_i2s->lock, flags);
+               /* first make sure it is low */
+               while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
+                       ;
+               /* then wait for the transition to high */
+               while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
+                       ;
+               /* Finally, enable the PSC.
+                * Receiver must always be enabled; even when we only want
+                * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
+               psc_cmd = MPC52xx_PSC_RX_ENABLE;
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       psc_cmd |= MPC52xx_PSC_TX_ENABLE;
+               out_8(&regs->command, psc_cmd);
+               spin_unlock_irqrestore(&psc_i2s->lock, flags);
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+               /* Turn off the PSC */
+               s->active = 0;
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       if (!psc_i2s->playback.active) {
+                               out_8(&regs->command, 2 << 4);  /* reset rx */
+                               out_8(&regs->command, 3 << 4);  /* reset tx */
+                               out_8(&regs->command, 4 << 4);  /* reset err */
+                       }
+               } else {
+                       out_8(&regs->command, 3 << 4);  /* reset tx */
+                       out_8(&regs->command, 4 << 4);  /* reset err */
+                       if (!psc_i2s->capture.active)
+                               out_8(&regs->command, 2 << 4);  /* reset rx */
+               }
+
+               bcom_disable(s->bcom_task);
+               while (!bcom_queue_empty(s->bcom_task))
+                       bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
+               break;
+
+       default:
+               dev_dbg(psc_i2s->dev, "invalid command\n");
+               return -EINVAL;
+       }
+
+       /* Update interrupt enable settings */
+       imr = 0;
+       if (psc_i2s->playback.active)
+               imr |= MPC52xx_PSC_IMR_TXEMP;
+       if (psc_i2s->capture.active)
+               imr |= MPC52xx_PSC_IMR_ORERR;
+       out_be16(&regs->isr_imr.imr, imr);
+
+       return 0;
+}
+
+/**
+ * psc_i2s_shutdown: shutdown the data transfer on a stream
+ *
+ * Shutdown the PSC if there are no other substreams open.
+ */
+static void psc_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+
+       dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream);
+
+       /*
+        * If this is the last active substream, disable the PSC and release
+        * the IRQ.
+        */
+       if (!psc_i2s->playback.active &&
+           !psc_i2s->capture.active) {
+
+               /* Disable all interrupts and reset the PSC */
+               out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
+               out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */
+               out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */
+               out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
+               out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+
+               /* Release irqs */
+               free_irq(psc_i2s->irq, psc_i2s);
+               free_irq(psc_i2s->capture.irq, &psc_i2s->capture);
+               free_irq(psc_i2s->playback.irq, &psc_i2s->playback);
+       }
+}
+
+/**
+ * psc_i2s_set_sysclk: set the clock frequency and direction
+ *
+ * This function is called by the machine driver to tell us what the clock
+ * frequency and direction are.
+ *
+ * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
+ * and we don't care about the frequency.  Return an error if the direction
+ * is not SND_SOC_CLOCK_IN.
+ *
+ * @clk_id: reserved, should be zero
+ * @freq: the frequency of the given clock ID, currently ignored
+ * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
+ */
+static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+                             int clk_id, unsigned int freq, int dir)
+{
+       struct psc_i2s *psc_i2s = cpu_dai->private_data;
+       dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
+                               cpu_dai, dir);
+       return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
+}
+
+/**
+ * psc_i2s_set_fmt: set the serial format.
+ *
+ * This function is called by the machine driver to tell us what serial
+ * format to use.
+ *
+ * This driver only supports I2S mode.  Return an error if the format is
+ * not SND_SOC_DAIFMT_I2S.
+ *
+ * @format: one of SND_SOC_DAIFMT_xxx
+ */
+static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
+{
+       struct psc_i2s *psc_i2s = cpu_dai->private_data;
+       dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
+                               cpu_dai, format);
+       return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_i2s_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_dai psc_i2s_dai_template = {
+       .type = SND_SOC_DAI_I2S,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = PSC_I2S_RATES,
+               .formats = PSC_I2S_FORMATS,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = PSC_I2S_RATES,
+               .formats = PSC_I2S_FORMATS,
+       },
+       .ops = {
+               .startup = psc_i2s_startup,
+               .hw_params = psc_i2s_hw_params,
+               .hw_free = psc_i2s_hw_free,
+               .shutdown = psc_i2s_shutdown,
+               .trigger = psc_i2s_trigger,
+       },
+       .dai_ops = {
+               .set_sysclk = psc_i2s_set_sysclk,
+               .set_fmt = psc_i2s_set_fmt,
+       },
+};
+
+/* ---------------------------------------------------------------------
+ * The PSC I2S 'ASoC platform' driver
+ *
+ * Can be referenced by an 'ASoC machine' driver
+ * This driver only deals with the audio bus; it doesn't have any
+ * interaction with the attached codec
+ */
+
+static const struct snd_pcm_hardware psc_i2s_pcm_hardware = {
+       .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+       .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
+                  SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .period_bytes_max       = 1024 * 1024,
+       .period_bytes_min       = 32,
+       .periods_min            = 2,
+       .periods_max            = 256,
+       .buffer_bytes_max       = 2 * 1024 * 1024,
+       .fifo_size              = 0,
+};
+
+static int psc_i2s_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       struct psc_i2s_stream *s;
+
+       dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream);
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_i2s->capture;
+       else
+               s = &psc_i2s->playback;
+
+       snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware);
+
+       s->stream = substream;
+       return 0;
+}
+
+static int psc_i2s_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       struct psc_i2s_stream *s;
+
+       dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream);
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_i2s->capture;
+       else
+               s = &psc_i2s->playback;
+
+       s->stream = NULL;
+       return 0;
+}
+
+static snd_pcm_uframes_t
+psc_i2s_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       struct psc_i2s_stream *s;
+       dma_addr_t count;
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_i2s->capture;
+       else
+               s = &psc_i2s->playback;
+
+       count = s->period_current_pt - s->period_start;
+
+       return bytes_to_frames(substream->runtime, count);
+}
+
+static struct snd_pcm_ops psc_i2s_pcm_ops = {
+       .open           = psc_i2s_pcm_open,
+       .close          = psc_i2s_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .pointer        = psc_i2s_pcm_pointer,
+};
+
+static u64 psc_i2s_pcm_dmamask = 0xffffffff;
+static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+                          struct snd_pcm *pcm)
+{
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       size_t size = psc_i2s_pcm_hardware.buffer_bytes_max;
+       int rc = 0;
+
+       dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n",
+               card, dai, pcm);
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &psc_i2s_pcm_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = 0xffffffff;
+
+       if (pcm->streams[0].substream) {
+               rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+                                       &pcm->streams[0].substream->dma_buffer);
+               if (rc)
+                       goto playback_alloc_err;
+       }
+
+       if (pcm->streams[1].substream) {
+               rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+                                       &pcm->streams[1].substream->dma_buffer);
+               if (rc)
+                       goto capture_alloc_err;
+       }
+
+       return 0;
+
+ capture_alloc_err:
+       if (pcm->streams[0].substream)
+               snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+ playback_alloc_err:
+       dev_err(card->dev, "Cannot allocate buffer(s)\n");
+       return -ENOMEM;
+}
+
+static void psc_i2s_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_pcm_substream *substream;
+       int stream;
+
+       dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm);
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (substream) {
+                       snd_dma_free_pages(&substream->dma_buffer);
+                       substream->dma_buffer.area = NULL;
+                       substream->dma_buffer.addr = 0;
+               }
+       }
+}
+
+struct snd_soc_platform psc_i2s_pcm_soc_platform = {
+       .name           = "mpc5200-psc-audio",
+       .pcm_ops        = &psc_i2s_pcm_ops,
+       .pcm_new        = &psc_i2s_pcm_new,
+       .pcm_free       = &psc_i2s_pcm_free,
+};
+
+/* ---------------------------------------------------------------------
+ * Sysfs attributes for debugging
+ */
+
+static ssize_t psc_i2s_status_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+
+       return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
+                       "tfnum=%i tfstat=0x%.4x\n",
+                       in_be16(&psc_i2s->psc_regs->sr_csr.status),
+                       in_be32(&psc_i2s->psc_regs->sicr),
+                       in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff,
+                       in_be16(&psc_i2s->fifo_regs->rfstat),
+                       in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff,
+                       in_be16(&psc_i2s->fifo_regs->tfstat));
+}
+
+static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name)
+{
+       if (strcmp(name, "playback_underrun") == 0)
+               return &psc_i2s->stats.underrun_count;
+       if (strcmp(name, "capture_overrun") == 0)
+               return &psc_i2s->stats.overrun_count;
+
+       return NULL;
+}
+
+static ssize_t psc_i2s_stat_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+       int *attrib;
+
+       attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
+       if (!attrib)
+               return 0;
+
+       return sprintf(buf, "%i\n", *attrib);
+}
+
+static ssize_t psc_i2s_stat_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf,
+                                 size_t count)
+{
+       struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+       int *attrib;
+
+       attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
+       if (!attrib)
+               return 0;
+
+       *attrib = simple_strtoul(buf, NULL, 0);
+       return count;
+}
+
+DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
+DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store);
+DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store);
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_i2s_of_probe(struct of_device *op,
+                                     const struct of_device_id *match)
+{
+       phys_addr_t fifo;
+       struct psc_i2s *psc_i2s;
+       struct resource res;
+       int size, psc_id, irq, rc;
+       const __be32 *prop;
+       void __iomem *regs;
+
+       dev_dbg(&op->dev, "probing psc i2s device\n");
+
+       /* Get the PSC ID */
+       prop = of_get_property(op->node, "cell-index", &size);
+       if (!prop || size < sizeof *prop)
+               return -ENODEV;
+       psc_id = be32_to_cpu(*prop);
+
+       /* Fetch the registers and IRQ of the PSC */
+       irq = irq_of_parse_and_map(op->node, 0);
+       if (of_address_to_resource(op->node, 0, &res)) {
+               dev_err(&op->dev, "Missing reg property\n");
+               return -ENODEV;
+       }
+       regs = ioremap(res.start, 1 + res.end - res.start);
+       if (!regs) {
+               dev_err(&op->dev, "Could not map registers\n");
+               return -ENODEV;
+       }
+
+       /* Allocate and initialize the driver private data */
+       psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL);
+       if (!psc_i2s) {
+               iounmap(regs);
+               return -ENOMEM;
+       }
+       spin_lock_init(&psc_i2s->lock);
+       psc_i2s->irq = irq;
+       psc_i2s->psc_regs = regs;
+       psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs;
+       psc_i2s->dev = &op->dev;
+       psc_i2s->playback.psc_i2s = psc_i2s;
+       psc_i2s->capture.psc_i2s = psc_i2s;
+       snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1);
+
+       /* Fill out the CPU DAI structure */
+       memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai);
+       psc_i2s->dai.private_data = psc_i2s;
+       psc_i2s->dai.name = psc_i2s->name;
+       psc_i2s->dai.id = psc_id;
+
+       /* Find the address of the fifo data registers and setup the
+        * DMA tasks */
+       fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+       psc_i2s->capture.bcom_task =
+               bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
+       psc_i2s->playback.bcom_task =
+               bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
+       if (!psc_i2s->capture.bcom_task ||
+           !psc_i2s->playback.bcom_task) {
+               dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+               iounmap(regs);
+               kfree(psc_i2s);
+               return -ENODEV;
+       }
+
+       /* Disable all interrupts and reset the PSC */
+       out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
+       out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */
+       out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */
+       out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
+       out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+
+       /* Configure the serial interface mode; defaulting to CODEC8 mode */
+       psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
+                       MPC52xx_PSC_SICR_CLKPOL;
+       if (of_get_property(op->node, "fsl,cellslave", NULL))
+               psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |
+                                MPC52xx_PSC_SICR_GENCLK;
+       out_be32(&psc_i2s->psc_regs->sicr,
+                psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
+
+       /* Check for the codec handle.  If it is not present then we
+        * are done */
+       if (!of_get_property(op->node, "codec-handle", NULL))
+               return 0;
+
+       /* Set up mode register;
+        * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
+        * Second write: register Normal mode for non loopback
+        */
+       out_8(&psc_i2s->psc_regs->mode, 0);
+       out_8(&psc_i2s->psc_regs->mode, 0);
+
+       /* Set the TX and RX fifo alarm thresholds */
+       out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100);
+       out_8(&psc_i2s->fifo_regs->rfcntl, 0x4);
+       out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100);
+       out_8(&psc_i2s->fifo_regs->tfcntl, 0x7);
+
+       /* Lookup the IRQ numbers */
+       psc_i2s->playback.irq =
+               bcom_get_task_irq(psc_i2s->playback.bcom_task);
+       psc_i2s->capture.irq =
+               bcom_get_task_irq(psc_i2s->capture.bcom_task);
+
+       /* Save what we've done so it can be found again later */
+       dev_set_drvdata(&op->dev, psc_i2s);
+
+       /* Register the SYSFS files */
+       rc = device_create_file(psc_i2s->dev, &dev_attr_status);
+       rc = device_create_file(psc_i2s->dev, &dev_attr_capture_overrun);
+       rc = device_create_file(psc_i2s->dev, &dev_attr_playback_underrun);
+       if (rc)
+               dev_info(psc_i2s->dev, "error creating sysfs files\n");
+
+       /* Tell the ASoC OF helpers about it */
+       of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node,
+                                    &psc_i2s->dai);
+
+       return 0;
+}
+
+static int __devexit psc_i2s_of_remove(struct of_device *op)
+{
+       struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev);
+
+       dev_dbg(&op->dev, "psc_i2s_remove()\n");
+
+       bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task);
+       bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task);
+
+       iounmap(psc_i2s->psc_regs);
+       iounmap(psc_i2s->fifo_regs);
+       kfree(psc_i2s);
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_i2s_match[] __devinitdata = {
+       { .compatible = "fsl,mpc5200-psc-i2s", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, psc_i2s_match);
+
+static struct of_platform_driver psc_i2s_driver = {
+       .match_table = psc_i2s_match,
+       .probe = psc_i2s_of_probe,
+       .remove = __devexit_p(psc_i2s_of_remove),
+       .driver = {
+               .name = "mpc5200-psc-i2s",
+               .owner = THIS_MODULE,
+       },
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in I2S mode.
+ */
+static int __init psc_i2s_init(void)
+{
+       return of_register_platform_driver(&psc_i2s_driver);
+}
+module_init(psc_i2s_init);
+
+static void __exit psc_i2s_exit(void)
+{
+       of_unregister_platform_driver(&psc_i2s_driver);
+}
+module_exit(psc_i2s_exit);
+
+
index 4bdc9d8fc90e0d8fa3f4f7d6d5f14813c4abe5da..94f89debde1fa463a043741b022040bad7971b3e 100644 (file)
@@ -68,10 +68,6 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
        guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
                machine_data->dma_channel_id[1], 0);
 
-       guts_set_pmuxcr_dma(machine_data->guts, 1, 0, 0);
-       guts_set_pmuxcr_dma(machine_data->guts, 1, 3, 0);
-       guts_set_pmuxcr_dma(machine_data->guts, 0, 3, 0);
-
        switch (machine_data->ssi_id) {
        case 0:
                clrsetbits_be32(&machine_data->guts->pmuxcr,
@@ -230,6 +226,8 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
        struct fsl_ssi_info ssi_info;
        struct fsl_dma_info dma_info;
        int ret = -ENODEV;
+       unsigned int playback_dma_channel;
+       unsigned int capture_dma_channel;
 
        machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
        if (!machine_data)
@@ -381,8 +379,9 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
                goto error;
        }
 
-       /* Find the DMA channels to use.  For now, we always use the first DMA
-          controller. */
+       /* Find the DMA channels to use.  Both SSIs need to use the same DMA
+        * controller, so let's use DMA#1.
+        */
        for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
                iprop = of_get_property(dma_np, "cell-index", NULL);
                if (iprop && (*iprop == 0)) {
@@ -397,14 +396,19 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
        }
        machine_data->dma_id = *iprop;
 
+       /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
+        * channels 2 and 3.  This is just how the MPC8610 is wired
+        * internally.
+        */
+       playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
+       capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
+
        /*
-        * Find the DMA channels to use.  For now, we always use DMA channel 0
-        * for playback, and DMA channel 1 for capture.
+        * Find the DMA channels to use.
         */
        while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
                iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-               /* Is it DMA channel 0? */
-               if (iprop && (*iprop == 0)) {
+               if (iprop && (*iprop == playback_dma_channel)) {
                        /* dma_channel[0] and dma_irq[0] are for playback */
                        dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
                        dma_info.dma_irq[0] =
@@ -412,7 +416,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
                        machine_data->dma_channel_id[0] = *iprop;
                        continue;
                }
-               if (iprop && (*iprop == 1)) {
+               if (iprop && (*iprop == capture_dma_channel)) {
                        /* dma_channel[1] and dma_irq[1] are for capture */
                        dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
                        dma_info.dma_irq[1] =
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
new file mode 100644 (file)
index 0000000..0382fda
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * OF helpers for ALSA SoC Layer
+ *
+ * Copyright (C) 2008, Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
+
+static DEFINE_MUTEX(of_snd_soc_mutex);
+static LIST_HEAD(of_snd_soc_device_list);
+static int of_snd_soc_next_index;
+
+struct of_snd_soc_device {
+       int id;
+       struct list_head list;
+       struct snd_soc_device device;
+       struct snd_soc_machine machine;
+       struct snd_soc_dai_link dai_link;
+       struct platform_device *pdev;
+       struct device_node *platform_node;
+       struct device_node *codec_node;
+};
+
+static struct snd_soc_ops of_snd_soc_ops = {
+};
+
+static struct of_snd_soc_device *
+of_snd_soc_get_device(struct device_node *codec_node)
+{
+       struct of_snd_soc_device *of_soc;
+
+       list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
+               if (of_soc->codec_node == codec_node)
+                       return of_soc;
+       }
+
+       of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
+       if (!of_soc)
+               return NULL;
+
+       /* Initialize the structure and add it to the global list */
+       of_soc->codec_node = codec_node;
+       of_soc->id = of_snd_soc_next_index++;
+       of_soc->machine.dai_link = &of_soc->dai_link;
+       of_soc->machine.num_links = 1;
+       of_soc->device.machine = &of_soc->machine;
+       of_soc->dai_link.ops = &of_snd_soc_ops;
+       list_add(&of_soc->list, &of_snd_soc_device_list);
+
+       return of_soc;
+}
+
+static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
+{
+       struct platform_device *pdev;
+       int rc;
+
+       /* Only register the device if both the codec and platform have
+        * been registered */
+       if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
+               return;
+
+       pr_info("platform<-->codec match achieved; registering machine\n");
+
+       pdev = platform_device_alloc("soc-audio", of_soc->id);
+       if (!pdev) {
+               pr_err("of_soc: platform_device_alloc() failed\n");
+               return;
+       }
+
+       pdev->dev.platform_data = of_soc;
+       platform_set_drvdata(pdev, &of_soc->device);
+       of_soc->device.dev = &pdev->dev;
+
+       /* The ASoC device is complete; register it */
+       rc = platform_device_add(pdev);
+       if (rc) {
+               pr_err("of_soc: platform_device_add() failed\n");
+               return;
+       }
+
+}
+
+int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
+                             void *codec_data, struct snd_soc_dai *dai,
+                             struct device_node *node)
+{
+       struct of_snd_soc_device *of_soc;
+       int rc = 0;
+
+       pr_info("registering ASoC codec driver: %s\n", node->full_name);
+
+       mutex_lock(&of_snd_soc_mutex);
+       of_soc = of_snd_soc_get_device(node);
+       if (!of_soc) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /* Store the codec data */
+       of_soc->device.codec_data = codec_data;
+       of_soc->device.codec_dev = codec_dev;
+       of_soc->dai_link.name = (char *)node->name;
+       of_soc->dai_link.stream_name = (char *)node->name;
+       of_soc->dai_link.codec_dai = dai;
+
+       /* Now try to register the SoC device */
+       of_snd_soc_register_device(of_soc);
+
+ out:
+       mutex_unlock(&of_snd_soc_mutex);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
+
+int of_snd_soc_register_platform(struct snd_soc_platform *platform,
+                                struct device_node *node,
+                                struct snd_soc_dai *cpu_dai)
+{
+       struct of_snd_soc_device *of_soc;
+       struct device_node *codec_node;
+       const phandle *handle;
+       int len, rc = 0;
+
+       pr_info("registering ASoC platform driver: %s\n", node->full_name);
+
+       handle = of_get_property(node, "codec-handle", &len);
+       if (!handle || len < sizeof(handle))
+               return -ENODEV;
+       codec_node = of_find_node_by_phandle(*handle);
+       if (!codec_node)
+               return -ENODEV;
+       pr_info("looking for codec: %s\n", codec_node->full_name);
+
+       mutex_lock(&of_snd_soc_mutex);
+       of_soc = of_snd_soc_get_device(codec_node);
+       if (!of_soc) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       of_soc->platform_node = node;
+       of_soc->dai_link.cpu_dai = cpu_dai;
+       of_soc->device.platform = platform;
+       of_soc->machine.name = of_soc->dai_link.cpu_dai->name;
+
+       /* Now try to register the SoC device */
+       of_snd_soc_register_device(of_soc);
+
+ out:
+       mutex_unlock(&of_snd_soc_mutex);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
index 87d0ed01f65adf5682dcf8bdc931424d454ba60d..d166b6b2a60dd9b78ade26cb76532cbe1b3c30a8 100644 (file)
@@ -290,6 +290,7 @@ static struct snd_soc_machine snd_soc_machine_n810 = {
 
 /* Audio private data */
 static struct aic3x_setup_data n810_aic33_setup = {
+       .i2c_bus = 2,
        .i2c_address = 0x18,
        .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
        .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
index 9212c37a33b8c8a9275d43e3ddfd45eb34e54456..f8c1cdd940acf54330c05fed9c69a3f4f7c7b0e6 100644 (file)
@@ -1,6 +1,7 @@
 config SND_PXA2XX_SOC
        tristate "SoC Audio for the Intel PXA2xx chip"
        depends on ARCH_PXA
+       select SND_PXA2XX_LIB
        help
          Say Y or M if you want to add support for codecs attached to
          the PXA2xx AC97, I2S or SSP interface. You will also need
@@ -13,6 +14,8 @@ config SND_PXA2XX_AC97
 config SND_PXA2XX_SOC_AC97
        tristate
        select AC97_BUS
+       select SND_ARM
+       select SND_PXA2XX_LIB_AC97
        select SND_SOC_AC97_BUS
 
 config SND_PXA2XX_SOC_I2S
index 0a53f72077fdc97b5797960dc84e8db9177d28ce..72b7a5140bf832d97667dd01bfbf4c936d9fc0fd 100644 (file)
@@ -330,6 +330,7 @@ static struct snd_soc_machine snd_soc_machine_corgi = {
 
 /* corgi audio private data */
 static struct wm8731_setup_data corgi_wm8731_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1b,
 };
 
index a4697f7e2921b42735ea0fd3f3589f6ed71a2d5d..f84f7d8db09a0f19d5eb75089203bd603f25708f 100644 (file)
@@ -284,6 +284,7 @@ static struct snd_soc_machine snd_soc_machine_poodle = {
 
 /* poodle audio private data */
 static struct wm8731_setup_data poodle_wm8731_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1b,
 };
 
index d94a495bd6bdc3c84e716de3d60b30ca84620602..a80ae074b0906b9664f5198caf776f209aed3c04 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
 
 #include <sound/core.h>
-#include <sound/pcm.h>
 #include <sound/ac97_codec.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
 
-#include <asm/irq.h>
-#include <linux/mutex.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
-#include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
-static DEFINE_MUTEX(car_mutex);
-static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
-static volatile long gsr_bits;
-static struct clk *ac97_clk;
-#ifdef CONFIG_PXA27x
-static struct clk *ac97conf_clk;
-#endif
-
-/*
- * Beware PXA27x bugs:
- *
- *   o Slot 12 read from modem space will hang controller.
- *   o CDONE, SDONE interrupt fails after any slot 12 IO.
- *
- * We therefore have an hybrid approach for waiting on SDONE (interrupt or
- * 1 jiffy timeout if interrupt never comes).
- */
-
-static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97,
-       unsigned short reg)
-{
-       unsigned short val = -1;
-       volatile u32 *reg_addr;
-
-       mutex_lock(&car_mutex);
-
-       /* set up primary or secondary codec/modem space */
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-       reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#else
-       if (reg == AC97_GPIO_STATUS)
-               reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
-       else
-               reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#endif
-       reg_addr += (reg >> 1);
-
-#ifndef CONFIG_PXA27x
-       if (reg == AC97_GPIO_STATUS) {
-               /* read from controller cache */
-               val = *reg_addr;
-               goto out;
-       }
-#endif
-
-       /* start read access across the ac97 link */
-       GSR = GSR_CDONE | GSR_SDONE;
-       gsr_bits = 0;
-       val = *reg_addr;
-
-       wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
-       if (!((GSR | gsr_bits) & GSR_SDONE)) {
-               printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n",
-                               __func__, reg, GSR | gsr_bits);
-               val = -1;
-               goto out;
-       }
-
-       /* valid data now */
-       GSR = GSR_CDONE | GSR_SDONE;
-       gsr_bits = 0;
-       val = *reg_addr;
-       /* but we've just started another cycle... */
-       wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
-
-out:   mutex_unlock(&car_mutex);
-       return val;
-}
-
-static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-       unsigned short val)
-{
-       volatile u32 *reg_addr;
-
-       mutex_lock(&car_mutex);
-
-       /* set up primary or secondary codec/modem space */
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-       reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#else
-       if (reg == AC97_GPIO_STATUS)
-               reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
-       else
-               reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
-#endif
-       reg_addr += (reg >> 1);
-
-       GSR = GSR_CDONE | GSR_SDONE;
-       gsr_bits = 0;
-       *reg_addr = val;
-       wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1);
-       if (!((GSR | gsr_bits) & GSR_CDONE))
-               printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n",
-                               __func__, reg, GSR | gsr_bits);
-
-       mutex_unlock(&car_mutex);
-}
-
 static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-#ifdef CONFIG_PXA3xx
-       int timeout = 100;
-#endif
-       gsr_bits = 0;
-
-#ifdef CONFIG_PXA27x
-       /* warm reset broken on Bulverde,
-          so manually keep AC97 reset high */
-       pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
-       udelay(10);
-       GCR |= GCR_WARM_RST;
-       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-       udelay(500);
-#elif defined(CONFIG_PXA3xx)
-       /* Can't use interrupts */
-       GCR |= GCR_WARM_RST;
-       while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
-               mdelay(1);
-#else
-       GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
-       wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif
-
-       if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
-               printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
-                                __func__, gsr_bits);
+       pxa2xx_ac97_try_warm_reset(ac97);
 
-       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-       GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+       pxa2xx_ac97_finish_reset(ac97);
 }
 
 static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-#ifdef CONFIG_PXA3xx
-       int timeout = 1000;
-
-       /* Hold CLKBPB for 100us */
-       GCR = 0;
-       GCR = GCR_CLKBPB;
-       udelay(100);
-       GCR = 0;
-#endif
+       pxa2xx_ac97_try_cold_reset(ac97);
 
-       GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
-       GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
-
-       gsr_bits = 0;
-#ifdef CONFIG_PXA27x
-       /* PXA27x Developers Manual section 13.5.2.2.1 */
-       clk_enable(ac97conf_clk);
-       udelay(5);
-       clk_disable(ac97conf_clk);
-       GCR = GCR_COLD_RST;
-       udelay(50);
-#elif defined(CONFIG_PXA3xx)
-       /* Can't use interrupts on PXA3xx */
-       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-
-       GCR = GCR_WARM_RST | GCR_COLD_RST;
-       while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
-               mdelay(10);
-#else
-       GCR = GCR_COLD_RST;
-       GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
-       wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
-#endif
-
-       if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
-               printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
-                                __func__, gsr_bits);
-
-       GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
-       GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
-}
-
-static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
-{
-       long status;
-
-       status = GSR;
-       if (status) {
-               GSR = status;
-               gsr_bits |= status;
-               wake_up(&gsr_wq);
-
-#ifdef CONFIG_PXA27x
-               /* Although we don't use those we still need to clear them
-                  since they tend to spuriously trigger when MMC is used
-                  (hardware bug? go figure)... */
-               MISR = MISR_EOC;
-               PISR = PISR_EOC;
-               MCSR = MCSR_EOC;
-#endif
-
-               return IRQ_HANDLED;
-       }
-
-       return IRQ_NONE;
+       pxa2xx_ac97_finish_reset(ac97);
 }
 
 struct snd_ac97_bus_ops soc_ac97_ops = {
@@ -285,24 +90,13 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
 static int pxa2xx_ac97_suspend(struct platform_device *pdev,
        struct snd_soc_dai *dai)
 {
-       GCR |= GCR_ACLINK_OFF;
-       clk_disable(ac97_clk);
-       return 0;
+       return pxa2xx_ac97_hw_suspend();
 }
 
 static int pxa2xx_ac97_resume(struct platform_device *pdev,
        struct snd_soc_dai *dai)
 {
-       pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
-       pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
-       pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
-       pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
-#ifdef CONFIG_PXA27x
-       /* Use GPIO 113 as AC97 Reset on Bulverde */
-       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-#endif
-       clk_enable(ac97_clk);
-       return 0;
+       return pxa2xx_ac97_hw_resume();
 }
 
 #else
@@ -313,61 +107,13 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev,
 static int pxa2xx_ac97_probe(struct platform_device *pdev,
                             struct snd_soc_dai *dai)
 {
-       int ret;
-
-       ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
-       if (ret < 0)
-               goto err;
-
-       pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
-       pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
-       pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
-       pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
-#ifdef CONFIG_PXA27x
-       /* Use GPIO 113 as AC97 Reset on Bulverde */
-       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-
-       ac97conf_clk = clk_get(&pdev->dev, "AC97CONFCLK");
-       if (IS_ERR(ac97conf_clk)) {
-               ret = PTR_ERR(ac97conf_clk);
-               ac97conf_clk = NULL;
-               goto err_irq;
-       }
-#endif
-       ac97_clk = clk_get(&pdev->dev, "AC97CLK");
-       if (IS_ERR(ac97_clk)) {
-               ret = PTR_ERR(ac97_clk);
-               ac97_clk = NULL;
-               goto err_irq;
-       }
-       clk_enable(ac97_clk);
-       return 0;
-
- err_irq:
-       GCR |= GCR_ACLINK_OFF;
-#ifdef CONFIG_PXA27x
-       if (ac97conf_clk) {
-               clk_put(ac97conf_clk);
-               ac97conf_clk = NULL;
-       }
-#endif
-       free_irq(IRQ_AC97, NULL);
- err:
-       return ret;
+       return pxa2xx_ac97_hw_probe(pdev);
 }
 
 static void pxa2xx_ac97_remove(struct platform_device *pdev,
                               struct snd_soc_dai *dai)
 {
-       GCR |= GCR_ACLINK_OFF;
-       free_irq(IRQ_AC97, NULL);
-#ifdef CONFIG_PXA27x
-       clk_put(ac97conf_clk);
-       ac97conf_clk = NULL;
-#endif
-       clk_disable(ac97_clk);
-       clk_put(ac97_clk);
-       ac97_clk = NULL;
+       pxa2xx_ac97_hw_remove(pdev);
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
index c796b1882776308390fa10e4225ff26820aaa9db..39d19212f6d3c3fb5a3bfe4cb828d5294c25a82a 100644 (file)
@@ -21,6 +21,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
 
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
+struct pxa2xx_gpio {
+       u32 sys;
+       u32     rx;
+       u32 tx;
+       u32 clk;
+       u32 frm;
+};
+
+
 struct pxa_i2s_port {
        u32 sadiv;
        u32 sacr0;
@@ -65,11 +75,6 @@ static struct pxa2xx_gpio gpio_bus[] = {
                .frm = GPIO31_SYNC_I2S_MD,
        },
        { /* I2S SoC Master */
-#ifdef CONFIG_PXA27x
-               .sys = GPIO113_I2S_SYSCLK_MD,
-#else
-               .sys = GPIO32_SYSCLK_I2S_MD,
-#endif
                .rx = GPIO29_SDATA_IN_I2S_MD,
                .tx = GPIO30_SDATA_OUT_I2S_MD,
                .clk = GPIO28_BITCLK_OUT_I2S_MD,
@@ -343,6 +348,11 @@ static struct platform_driver pxa2xx_i2s_driver = {
 
 static int __init pxa2xx_i2s_init(void)
 {
+       if (cpu_is_pxa27x())
+               gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD;
+       else
+               gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD;
+
        clk_i2s = ERR_PTR(-ENOENT);
        return platform_driver_register(&pxa2xx_i2s_driver);
 }
index 4345f387fe41f7891d95fddfa37efad8fd2e68e0..afcd892cd2fa42f0526defd607bd58db9f5722ec 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/dma-mapping.h>
 
 #include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/pxa-regs.h>
-#include <mach/audio.h>
+#include <sound/pxa2xx-lib.h>
 
 #include "pxa2xx-pcm.h"
-
-static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_PAUSE |
-                                 SNDRV_PCM_INFO_RESUME,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                       SNDRV_PCM_FMTBIT_S24_LE |
-                                       SNDRV_PCM_FMTBIT_S32_LE,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192 - 32,
-       .periods_min            = 1,
-       .periods_max            = PAGE_SIZE/sizeof(pxa_dma_desc),
-       .buffer_bytes_max       = 128 * 1024,
-       .fifo_size              = 32,
-};
-
-struct pxa2xx_runtime_data {
-       int dma_ch;
-       struct pxa2xx_pcm_dma_params *params;
-       pxa_dma_desc *dma_desc_array;
-       dma_addr_t dma_desc_array_phys;
-};
-
-static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
-{
-       struct snd_pcm_substream *substream = dev_id;
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-       int dcsr;
-
-       dcsr = DCSR(dma_ch);
-       DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
-
-       if (dcsr & DCSR_ENDINTR) {
-               snd_pcm_period_elapsed(substream);
-       } else {
-               printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-                       prtd->params->name, dma_ch, dcsr);
-       }
-}
+#include "../../arm/pxa2xx-pcm.h"
 
 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
@@ -76,10 +26,6 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct pxa2xx_runtime_data *prtd = runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
-       size_t totsize = params_buffer_bytes(params);
-       size_t period = params_period_bytes(params);
-       pxa_dma_desc *dma_desc;
-       dma_addr_t dma_buff_phys, next_desc_phys;
        int ret;
 
        /* return if this is a bufferless transfer e.g.
@@ -106,42 +52,16 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
                prtd->dma_ch = ret;
        }
 
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = totsize;
-
-       dma_desc = prtd->dma_desc_array;
-       next_desc_phys = prtd->dma_desc_array_phys;
-       dma_buff_phys = runtime->dma_addr;
-       do {
-               next_desc_phys += sizeof(pxa_dma_desc);
-               dma_desc->ddadr = next_desc_phys;
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       dma_desc->dsadr = dma_buff_phys;
-                       dma_desc->dtadr = prtd->params->dev_addr;
-               } else {
-                       dma_desc->dsadr = prtd->params->dev_addr;
-                       dma_desc->dtadr = dma_buff_phys;
-               }
-               if (period > totsize)
-                       period = totsize;
-               dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN;
-               dma_desc++;
-               dma_buff_phys += period;
-       } while (totsize -= period);
-       dma_desc[-1].ddadr = prtd->dma_desc_array_phys;
-
-       return 0;
+       return __pxa2xx_pcm_hw_params(substream, params);
 }
 
 static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
 
-       if (prtd && prtd->params)
-               *prtd->params->drcmr = 0;
+       __pxa2xx_pcm_hw_free(substream);
 
        if (prtd->dma_ch) {
-               snd_pcm_set_runtime_buffer(substream, NULL);
                pxa_free_dma(prtd->dma_ch);
                prtd->dma_ch = 0;
        }
@@ -149,188 +69,21 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-
-       DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-       DCSR(prtd->dma_ch) = 0;
-       DCMD(prtd->dma_ch) = 0;
-       *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
-
-       return 0;
-}
-
-static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-               DCSR(prtd->dma_ch) = DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-               DCSR(prtd->dma_ch) |= DCSR_RUN;
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-               DCSR(prtd->dma_ch) |= DCSR_RUN;
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static snd_pcm_uframes_t
-pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *prtd = runtime->private_data;
-
-       dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                        DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
-       snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-
-       if (x == runtime->buffer_size)
-               x = 0;
-       return x;
-}
-
-static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *prtd;
-       int ret;
-
-       snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware);
-
-       /*
-        * For mysterious reasons (and despite what the manual says)
-        * playback samples are lost if the DMA count is not a multiple
-        * of the DMA burst size.  Let's add a rule to enforce that.
-        */
-       ret = snd_pcm_hw_constraint_step(runtime, 0,
-               SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
-       if (ret)
-               goto out;
-
-       ret = snd_pcm_hw_constraint_step(runtime, 0,
-               SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
-       if (ret)
-               goto out;
-
-       ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               goto out;
-
-       prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL);
-       if (prtd == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       prtd->dma_desc_array =
-               dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                                      &prtd->dma_desc_array_phys, GFP_KERNEL);
-       if (!prtd->dma_desc_array) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       runtime->private_data = prtd;
-       return 0;
-
- err1:
-       kfree(prtd);
- out:
-       return ret;
-}
-
-static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *prtd = runtime->private_data;
-
-       dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                             prtd->dma_desc_array, prtd->dma_desc_array_phys);
-       kfree(prtd);
-       return 0;
-}
-
-static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
-       struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
 struct snd_pcm_ops pxa2xx_pcm_ops = {
-       .open           = pxa2xx_pcm_open,
-       .close          = pxa2xx_pcm_close,
+       .open           = __pxa2xx_pcm_open,
+       .close          = __pxa2xx_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = pxa2xx_pcm_hw_params,
        .hw_free        = pxa2xx_pcm_hw_free,
-       .prepare        = pxa2xx_pcm_prepare,
+       .prepare        = __pxa2xx_pcm_prepare,
        .trigger        = pxa2xx_pcm_trigger,
        .pointer        = pxa2xx_pcm_pointer,
        .mmap           = pxa2xx_pcm_mmap,
 };
 
-static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-       buf->bytes = size;
-       return 0;
-}
-
-static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
 static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK;
 
-int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
        int ret = 0;
@@ -360,7 +113,7 @@ int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
 struct snd_soc_platform pxa2xx_soc_platform = {
        .name           = "pxa2xx-audio",
        .pcm_ops        = &pxa2xx_pcm_ops,
-       .pcm_new        = pxa2xx_pcm_new,
+       .pcm_new        = pxa2xx_soc_pcm_new,
        .pcm_free       = pxa2xx_pcm_free_dma_buffers,
 };
 EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
index 54c9c755e5085b61d074cfe58b5033e0af947d2e..60c3b20aeeb4b02385945b98e48e10264141cad8 100644 (file)
 #ifndef _PXA2XX_PCM_H
 #define _PXA2XX_PCM_H
 
-struct pxa2xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-       u32 dcmd;                       /* DMA descriptor dcmd field */
-       volatile u32 *drcmr;            /* the DMA request channel to use */
-       u32 dev_addr;                   /* device physical address for DMA */
-};
-
-struct pxa2xx_gpio {
-       u32 sys;
-       u32     rx;
-       u32 tx;
-       u32 clk;
-       u32 frm;
-};
-
 /* platform data */
 extern struct snd_soc_platform pxa2xx_soc_platform;
 
index 37cb768fc933d377647f89b92d8c999efeaf2393..3d4738c06e7eecc239abd796cb325b63766dff71 100644 (file)
@@ -337,6 +337,7 @@ static struct snd_soc_machine snd_soc_machine_spitz = {
 
 /* spitz audio private data */
 static struct wm8750_setup_data spitz_wm8750_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1b,
 };
 
index 8089f8ee05c0413f2bf4ff7f9b365a26228a8895..73a50e93a9a222e5296f9a0d5191f9756a275a64 100644 (file)
@@ -24,6 +24,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 
+#include <asm/mach-types.h>
 #include <asm/hardware/scoop.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
@@ -586,6 +587,7 @@ static struct snd_soc_machine neo1973 = {
 };
 
 static struct wm8753_setup_data neo1973_wm8753_setup = {
+       .i2c_bus = 0,
        .i2c_address = 0x1a,
 };
 
@@ -596,54 +598,20 @@ static struct snd_soc_device neo1973_snd_devdata = {
        .codec_data = &neo1973_wm8753_setup,
 };
 
-static struct i2c_client client_template;
-
-static const unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
+static int lm4857_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
 {
-       int ret;
-
        DBG("Entered %s\n", __func__);
 
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL)
-               return -ENOMEM;
-
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
-               goto exit_err;
-       }
-
        lm4857_write_regs();
-       return ret;
-
-exit_err:
-       kfree(i2c);
-       return ret;
-}
-
-static int lm4857_i2c_detach(struct i2c_client *client)
-{
-       DBG("Entered %s\n", __func__);
-
-       i2c_detach_client(client);
-       kfree(client);
        return 0;
 }
 
-static int lm4857_i2c_attach(struct i2c_adapter *adap)
+static int lm4857_i2c_remove(struct i2c_client *client)
 {
        DBG("Entered %s\n", __func__);
 
-       return i2c_probe(adap, &addr_data, lm4857_amp_probe);
+       return 0;
 }
 
 static u8 lm4857_state;
@@ -681,27 +649,67 @@ static void lm4857_shutdown(struct i2c_client *dev)
        lm4857_write_regs();
 }
 
-/* corgi i2c codec control layer */
+static const struct i2c_device_id lm4857_i2c_id[] = {
+       { "neo1973_lm4857", 0 }
+       { }
+};
+
 static struct i2c_driver lm4857_i2c_driver = {
        .driver = {
                .name = "LM4857 I2C Amp",
                .owner = THIS_MODULE,
        },
-       .id =             I2C_DRIVERID_LM4857,
        .suspend =        lm4857_suspend,
        .resume =         lm4857_resume,
        .shutdown =       lm4857_shutdown,
-       .attach_adapter = lm4857_i2c_attach,
-       .detach_client =  lm4857_i2c_detach,
-       .command =        NULL,
-};
-
-static struct i2c_client client_template = {
-       .name =   "LM4857",
-       .driver = &lm4857_i2c_driver,
+       .probe =          lm4857_i2c_probe,
+       .remove =         lm4857_i2c_remove,
+       .id_table =       lm4857_i2c_id,
 };
 
 static struct platform_device *neo1973_snd_device;
+static struct i2c_client *lm4857_client;
+
+static int __init neo1973_add_lm4857_device(struct platform_device *pdev,
+                                           int i2c_bus,
+                                           unsigned short i2c_address)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&lm4857_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add lm4857 driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = i2c_address;
+       strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       lm4857_client = client;
+       return 0;
+
+err_driver:
+       i2c_del_driver(&lm4857_i2c_driver);
+       return -ENODEV;
+}
 
 static int __init neo1973_init(void)
 {
@@ -709,6 +717,12 @@ static int __init neo1973_init(void)
 
        DBG("Entered %s\n", __func__);
 
+       if (!machine_is_neo1973_gta01()) {
+               printk(KERN_INFO
+                       "Only GTA01 hardware supported by ASoC driver\n");
+               return -ENODEV;
+       }
+
        neo1973_snd_device = platform_device_alloc("soc-audio", -1);
        if (!neo1973_snd_device)
                return -ENOMEM;
@@ -717,12 +731,15 @@ static int __init neo1973_init(void)
        neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
        ret = platform_device_add(neo1973_snd_device);
 
-       if (ret)
+       if (ret) {
                platform_device_put(neo1973_snd_device);
+               return ret;
+       }
 
-       ret = i2c_add_driver(&lm4857_i2c_driver);
+       ret = neo1973_add_lm4857_device(neo1973_snd_device,
+                                       neo1973_wm8753_setup, 0x7C);
        if (ret != 0)
-               printk(KERN_ERR "can't add i2c driver");
+               platform_device_unregister(neo1973_snd_device);
 
        return ret;
 }
@@ -731,6 +748,7 @@ static void __exit neo1973_exit(void)
 {
        DBG("Entered %s\n", __func__);
 
+       i2c_unregister_device(lm4857_client);
        i2c_del_driver(&lm4857_i2c_driver);
        platform_device_unregister(neo1973_snd_device);
 }
index 83f1190293a8287c2a516a81a07575dc7f4933c7..ad381138fc2e482e0bf0110a96cf32c385ba8c04 100644 (file)
@@ -340,6 +340,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        }
        codec->active--;
 
+       /* Muting the DAC suppresses artifacts caused during digital
+        * shutdown, for example from stopping clocks.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_dai_digital_mute(codec_dai, 1);
+
        if (cpu_dai->ops.shutdown)
                cpu_dai->ops.shutdown(substream);
 
@@ -970,9 +976,29 @@ static ssize_t codec_reg_show(struct device *dev,
                step = codec->reg_cache_step;
 
        count += sprintf(buf, "%s registers\n", codec->name);
-       for (i = 0; i < codec->reg_cache_size; i += step)
-               count += sprintf(buf + count, "%2x: %4x\n", i,
-                       codec->read(codec, i));
+       for (i = 0; i < codec->reg_cache_size; i += step) {
+               count += sprintf(buf + count, "%2x: ", i);
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               if (codec->display_register)
+                       count += codec->display_register(codec, buf + count,
+                                                        PAGE_SIZE - count, i);
+               else
+                       count += snprintf(buf + count, PAGE_SIZE - count,
+                                         "%4x", codec->read(codec, i));
+
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+               if (count >= PAGE_SIZE - 1)
+                       break;
+       }
+
+       /* Truncate count; min() would cause a warning */
+       if (count >= PAGE_SIZE)
+               count = PAGE_SIZE - 1;
 
        return count;
 }
@@ -1296,10 +1322,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
-       uinfo->value.enumerated.items = e->mask;
+       uinfo->value.enumerated.items = e->max;
 
-       if (uinfo->value.enumerated.item > e->mask - 1)
-               uinfo->value.enumerated.item = e->mask - 1;
+       if (uinfo->value.enumerated.item > e->max - 1)
+               uinfo->value.enumerated.item = e->max - 1;
        strcpy(uinfo->value.enumerated.name,
                e->texts[uinfo->value.enumerated.item]);
        return 0;
@@ -1322,7 +1348,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned short val, bitmask;
 
-       for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
        val = snd_soc_read(codec, e->reg);
        ucontrol->value.enumerated.item[0]
@@ -1352,14 +1378,14 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
        unsigned short val;
        unsigned short mask, bitmask;
 
-       for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
-       if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+       if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
        val = ucontrol->value.enumerated.item[0] << e->shift_l;
        mask = (bitmask - 1) << e->shift_l;
        if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+               if (ucontrol->value.enumerated.item[1] > e->max - 1)
                        return -EINVAL;
                val |= ucontrol->value.enumerated.item[1] << e->shift_r;
                mask |= (bitmask - 1) << e->shift_r;
@@ -1386,10 +1412,10 @@ int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
-       uinfo->value.enumerated.items = e->mask;
+       uinfo->value.enumerated.items = e->max;
 
-       if (uinfo->value.enumerated.item > e->mask - 1)
-               uinfo->value.enumerated.item = e->mask - 1;
+       if (uinfo->value.enumerated.item > e->max - 1)
+               uinfo->value.enumerated.item = e->max - 1;
        strcpy(uinfo->value.enumerated.name,
                e->texts[uinfo->value.enumerated.item]);
        return 0;
@@ -1434,9 +1460,11 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
 int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo)
 {
-       int max = (kcontrol->private_value >> 16) & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int rshift = (kcontrol->private_value >> 12) & 0x0f;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int max = mc->max;
+       unsigned int shift = mc->min;
+       unsigned int rshift = mc->rshift;
 
        if (max == 1)
                uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -1462,13 +1490,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int max = (kcontrol->private_value >> 16) & 0xff;
-       int mask = (1 << fls(max)) - 1;
-       int invert = (kcontrol->private_value >> 24) & 0x01;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
 
        ucontrol->value.integer.value[0] =
                (snd_soc_read(codec, reg) >> shift) & mask;
@@ -1499,13 +1529,15 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
 int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int max = (kcontrol->private_value >> 16) & 0xff;
-       int mask = (1 << fls(max)) - 1;
-       int invert = (kcontrol->private_value >> 24) & 0x01;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
        unsigned short val, val2, val_mask;
 
        val = (ucontrol->value.integer.value[0] & mask);
@@ -1537,7 +1569,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo)
 {
-       int max = (kcontrol->private_value >> 12) & 0xff;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int max = mc->max;
 
        if (max == 1)
                uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -1563,13 +1597,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
 int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int reg2 = (kcontrol->private_value >> 24) & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int max = (kcontrol->private_value >> 12) & 0xff;
-       int mask = (1<<fls(max))-1;
-       int invert = (kcontrol->private_value >> 20) & 0x01;
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1<<fls(max))-1;
+       unsigned int invert = mc->invert;
 
        ucontrol->value.integer.value[0] =
                (snd_soc_read(codec, reg) >> shift) & mask;
@@ -1598,13 +1634,15 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);
 int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int reg2 = (kcontrol->private_value >> 24) & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int max = (kcontrol->private_value >> 12) & 0xff;
-       int mask = (1 << fls(max)) - 1;
-       int invert = (kcontrol->private_value >> 20) & 0x01;
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
        int err;
        unsigned short val, val2, val_mask;
 
@@ -1641,8 +1679,10 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
 int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo)
 {
-       int max = (signed char)((kcontrol->private_value >> 16) & 0xff);
-       int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int max = mc->max;
+       int min = mc->min;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 2;
@@ -1664,9 +1704,11 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8);
 int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+       unsigned int reg = mc->reg;
+       int min = mc->min;
        int val = snd_soc_read(codec, reg);
 
        ucontrol->value.integer.value[0] =
@@ -1689,9 +1731,11 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8);
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+       unsigned int reg = mc->reg;
+       int min = mc->min;
        unsigned short val;
 
        val = (ucontrol->value.integer.value[0]+min) & 0xff;
index f9d100bc8479e970225c6f1274c824f3ee12dfee..9ca9c08610fa85bfd7fa7967555f07e1c6ac8082 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
+#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -67,7 +68,9 @@ static int dapm_status = 1;
 module_param(dapm_status, int, 0);
 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
 
-static unsigned int pop_time;
+static struct dentry *asoc_debugfs;
+
+static u32 pop_time;
 
 static void pop_wait(void)
 {
@@ -104,10 +107,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_switch:
        case snd_soc_dapm_mixer: {
                int val;
-               int reg = w->kcontrols[i].private_value & 0xff;
-               int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
-               int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
-               int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
+               struct soc_mixer_control *mc = (struct soc_mixer_control *)
+                       w->kcontrols[i].private_value;
+               unsigned int reg = mc->reg;
+               unsigned int shift = mc->shift;
+               int max = mc->max;
+               unsigned int mask = (1 << fls(max)) - 1;
+               unsigned int invert = mc->invert;
 
                val = snd_soc_read(w->codec, reg);
                val = (val >> shift) & mask;
@@ -122,13 +128,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
                int val, item, bitmask;
 
-               for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+               for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
                val = snd_soc_read(w->codec, e->reg);
                item = (val >> e->shift_l) & (bitmask - 1);
 
                p->connect = 0;
-               for (i = 0; i < e->mask; i++) {
+               for (i = 0; i < e->max; i++) {
                        if (!(strcmp(p->name, e->texts[i])) && item == i)
                                p->connect = 1;
                }
@@ -165,7 +171,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        int i;
 
-       for (i = 0; i < e->mask; i++) {
+       for (i = 0; i < e->max; i++) {
                if (!(strcmp(control_name, e->texts[i]))) {
                        list_add(&path->list, &codec->dapm_paths);
                        list_add(&path->list_sink, &dest->sources);
@@ -247,16 +253,19 @@ static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
                return 0;
 
        if (widget->num_kcontrols && k) {
-               int reg = k->private_value & 0xff;
-               int shift = (k->private_value >> 8) & 0x0f;
-               int mask = (k->private_value >> 16) & 0xff;
-               int invert = (k->private_value >> 24) & 0x01;
+               struct soc_mixer_control *mc =
+                       (struct soc_mixer_control *)k->private_value;
+               unsigned int reg = mc->reg;
+               unsigned int shift = mc->shift;
+               int max = mc->max;
+               unsigned int mask = (1 << fls(max)) - 1;
+               unsigned int invert = mc->invert;
 
                if (power) {
                        int i;
                        /* power up has happended, increase volume to last level */
                        if (invert) {
-                               for (i = mask; i > widget->saved_value; i--)
+                               for (i = max; i > widget->saved_value; i--)
                                        snd_soc_update_bits(widget->codec, reg, mask, i);
                        } else {
                                for (i = 0; i < widget->saved_value; i++)
@@ -684,7 +693,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
 /* test and update the power status of a mux widget */
 static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                                 struct snd_kcontrol *kcontrol, int mask,
-                                int val, struct soc_enum* e)
+                                int mux, int val, struct soc_enum *e)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
@@ -700,12 +709,12 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                if (path->kcontrol != kcontrol)
                        continue;
 
-               if (!path->name || ! e->texts[val])
+               if (!path->name || !e->texts[mux])
                        continue;
 
                found = 1;
                /* we now need to match the string in the enum to the path */
-               if (!(strcmp(path->name, e->texts[val])))
+               if (!(strcmp(path->name, e->texts[mux])))
                        path->connect = 1; /* new connection */
                else
                        path->connect = 0; /* old connection must be powered down */
@@ -811,51 +820,35 @@ static ssize_t dapm_widget_show(struct device *dev,
 
 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
-/* pop/click delay times */
-static ssize_t dapm_pop_time_show(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%d\n", pop_time);
-}
-
-static ssize_t dapm_pop_time_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t count)
-
-{
-       unsigned long val;
-
-       if (strict_strtoul(buf, 10, &val) >= 0)
-               pop_time = val;
-       else
-               printk(KERN_ERR "Unable to parse pop_time setting\n");
-
-       return count;
-}
-
-static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
-                  dapm_pop_time_store);
-
 int snd_soc_dapm_sys_add(struct device *dev)
 {
        int ret = 0;
 
-       if (dapm_status) {
-               ret = device_create_file(dev, &dev_attr_dapm_widget);
+       if (!dapm_status)
+               return 0;
 
-               if (ret == 0)
-                       ret = device_create_file(dev, &dev_attr_dapm_pop_time);
-       }
+       ret = device_create_file(dev, &dev_attr_dapm_widget);
+       if (ret != 0)
+               return ret;
 
-       return ret;
+       asoc_debugfs = debugfs_create_dir("asoc", NULL);
+       if (!IS_ERR(asoc_debugfs))
+               debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs,
+                                  &pop_time);
+       else
+               asoc_debugfs = NULL;
+
+       return 0;
 }
 
 static void snd_soc_dapm_sys_remove(struct device *dev)
 {
        if (dapm_status) {
-               device_remove_file(dev, &dev_attr_dapm_pop_time);
                device_remove_file(dev, &dev_attr_dapm_widget);
        }
+
+       if (asoc_debugfs)
+               debugfs_remove_recursive(asoc_debugfs);
 }
 
 /* free all dapm widgets and resources */
@@ -1133,12 +1126,14 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int max = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0x01;
-       int mask = (1 << fls(max)) - 1;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       int max = mc->max;
+       unsigned int invert = mc->invert;
+       unsigned int mask = (1 << fls(max)) - 1;
 
        /* return the saved value if we are powered down */
        if (widget->id == snd_soc_dapm_pga && !widget->power) {
@@ -1176,12 +1171,14 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int max = (kcontrol->private_value >> 16) & 0xff;
-       int mask = (1 << fls(max)) - 1;
-       int invert = (kcontrol->private_value >> 24) & 0x01;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
        unsigned short val, val2, val_mask;
        int ret;
 
@@ -1248,7 +1245,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned short val, bitmask;
 
-       for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
        val = snd_soc_read(widget->codec, e->reg);
        ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
@@ -1278,15 +1275,15 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        unsigned short mask, bitmask;
        int ret = 0;
 
-       for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
-       if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+       if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
        mux = ucontrol->value.enumerated.item[0];
        val = mux << e->shift_l;
        mask = (bitmask - 1) << e->shift_l;
        if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+               if (ucontrol->value.enumerated.item[1] > e->max - 1)
                        return -EINVAL;
                val |= ucontrol->value.enumerated.item[1] << e->shift_r;
                mask |= (bitmask - 1) << e->shift_r;
@@ -1294,7 +1291,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
-       dapm_mux_update_power(widget, kcontrol, mask, mux, e);
+       dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
        if (widget->event) {
                if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
                        ret = widget->event(widget,
index 1b04259a4328486357059acfd892bb3015285203..4ae07e236b36a81d87a51307a9272b50cef17528 100644 (file)
@@ -1,5 +1,61 @@
 /*
- *     Sound core handling. Breaks out sound functions to submodules
+ *     Sound core.  This file is composed of two parts.  sound_class
+ *     which is common to both OSS and ALSA and OSS sound core which
+ *     is used OSS or emulation of it.
+ */
+
+/*
+ * First, the common part.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+
+#ifdef CONFIG_SOUND_OSS_CORE
+static int __init init_oss_soundcore(void);
+static void cleanup_oss_soundcore(void);
+#else
+static inline int init_oss_soundcore(void)     { return 0; }
+static inline void cleanup_oss_soundcore(void) { }
+#endif
+
+struct class *sound_class;
+EXPORT_SYMBOL(sound_class);
+
+MODULE_DESCRIPTION("Core sound module");
+MODULE_AUTHOR("Alan Cox");
+MODULE_LICENSE("GPL");
+
+static int __init init_soundcore(void)
+{
+       int rc;
+
+       rc = init_oss_soundcore();
+       if (rc)
+               return rc;
+
+       sound_class = class_create(THIS_MODULE, "sound");
+       if (IS_ERR(sound_class)) {
+               cleanup_oss_soundcore();
+               return PTR_ERR(sound_class);
+       }
+
+       return 0;
+}
+
+static void __exit cleanup_soundcore(void)
+{
+       cleanup_oss_soundcore();
+       class_destroy(sound_class);
+}
+
+module_init(init_soundcore);
+module_exit(cleanup_soundcore);
+
+
+#ifdef CONFIG_SOUND_OSS_CORE
+/*
+ *     OSS sound core handling. Breaks out sound functions to submodules
  *     
  *     Author:         Alan Cox <alan.cox@linux.org>
  *
  *     locking at some point in 2.3.x.
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/sound.h>
 #include <linux/major.h>
 #include <linux/kmod.h>
-#include <linux/device.h>
 
 #define SOUND_STEP 16
 
-
 struct sound_unit
 {
        int unit_minor;
@@ -64,9 +116,6 @@ extern int msnd_classic_init(void);
 extern int msnd_pinnacle_init(void);
 #endif
 
-struct class *sound_class;
-EXPORT_SYMBOL(sound_class);
-
 /*
  *     Low level list operator. Scan the ordered list, find a hole and
  *     join into it. Called with the lock asserted
@@ -523,31 +572,23 @@ int soundcore_open(struct inode *inode, struct file *file)
        return -ENODEV;
 }
 
-MODULE_DESCRIPTION("Core sound module");
-MODULE_AUTHOR("Alan Cox");
-MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
 
-static void __exit cleanup_soundcore(void)
+static void cleanup_oss_soundcore(void)
 {
        /* We have nothing to really do here - we know the lists must be
           empty */
        unregister_chrdev(SOUND_MAJOR, "sound");
-       class_destroy(sound_class);
 }
 
-static int __init init_soundcore(void)
+static int __init init_oss_soundcore(void)
 {
        if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) {
                printk(KERN_ERR "soundcore: sound device already in use.\n");
                return -EBUSY;
        }
-       sound_class = class_create(THIS_MODULE, "sound");
-       if (IS_ERR(sound_class))
-               return PTR_ERR(sound_class);
 
        return 0;
 }
 
-module_init(init_soundcore);
-module_exit(cleanup_soundcore);
+#endif /* CONFIG_SOUND_OSS_CORE */
index 0c63e0585b15eed7d819dc55531db1d321865830..49acee0c4840216c968e1097ee9ed31e96464809 100644 (file)
@@ -765,7 +765,6 @@ static int __devinit snd_amd7930_pcm(struct snd_amd7930 *amd)
                               /* playback count */ 1,
                               /* capture count */  1, &pcm)) < 0)
                return err;
-       snd_assert(pcm != NULL, return -EINVAL);
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_amd7930_playback_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_amd7930_capture_ops);
@@ -788,13 +787,6 @@ static int __devinit snd_amd7930_pcm(struct snd_amd7930 *amd)
 
 static int snd_amd7930_info_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
 {
-       int type = kctl->private_value;
-
-       snd_assert(type == VOLUME_MONITOR ||
-                  type == VOLUME_CAPTURE ||
-                  type == VOLUME_PLAYBACK, return -EINVAL);
-       (void) type;
-
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
        uinfo->value.integer.min = 0;
@@ -809,10 +801,6 @@ static int snd_amd7930_get_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem
        int type = kctl->private_value;
        int *swval;
 
-       snd_assert(type == VOLUME_MONITOR ||
-                  type == VOLUME_CAPTURE ||
-                  type == VOLUME_PLAYBACK, return -EINVAL);
-
        switch (type) {
        case VOLUME_MONITOR:
                swval = &amd->mgain;
@@ -838,10 +826,6 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem
        int type = kctl->private_value;
        int *swval, change;
 
-       snd_assert(type == VOLUME_MONITOR ||
-                  type == VOLUME_CAPTURE ||
-                  type == VOLUME_PLAYBACK, return -EINVAL);
-
        switch (type) {
        case VOLUME_MONITOR:
                swval = &amd->mgain;
@@ -904,7 +888,8 @@ static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd)
        struct snd_card *card;
        int idx, err;
 
-       snd_assert(amd != NULL && amd->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!amd || !amd->card))
+               return -EINVAL;
 
        card = amd->card;
        strcpy(card->mixername, card->shortname);
index 1c4797be72ee774a54b6e3dd7ec8b0e476ee2381..791d2fb821d17b40495a1cdfc127016752ba6790 100644 (file)
@@ -1560,7 +1560,8 @@ static int __init snd_cs4231_mixer(struct snd_card *card)
        struct snd_cs4231 *chip = card->private_data;
        int err, idx;
 
-       snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
+       if (snd_BUG_ON(!chip || !chip->pcm))
+               return -EINVAL;
 
        strcpy(card->mixername, chip->pcm->name);
 
index ee2e1b4f35514dfa999dabcccfb689bf9ecd077d..c534a2a849fad3e1250f199ca1764b91540227b1 100644 (file)
@@ -2223,7 +2223,6 @@ static int __devinit snd_dbri_pcm(struct snd_card *card)
                               /* playback count */ 1,
                               /* capture count */  1, &pcm)) < 0)
                return err;
-       snd_assert(pcm != NULL, return -EINVAL);
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops);
@@ -2263,9 +2262,10 @@ static int snd_cs4215_get_volume(struct snd_kcontrol *kcontrol,
 {
        struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
        struct dbri_streaminfo *info;
-       snd_assert(dbri != NULL, return -EINVAL);
+
+       if (snd_BUG_ON(!dbri))
+               return -EINVAL;
        info = &dbri->stream_info[kcontrol->private_value];
-       snd_assert(info != NULL, return -EINVAL);
 
        ucontrol->value.integer.value[0] = info->left_gain;
        ucontrol->value.integer.value[1] = info->right_gain;
@@ -2331,7 +2331,9 @@ static int snd_cs4215_get_single(struct snd_kcontrol *kcontrol,
        int shift = (kcontrol->private_value >> 8) & 0xff;
        int mask = (kcontrol->private_value >> 16) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 1;
-       snd_assert(dbri != NULL, return -EINVAL);
+
+       if (snd_BUG_ON(!dbri))
+               return -EINVAL;
 
        if (elem < 4)
                ucontrol->value.integer.value[0] =
@@ -2356,7 +2358,9 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol,
        int invert = (kcontrol->private_value >> 24) & 1;
        int changed = 0;
        unsigned short val;
-       snd_assert(dbri != NULL, return -EINVAL);
+
+       if (snd_BUG_ON(!dbri))
+               return -EINVAL;
 
        val = (ucontrol->value.integer.value[0] & mask);
        if (invert == 1)
@@ -2432,7 +2436,8 @@ static int __devinit snd_dbri_mixer(struct snd_card *card)
        int idx, err;
        struct snd_dbri *dbri;
 
-       snd_assert(card != NULL && card->private_data != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card || !card->private_data))
+               return -EINVAL;
        dbri = card->private_data;
 
        strcpy(card->mixername, card->shortname);
index c89d2ea594b9f5dbd36d94c04e2e8fdacc5571bb..f16a3fce45975a30c18975519283c92695d44c15 100644 (file)
@@ -93,10 +93,10 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch
        int err;
        struct snd_sf_callback sf_cb;
 
-       snd_assert(emu->hw != NULL, return -EINVAL);
-       snd_assert(emu->max_voices > 0, return -EINVAL);
-       snd_assert(card != NULL, return -EINVAL);
-       snd_assert(name != NULL, return -EINVAL);
+       if (snd_BUG_ON(!emu->hw || emu->max_voices <= 0))
+               return -EINVAL;
+       if (snd_BUG_ON(!card || !name))
+               return -EINVAL;
 
        emu->card = card;
        emu->name = kstrdup(name, GFP_KERNEL);
index c6917ba2c934f1208078fbc7226cb3870f252879..00fc005ecf6e6f6bc8c21285703d246bdee658b7 100644 (file)
@@ -289,8 +289,8 @@ snd_emux_nrpn(void *p, struct snd_midi_channel *chan,
        struct snd_emux_port *port;
 
        port = p;
-       snd_assert(port != NULL, return);
-       snd_assert(chan != NULL, return);
+       if (snd_BUG_ON(!port || !chan))
+               return;
 
        if (chan->control[MIDI_CTL_NONREG_PARM_NUM_MSB] == 127 &&
            chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB] <= 26) {
@@ -379,8 +379,8 @@ snd_emux_sysex(void *p, unsigned char *buf, int len, int parsed,
        struct snd_emux *emu;
 
        port = p;
-       snd_assert(port != NULL, return);
-       snd_assert(chset != NULL, return);
+       if (snd_BUG_ON(!port || !chset))
+               return;
        emu = port->emu;
 
        switch (parsed) {
index f60a98ef7dec3d0d4e1dafc325471ae16e1de93c..5c47b6c09264e26414276e1663a4723cff005650 100644 (file)
@@ -114,7 +114,8 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
        char tmpname[64];
 
        emu = closure;
-       snd_assert(arg != NULL && emu != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg || !emu))
+               return -ENXIO;
 
        mutex_lock(&emu->register_mutex);
 
@@ -183,12 +184,15 @@ snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
        struct snd_emux *emu;
        struct snd_emux_port *p;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        p = arg->private_data;
-       snd_assert(p != NULL, return -ENXIO);
+       if (snd_BUG_ON(!p))
+               return -ENXIO;
 
        emu = p->emu;
-       snd_assert(emu != NULL, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
 
        mutex_lock(&emu->register_mutex);
        snd_emux_sounds_off_all(p);
@@ -212,12 +216,15 @@ snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
        struct snd_emux_port *p;
        int rc;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        p = arg->private_data;
-       snd_assert(p != NULL, return -ENXIO);
+       if (snd_BUG_ON(!p))
+               return -ENXIO;
 
        emu = p->emu;
-       snd_assert(emu != NULL, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
 
        if (format == GUS_PATCH)
                rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
@@ -252,12 +259,15 @@ snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned l
        struct snd_emux_port *p;
        struct snd_emux *emu;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        p = arg->private_data;
-       snd_assert(p != NULL, return -ENXIO);
+       if (snd_BUG_ON(!p))
+               return -ENXIO;
 
        emu = p->emu;
-       snd_assert(emu != NULL, return -ENXIO);
+       if (snd_BUG_ON(!emu))
+               return -ENXIO;
 
        switch (cmd) {
        case SNDCTL_SEQ_RESETSAMPLES:
@@ -282,9 +292,11 @@ snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg)
 {
        struct snd_emux_port *p;
 
-       snd_assert(arg != NULL, return -ENXIO);
+       if (snd_BUG_ON(!arg))
+               return -ENXIO;
        p = arg->private_data;
-       snd_assert(p != NULL, return -ENXIO);
+       if (snd_BUG_ON(!p))
+               return -ENXIO;
        snd_emux_reset_port(p);
        return 0;
 }
@@ -302,9 +314,11 @@ snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_dat
        unsigned char cmd, *data;
 
        p = private_data;
-       snd_assert(p != NULL, return -EINVAL);
+       if (snd_BUG_ON(!p))
+               return -EINVAL;
        emu = p->emu;
-       snd_assert(emu != NULL, return -EINVAL);
+       if (snd_BUG_ON(!emu))
+               return -EINVAL;
        if (ev->type != SNDRV_SEQ_EVENT_OSS)
                return snd_emux_event_input(ev, direct, private_data, atomic, hop);
 
index d176cc01742d2069a400bfaf5585bfed1fb2e052..335aa2ce257427dc44a8af0f33021a1c9064b9c0 100644 (file)
@@ -257,7 +257,8 @@ snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data,
        struct snd_emux_port *port;
 
        port = private_data;
-       snd_assert(port != NULL && ev != NULL, return -EINVAL);
+       if (snd_BUG_ON(!port || !ev))
+               return -EINVAL;
 
        snd_midi_process_event(&emux_ops, ev, &port->chset);
 
@@ -308,9 +309,11 @@ snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info)
        struct snd_emux *emu;
 
        p = private_data;
-       snd_assert(p != NULL, return -EINVAL);
+       if (snd_BUG_ON(!p))
+               return -EINVAL;
        emu = p->emu;
-       snd_assert(emu != NULL, return -EINVAL);
+       if (snd_BUG_ON(!emu))
+               return -EINVAL;
 
        mutex_lock(&emu->register_mutex);
        snd_emux_init_port(p);
@@ -329,9 +332,11 @@ snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info)
        struct snd_emux *emu;
 
        p = private_data;
-       snd_assert(p != NULL, return -EINVAL);
+       if (snd_BUG_ON(!p))
+               return -EINVAL;
        emu = p->emu;
-       snd_assert(emu != NULL, return -EINVAL);
+       if (snd_BUG_ON(!emu))
+               return -EINVAL;
 
        mutex_lock(&emu->register_mutex);
        snd_emux_sounds_off_all(p);
index b343818dbb964ae3137b7e90c08284ffa03e92c6..2cc6f6f7906574f77bc471cfc7405085c98434e1 100644 (file)
@@ -66,12 +66,12 @@ snd_emux_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        struct snd_emux_port *port;
 
        port = p;
-       snd_assert(port != NULL && chan != NULL, return);
+       if (snd_BUG_ON(!port || !chan))
+               return;
 
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.get_voice != NULL, return);
-       snd_assert(emu->ops.trigger != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.get_voice || !emu->ops.trigger))
+               return;
 
        key = note; /* remember the original note */
        nvoices = get_zone(emu, port, &note, vel, chan, table);
@@ -164,11 +164,12 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
        struct snd_emux_port *port;
 
        port = p;
-       snd_assert(port != NULL && chan != NULL, return);
+       if (snd_BUG_ON(!port || !chan))
+               return;
 
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.release != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.release))
+               return;
 
        spin_lock_irqsave(&emu->voice_lock, flags);
        for (ch = 0; ch < emu->max_voices; ch++) {
@@ -242,11 +243,12 @@ snd_emux_key_press(void *p, int note, int vel, struct snd_midi_channel *chan)
        struct snd_emux_port *port;
 
        port = p;
-       snd_assert(port != NULL && chan != NULL, return);
+       if (snd_BUG_ON(!port || !chan))
+               return;
 
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.update != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.update))
+               return;
 
        spin_lock_irqsave(&emu->voice_lock, flags);
        for (ch = 0; ch < emu->max_voices; ch++) {
@@ -276,8 +278,8 @@ snd_emux_update_channel(struct snd_emux_port *port, struct snd_midi_channel *cha
                return;
 
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.update != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.update))
+               return;
 
        spin_lock_irqsave(&emu->voice_lock, flags);
        for (i = 0; i < emu->max_voices; i++) {
@@ -303,8 +305,8 @@ snd_emux_update_port(struct snd_emux_port *port, int update)
                return;
 
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.update != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.update))
+               return;
 
        spin_lock_irqsave(&emu->voice_lock, flags);
        for (i = 0; i < emu->max_voices; i++) {
@@ -326,7 +328,8 @@ snd_emux_control(void *p, int type, struct snd_midi_channel *chan)
        struct snd_emux_port *port;
 
        port = p;
-       snd_assert(port != NULL && chan != NULL, return);
+       if (snd_BUG_ON(!port || !chan))
+               return;
 
        switch (type) {
        case MIDI_CTL_MSB_MAIN_VOLUME:
@@ -400,11 +403,12 @@ snd_emux_terminate_note(void *p, int note, struct snd_midi_channel *chan)
        struct snd_emux_port *port;
 
        port = p;
-       snd_assert(port != NULL && chan != NULL, return);
+       if (snd_BUG_ON(!port || !chan))
+               return;
 
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.terminate != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.terminate))
+               return;
 
        terminate_note1(emu, note, chan, 1);
 }
@@ -451,10 +455,11 @@ snd_emux_sounds_off_all(struct snd_emux_port *port)
        struct snd_emux_voice *vp;
        unsigned long flags;
 
-       snd_assert(port != NULL, return);
+       if (snd_BUG_ON(!port))
+               return;
        emu = port->emu;
-       snd_assert(emu != NULL, return);
-       snd_assert(emu->ops.terminate != NULL, return);
+       if (snd_BUG_ON(!emu || !emu->ops.terminate))
+               return;
 
        spin_lock_irqsave(&emu->voice_lock, flags);
        for (i = 0; i < emu->max_voices; i++) {
index deabe5f899c494780eb29c188f9fe23edf8c92e8..c85522e3808da75afa81283fe74c002c8a362f59 100644 (file)
@@ -55,7 +55,8 @@ void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
 {
        struct list_head *p;
 
-       snd_assert(hdr != NULL, return);
+       if (!hdr)
+               return;
        /* release all blocks */
        while ((p = hdr->block.next) != &hdr->block) {
                list_del(p);
@@ -74,8 +75,8 @@ __snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
        unsigned int units, prev_offset;
        struct list_head *p;
 
-       snd_assert(hdr != NULL, return NULL);
-       snd_assert(size > 0, return NULL);
+       if (snd_BUG_ON(!hdr || size <= 0))
+               return NULL;
 
        /* word alignment */
        units = size;
@@ -161,7 +162,8 @@ __snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
  */
 int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
 {
-       snd_assert(hdr && blk, return -EINVAL);
+       if (snd_BUG_ON(!hdr || !blk))
+               return -EINVAL;
 
        mutex_lock(&hdr->block_mutex);
        __snd_util_mem_free(hdr, blk);
index ffcdc8f4ef66de645e41ffa2881d12fc1ce5e0e9..4f0eac9bff1e1afb10e3540e3871c9b6be2fff66 100644 (file)
@@ -67,5 +67,17 @@ config SND_USB_CAIAQ_INPUT
           * Native Instruments Kore Controller 2
           * Native Instruments Audio Kontrol 1
 
+config SND_USB_US122L
+       tristate "Tascam US-122L USB driver"
+       depends on X86 && EXPERIMENTAL
+       select SND_HWDEP
+       select SND_RAWMIDI
+       help
+         Say Y here to include support for Tascam US-122L USB Audio/MIDI
+         interfaces.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-usb-us122l.
+
 endif  # SND_USB
 
index aa252ef2ebfbd3ab81da82a89f7883ac49132190..abb288bfe35db2a721bb1d512275bbac03e7f145 100644 (file)
@@ -8,5 +8,6 @@ snd-usb-lib-objs := usbmidi.o
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o
+obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o
 
 obj-$(CONFIG_SND) += usx2y/ caiaq/
index b8cfb7c2276872a05f40a07a0ed57d0b57357e8e..bbd70d5814a083fff3d130cf5b2be652abd7f2f9 100644 (file)
@@ -71,6 +71,7 @@ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
 static int nrpacks = 8;                /* max. number of packets per urb */
 static int async_unlink = 1;
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
+static int ignore_ctl_error;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -88,7 +89,9 @@ module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 module_param_array(device_setup, int, NULL, 0444);
 MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
-
+module_param(ignore_ctl_error, bool, 0444);
+MODULE_PARM_DESC(ignore_ctl_error,
+                "Ignore errors from USB controller for mixer interfaces.");
 
 /*
  * debug the h/w constraints
@@ -481,7 +484,7 @@ static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs,
 }
 
 /*
- * process after E-Mu 0202/0404 high speed playback sync complete
+ * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete
  *
  * These devices return the number of samples per packet instead of the number
  * of samples per microframe.
@@ -841,7 +844,8 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
                return -EBADFD;
 
        for (i = 0; i < subs->nurbs; i++) {
-               snd_assert(subs->dataurb[i].urb, return -EINVAL);
+               if (snd_BUG_ON(!subs->dataurb[i].urb))
+                       return -EINVAL;
                if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
                        snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
                        goto __error;
@@ -849,7 +853,8 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
        }
        if (subs->syncpipe) {
                for (i = 0; i < SYNC_URBS; i++) {
-                       snd_assert(subs->syncurb[i].urb, return -EINVAL);
+                       if (snd_BUG_ON(!subs->syncurb[i].urb))
+                               return -EINVAL;
                        if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
                                snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
                                goto __error;
@@ -1321,10 +1326,12 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        int err;
 
        iface = usb_ifnum_to_if(dev, fmt->iface);
-       snd_assert(iface, return -EINVAL);
+       if (WARN_ON(!iface))
+               return -EINVAL;
        alts = &iface->altsetting[fmt->altset_idx];
        altsd = get_iface_desc(alts);
-       snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL);
+       if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting))
+               return -EINVAL;
 
        if (fmt == subs->cur_audiofmt)
                return 0;
@@ -2257,6 +2264,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo
                switch (as->chip->usb_id) {
                case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
                case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
+               case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
                        subs->ops.retire_sync = retire_playback_sync_urb_hs_emu;
                        break;
                }
@@ -2989,12 +2997,12 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
 }
 
 /*
- * Create a stream for an Edirol UA-700/UA-25 interface.  The only way
- * to detect the sample rate is by looking at wMaxPacketSize.
+ * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.  
+ * The only way to detect the sample rate is by looking at wMaxPacketSize.
  */
-static int create_ua700_ua25_quirk(struct snd_usb_audio *chip,
-                                  struct usb_interface *iface,
-                                  const struct snd_usb_audio_quirk *quirk)
+static int create_uaxx_quirk(struct snd_usb_audio *chip,
+                             struct usb_interface *iface,
+                             const struct snd_usb_audio_quirk *quirk)
 {
        static const struct audioformat ua_format = {
                .format = SNDRV_PCM_FORMAT_S24_3LE,
@@ -3009,8 +3017,8 @@ static int create_ua700_ua25_quirk(struct snd_usb_audio *chip,
        struct audioformat *fp;
        int stream, err;
 
-       /* both PCM and MIDI interfaces have 2 altsettings */
-       if (iface->num_altsetting != 2)
+       /* both PCM and MIDI interfaces have 2 or more altsettings */
+       if (iface->num_altsetting < 2)
                return -ENXIO;
        alts = &iface->altsetting[1];
        altsd = get_iface_desc(alts);
@@ -3024,20 +3032,20 @@ static int create_ua700_ua25_quirk(struct snd_usb_audio *chip,
                        .type = QUIRK_MIDI_FIXED_ENDPOINT,
                        .data = &ua700_ep
                };
-               static const struct snd_usb_midi_endpoint_info ua25_ep = {
+               static const struct snd_usb_midi_endpoint_info uaxx_ep = {
                        .out_cables = 0x0001,
                        .in_cables  = 0x0001
                };
-               static const struct snd_usb_audio_quirk ua25_quirk = {
+               static const struct snd_usb_audio_quirk uaxx_quirk = {
                        .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                       .data = &ua25_ep
+                       .data = &uaxx_ep
                };
                if (chip->usb_id == USB_ID(0x0582, 0x002b))
                        return snd_usb_create_midi_interface(chip, iface,
                                                             &ua700_quirk);
                else
                        return snd_usb_create_midi_interface(chip, iface,
-                                                            &ua25_quirk);
+                                                            &uaxx_quirk);
        }
 
        if (altsd->bNumEndpoints != 1)
@@ -3369,9 +3377,9 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
-               [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
                [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
                [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk,
+               [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk
        };
 
        if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -3629,7 +3637,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
        if (err > 0) {
                /* create normal USB audio interfaces */
                if (snd_usb_create_streams(chip, ifnum) < 0 ||
-                   snd_usb_create_mixer(chip, ifnum) < 0) {
+                   snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
                        goto __error;
                }
        }
index 7cf18c38dc424c14a1decd29614105cfc4412e81..36e4f7a29adc5548b05b5366fa0191f13466145b 100644 (file)
@@ -156,11 +156,12 @@ enum quirk_type {
        QUIRK_MIDI_RAW,
        QUIRK_MIDI_EMAGIC,
        QUIRK_MIDI_CME,
+       QUIRK_MIDI_US122L,
        QUIRK_AUDIO_STANDARD_INTERFACE,
        QUIRK_AUDIO_FIXED_ENDPOINT,
-       QUIRK_AUDIO_EDIROL_UA700_UA25,
        QUIRK_AUDIO_EDIROL_UA1000,
        QUIRK_AUDIO_EDIROL_UA101,
+       QUIRK_AUDIO_EDIROL_UAXX,
 
        QUIRK_TYPE_COUNT
 };
@@ -222,7 +223,8 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe,
                    __u8 request, __u8 requesttype, __u16 value, __u16 index,
                    void *data, __u16 size, int timeout);
 
-int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif);
+int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
+                        int ignore_error);
 void snd_usb_mixer_disconnect(struct list_head *p);
 
 int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface,
index 6676a177c99e3342117051a179c4588bdbdd0335..5962e4b8442394fbe4812c2bfd21a013cf04f29c 100644 (file)
@@ -669,6 +669,42 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = {
        .output = snd_usbmidi_raw_output,
 };
 
+static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,
+                                    uint8_t *buffer, int buffer_length)
+{
+       if (buffer_length != 9)
+               return;
+       buffer_length = 8;
+       while (buffer_length && buffer[buffer_length - 1] == 0xFD)
+               buffer_length--;
+       if (buffer_length)
+               snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
+}
+
+static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep)
+{
+       int count;
+
+       if (!ep->ports[0].active)
+               return;
+       count = ep->urb->dev->speed == USB_SPEED_HIGH ? 1 : 2;
+       count = snd_rawmidi_transmit(ep->ports[0].substream,
+                                    ep->urb->transfer_buffer,
+                                    count);
+       if (count < 1) {
+               ep->ports[0].active = 0;
+               return;
+       }
+
+       memset(ep->urb->transfer_buffer + count, 0xFD, 9 - count);
+       ep->urb->transfer_buffer_length = count;
+}
+
+static struct usb_protocol_ops snd_usbmidi_122l_ops = {
+       .input = snd_usbmidi_us122l_input,
+       .output = snd_usbmidi_us122l_output,
+};
+
 /*
  * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching.
  */
@@ -1076,6 +1112,15 @@ void snd_usbmidi_disconnect(struct list_head* p)
                }
                if (ep->in)
                        usb_kill_urb(ep->in->urb);
+               /* free endpoints here; later call can result in Oops */
+               if (ep->out) {
+                       snd_usbmidi_out_endpoint_delete(ep->out);
+                       ep->out = NULL;
+               }
+               if (ep->in) {
+                       snd_usbmidi_in_endpoint_delete(ep->in);
+                       ep->in = NULL;
+               }
        }
        del_timer_sync(&umidi->error_timer);
 }
@@ -1714,6 +1759,9 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
                        umidi->usb_protocol_ops =
                                &snd_usbmidi_maudio_broken_running_status_ops;
                break;
+       case QUIRK_MIDI_US122L:
+               umidi->usb_protocol_ops = &snd_usbmidi_122l_ops;
+               /* fall through */
        case QUIRK_MIDI_FIXED_ENDPOINT:
                memcpy(&endpoints[0], quirk->data,
                       sizeof(struct snd_usb_midi_endpoint_info));
index 89c63d073cc6fac8f0c00ca1646377994157c64b..a49246113e7563c60f08c47d6104c7774d1073ac 100644 (file)
@@ -59,12 +59,13 @@ static const struct rc_config {
        u8  offset;
        u8  length;
        u8  packet_length;
+       u8  min_packet_length; /* minimum accepted length of the URB result */
        u8  mute_mixer_id;
        u32 mute_code;
 } rc_configs[] = {
-       { USB_ID(0x041e, 0x3000), 0, 1, 2,  18, 0x0013 }, /* Extigy       */
-       { USB_ID(0x041e, 0x3020), 2, 1, 6,  18, 0x0013 }, /* Audigy 2 NX  */
-       { USB_ID(0x041e, 0x3040), 2, 2, 6,  2,  0x6e91 }, /* Live! 24-bit */
+       { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
+       { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
+       { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
 };
 
 struct usb_mixer_interface {
@@ -1388,7 +1389,8 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
        char **itemlist = (char **)kcontrol->private_value;
 
-       snd_assert(itemlist, return -EINVAL);
+       if (snd_BUG_ON(!itemlist))
+               return -EINVAL;
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = cval->max;
@@ -1781,7 +1783,7 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb)
        const struct rc_config *rc = mixer->rc_cfg;
        u32 code;
 
-       if (urb->status < 0 || urb->actual_length < rc->packet_length)
+       if (urb->status < 0 || urb->actual_length < rc->min_packet_length)
                return;
 
        code = mixer->rc_buffer[rc->offset];
@@ -2012,7 +2014,8 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
        }
 }
 
-int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
+int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
+                        int ignore_error)
 {
        static struct snd_device_ops dev_ops = {
                .dev_free = snd_usb_mixer_dev_free
@@ -2027,9 +2030,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
                return -ENOMEM;
        mixer->chip = chip;
        mixer->ctrlif = ctrlif;
-#ifdef IGNORE_CTL_ERROR
-       mixer->ignore_ctl_error = 1;
-#endif
+       mixer->ignore_ctl_error = ignore_error;
        mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL);
        if (!mixer->id_elems) {
                kfree(mixer);
index 9ea726c049c6c1f5d7b891e2e25bcd62ff934e40..69689e79bf799b512efb44f82d542bad8d250b56 100644 (file)
        .idProduct = 0x3f04,
        .bInterfaceClass = USB_CLASS_AUDIO,
 },
+{
+       /* E-Mu Tracker Pre */
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor = 0x041e,
+       .idProduct = 0x3f0a,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+},
 
 /*
  * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
@@ -855,15 +862,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_EDIROL_UA700_UA25
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
                        },
                        {
                                .ifnum = 2,
-                               .type = QUIRK_AUDIO_EDIROL_UA700_UA25
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
                        },
                        {
                                .ifnum = 3,
-                               .type = QUIRK_AUDIO_EDIROL_UA700_UA25
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
                        },
                        {
                                .ifnum = -1
@@ -1197,15 +1204,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_AUDIO_EDIROL_UA700_UA25
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_EDIROL_UA700_UA25
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
                        },
                        {
                                .ifnum = 2,
-                               .type = QUIRK_AUDIO_EDIROL_UA700_UA25
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
                        },
                        {
                                .ifnum = -1
@@ -1337,6 +1344,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        .in_cables  = 0x000f
                }
        }
+},
+{
+       /*
+        * This quirk is for the "Advanced Driver" mode. If off, the UA-4FX
+        * is standard compliant, but has only 16-bit PCM and no MIDI.
+        */
+       USB_DEVICE(0x0582, 0x00a3),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-4FX",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_EDIROL_UAXX
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
 },
        /* TODO: add Edirol MD-P1 support */
 {
@@ -1383,7 +1420,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-
 {
        /* Roland SonicCell */
        USB_DEVICE(0x0582, 0x00c2),
@@ -1415,7 +1451,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-
+{
+       /* BOSS GT-10 */
+       USB_DEVICE(0x0582, 0x00da),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
index 9ac22bce1124b67385a28c62b65b7fd7858399a6..748933054b6cfebb986b03bce37a32f4a1ffc3f8 100644 (file)
@@ -1,3 +1,5 @@
 snd-usb-usx2y-objs := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o
+snd-usb-us122l-objs := us122l.o
 
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o
+obj-$(CONFIG_SND_USB_US122L) += snd-usb-us122l.o
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
new file mode 100644 (file)
index 0000000..b441fe2
--- /dev/null
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sound/core.h>
+#include <sound/hwdep.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#define MODNAME "US122L"
+#include "usb_stream.c"
+#include "../usbaudio.h"
+#include "us122l.h"
+
+MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.5");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-max */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* Id for this card */
+                                                       /* Enable this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
+
+static int snd_us122l_card_used[SNDRV_CARDS];
+
+
+static int us122l_create_usbmidi(struct snd_card *card)
+{
+       static struct snd_usb_midi_endpoint_info quirk_data = {
+               .out_ep = 4,
+               .in_ep = 3,
+               .out_cables =   0x001,
+               .in_cables =    0x001
+       };
+       static struct snd_usb_audio_quirk quirk = {
+               .vendor_name =  "US122L",
+               .product_name = NAME_ALLCAPS,
+               .ifnum =        1,
+               .type = QUIRK_MIDI_US122L,
+               .data = &quirk_data
+       };
+       struct usb_device *dev = US122L(card)->chip.dev;
+       struct usb_interface *iface = usb_ifnum_to_if(dev, 1);
+
+       return snd_usb_create_midi_interface(&US122L(card)->chip,
+                                            iface, &quirk);
+}
+
+/*
+ * Wrapper for usb_control_msg().
+ * Allocates a temp buffer to prevent dmaing from/to the stack.
+ */
+static int us122l_ctl_msg(struct usb_device *dev, unsigned int pipe,
+                         __u8 request, __u8 requesttype,
+                         __u16 value, __u16 index, void *data,
+                         __u16 size, int timeout)
+{
+       int err;
+       void *buf = NULL;
+
+       if (size > 0) {
+               buf = kmemdup(data, size, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+       }
+       err = usb_control_msg(dev, pipe, request, requesttype,
+                             value, index, buf, size, timeout);
+       if (size > 0) {
+               memcpy(data, buf, size);
+               kfree(buf);
+       }
+       return err;
+}
+
+static void pt_info_set(struct usb_device *dev, u8 v)
+{
+       int ret;
+
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                             'I',
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             v, 0, NULL, 0, 1000);
+       snd_printdd(KERN_DEBUG "%i\n", ret);
+}
+
+static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
+{
+       struct us122l *us122l = area->vm_private_data;
+       atomic_inc(&us122l->mmap_count);
+       snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
+}
+
+static int usb_stream_hwdep_vm_fault(struct vm_area_struct *area,
+                                    struct vm_fault *vmf)
+{
+       unsigned long offset;
+       struct page *page;
+       void *vaddr;
+       struct us122l *us122l = area->vm_private_data;
+       struct usb_stream *s;
+       int vm_f = VM_FAULT_SIGBUS;
+
+       mutex_lock(&us122l->mutex);
+       s = us122l->sk.s;
+       if (!s)
+               goto out;
+
+       offset = vmf->pgoff << PAGE_SHIFT;
+       if (offset < PAGE_ALIGN(s->read_size))
+               vaddr = (char *)s + offset;
+       else {
+               offset -= PAGE_ALIGN(s->read_size);
+               if (offset >= PAGE_ALIGN(s->write_size))
+                       goto out;
+
+               vaddr = us122l->sk.write_page + offset;
+       }
+       page = virt_to_page(vaddr);
+
+       get_page(page);
+       mutex_unlock(&us122l->mutex);
+
+       vmf->page = page;
+       vm_f = 0;
+out:
+       return vm_f;
+}
+
+static void usb_stream_hwdep_vm_close(struct vm_area_struct *area)
+{
+       struct us122l *us122l = area->vm_private_data;
+       atomic_dec(&us122l->mmap_count);
+       snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
+}
+
+static struct vm_operations_struct usb_stream_hwdep_vm_ops = {
+       .open = usb_stream_hwdep_vm_open,
+       .fault = usb_stream_hwdep_vm_fault,
+       .close = usb_stream_hwdep_vm_close,
+};
+
+
+static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
+{
+       struct us122l   *us122l = hw->private_data;
+       struct usb_interface *iface;
+       snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
+       if (hw->used >= 2)
+               return -EBUSY;
+
+       if (!us122l->first)
+               us122l->first = file;
+       iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+       usb_autopm_get_interface(iface);
+       return 0;
+}
+
+static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
+{
+       struct us122l   *us122l = hw->private_data;
+       struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+       snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
+       usb_autopm_put_interface(iface);
+       if (us122l->first == file)
+               us122l->first = NULL;
+       mutex_lock(&us122l->mutex);
+       if (us122l->master == file)
+               us122l->master = us122l->slave;
+
+       us122l->slave = NULL;
+       mutex_unlock(&us122l->mutex);
+       return 0;
+}
+
+static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
+                                struct file *filp, struct vm_area_struct *area)
+{
+       unsigned long   size = area->vm_end - area->vm_start;
+       struct us122l   *us122l = hw->private_data;
+       unsigned long offset;
+       struct usb_stream *s;
+       int err = 0;
+       bool read;
+
+       offset = area->vm_pgoff << PAGE_SHIFT;
+       mutex_lock(&us122l->mutex);
+       s = us122l->sk.s;
+       read = offset < s->read_size;
+       if (read && area->vm_flags & VM_WRITE) {
+               err = -EPERM;
+               goto out;
+       }
+       snd_printdd(KERN_DEBUG "%lu %u\n", size,
+                   read ? s->read_size : s->write_size);
+       /* if userspace tries to mmap beyond end of our buffer, fail */
+       if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) {
+               snd_printk(KERN_WARNING "%lu > %u\n", size,
+                          read ? s->read_size : s->write_size);
+               err = -EINVAL;
+               goto out;
+       }
+
+       area->vm_ops = &usb_stream_hwdep_vm_ops;
+       area->vm_flags |= VM_RESERVED;
+       area->vm_private_data = us122l;
+       atomic_inc(&us122l->mmap_count);
+out:
+       mutex_unlock(&us122l->mutex);
+       return err;
+}
+
+static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,
+                                         struct file *file, poll_table *wait)
+{
+       struct us122l   *us122l = hw->private_data;
+       struct usb_stream *s = us122l->sk.s;
+       unsigned        *polled;
+       unsigned int    mask;
+
+       poll_wait(file, &us122l->sk.sleep, wait);
+
+       switch (s->state) {
+       case usb_stream_ready:
+               if (us122l->first == file)
+                       polled = &s->periods_polled;
+               else
+                       polled = &us122l->second_periods_polled;
+               if (*polled != s->periods_done) {
+                       *polled = s->periods_done;
+                       mask = POLLIN | POLLOUT | POLLWRNORM;
+                       break;
+               }
+               /* Fall through */
+               mask = 0;
+               break;
+       default:
+               mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR;
+               break;
+       }
+       return mask;
+}
+
+static void us122l_stop(struct us122l *us122l)
+{
+       struct list_head *p;
+       list_for_each(p, &us122l->chip.midi_list)
+               snd_usbmidi_input_stop(p);
+
+       usb_stream_stop(&us122l->sk);
+       usb_stream_free(&us122l->sk);
+}
+
+static int us122l_set_sample_rate(struct usb_device *dev, int rate)
+{
+       unsigned int ep = 0x81;
+       unsigned char data[3];
+       int err;
+
+       data[0] = rate;
+       data[1] = rate >> 8;
+       data[2] = rate >> 16;
+       err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+                            USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
+                            SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000);
+       if (err < 0)
+               snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n",
+                          dev->devnum, rate, ep);
+       return err;
+}
+
+static bool us122l_start(struct us122l *us122l,
+                        unsigned rate, unsigned period_frames)
+{
+       struct list_head *p;
+       int err;
+       unsigned use_packsize = 0;
+       bool success = false;
+
+       if (us122l->chip.dev->speed == USB_SPEED_HIGH) {
+               /* The us-122l's descriptor defaults to iso max_packsize 78,
+                  which isn't needed for samplerates <= 48000.
+                  Lets save some memory:
+               */
+               switch (rate) {
+               case 44100:
+                       use_packsize = 36;
+                       break;
+               case 48000:
+                       use_packsize = 42;
+                       break;
+               case 88200:
+                       use_packsize = 72;
+                       break;
+               }
+       }
+       if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2,
+                           rate, use_packsize, period_frames, 6))
+               goto out;
+
+       err = us122l_set_sample_rate(us122l->chip.dev, rate);
+       if (err < 0) {
+               us122l_stop(us122l);
+               snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
+               goto out;
+       }
+       err = usb_stream_start(&us122l->sk);
+       if (err < 0) {
+               us122l_stop(us122l);
+               snd_printk(KERN_ERR "us122l_start error %i \n", err);
+               goto out;
+       }
+       list_for_each(p, &us122l->chip.midi_list)
+               snd_usbmidi_input_start(p);
+       success = true;
+out:
+       return success;
+}
+
+static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+                                 unsigned cmd, unsigned long arg)
+{
+       struct usb_stream_config *cfg;
+       struct us122l *us122l = hw->private_data;
+       unsigned min_period_frames;
+       int err = 0;
+       bool high_speed;
+
+       if (cmd != SNDRV_USB_STREAM_IOCTL_SET_PARAMS)
+               return -ENOTTY;
+
+       cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+
+       if (copy_from_user(cfg, (void *)arg, sizeof(*cfg))) {
+               err = -EFAULT;
+               goto free;
+       }
+       if (cfg->version != USB_STREAM_INTERFACE_VERSION) {
+               err = -ENXIO;
+               goto free;
+       }
+       high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH;
+       if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000  &&
+            (!high_speed ||
+             (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) ||
+           cfg->frame_size != 6 ||
+           cfg->period_frames > 0x3000) {
+               err = -EINVAL;
+               goto free;
+       }
+       switch (cfg->sample_rate) {
+       case 44100:
+               min_period_frames = 48;
+               break;
+       case 48000:
+               min_period_frames = 52;
+               break;
+       default:
+               min_period_frames = 104;
+               break;
+       }
+       if (!high_speed)
+               min_period_frames <<= 1;
+       if (cfg->period_frames < min_period_frames) {
+               err = -EINVAL;
+               goto free;
+       }
+
+       snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);
+
+       mutex_lock(&us122l->mutex);
+       if (!us122l->master)
+               us122l->master = file;
+       else if (us122l->master != file) {
+               if (memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg))) {
+                       err = -EIO;
+                       goto unlock;
+               }
+               us122l->slave = file;
+       }
+       if (!us122l->sk.s ||
+           memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg)) ||
+           us122l->sk.s->state == usb_stream_xrun) {
+               us122l_stop(us122l);
+               if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames))
+                       err = -EIO;
+               else
+                       err = 1;
+       }
+unlock:
+       mutex_unlock(&us122l->mutex);
+free:
+       kfree(cfg);
+       return err;
+}
+
+#define SND_USB_STREAM_ID "USB STREAM"
+static int usb_stream_hwdep_new(struct snd_card *card)
+{
+       int err;
+       struct snd_hwdep *hw;
+       struct usb_device *dev = US122L(card)->chip.dev;
+
+       err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw);
+       if (err < 0)
+               return err;
+
+       hw->iface = SNDRV_HWDEP_IFACE_USB_STREAM;
+       hw->private_data = US122L(card);
+       hw->ops.open = usb_stream_hwdep_open;
+       hw->ops.release = usb_stream_hwdep_release;
+       hw->ops.ioctl = usb_stream_hwdep_ioctl;
+       hw->ops.ioctl_compat = usb_stream_hwdep_ioctl;
+       hw->ops.mmap = usb_stream_hwdep_mmap;
+       hw->ops.poll = usb_stream_hwdep_poll;
+
+       sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm",
+               dev->bus->busnum, dev->devnum);
+       return 0;
+}
+
+
+static bool us122l_create_card(struct snd_card *card)
+{
+       int err;
+       struct us122l *us122l = US122L(card);
+
+       err = usb_set_interface(us122l->chip.dev, 1, 1);
+       if (err) {
+               snd_printk(KERN_ERR "usb_set_interface error \n");
+               return false;
+       }
+
+       pt_info_set(us122l->chip.dev, 0x11);
+       pt_info_set(us122l->chip.dev, 0x10);
+
+       if (!us122l_start(us122l, 44100, 256))
+               return false;
+
+       err = us122l_create_usbmidi(card);
+       if (err < 0) {
+               snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err);
+               us122l_stop(us122l);
+               return false;
+       }
+       err = usb_stream_hwdep_new(card);
+       if (err < 0) {
+/* release the midi resources */
+               struct list_head *p;
+               list_for_each(p, &us122l->chip.midi_list)
+                       snd_usbmidi_disconnect(p);
+
+               us122l_stop(us122l);
+               return false;
+       }
+       return true;
+}
+
+static struct snd_card *usx2y_create_card(struct usb_device *device)
+{
+       int             dev;
+       struct snd_card *card;
+       for (dev = 0; dev < SNDRV_CARDS; ++dev)
+               if (enable[dev] && !snd_us122l_card_used[dev])
+                       break;
+       if (dev >= SNDRV_CARDS)
+               return NULL;
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
+                           sizeof(struct us122l));
+       if (!card)
+               return NULL;
+       snd_us122l_card_used[US122L(card)->chip.index = dev] = 1;
+
+       US122L(card)->chip.dev = device;
+       US122L(card)->chip.card = card;
+       mutex_init(&US122L(card)->mutex);
+       init_waitqueue_head(&US122L(card)->sk.sleep);
+       INIT_LIST_HEAD(&US122L(card)->chip.midi_list);
+       strcpy(card->driver, "USB "NAME_ALLCAPS"");
+       sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
+       sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
+               card->shortname,
+               le16_to_cpu(device->descriptor.idVendor),
+               le16_to_cpu(device->descriptor.idProduct),
+               0,
+               US122L(card)->chip.dev->bus->busnum,
+               US122L(card)->chip.dev->devnum
+               );
+       snd_card_set_dev(card, &device->dev);
+       return card;
+}
+
+static void *us122l_usb_probe(struct usb_interface *intf,
+                             const struct usb_device_id *device_id)
+{
+       struct usb_device *device = interface_to_usbdev(intf);
+       struct snd_card *card = usx2y_create_card(device);
+
+       if (!card)
+               return NULL;
+
+       if (!us122l_create_card(card) ||
+           snd_card_register(card) < 0) {
+               snd_card_free(card);
+               return NULL;
+       }
+
+       usb_get_dev(device);
+       return card;
+}
+
+static int snd_us122l_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
+{
+       struct snd_card *card;
+       snd_printdd(KERN_DEBUG"%p:%i\n",
+                   intf, intf->cur_altsetting->desc.bInterfaceNumber);
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
+               return 0;
+
+       card = us122l_usb_probe(usb_get_intf(intf), id);
+
+       if (card) {
+               usb_set_intfdata(intf, card);
+               return 0;
+       }
+
+       usb_put_intf(intf);
+       return -EIO;
+}
+
+static void snd_us122l_disconnect(struct usb_interface *intf)
+{
+       struct snd_card *card;
+       struct us122l *us122l;
+       struct list_head *p;
+
+       card = usb_get_intfdata(intf);
+       if (!card)
+               return;
+
+       snd_card_disconnect(card);
+
+       us122l = US122L(card);
+       mutex_lock(&us122l->mutex);
+       us122l_stop(us122l);
+       mutex_unlock(&us122l->mutex);
+       us122l->chip.shutdown = 1;
+
+/* release the midi resources */
+       list_for_each(p, &us122l->chip.midi_list) {
+               snd_usbmidi_disconnect(p);
+       }
+
+       usb_put_intf(intf);
+       usb_put_dev(US122L(card)->chip.dev);
+
+       while (atomic_read(&us122l->mmap_count))
+               msleep(500);
+
+       snd_card_free(card);
+}
+
+static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct snd_card *card;
+       struct us122l *us122l;
+       struct list_head *p;
+
+       card = dev_get_drvdata(&intf->dev);
+       if (!card)
+               return 0;
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+       us122l = US122L(card);
+       if (!us122l)
+               return 0;
+
+       list_for_each(p, &us122l->chip.midi_list)
+               snd_usbmidi_input_stop(p);
+
+       mutex_lock(&us122l->mutex);
+       usb_stream_stop(&us122l->sk);
+       mutex_unlock(&us122l->mutex);
+
+       return 0;
+}
+
+static int snd_us122l_resume(struct usb_interface *intf)
+{
+       struct snd_card *card;
+       struct us122l *us122l;
+       struct list_head *p;
+       int err;
+
+       card = dev_get_drvdata(&intf->dev);
+       if (!card)
+               return 0;
+
+       us122l = US122L(card);
+       if (!us122l)
+               return 0;
+
+       mutex_lock(&us122l->mutex);
+       /* needed, doesn't restart without: */
+       err = usb_set_interface(us122l->chip.dev, 1, 1);
+       if (err) {
+               snd_printk(KERN_ERR "usb_set_interface error \n");
+               goto unlock;
+       }
+
+       pt_info_set(us122l->chip.dev, 0x11);
+       pt_info_set(us122l->chip.dev, 0x10);
+
+       err = us122l_set_sample_rate(us122l->chip.dev,
+                                    us122l->sk.s->cfg.sample_rate);
+       if (err < 0) {
+               snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
+               goto unlock;
+       }
+       err = usb_stream_start(&us122l->sk);
+       if (err)
+               goto unlock;
+
+       list_for_each(p, &us122l->chip.midi_list)
+               snd_usbmidi_input_start(p);
+unlock:
+       mutex_unlock(&us122l->mutex);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return err;
+}
+
+static struct usb_device_id snd_us122l_usb_id_table[] = {
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     0x0644,
+               .idProduct =    USB_ID_US122L
+       },
+/*     { */            /* US-144 maybe works when @USB1.1. Untested. */
+/*             .match_flags =  USB_DEVICE_ID_MATCH_DEVICE, */
+/*             .idVendor =     0x0644, */
+/*             .idProduct =    USB_ID_US144 */
+/*     }, */
+       { /* terminator */ }
+};
+
+MODULE_DEVICE_TABLE(usb, snd_us122l_usb_id_table);
+static struct usb_driver snd_us122l_usb_driver = {
+       .name =         "snd-usb-us122l",
+       .probe =        snd_us122l_probe,
+       .disconnect =   snd_us122l_disconnect,
+       .suspend =      snd_us122l_suspend,
+       .resume =       snd_us122l_resume,
+       .reset_resume = snd_us122l_resume,
+       .id_table =     snd_us122l_usb_id_table,
+       .supports_autosuspend = 1
+};
+
+
+static int __init snd_us122l_module_init(void)
+{
+       return usb_register(&snd_us122l_usb_driver);
+}
+
+static void __exit snd_us122l_module_exit(void)
+{
+       usb_deregister(&snd_us122l_usb_driver);
+}
+
+module_init(snd_us122l_module_init)
+module_exit(snd_us122l_module_exit)
diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h
new file mode 100644 (file)
index 0000000..3d10c4b
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef US122L_H
+#define US122L_H
+
+
+struct us122l {
+       struct snd_usb_audio    chip;
+       int                     stride;
+       struct usb_stream_kernel sk;
+
+       struct mutex            mutex;
+       struct file             *first;
+       unsigned                second_periods_polled;
+       struct file             *master;
+       struct file             *slave;
+
+       atomic_t                mmap_count;
+};
+
+
+#define US122L(c) ((struct us122l *)(c)->private_data)
+
+#define NAME_ALLCAPS "US-122L"
+
+#define USB_ID_US122L 0x800E
+#define USB_ID_US144 0x800F
+
+#endif
diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c
new file mode 100644 (file)
index 0000000..ff23cc1
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+
+#include "usb_stream.h"
+
+
+/*                             setup                                  */
+
+static unsigned usb_stream_next_packet_size(struct usb_stream_kernel *sk)
+{
+       struct usb_stream *s = sk->s;
+       sk->out_phase_peeked = (sk->out_phase & 0xffff) + sk->freqn;
+       return (sk->out_phase_peeked >> 16) * s->cfg.frame_size;
+}
+
+static void playback_prep_freqn(struct usb_stream_kernel *sk, struct urb *urb)
+{
+       struct usb_stream *s = sk->s;
+       unsigned l = 0;
+       int pack;
+
+       urb->iso_frame_desc[0].offset = 0;
+       urb->iso_frame_desc[0].length = usb_stream_next_packet_size(sk);
+       sk->out_phase = sk->out_phase_peeked;
+       urb->transfer_buffer_length = urb->iso_frame_desc[0].length;
+
+       for (pack = 1; pack < sk->n_o_ps; pack++) {
+               l = usb_stream_next_packet_size(sk);
+               if (s->idle_outsize + urb->transfer_buffer_length + l >
+                   s->period_size)
+                       goto check;
+
+               sk->out_phase = sk->out_phase_peeked;
+               urb->iso_frame_desc[pack].offset = urb->transfer_buffer_length;
+               urb->iso_frame_desc[pack].length = l;
+               urb->transfer_buffer_length += l;
+       }
+       snd_printdd(KERN_DEBUG "%i\n", urb->transfer_buffer_length);
+
+check:
+       urb->number_of_packets = pack;
+       s->idle_outsize += urb->transfer_buffer_length - s->period_size;
+       snd_printdd(KERN_DEBUG "idle=%i ul=%i ps=%i\n", s->idle_outsize,
+                   urb->transfer_buffer_length, s->period_size);
+}
+
+static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize,
+                          struct urb **urbs, char *transfer,
+                          struct usb_device *dev, int pipe)
+{
+       int u, p;
+       int maxpacket = use_packsize ?
+               use_packsize : usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+       int transfer_length = maxpacket * sk->n_o_ps;
+
+       for (u = 0; u < USB_STREAM_NURBS;
+            ++u, transfer += transfer_length) {
+               struct urb *urb = urbs[u];
+               struct usb_iso_packet_descriptor *desc;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = transfer;
+               urb->dev = dev;
+               urb->pipe = pipe;
+               urb->number_of_packets = sk->n_o_ps;
+               urb->context = sk;
+               urb->interval = 1;
+               if (usb_pipeout(pipe))
+                       continue;
+
+               urb->transfer_buffer_length = transfer_length;
+               desc = urb->iso_frame_desc;
+               desc->offset = 0;
+               desc->length = maxpacket;
+               for (p = 1; p < sk->n_o_ps; ++p) {
+                       desc[p].offset = desc[p - 1].offset + maxpacket;
+                       desc[p].length = maxpacket;
+               }
+       }
+}
+
+static void init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize,
+                     struct usb_device *dev, int in_pipe, int out_pipe)
+{
+       struct usb_stream       *s = sk->s;
+       char                    *indata = (char *)s + sizeof(*s) +
+                                       sizeof(struct usb_stream_packet) *
+                                       s->inpackets;
+       int                     u;
+
+       for (u = 0; u < USB_STREAM_NURBS; ++u) {
+               sk->inurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL);
+               sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL);
+       }
+
+       init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe);
+       init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev,
+                      out_pipe);
+}
+
+
+/*
+ * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
+ * this will overflow at approx 524 kHz
+ */
+static inline unsigned get_usb_full_speed_rate(unsigned rate)
+{
+       return ((rate << 13) + 62) / 125;
+}
+
+/*
+ * convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
+ * this will overflow at approx 4 MHz
+ */
+static inline unsigned get_usb_high_speed_rate(unsigned rate)
+{
+       return ((rate << 10) + 62) / 125;
+}
+
+void usb_stream_free(struct usb_stream_kernel *sk)
+{
+       struct usb_stream *s;
+       unsigned u;
+
+       for (u = 0; u < USB_STREAM_NURBS; ++u) {
+               usb_free_urb(sk->inurb[u]);
+               sk->inurb[u] = NULL;
+               usb_free_urb(sk->outurb[u]);
+               sk->outurb[u] = NULL;
+       }
+
+       s = sk->s;
+       if (!s)
+               return;
+
+       free_pages((unsigned long)sk->write_page, get_order(s->write_size));
+       sk->write_page = NULL;
+       free_pages((unsigned long)s, get_order(s->read_size));
+       sk->s = NULL;
+}
+
+struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
+                                 struct usb_device *dev,
+                                 unsigned in_endpoint, unsigned out_endpoint,
+                                 unsigned sample_rate, unsigned use_packsize,
+                                 unsigned period_frames, unsigned frame_size)
+{
+       int packets, max_packsize;
+       int in_pipe, out_pipe;
+       int read_size = sizeof(struct usb_stream);
+       int write_size;
+       int usb_frames = dev->speed == USB_SPEED_HIGH ? 8000 : 1000;
+       int pg;
+
+       in_pipe = usb_rcvisocpipe(dev, in_endpoint);
+       out_pipe = usb_sndisocpipe(dev, out_endpoint);
+
+       max_packsize = use_packsize ?
+               use_packsize : usb_maxpacket(dev, in_pipe, 0);
+
+       /*
+               t_period = period_frames / sample_rate
+               iso_packs = t_period / t_iso_frame
+                       = (period_frames / sample_rate) * (1 / t_iso_frame)
+       */
+
+       packets = period_frames * usb_frames / sample_rate + 1;
+
+       if (dev->speed == USB_SPEED_HIGH)
+               packets = (packets + 7) & ~7;
+
+       read_size += packets * USB_STREAM_URBDEPTH *
+               (max_packsize + sizeof(struct usb_stream_packet));
+
+       max_packsize = usb_maxpacket(dev, out_pipe, 1);
+       write_size = max_packsize * packets * USB_STREAM_URBDEPTH;
+
+       if (read_size >= 256*PAGE_SIZE || write_size >= 256*PAGE_SIZE) {
+               snd_printk(KERN_WARNING "a size exceeds 128*PAGE_SIZE\n");
+               goto out;
+       }
+
+       pg = get_order(read_size);
+       sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg);
+       if (!sk->s) {
+               snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
+               goto out;
+       }
+       sk->s->cfg.version = USB_STREAM_INTERFACE_VERSION;
+
+       sk->s->read_size = read_size;
+
+       sk->s->cfg.sample_rate = sample_rate;
+       sk->s->cfg.frame_size = frame_size;
+       sk->n_o_ps = packets;
+       sk->s->inpackets = packets * USB_STREAM_URBDEPTH;
+       sk->s->cfg.period_frames = period_frames;
+       sk->s->period_size = frame_size * period_frames;
+
+       sk->s->write_size = write_size;
+       pg = get_order(write_size);
+
+       sk->write_page =
+               (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg);
+       if (!sk->write_page) {
+               snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
+               usb_stream_free(sk);
+               return NULL;
+       }
+
+       /* calculate the frequency in 16.16 format */
+       if (dev->speed == USB_SPEED_FULL)
+               sk->freqn = get_usb_full_speed_rate(sample_rate);
+       else
+               sk->freqn = get_usb_high_speed_rate(sample_rate);
+
+       init_urbs(sk, use_packsize, dev, in_pipe, out_pipe);
+       sk->s->state = usb_stream_stopped;
+out:
+       return sk->s;
+}
+
+
+/*                             start                                  */
+
+static bool balance_check(struct usb_stream_kernel *sk, struct urb *urb)
+{
+       bool r;
+       if (unlikely(urb->status)) {
+               if (urb->status != -ESHUTDOWN && urb->status != -ENOENT)
+                       snd_printk(KERN_WARNING "status=%i\n", urb->status);
+               sk->iso_frame_balance = 0x7FFFFFFF;
+               return false;
+       }
+       r = sk->iso_frame_balance == 0;
+       if (!r)
+               sk->i_urb = urb;
+       return r;
+}
+
+static bool balance_playback(struct usb_stream_kernel *sk, struct urb *urb)
+{
+       sk->iso_frame_balance += urb->number_of_packets;
+       return balance_check(sk, urb);
+}
+
+static bool balance_capture(struct usb_stream_kernel *sk, struct urb *urb)
+{
+       sk->iso_frame_balance -= urb->number_of_packets;
+       return balance_check(sk, urb);
+}
+
+static void subs_set_complete(struct urb **urbs, void (*complete)(struct urb *))
+{
+       int u;
+
+       for (u = 0; u < USB_STREAM_NURBS; u++) {
+               struct urb *urb = urbs[u];
+               urb->complete = complete;
+       }
+}
+
+int usb_stream_prepare_playback(struct usb_stream_kernel *sk, struct urb *inurb)
+{
+       struct usb_stream *s = sk->s;
+       struct urb *io;
+       struct usb_iso_packet_descriptor *id, *od;
+       int p, l = 0;
+
+       io = sk->idle_outurb;
+       od = io->iso_frame_desc;
+       io->transfer_buffer_length = 0;
+
+       for (p = 0; s->sync_packet < 0; ++p, ++s->sync_packet) {
+               struct urb *ii = sk->completed_inurb;
+               id = ii->iso_frame_desc +
+                       ii->number_of_packets + s->sync_packet;
+               l = id->actual_length;
+
+               od[p].length = l;
+               od[p].offset = io->transfer_buffer_length;
+               io->transfer_buffer_length += l;
+       }
+
+       for (;
+            s->sync_packet < inurb->number_of_packets && p < sk->n_o_ps;
+            ++p, ++s->sync_packet) {
+               l = inurb->iso_frame_desc[s->sync_packet].actual_length;
+
+               if (s->idle_outsize + io->transfer_buffer_length + l >
+                   s->period_size)
+                       goto check_ok;
+
+               od[p].length = l;
+               od[p].offset = io->transfer_buffer_length;
+               io->transfer_buffer_length += l;
+       }
+
+check_ok:
+       s->sync_packet -= inurb->number_of_packets;
+       if (s->sync_packet < -2 || s->sync_packet > 0) {
+               snd_printk(KERN_WARNING "invalid sync_packet = %i;"
+                          " p=%i nop=%i %i %x %x %x > %x\n",
+                          s->sync_packet, p, inurb->number_of_packets,
+                          s->idle_outsize + io->transfer_buffer_length + l,
+                          s->idle_outsize, io->transfer_buffer_length,  l,
+                          s->period_size);
+               return -1;
+       }
+       if (io->transfer_buffer_length % s->cfg.frame_size) {
+               snd_printk(KERN_WARNING"invalid outsize = %i\n",
+                          io->transfer_buffer_length);
+               return -1;
+       }
+       s->idle_outsize += io->transfer_buffer_length - s->period_size;
+       io->number_of_packets = p;
+       if (s->idle_outsize > 0) {
+               snd_printk(KERN_WARNING "idle=%i\n", s->idle_outsize);
+               return -1;
+       }
+       return 0;
+}
+
+static void prepare_inurb(int number_of_packets, struct urb *iu)
+{
+       struct usb_iso_packet_descriptor *id;
+       int p;
+
+       iu->number_of_packets = number_of_packets;
+       id = iu->iso_frame_desc;
+       id->offset = 0;
+       for (p = 0; p < iu->number_of_packets - 1; ++p)
+               id[p + 1].offset = id[p].offset + id[p].length;
+
+       iu->transfer_buffer_length =
+               id[0].length * iu->number_of_packets;
+}
+
+static int submit_urbs(struct usb_stream_kernel *sk,
+                      struct urb *inurb, struct urb *outurb)
+{
+       int err;
+       prepare_inurb(sk->idle_outurb->number_of_packets, sk->idle_inurb);
+       err = usb_submit_urb(sk->idle_inurb, GFP_ATOMIC);
+       if (err < 0) {
+               snd_printk(KERN_ERR "%i\n", err);
+               return err;
+       }
+       sk->idle_inurb = sk->completed_inurb;
+       sk->completed_inurb = inurb;
+       err = usb_submit_urb(sk->idle_outurb, GFP_ATOMIC);
+       if (err < 0) {
+               snd_printk(KERN_ERR "%i\n", err);
+               return err;
+       }
+       sk->idle_outurb = sk->completed_outurb;
+       sk->completed_outurb = outurb;
+       return 0;
+}
+
+#ifdef DEBUG_LOOP_BACK
+/*
+  This loop_back() shows how to read/write the period data.
+ */
+static void loop_back(struct usb_stream *s)
+{
+       char *i, *o;
+       int il, ol, l, p;
+       struct urb *iu;
+       struct usb_iso_packet_descriptor *id;
+
+       o = s->playback1st_to;
+       ol = s->playback1st_size;
+       l = 0;
+
+       if (s->insplit_pack >= 0) {
+               iu = sk->idle_inurb;
+               id = iu->iso_frame_desc;
+               p = s->insplit_pack;
+       } else
+               goto second;
+loop:
+       for (; p < iu->number_of_packets && l < s->period_size; ++p) {
+               i = iu->transfer_buffer + id[p].offset;
+               il = id[p].actual_length;
+               if (l + il > s->period_size)
+                       il = s->period_size - l;
+               if (il <= ol) {
+                       memcpy(o, i, il);
+                       o += il;
+                       ol -= il;
+               } else {
+                       memcpy(o, i, ol);
+                       singen_6pack(o, ol);
+                       o = s->playback_to;
+                       memcpy(o, i + ol, il - ol);
+                       o += il - ol;
+                       ol = s->period_size - s->playback1st_size;
+               }
+               l += il;
+       }
+       if (iu == sk->completed_inurb) {
+               if (l != s->period_size)
+                       printk(KERN_DEBUG"%s:%i %i\n", __func__, __LINE__,
+                              l/(int)s->cfg.frame_size);
+
+               return;
+       }
+second:
+       iu = sk->completed_inurb;
+       id = iu->iso_frame_desc;
+       p = 0;
+       goto loop;
+
+}
+#else
+static void loop_back(struct usb_stream *s)
+{
+}
+#endif
+
+static void stream_idle(struct usb_stream_kernel *sk,
+                       struct urb *inurb, struct urb *outurb)
+{
+       struct usb_stream *s = sk->s;
+       int l, p;
+       int insize = s->idle_insize;
+       int urb_size = 0;
+
+       s->inpacket_split = s->next_inpacket_split;
+       s->inpacket_split_at = s->next_inpacket_split_at;
+       s->next_inpacket_split = -1;
+       s->next_inpacket_split_at = 0;
+
+       for (p = 0; p < inurb->number_of_packets; ++p) {
+               struct usb_iso_packet_descriptor *id = inurb->iso_frame_desc;
+               l = id[p].actual_length;
+               if (unlikely(l == 0 || id[p].status)) {
+                       snd_printk(KERN_WARNING "underrun, status=%u\n",
+                                  id[p].status);
+                       goto err_out;
+               }
+               s->inpacket_head++;
+               s->inpacket_head %= s->inpackets;
+               if (s->inpacket_split == -1)
+                       s->inpacket_split = s->inpacket_head;
+
+               s->inpacket[s->inpacket_head].offset =
+                       id[p].offset + (inurb->transfer_buffer - (void *)s);
+               s->inpacket[s->inpacket_head].length = l;
+               if (insize + l > s->period_size &&
+                   s->next_inpacket_split == -1) {
+                       s->next_inpacket_split = s->inpacket_head;
+                       s->next_inpacket_split_at = s->period_size - insize;
+               }
+               insize += l;
+               urb_size += l;
+       }
+       s->idle_insize += urb_size - s->period_size;
+       if (s->idle_insize < 0) {
+               snd_printk(KERN_WARNING "%i\n",
+                          (s->idle_insize)/(int)s->cfg.frame_size);
+               goto err_out;
+       }
+       s->insize_done += urb_size;
+
+       l = s->idle_outsize;
+       s->outpacket[0].offset = (sk->idle_outurb->transfer_buffer -
+                                 sk->write_page) - l;
+
+       if (usb_stream_prepare_playback(sk, inurb) < 0)
+               goto err_out;
+
+       s->outpacket[0].length = sk->idle_outurb->transfer_buffer_length + l;
+       s->outpacket[1].offset = sk->completed_outurb->transfer_buffer -
+               sk->write_page;
+
+       if (submit_urbs(sk, inurb, outurb) < 0)
+               goto err_out;
+
+       loop_back(s);
+       s->periods_done++;
+       wake_up_all(&sk->sleep);
+       return;
+err_out:
+       s->state = usb_stream_xrun;
+       wake_up_all(&sk->sleep);
+}
+
+static void i_capture_idle(struct urb *urb)
+{
+       struct usb_stream_kernel *sk = urb->context;
+       if (balance_capture(sk, urb))
+               stream_idle(sk, urb, sk->i_urb);
+}
+
+static void i_playback_idle(struct urb *urb)
+{
+       struct usb_stream_kernel *sk = urb->context;
+       if (balance_playback(sk, urb))
+               stream_idle(sk, sk->i_urb, urb);
+}
+
+static void stream_start(struct usb_stream_kernel *sk,
+                        struct urb *inurb, struct urb *outurb)
+{
+       struct usb_stream *s = sk->s;
+       if (s->state >= usb_stream_sync1) {
+               int l, p, max_diff, max_diff_0;
+               int urb_size = 0;
+               unsigned frames_per_packet, min_frames = 0;
+               frames_per_packet = (s->period_size - s->idle_insize);
+               frames_per_packet <<= 8;
+               frames_per_packet /=
+                       s->cfg.frame_size * inurb->number_of_packets;
+               frames_per_packet++;
+
+               max_diff_0 = s->cfg.frame_size;
+               if (s->cfg.period_frames >= 256)
+                       max_diff_0 <<= 1;
+               if (s->cfg.period_frames >= 1024)
+                       max_diff_0 <<= 1;
+               max_diff = max_diff_0;
+               for (p = 0; p < inurb->number_of_packets; ++p) {
+                       int diff;
+                       l = inurb->iso_frame_desc[p].actual_length;
+                       urb_size += l;
+
+                       min_frames += frames_per_packet;
+                       diff = urb_size -
+                               (min_frames >> 8) * s->cfg.frame_size;
+                       if (diff < max_diff) {
+                               snd_printdd(KERN_DEBUG "%i %i %i %i\n",
+                                           s->insize_done,
+                                           urb_size / (int)s->cfg.frame_size,
+                                           inurb->number_of_packets, diff);
+                               max_diff = diff;
+                       }
+               }
+               s->idle_insize -= max_diff - max_diff_0;
+               s->idle_insize += urb_size - s->period_size;
+               if (s->idle_insize < 0) {
+                       snd_printk("%i %i %i\n",
+                                  s->idle_insize, urb_size, s->period_size);
+                       return;
+               } else if (s->idle_insize == 0) {
+                       s->next_inpacket_split =
+                               (s->inpacket_head + 1) % s->inpackets;
+                       s->next_inpacket_split_at = 0;
+               } else {
+                       unsigned split = s->inpacket_head;
+                       l = s->idle_insize;
+                       while (l > s->inpacket[split].length) {
+                               l -= s->inpacket[split].length;
+                               if (split == 0)
+                                       split = s->inpackets - 1;
+                               else
+                                       split--;
+                       }
+                       s->next_inpacket_split = split;
+                       s->next_inpacket_split_at =
+                               s->inpacket[split].length - l;
+               }
+
+               s->insize_done += urb_size;
+
+               if (usb_stream_prepare_playback(sk, inurb) < 0)
+                       return;
+
+       } else
+               playback_prep_freqn(sk, sk->idle_outurb);
+
+       if (submit_urbs(sk, inurb, outurb) < 0)
+               return;
+
+       if (s->state == usb_stream_sync1 && s->insize_done > 360000) {
+               /* just guesswork                            ^^^^^^ */
+               s->state = usb_stream_ready;
+               subs_set_complete(sk->inurb, i_capture_idle);
+               subs_set_complete(sk->outurb, i_playback_idle);
+       }
+}
+
+static void i_capture_start(struct urb *urb)
+{
+       struct usb_iso_packet_descriptor *id = urb->iso_frame_desc;
+       struct usb_stream_kernel *sk = urb->context;
+       struct usb_stream *s = sk->s;
+       int p;
+       int empty = 0;
+
+       if (urb->status) {
+               snd_printk(KERN_WARNING "status=%i\n", urb->status);
+               return;
+       }
+
+       for (p = 0; p < urb->number_of_packets; ++p) {
+               int l = id[p].actual_length;
+               if (l < s->cfg.frame_size) {
+                       ++empty;
+                       if (s->state >= usb_stream_sync0) {
+                               snd_printk(KERN_WARNING "%i\n", l);
+                               return;
+                       }
+               }
+               s->inpacket_head++;
+               s->inpacket_head %= s->inpackets;
+               s->inpacket[s->inpacket_head].offset =
+                       id[p].offset + (urb->transfer_buffer - (void *)s);
+               s->inpacket[s->inpacket_head].length = l;
+       }
+#ifdef SHOW_EMPTY
+       if (empty) {
+               printk(KERN_DEBUG"%s:%i: %i", __func__, __LINE__,
+                      urb->iso_frame_desc[0].actual_length);
+               for (pack = 1; pack < urb->number_of_packets; ++pack) {
+                       int l = urb->iso_frame_desc[pack].actual_length;
+                       printk(" %i", l);
+               }
+               printk("\n");
+       }
+#endif
+       if (!empty && s->state < usb_stream_sync1)
+               ++s->state;
+
+       if (balance_capture(sk, urb))
+               stream_start(sk, urb, sk->i_urb);
+}
+
+static void i_playback_start(struct urb *urb)
+{
+       struct usb_stream_kernel *sk = urb->context;
+       if (balance_playback(sk, urb))
+               stream_start(sk, sk->i_urb, urb);
+}
+
+int usb_stream_start(struct usb_stream_kernel *sk)
+{
+       struct usb_stream *s = sk->s;
+       int frame = 0, iters = 0;
+       int u, err;
+       int try = 0;
+
+       if (s->state != usb_stream_stopped)
+               return -EAGAIN;
+
+       subs_set_complete(sk->inurb, i_capture_start);
+       subs_set_complete(sk->outurb, i_playback_start);
+       memset(sk->write_page, 0, s->write_size);
+dotry:
+       s->insize_done = 0;
+       s->idle_insize = 0;
+       s->idle_outsize = 0;
+       s->sync_packet = -1;
+       s->inpacket_head = -1;
+       sk->iso_frame_balance = 0;
+       ++try;
+       for (u = 0; u < 2; u++) {
+               struct urb *inurb = sk->inurb[u];
+               struct urb *outurb = sk->outurb[u];
+               playback_prep_freqn(sk, outurb);
+               inurb->number_of_packets = outurb->number_of_packets;
+               inurb->transfer_buffer_length =
+                       inurb->number_of_packets *
+                       inurb->iso_frame_desc[0].length;
+               preempt_disable();
+               if (u == 0) {
+                       int now;
+                       struct usb_device *dev = inurb->dev;
+                       frame = usb_get_current_frame_number(dev);
+                       do {
+                               now = usb_get_current_frame_number(dev);
+                               ++iters;
+                       } while (now > -1 && now == frame);
+               }
+               err = usb_submit_urb(inurb, GFP_ATOMIC);
+               if (err < 0) {
+                       preempt_enable();
+                       snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])"
+                                  " returned %i\n", u, err);
+                       return err;
+               }
+               err = usb_submit_urb(outurb, GFP_ATOMIC);
+               if (err < 0) {
+                       preempt_enable();
+                       snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])"
+                                  " returned %i\n", u, err);
+                       return err;
+               }
+               preempt_enable();
+               if (inurb->start_frame != outurb->start_frame) {
+                       snd_printd(KERN_DEBUG
+                                  "u[%i] start_frames differ in:%u out:%u\n",
+                                  u, inurb->start_frame, outurb->start_frame);
+                       goto check_retry;
+               }
+       }
+       snd_printdd(KERN_DEBUG "%i %i\n", frame, iters);
+       try = 0;
+check_retry:
+       if (try) {
+               usb_stream_stop(sk);
+               if (try < 5) {
+                       msleep(1500);
+                       snd_printd(KERN_DEBUG "goto dotry;\n");
+                       goto dotry;
+               }
+               snd_printk(KERN_WARNING"couldn't start"
+                          " all urbs on the same start_frame.\n");
+               return -EFAULT;
+       }
+
+       sk->idle_inurb = sk->inurb[USB_STREAM_NURBS - 2];
+       sk->idle_outurb = sk->outurb[USB_STREAM_NURBS - 2];
+       sk->completed_inurb = sk->inurb[USB_STREAM_NURBS - 1];
+       sk->completed_outurb = sk->outurb[USB_STREAM_NURBS - 1];
+
+/* wait, check */
+       {
+               int wait_ms = 3000;
+               while (s->state != usb_stream_ready && wait_ms > 0) {
+                       snd_printdd(KERN_DEBUG "%i\n", s->state);
+                       msleep(200);
+                       wait_ms -= 200;
+               }
+       }
+
+       return s->state == usb_stream_ready ? 0 : -EFAULT;
+}
+
+
+/*                             stop                                   */
+
+void usb_stream_stop(struct usb_stream_kernel *sk)
+{
+       int u;
+       if (!sk->s)
+               return;
+       for (u = 0; u < USB_STREAM_NURBS; ++u) {
+               usb_kill_urb(sk->inurb[u]);
+               usb_kill_urb(sk->outurb[u]);
+       }
+       sk->s->state = usb_stream_stopped;
+       msleep(400);
+}
diff --git a/sound/usb/usx2y/usb_stream.h b/sound/usb/usx2y/usb_stream.h
new file mode 100644 (file)
index 0000000..4dd74ab
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define USB_STREAM_INTERFACE_VERSION 2
+
+#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
+       _IOW('H', 0x90, struct usb_stream_config)
+
+struct usb_stream_packet {
+       unsigned offset;
+       unsigned length;
+};
+
+
+struct usb_stream_config {
+       unsigned version;
+       unsigned sample_rate;
+       unsigned period_frames;
+       unsigned frame_size;
+};
+
+struct usb_stream {
+       struct usb_stream_config cfg;
+       unsigned read_size;
+       unsigned write_size;
+
+       int period_size;
+
+       unsigned state;
+
+       int idle_insize;
+       int idle_outsize;
+       int sync_packet;
+       unsigned insize_done;
+       unsigned periods_done;
+       unsigned periods_polled;
+
+       struct usb_stream_packet outpacket[2];
+       unsigned                 inpackets;
+       unsigned                 inpacket_head;
+       unsigned                 inpacket_split;
+       unsigned                 inpacket_split_at;
+       unsigned                 next_inpacket_split;
+       unsigned                 next_inpacket_split_at;
+       struct usb_stream_packet inpacket[0];
+};
+
+enum usb_stream_state {
+       usb_stream_invalid,
+       usb_stream_stopped,
+       usb_stream_sync0,
+       usb_stream_sync1,
+       usb_stream_ready,
+       usb_stream_running,
+       usb_stream_xrun,
+};
+
+#if __KERNEL__
+
+#define USB_STREAM_NURBS 4
+#define USB_STREAM_URBDEPTH 4
+
+struct usb_stream_kernel {
+       struct usb_stream *s;
+
+       void *write_page;
+
+       unsigned n_o_ps;
+
+       struct urb *inurb[USB_STREAM_NURBS];
+       struct urb *idle_inurb;
+       struct urb *completed_inurb;
+       struct urb *outurb[USB_STREAM_NURBS];
+       struct urb *idle_outurb;
+       struct urb *completed_outurb;
+       struct urb *i_urb;
+
+       int iso_frame_balance;
+
+       wait_queue_head_t sleep;
+
+       unsigned out_phase;
+       unsigned out_phase_peeked;
+       unsigned freqn;
+};
+
+struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
+                                 struct usb_device *dev,
+                                 unsigned in_endpoint, unsigned out_endpoint,
+                                 unsigned sample_rate, unsigned use_packsize,
+                                 unsigned period_frames, unsigned frame_size);
+void usb_stream_free(struct usb_stream_kernel *);
+int usb_stream_start(struct usb_stream_kernel *);
+void usb_stream_stop(struct usb_stream_kernel *);
+
+
+#endif