summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/s390/CommonIO11
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt62
-rw-r--r--Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl62
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/arm/plat-omap/include/mach/mtd-xip.h2
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/include/asm/dasd.h13
-rw-r--r--arch/s390/include/asm/delay.h1
-rw-r--r--arch/s390/include/asm/pgtable.h45
-rw-r--r--arch/s390/include/asm/ptrace.h1
-rw-r--r--arch/s390/include/asm/qdio.h8
-rw-r--r--arch/s390/include/asm/syscall.h80
-rw-r--r--arch/s390/include/asm/thread_info.h2
-rw-r--r--arch/s390/kernel/compat_linux.c8
-rw-r--r--arch/s390/kernel/compat_linux.h1
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/entry.S50
-rw-r--r--arch/s390/kernel/entry64.S42
-rw-r--r--arch/s390/kernel/ptrace.c61
-rw-r--r--arch/s390/kernel/signal.c13
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/s390/kernel/time.c2
-rw-r--r--arch/s390/lib/delay.c13
-rw-r--r--arch/s390/mm/extmem.c251
-rw-r--r--arch/um/Kconfig.char4
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c13
-rw-r--r--arch/x86/kernel/cpu/cpufreq/elanfreq.c42
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k6.c41
-rw-r--r--drivers/cpufreq/cpufreq.c30
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c5
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c147
-rw-r--r--drivers/cpufreq/cpufreq_performance.c4
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c4
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c13
-rw-r--r--drivers/s390/block/dasd.c32
-rw-r--r--drivers/s390/block/dasd_3990_erp.c2
-rw-r--r--drivers/s390/block/dasd_devmap.c28
-rw-r--r--drivers/s390/block/dasd_eckd.c132
-rw-r--r--drivers/s390/block/dasd_eer.c6
-rw-r--r--drivers/s390/block/dasd_fba.c4
-rw-r--r--drivers/s390/block/dasd_int.h4
-rw-r--r--drivers/s390/block/dasd_proc.c2
-rw-r--r--drivers/s390/block/dcssblk.c516
-rw-r--r--drivers/s390/block/xpram.c37
-rw-r--r--drivers/s390/char/con3215.c53
-rw-r--r--drivers/s390/char/con3270.c27
-rw-r--r--drivers/s390/char/raw3270.c4
-rw-r--r--drivers/s390/char/sclp_con.c24
-rw-r--r--drivers/s390/char/sclp_vt220.c26
-rw-r--r--drivers/s390/char/tape_3590.c132
-rw-r--r--drivers/s390/char/tape_block.c2
-rw-r--r--drivers/s390/char/tape_core.c21
-rw-r--r--drivers/s390/char/tape_proc.c2
-rw-r--r--drivers/s390/char/tape_std.c13
-rw-r--r--drivers/s390/char/vmlogrdr.c5
-rw-r--r--drivers/s390/char/vmur.c6
-rw-r--r--drivers/s390/cio/blacklist.c11
-rw-r--r--drivers/s390/cio/ccwgroup.c3
-rw-r--r--drivers/s390/cio/chp.c3
-rw-r--r--drivers/s390/cio/chsc_sch.c2
-rw-r--r--drivers/s390/cio/cio.c56
-rw-r--r--drivers/s390/cio/cio.h4
-rw-r--r--drivers/s390/cio/css.c4
-rw-r--r--drivers/s390/cio/device.c118
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c6
-rw-r--r--drivers/s390/cio/device_ops.c2
-rw-r--r--drivers/s390/cio/io_sch.h22
-rw-r--r--drivers/s390/cio/ioasm.h49
-rw-r--r--drivers/s390/cio/qdio.h11
-rw-r--r--drivers/s390/cio/qdio_debug.c2
-rw-r--r--drivers/s390/cio/qdio_main.c32
-rw-r--r--drivers/s390/crypto/ap_bus.c4
-rw-r--r--drivers/s390/kvm/kvm_virtio.c15
-rw-r--r--drivers/s390/net/claw.c36
-rw-r--r--drivers/s390/net/claw.h2
-rw-r--r--drivers/s390/net/ctcm_main.c22
-rw-r--r--drivers/s390/net/ctcm_main.h2
-rw-r--r--drivers/s390/net/lcs.c34
-rw-r--r--drivers/s390/net/netiucv.c2
-rw-r--r--drivers/s390/net/qeth_core.h10
-rw-r--r--drivers/s390/net/qeth_core_main.c10
-rw-r--r--drivers/s390/s390_rdev.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c7
-rw-r--r--drivers/s390/scsi/zfcp_def.h4
-rw-r--r--drivers/s390/scsi/zfcp_erp.c2
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c2
-rw-r--r--drivers/usb/host/ehci-ixp4xx.c2
-rw-r--r--include/linux/cpufreq.h7
-rw-r--r--include/linux/tick.h2
-rw-r--r--include/sound/ad1848.h218
-rw-r--r--include/sound/asound.h52
-rw-r--r--include/sound/asoundef.h89
-rw-r--r--include/sound/core.h32
-rw-r--r--include/sound/cs4231.h175
-rw-r--r--include/sound/jack.h75
-rw-r--r--include/sound/memalloc.h16
-rw-r--r--include/sound/minors.h2
-rw-r--r--include/sound/pcm.h39
-rw-r--r--include/sound/pxa2xx-lib.h45
-rw-r--r--include/sound/sb.h5
-rw-r--r--include/sound/snd_wavefront.h1
-rw-r--r--include/sound/soc-of-simple.h25
-rw-r--r--include/sound/soc.h74
-rw-r--r--include/sound/version.h2
-rw-r--r--include/sound/vx_core.h9
-rw-r--r--include/sound/wss.h235
-rw-r--r--kernel/time/tick-sched.c11
-rwxr-xr-xscripts/checkstack.pl5
-rw-r--r--sound/Kconfig5
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.c6
-rw-r--r--sound/arm/Kconfig9
-rw-r--r--sound/arm/Makefile4
-rw-r--r--sound/arm/aaci.c6
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c384
-rw-r--r--sound/arm/pxa2xx-ac97.c247
-rw-r--r--sound/arm/pxa2xx-pcm-lib.c278
-rw-r--r--sound/arm/pxa2xx-pcm.c252
-rw-r--r--sound/arm/pxa2xx-pcm.h13
-rw-r--r--sound/arm/sa11xx-uda1341.c7
-rw-r--r--sound/core/Kconfig10
-rw-r--r--sound/core/Makefile1
-rw-r--r--sound/core/control.c54
-rw-r--r--sound/core/control_compat.c3
-rw-r--r--sound/core/device.c26
-rw-r--r--sound/core/hwdep.c16
-rw-r--r--sound/core/info.c23
-rw-r--r--sound/core/info_oss.c6
-rw-r--r--sound/core/init.c3
-rw-r--r--sound/core/jack.c163
-rw-r--r--sound/core/memalloc.c56
-rw-r--r--sound/core/oss/copy.c30
-rw-r--r--sound/core/oss/io.c24
-rw-r--r--sound/core/oss/linear.c29
-rw-r--r--sound/core/oss/mixer_oss.c18
-rw-r--r--sound/core/oss/mulaw.c27
-rw-r--r--sound/core/oss/pcm_oss.c52
-rw-r--r--sound/core/oss/pcm_plugin.c38
-rw-r--r--sound/core/oss/rate.c42
-rw-r--r--sound/core/oss/route.c12
-rw-r--r--sound/core/pcm.c84
-rw-r--r--sound/core/pcm_compat.c3
-rw-r--r--sound/core/pcm_lib.c102
-rw-r--r--sound/core/pcm_memory.c40
-rw-r--r--sound/core/pcm_native.c140
-rw-r--r--sound/core/pcm_timer.c6
-rw-r--r--sound/core/rawmidi.c25
-rw-r--r--sound/core/rtctimer.c6
-rw-r--r--sound/core/seq/oss/seq_oss.c12
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c6
-rw-r--r--sound/core/seq/seq_clientmgr.c30
-rw-r--r--sound/core/seq/seq_compat.c3
-rw-r--r--sound/core/seq/seq_device.c6
-rw-r--r--sound/core/seq/seq_fifo.c15
-rw-r--r--sound/core/seq/seq_memory.c12
-rw-r--r--sound/core/seq/seq_midi.c15
-rw-r--r--sound/core/seq/seq_ports.c13
-rw-r--r--sound/core/seq/seq_prioq.c4
-rw-r--r--sound/core/seq/seq_queue.c6
-rw-r--r--sound/core/seq/seq_timer.c24
-rw-r--r--sound/core/sgbuf.c62
-rw-r--r--sound/core/sound.c14
-rw-r--r--sound/core/sound_oss.c12
-rw-r--r--sound/core/timer.c33
-rw-r--r--sound/core/timer_compat.c9
-rw-r--r--sound/drivers/dummy.c41
-rw-r--r--sound/drivers/mtpav.c8
-rw-r--r--sound/drivers/opl3/opl3_lib.c6
-rw-r--r--sound/drivers/opl3/opl3_midi.c6
-rw-r--r--sound/drivers/opl3/opl3_oss.c15
-rw-r--r--sound/drivers/opl3/opl3_synth.c3
-rw-r--r--sound/drivers/opl4/opl4_synth.c2
-rw-r--r--sound/drivers/vx/vx_cmd.c3
-rw-r--r--sound/drivers/vx/vx_core.c21
-rw-r--r--sound/drivers/vx/vx_hwdep.c6
-rw-r--r--sound/drivers/vx/vx_mixer.c3
-rw-r--r--sound/drivers/vx/vx_pcm.c9
-rw-r--r--sound/drivers/vx/vx_uer.c6
-rw-r--r--sound/i2c/cs8427.c15
-rw-r--r--sound/i2c/i2c.c6
-rw-r--r--sound/i2c/l3/uda1341.c3
-rw-r--r--sound/i2c/other/ak4114.c3
-rw-r--r--sound/i2c/other/ak4117.c3
-rw-r--r--sound/i2c/other/ak4xxx-adda.c4
-rw-r--r--sound/isa/Kconfig44
-rw-r--r--sound/isa/Makefile2
-rw-r--r--sound/isa/ad1816a/ad1816a.c4
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c6
-rw-r--r--sound/isa/ad1848/Makefile2
-rw-r--r--sound/isa/ad1848/ad1848.c17
-rw-r--r--sound/isa/ad1848/ad1848_lib.c1267
-rw-r--r--sound/isa/azt2320.c29
-rw-r--r--sound/isa/cmi8330.c106
-rw-r--r--sound/isa/cs423x/Makefile2
-rw-r--r--sound/isa/cs423x/cs4231.c18
-rw-r--r--sound/isa/cs423x/cs4231_lib.c1945
-rw-r--r--sound/isa/cs423x/cs4236.c51
-rw-r--r--sound/isa/cs423x/cs4236_lib.c349
-rw-r--r--sound/isa/es1688/es1688_lib.c3
-rw-r--r--sound/isa/gus/gus_main.c6
-rw-r--r--sound/isa/gus/gus_mixer.c6
-rw-r--r--sound/isa/gus/gus_pcm.c12
-rw-r--r--sound/isa/gus/gusmax.c50
-rw-r--r--sound/isa/gus/interwave.c67
-rw-r--r--sound/isa/opl3sa2.c99
-rw-r--r--sound/isa/opti9xx/miro.c28
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c70
-rw-r--r--sound/isa/sb/emu8000.c3
-rw-r--r--sound/isa/sb/emu8000_patch.c3
-rw-r--r--sound/isa/sb/sb16_csp.c9
-rw-r--r--sound/isa/sb/sb16_main.c3
-rw-r--r--sound/isa/sb/sb8_main.c8
-rw-r--r--sound/isa/sb/sb_common.c3
-rw-r--r--sound/isa/sb/sb_mixer.c9
-rw-r--r--sound/isa/sc6000.c18
-rw-r--r--sound/isa/sgalaxy.c43
-rw-r--r--sound/isa/sscape.c63
-rw-r--r--sound/isa/wavefront/wavefront.c62
-rw-r--r--sound/isa/wavefront/wavefront_fx.c8
-rw-r--r--sound/isa/wavefront/wavefront_midi.c24
-rw-r--r--sound/isa/wavefront/wavefront_synth.c7
-rw-r--r--sound/isa/wss/Makefile10
-rw-r--r--sound/isa/wss/wss_lib.c2322
-rw-r--r--sound/mips/au1x00.c6
-rw-r--r--sound/oss/Kconfig35
-rw-r--r--sound/oss/Makefile1
-rw-r--r--sound/oss/aedsp16.c8
-rw-r--r--sound/oss/dmasound/Kconfig1
-rw-r--r--sound/oss/hal2.c1558
-rw-r--r--sound/oss/hal2.h248
-rw-r--r--sound/oss/mpu401.c2
-rw-r--r--sound/parisc/harmony.c3
-rw-r--r--sound/pci/Kconfig33
-rw-r--r--sound/pci/ac97/ac97_codec.c41
-rw-r--r--sound/pci/ac97/ac97_patch.c208
-rw-r--r--sound/pci/ad1889.c6
-rw-r--r--sound/pci/ak4531_codec.c10
-rw-r--r--sound/pci/als4000.c391
-rw-r--r--sound/pci/atiixp.c13
-rw-r--r--sound/pci/atiixp_modem.c10
-rw-r--r--sound/pci/au88x0/au88x0.h7
-rw-r--r--sound/pci/au88x0/au88x0_core.c40
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c14
-rw-r--r--sound/pci/azt3328.c6
-rw-r--r--sound/pci/bt87x.c5
-rw-r--r--sound/pci/ca0106/ca0106_main.c2
-rw-r--r--sound/pci/ca0106/ca_midi.c20
-rw-r--r--sound/pci/cmipci.c9
-rw-r--r--sound/pci/cs4281.c13
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c91
-rw-r--r--sound/pci/cs46xx/dsp_spos.c51
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c115
-rw-r--r--sound/pci/echoaudio/darla20_dsp.c3
-rw-r--r--sound/pci/echoaudio/darla24_dsp.c8
-rw-r--r--sound/pci/echoaudio/echo3g_dsp.c9
-rw-r--r--sound/pci/echoaudio/echoaudio.c22
-rw-r--r--sound/pci/echoaudio/echoaudio_3g.c11
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c21
-rw-r--r--sound/pci/echoaudio/echoaudio_gml.c6
-rw-r--r--sound/pci/echoaudio/gina20_dsp.c6
-rw-r--r--sound/pci/echoaudio/gina24_dsp.c11
-rw-r--r--sound/pci/echoaudio/indigo_dsp.c8
-rw-r--r--sound/pci/echoaudio/indigodj_dsp.c8
-rw-r--r--sound/pci/echoaudio/indigoio_dsp.c8
-rw-r--r--sound/pci/echoaudio/layla20_dsp.c9
-rw-r--r--sound/pci/echoaudio/layla24_dsp.c11
-rw-r--r--sound/pci/echoaudio/mia_dsp.c13
-rw-r--r--sound/pci/echoaudio/midi.c6
-rw-r--r--sound/pci/echoaudio/mona_dsp.c6
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c6
-rw-r--r--sound/pci/emu10k1/emu10k1_patch.c23
-rw-r--r--sound/pci/emu10k1/emu10k1x.c18
-rw-r--r--sound/pci/emu10k1/emufx.c6
-rw-r--r--sound/pci/emu10k1/emumpu401.c18
-rw-r--r--sound/pci/emu10k1/memory.c31
-rw-r--r--sound/pci/emu10k1/voice.c9
-rw-r--r--sound/pci/es1938.c3
-rw-r--r--sound/pci/es1968.c6
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_beep.c134
-rw-r--r--sound/pci/hda/hda_beep.h44
-rw-r--r--sound/pci/hda/hda_codec.c113
-rw-r--r--sound/pci/hda/hda_codec.h93
-rw-r--r--sound/pci/hda/hda_generic.c3
-rw-r--r--sound/pci/hda/hda_intel.c146
-rw-r--r--sound/pci/hda/hda_local.h24
-rw-r--r--sound/pci/hda/hda_patch.h2
-rw-r--r--sound/pci/hda/hda_proc.c25
-rw-r--r--sound/pci/hda/patch_analog.c96
-rw-r--r--sound/pci/hda/patch_atihdmi.c45
-rw-r--r--sound/pci/hda/patch_nvhdmi.c164
-rw-r--r--sound/pci/hda/patch_realtek.c1816
-rw-r--r--sound/pci/hda/patch_sigmatel.c958
-rw-r--r--sound/pci/hda/patch_via.c1407
-rw-r--r--sound/pci/ice1712/ak4xxx.c3
-rw-r--r--sound/pci/ice1712/aureon.c699
-rw-r--r--sound/pci/ice1712/delta.c2
-rw-r--r--sound/pci/ice1712/delta.h1
-rw-r--r--sound/pci/ice1712/ews.c9
-rw-r--r--sound/pci/ice1712/ice1712.c240
-rw-r--r--sound/pci/ice1712/ice1712.h52
-rw-r--r--sound/pci/ice1712/ice1724.c188
-rw-r--r--sound/pci/ice1712/juli.c47
-rw-r--r--sound/pci/ice1712/phase.c277
-rw-r--r--sound/pci/ice1712/phase.h8
-rw-r--r--sound/pci/ice1712/pontis.c5
-rw-r--r--sound/pci/ice1712/revo.c25
-rw-r--r--sound/pci/ice1712/wtm.c104
-rw-r--r--sound/pci/ice1712/wtm.h4
-rw-r--r--sound/pci/intel8x0.c50
-rw-r--r--sound/pci/intel8x0m.c3
-rw-r--r--sound/pci/korg1212/korg1212.c9
-rw-r--r--sound/pci/maestro3.c10
-rw-r--r--sound/pci/mixart/mixart.c4
-rw-r--r--sound/pci/mixart/mixart_core.c18
-rw-r--r--sound/pci/mixart/mixart_hwdep.c19
-rw-r--r--sound/pci/mixart/mixart_mixer.c8
-rw-r--r--sound/pci/nm256/nm256.c15
-rw-r--r--sound/pci/oxygen/hifier.c15
-rw-r--r--sound/pci/oxygen/oxygen.c92
-rw-r--r--sound/pci/oxygen/oxygen.h103
-rw-r--r--sound/pci/oxygen/oxygen_io.c22
-rw-r--r--sound/pci/oxygen/oxygen_lib.c101
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c48
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c47
-rw-r--r--sound/pci/oxygen/virtuoso.c594
-rw-r--r--sound/pci/pcxhr/pcxhr.c6
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c27
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c15
-rw-r--r--sound/pci/riptide/riptide.c31
-rw-r--r--sound/pci/rme9652/hdsp.c25
-rw-r--r--sound/pci/rme9652/hdspm.c52
-rw-r--r--sound/pci/rme9652/rme9652.c23
-rw-r--r--sound/pci/sonicvibes.c10
-rw-r--r--sound/pci/trident/trident_main.c22
-rw-r--r--sound/pci/trident/trident_memory.c37
-rw-r--r--sound/pci/via82xx.c60
-rw-r--r--sound/pci/via82xx_modem.c8
-rw-r--r--sound/pci/vx222/vx222_ops.c12
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c21
-rw-r--r--sound/pcmcia/vx/vxp_ops.c3
-rw-r--r--sound/ppc/awacs.c23
-rw-r--r--sound/ppc/beep.c6
-rw-r--r--sound/ppc/tumbler.c17
-rw-r--r--sound/sh/aica.c9
-rw-r--r--sound/soc/Kconfig2
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/at32/playpaq_wm8510.c7
-rw-r--r--sound/soc/at91/at91-ssc.c2
-rw-r--r--sound/soc/at91/eti_b1_wm8731.c1
-rw-r--r--sound/soc/blackfin/Kconfig85
-rw-r--r--sound/soc/blackfin/Makefile20
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c429
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.h29
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c407
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.h36
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c113
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c288
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.h29
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c292
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.h14
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c1032
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h192
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c186
-rw-r--r--sound/soc/codecs/Kconfig91
-rw-r--r--sound/soc/codecs/Makefile22
-rw-r--r--sound/soc/codecs/ad1980.c309
-rw-r--r--sound/soc/codecs/ad1980.h23
-rw-r--r--sound/soc/codecs/ak4535.c116
-rw-r--r--sound/soc/codecs/ak4535.h1
-rw-r--r--sound/soc/codecs/ssm2602.c776
-rw-r--r--sound/soc/codecs/ssm2602.h130
-rw-r--r--sound/soc/codecs/tlv320aic26.c520
-rw-r--r--sound/soc/codecs/tlv320aic26.h96
-rw-r--r--sound/soc/codecs/tlv320aic3x.c108
-rw-r--r--sound/soc/codecs/tlv320aic3x.h3
-rw-r--r--sound/soc/codecs/uda1380.c115
-rw-r--r--sound/soc/codecs/uda1380.h1
-rw-r--r--sound/soc/codecs/wm8510.c112
-rw-r--r--sound/soc/codecs/wm8510.h1
-rw-r--r--sound/soc/codecs/wm8580.c1055
-rw-r--r--sound/soc/codecs/wm8580.h42
-rw-r--r--sound/soc/codecs/wm8731.c178
-rw-r--r--sound/soc/codecs/wm8731.h2
-rw-r--r--sound/soc/codecs/wm8750.c177
-rw-r--r--sound/soc/codecs/wm8750.h2
-rw-r--r--sound/soc/codecs/wm8753.c106
-rw-r--r--sound/soc/codecs/wm8753.h1
-rw-r--r--sound/soc/codecs/wm8900.c1542
-rw-r--r--sound/soc/codecs/wm8900.h64
-rw-r--r--sound/soc/codecs/wm8903.c1813
-rw-r--r--sound/soc/codecs/wm8903.h1463
-rw-r--r--sound/soc/codecs/wm8971.c942
-rw-r--r--sound/soc/codecs/wm8971.h64
-rw-r--r--sound/soc/codecs/wm8990.c109
-rw-r--r--sound/soc/codecs/wm8990.h1
-rw-r--r--sound/soc/codecs/wm9713.c34
-rw-r--r--sound/soc/davinci/davinci-evm.c3
-rw-r--r--sound/soc/davinci/davinci-i2s.c4
-rw-r--r--sound/soc/davinci/davinci-i2s.h2
-rw-r--r--sound/soc/davinci/davinci-pcm.c2
-rw-r--r--sound/soc/davinci/davinci-pcm.h2
-rw-r--r--sound/soc/fsl/Kconfig10
-rw-r--r--sound/soc/fsl/Makefile5
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c884
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c26
-rw-r--r--sound/soc/fsl/soc-of-simple.c171
-rw-r--r--sound/soc/omap/n810.c1
-rw-r--r--sound/soc/pxa/Kconfig3
-rw-r--r--sound/soc/pxa/corgi.c1
-rw-r--r--sound/soc/pxa/poodle.c1
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c272
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c20
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c265
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.h15
-rw-r--r--sound/soc/pxa/spitz.c1
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c120
-rw-r--r--sound/soc/soc-core.c138
-rw-r--r--sound/soc/soc-dapm.c127
-rw-r--r--sound/sound_core.c79
-rw-r--r--sound/sparc/amd7930.c19
-rw-r--r--sound/sparc/cs4231.c3
-rw-r--r--sound/sparc/dbri.c17
-rw-r--r--sound/synth/emux/emux.c8
-rw-r--r--sound/synth/emux/emux_nrpn.c8
-rw-r--r--sound/synth/emux/emux_oss.c42
-rw-r--r--sound/synth/emux/emux_seq.c15
-rw-r--r--sound/synth/emux/emux_synth.c47
-rw-r--r--sound/synth/util_mem.c10
-rw-r--r--sound/usb/Kconfig12
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/usbaudio.c46
-rw-r--r--sound/usb/usbaudio.h6
-rw-r--r--sound/usb/usbmidi.c48
-rw-r--r--sound/usb/usbmixer.c19
-rw-r--r--sound/usb/usbquirks.h80
-rw-r--r--sound/usb/usx2y/Makefile2
-rw-r--r--sound/usb/usx2y/us122l.c692
-rw-r--r--sound/usb/usx2y/us122l.h27
-rw-r--r--sound/usb/usx2y/usb_stream.c761
-rw-r--r--sound/usb/usx2y/usb_stream.h112
442 files changed, 30647 insertions, 11387 deletions
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index bf0baa19ec2..339207d11d9 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -70,13 +70,19 @@ Command line parameters
Note: While already known devices can be added to the list of devices to be
ignored, there will be no effect on then. However, if such a device
- disappears and then reappears, it will then be ignored.
+ disappears and then reappears, it will then be ignored. To make
+ known devices go away, you need the "purge" command (see below).
For example,
"echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore"
will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
devices.
+ You can remove already known but now ignored devices via
+ "echo purge > /proc/cio_ignore"
+ All devices ignored but still registered and not online (= not in use)
+ will be deregistered and thus removed from the system.
+
The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
numbers given as 0xabcd will be interpreted as 0.0.abcd.
@@ -98,8 +104,7 @@ debugfs entries
handling).
- /sys/kernel/debug/s390dbf/cio_msg/sprintf
- Various debug messages from the common I/O-layer, including messages
- printed when cio_msg=yes.
+ Various debug messages from the common I/O-layer.
- /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
Logs the calling of functions in the common I/O-layer and, if applicable,
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index b117e42a616..e0e54a27fc1 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -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.
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index e13c4e67029..b54cb5048df 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -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>
diff --git a/MAINTAINERS b/MAINTAINERS
index 7a03bd5a91a..ece4e27f997 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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
diff --git a/arch/arm/plat-omap/include/mach/mtd-xip.h b/arch/arm/plat-omap/include/mach/mtd-xip.h
index 5cee7e16a1b..39b591ff54b 100644
--- a/arch/arm/plat-omap/include/mach/mtd-xip.h
+++ b/arch/arm/plat-omap/include/mach/mtd-xip.h
@@ -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
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8d41908e251..4c03049e7db 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -74,6 +74,7 @@ config S390
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_KVM if 64BIT
+ select HAVE_ARCH_TRACEHOOK
source "init/Kconfig"
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h
index 3f002e13d02..55b2b80cdf6 100644
--- a/arch/s390/include/asm/dasd.h
+++ b/arch/s390/include/asm/dasd.h
@@ -3,6 +3,8 @@
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
*
* This file is the interface of the DASD device driver, which is exported to user space
* any future changes wrt the API will result in a change of the APIVERSION reported
@@ -202,6 +204,16 @@ typedef struct attrib_data_t {
#define DASD_SEQ_PRESTAGE 0x4
#define DASD_REC_ACCESS 0x5
+/*
+ * Perform EMC Symmetrix I/O
+ */
+typedef struct dasd_symmio_parms {
+ unsigned char reserved[8]; /* compat with older releases */
+ unsigned long long psf_data; /* char * cast to u64 */
+ unsigned long long rssd_result; /* char * cast to u64 */
+ int psf_data_len;
+ int rssd_result_len;
+} __attribute__ ((packed)) dasd_symmio_parms_t;
/********************************************************************************
* SECTION: Definition of IOCTLs
@@ -247,6 +259,7 @@ typedef struct attrib_data_t {
/* Set Attributes (cache operations) */
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t)
+#define BIODASDSYMMIO _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)
#endif /* DASD_H */
diff --git a/arch/s390/include/asm/delay.h b/arch/s390/include/asm/delay.h
index 78357314c45..a356c958e26 100644
--- a/arch/s390/include/asm/delay.h
+++ b/arch/s390/include/asm/delay.h
@@ -15,6 +15,7 @@
#define _S390_DELAY_H
extern void __udelay(unsigned long usecs);
+extern void udelay_simple(unsigned long usecs);
extern void __delay(unsigned long loops);
#define udelay(n) __udelay(n)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 0bdb704ae05..1a928f84afd 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -281,6 +281,9 @@ extern char empty_zero_page[PAGE_SIZE];
#define RCP_GR_BIT 50
#define RCP_GC_BIT 49
+/* User dirty bit for KVM's migration feature */
+#define KVM_UD_BIT 47
+
#ifndef __s390x__
/* Bits in the segment table address-space-control-element */
@@ -575,12 +578,16 @@ static inline void ptep_rcp_copy(pte_t *ptep)
unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
skey = page_get_storage_key(page_to_phys(page));
- if (skey & _PAGE_CHANGED)
+ if (skey & _PAGE_CHANGED) {
set_bit_simple(RCP_GC_BIT, pgste);
+ set_bit_simple(KVM_UD_BIT, pgste);
+ }
if (skey & _PAGE_REFERENCED)
set_bit_simple(RCP_GR_BIT, pgste);
- if (test_and_clear_bit_simple(RCP_HC_BIT, pgste))
+ if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
SetPageDirty(page);
+ set_bit_simple(KVM_UD_BIT, pgste);
+ }
if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
SetPageReferenced(page);
#endif
@@ -744,6 +751,40 @@ static inline pte_t pte_mkspecial(pte_t pte)
return pte;
}
+#ifdef CONFIG_PGSTE
+/*
+ * Get (and clear) the user dirty bit for a PTE.
+ */
+static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
+ pte_t *ptep)
+{
+ int dirty;
+ unsigned long *pgste;
+ struct page *page;
+ unsigned int skey;
+
+ if (!mm->context.pgstes)
+ return -EINVAL;
+ rcp_lock(ptep);
+ pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+ page = virt_to_page(pte_val(*ptep));
+ skey = page_get_storage_key(page_to_phys(page));
+ if (skey & _PAGE_CHANGED) {
+ set_bit_simple(RCP_GC_BIT, pgste);
+ set_bit_simple(KVM_UD_BIT, pgste);
+ }
+ if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
+ SetPageDirty(page);
+ set_bit_simple(KVM_UD_BIT, pgste);
+ }
+ dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
+ if (skey & _PAGE_CHANGED)
+ page_clear_dirty(page);
+ rcp_unlock(ptep);
+ return dirty;
+}
+#endif
+
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index af2c9ac28a0..a7226f8143f 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -490,6 +490,7 @@ extern void user_disable_single_step(struct task_struct *);
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
+#define user_stack_pointer(regs)((regs)->gprs[15])
#define regs_return_value(regs)((regs)->gprs[2])
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs * regs);
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 6813772171f..4734c3f0535 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -299,7 +299,13 @@ struct qdio_ssqd_desc {
u8 mbccnt;
u16 qdioac2;
u64 sch_token;
- u64:64;
+ u8 mro;
+ u8 mri;
+ u8:8;
+ u8 sbalic;
+ u16:16;
+ u8:8;
+ u8 mmwc;
} __attribute__ ((packed));
/* params are: ccw_device, qdio_error, queue_number,
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
new file mode 100644
index 00000000000..6e623971fbb
--- /dev/null
+++ b/arch/s390/include/asm/syscall.h
@@ -0,0 +1,80 @@
+/*
+ * Access to user system call parameters and results
+ *
+ * Copyright IBM Corp. 2008
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.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 only)
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H 1
+
+#include <asm/ptrace.h>
+
+static inline long syscall_get_nr(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ if (regs->trap != __LC_SVC_OLD_PSW)
+ return -1;
+ return regs->gprs[2];
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ regs->gprs[2] = regs->orig_gpr2;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->gprs[2];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs,
+ int error, long val)
+{
+ regs->gprs[2] = error ? -error : val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+#ifdef CONFIG_COMPAT
+ if (test_tsk_thread_flag(task, TIF_31BIT)) {
+ if (i + n == 6)
+ args[--n] = (u32) regs->args[0];
+ while (n-- > 0)
+ args[n] = (u32) regs->gprs[2 + i + n];
+ }
+#endif
+ if (i + n == 6)
+ args[--n] = regs->args[0];
+ memcpy(args, &regs->gprs[2 + i], n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ const unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+ if (i + n == 6)
+ regs->args[0] = args[--n];
+ memcpy(&regs->gprs[2 + i], args, n * sizeof(args[0]));
+}
+
+#endif /* _ASM_SYSCALL_H */
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 91a8f93ad35..ea40a9d690f 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -86,6 +86,7 @@ static inline struct thread_info *current_thread_info(void)
* thread information flags bit numbers
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTART_SVC 4 /* restart svc with new svc number */
@@ -100,6 +101,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index d7f22226fc4..98e246dc023 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -608,14 +608,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct time
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return -ERESTARTNOHAND;
-}
-
asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
size_t count, u32 poshi, u32 poslo)
{
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 20723a06201..05f8516366a 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -206,7 +206,6 @@ long sys32_gettimeofday(struct compat_timeval __user *tv,
struct timezone __user *tz);
long sys32_settimeofday(struct compat_timeval __user *tv,
struct timezone __user *tz);
-long sys32_pause(void);
long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
u32 poshi, u32 poslo);
long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 328a20e880b..ee51ca9e23b 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -128,8 +128,6 @@ sys32_alarm_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_alarm # branch to system call
-#sys32_pause_wrapper # void
-
.globl compat_sys_utime_wrapper
compat_sys_utime_wrapper:
llgtr %r2,%r2 # char *
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 708cf9cf9a3..ed500ef799b 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -49,9 +49,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
@@ -318,6 +318,8 @@ sysc_work:
bo BASED(sysc_reschedule)
tm __TI_flags+3(%r9),_TIF_SIGPENDING
bnz BASED(sysc_sigpending)
+ tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME
+ bnz BASED(sysc_notify_resume)
tm __TI_flags+3(%r9),_TIF_RESTART_SVC
bo BASED(sysc_restart)
tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
@@ -356,6 +358,16 @@ sysc_sigpending:
b BASED(sysc_work_loop)
#
+# _TIF_NOTIFY_RESUME is set, call do_notify_resume
+#
+sysc_notify_resume:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ldo_notify_resume)
+ la %r14,BASED(sysc_work_loop)
+ br %r1 # call do_notify_resume
+
+
+#
# _TIF_RESTART_SVC is set, set up registers and restart svc
#
sysc_restart:
@@ -378,20 +390,21 @@ sysc_singlestep:
br %r1 # branch to do_single_step
#
-# call trace before and after sys_call
+# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
+# and after the system call
#
sysc_tracesys:
- l %r1,BASED(.Ltrace)
+ l %r1,BASED(.Ltrace_entry)
la %r2,SP_PTREGS(%r15) # load pt_regs
la %r3,0
srl %r7,2
st %r7,SP_R2(%r15)
basr %r14,%r1
- clc SP_R2(4,%r15),BASED(.Lnr_syscalls)
+ cl %r2,BASED(.Lnr_syscalls)
bnl BASED(sysc_tracenogo)
l %r8,BASED(.Lsysc_table)
- l %r7,SP_R2(%r15) # strace might have changed the
- sll %r7,2 # system call
+ lr %r7,%r2
+ sll %r7,2 # *4
l %r8,0(%r7,%r8)
sysc_tracego:
lm %r3,%r6,SP_R3(%r15)
@@ -401,9 +414,8 @@ sysc_tracego:
sysc_tracenogo:
tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
bz BASED(sysc_return)
- l %r1,BASED(.Ltrace)
+ l %r1,BASED(.Ltrace_exit)
la %r2,SP_PTREGS(%r15) # load pt_regs
- la %r3,1
la %r14,BASED(sysc_return)
br %r1
@@ -666,6 +678,8 @@ io_work_loop:
bo BASED(io_reschedule)
tm __TI_flags+3(%r9),_TIF_SIGPENDING
bnz BASED(io_sigpending)
+ tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME
+ bnz BASED(io_notify_resume)
b BASED(io_restore)
io_work_done:
@@ -704,6 +718,19 @@ io_sigpending:
TRACE_IRQS_OFF
b BASED(io_work_loop)
+#
+# _TIF_SIGPENDING is set, call do_signal
+#
+io_notify_resume:
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ldo_notify_resume)
+ basr %r14,%r1 # call do_signal
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ TRACE_IRQS_OFF
+ b BASED(io_work_loop)
+
/*
* External interrupt handler routine
*/
@@ -1070,6 +1097,8 @@ cleanup_io_leave_insn:
.Ldo_IRQ: .long do_IRQ
.Ldo_extint: .long do_extint
.Ldo_signal: .long do_signal
+.Ldo_notify_resume:
+ .long do_notify_resume
.Lhandle_per: .long do_single_step
.Ldo_execve: .long do_execve
.Lexecve_tail: .long execve_tail
@@ -1079,7 +1108,8 @@ cleanup_io_leave_insn:
.Lpreempt_schedule_irq:
.long preempt_schedule_irq
#endif
-.Ltrace: .long syscall_trace
+.Ltrace_entry: .long do_syscall_trace_enter
+.Ltrace_exit: .long do_syscall_trace_exit
.Lschedtail: .long schedule_tail
.Lsysc_table: .long sys_call_table
#ifdef CONFIG_TRACE_IRQFLAGS
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index fee10177dbf..d7ce150453f 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -52,9 +52,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
#define BASED(name) name-system_call(%r13)
@@ -310,6 +310,8 @@ sysc_work:
jo sysc_reschedule
tm __TI_flags+7(%r9),_TIF_SIGPENDING
jnz sysc_sigpending
+ tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME
+ jnz sysc_notify_resume
tm __TI_flags+7(%r9),_TIF_RESTART_SVC
jo sysc_restart
tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
@@ -345,6 +347,14 @@ sysc_sigpending:
j sysc_work_loop
#
+# _TIF_NOTIFY_RESUME is set, call do_notify_resume
+#
+sysc_notify_resume:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ larl %r14,sysc_work_loop
+ jg do_notify_resume # call do_notify_resume
+
+#
# _TIF_RESTART_SVC is set, set up registers and restart svc
#
sysc_restart:
@@ -367,20 +377,19 @@ sysc_singlestep:
jg do_single_step # branch to do_sigtrap
#
-# call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
+# and after the system call
#
sysc_tracesys:
la %r2,SP_PTREGS(%r15) # load pt_regs
la %r3,0
srl %r7,2
stg %r7,SP_R2(%r15)
- brasl %r14,syscall_trace
+ brasl %r14,do_syscall_trace_enter
lghi %r0,NR_syscalls
- clg %r0,SP_R2(%r15)
+ clgr %r0,%r2
jnh sysc_tracenogo
- lg %r7,SP_R2(%r15) # strace might have changed the
- sll %r7,2 # system call
+ slag %r7,%r2,2 # *4
lgf %r8,0(%r7,%r10)
sysc_tracego:
lmg %r3,%r6,SP_R3(%r15)
@@ -391,9 +400,8 @@ sysc_tracenogo:
tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
jz sysc_return
la %r2,SP_PTREGS(%r15) # load pt_regs
- la %r3,1
larl %r14,sysc_return # return point is sysc_return
- jg syscall_trace
+ jg do_syscall_trace_exit
#
# a new process exits the kernel with ret_from_fork
@@ -672,6 +680,8 @@ io_work_loop:
jo io_reschedule
tm __TI_flags+7(%r9),_TIF_SIGPENDING
jnz io_sigpending
+ tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME
+ jnz io_notify_resume
j io_restore
io_work_done:
@@ -712,6 +722,18 @@ io_sigpending:
TRACE_IRQS_OFF
j io_work_loop
+#
+# _TIF_NOTIFY_RESUME or is set, call do_notify_resume
+#
+io_notify_resume:
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,do_notify_resume # call do_notify_resume
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ TRACE_IRQS_OFF
+ j io_work_loop
+
/*
* External interrupt handler routine
*/
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index c8b08289eb8..1f31be1ecc4 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -35,6 +35,7 @@
#include <linux/signal.h>
#include <linux/elf.h>
#include <linux/regset.h>
+#include <linux/tracehook.h>
#include <asm/segment.h>
#include <asm/page.h>
@@ -639,40 +640,44 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
}
#endif
-asmlinkage void
-syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
{
- if (unlikely(current->audit_context) && entryexit)
- audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
-
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- goto out;
- if (!(current->ptrace & PT_PTRACED))
- goto out;
- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0));
+ long ret;
/*
- * If the debuffer has set an invalid system call number,
- * we prepare to skip the system call restart handling.
+ * The sysc_tracesys code in entry.S stored the system
+ * call number to gprs[2].
*/
- if (!entryexit && regs->gprs[2] >= NR_syscalls)
+ ret = regs->gprs[2];
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ (tracehook_report_syscall_entry(regs) ||
+ regs->gprs[2] >= NR_syscalls)) {
+ /*
+ * Tracing decided this syscall should not happen or the
+ * debugger stored an invalid system call number. Skip
+ * the system call and the system call restart handling.
+ */
regs->trap = -1;
-
- /*
- * this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
+ ret = -1;
}
- out:
- if (unlikely(current->audit_context) && !entryexit)
- audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
- regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
- regs->gprs[4], regs->gprs[5]);
+
+ if (unlikely(current->audit_context))
+ audit_syscall_entry(test_thread_flag(TIF_31BIT) ?
+ AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
+ regs->gprs[2], regs->orig_gpr2,
+ regs->gprs[3], regs->gprs[4],
+ regs->gprs[5]);
+ return ret;
+}
+
+asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
+{
+ if (unlikely(current->audit_context))
+ audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
+ regs->gprs[2]);
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, 0);
}
/*
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index b9768204021..4f7fc3059a8 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -24,6 +24,7 @@
#include <linux/tty.h>
#include <linux/personality.h>
#include <linux/binfmts.h>
+#include <linux/tracehook.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/lowcore.h>
@@ -507,6 +508,12 @@ void do_signal(struct pt_regs *regs)
*/
if (current->thread.per_info.single_step)
set_thread_flag(TIF_SINGLE_STEP);
+
+ /*
+ * Let tracing know that we've done the handler setup.
+ */
+ tracehook_signal_handler(signr, &info, &ka, regs,
+ test_thread_flag(TIF_SINGLE_STEP));
}
return;
}
@@ -526,3 +533,9 @@ void do_signal(struct pt_regs *regs)
set_thread_flag(TIF_RESTART_SVC);
}
}
+
+void do_notify_resume(struct pt_regs *regs)
+{
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index c66d35e5514..3ae303914b4 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -37,7 +37,7 @@ SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall *
SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
NI_SYSCALL /* old fstat syscall */
-SYSCALL(sys_pause,sys_pause,sys32_pause)
+SYSCALL(sys_pause,sys_pause,sys_pause)
SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */
NI_SYSCALL /* old stty syscall */
NI_SYSCALL /* old gtty syscall */
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 06acb1a18bb..b94e9e3b694 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -1356,7 +1356,7 @@ static void __init stp_reset(void)
stp_page = alloc_bootmem_pages(PAGE_SIZE);
rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
- if (rc == 1)
+ if (rc == 0)
set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
else if (stp_online) {
printk(KERN_WARNING "Running on non STP capable machine.\n");
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 0953cee05ef..6ccb9fab055 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -92,3 +92,16 @@ out:
local_irq_restore(flags);
preempt_enable();
}
+
+/*
+ * Simple udelay variant. To be used on startup and reboot
+ * when the interrupt handler isn't working.
+ */
+void udelay_simple(unsigned long usecs)
+{
+ u64 end;
+
+ end = get_clock() + ((u64) usecs << 12);
+ while (get_clock() < end)
+ cpu_relax();
+}
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index f231f5ec74b..580fc64cc73 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -43,20 +43,40 @@
#define DCSS_FINDSEG 0x0c
#define DCSS_LOADNOLY 0x10
#define DCSS_SEGEXT 0x18
+#define DCSS_LOADSHRX 0x20
+#define DCSS_LOADNSRX 0x24
+#define DCSS_FINDSEGX 0x2c
+#define DCSS_SEGEXTX 0x38
#define DCSS_FINDSEGA 0x0c
struct qrange {
- unsigned int start; // 3byte start address, 1 byte type
- unsigned int end; // 3byte end address, 1 byte reserved
+ unsigned long start; /* last byte type */
+ unsigned long end; /* last byte reserved */
};
struct qout64 {
+ unsigned long segstart;
+ unsigned long segend;
+ int segcnt;
+ int segrcnt;
+ struct qrange range[6];
+};
+
+#ifdef CONFIG_64BIT
+struct qrange_old {
+ unsigned int start; /* last byte type */
+ unsigned int end; /* last byte reserved */
+};
+
+/* output area format for the Diag x'64' old subcode x'18' */
+struct qout64_old {
int segstart;
int segend;
int segcnt;
int segrcnt;
- struct qrange range[6];
+ struct qrange_old range[6];
};
+#endif
struct qin64 {
char qopcode;
@@ -86,6 +106,55 @@ static DEFINE_MUTEX(dcss_lock);
static LIST_HEAD(dcss_list);
static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
"EW/EN-MIXED" };
+static int loadshr_scode, loadnsr_scode, findseg_scode;
+static int segext_scode, purgeseg_scode;
+static int scode_set;
+
+/* set correct Diag x'64' subcodes. */
+static int
+dcss_set_subcodes(void)
+{
+#ifdef CONFIG_64BIT
+ char *name = kmalloc(8 * sizeof(char), GFP_DMA);
+ unsigned long rx, ry;
+ int rc;
+
+ if (name == NULL)
+ return -ENOMEM;
+
+ rx = (unsigned long) name;
+ ry = DCSS_FINDSEGX;
+
+ strcpy(name, "dummy");
+ asm volatile(
+ " diag %0,%1,0x64\n"
+ "0: ipm %2\n"
+ " srl %2,28\n"
+ " j 2f\n"
+ "1: la %2,3\n"
+ "2:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+
+ kfree(name);
+ /* Diag x'64' new subcodes are supported, set to new subcodes */
+ if (rc != 3) {
+ loadshr_scode = DCSS_LOADSHRX;
+ loadnsr_scode = DCSS_LOADNSRX;
+ purgeseg_scode = DCSS_PURGESEG;
+ findseg_scode = DCSS_FINDSEGX;
+ segext_scode = DCSS_SEGEXTX;
+ return 0;
+ }
+#endif
+ /* Diag x'64' new subcodes are not supported, set to old subcodes */
+ loadshr_scode = DCSS_LOADNOLY;
+ loadnsr_scode = DCSS_LOADNSR;
+ purgeseg_scode = DCSS_PURGESEG;
+ findseg_scode = DCSS_FINDSEG;
+ segext_scode = DCSS_SEGEXT;
+ return 0;
+}
/*
* Create the 8 bytes, ebcdic VM segment name from
@@ -135,25 +204,45 @@ segment_by_name (char *name)
* Perform a function on a dcss segment.
*/
static inline int
-dcss_diag (__u8 func, void *parameter,
+dcss_diag(int *func, void *parameter,
unsigned long *ret1, unsigned long *ret2)
{
unsigned long rx, ry;
int rc;
+ if (scode_set == 0) {
+ rc = dcss_set_subcodes();
+ if (rc < 0)
+ return rc;
+ scode_set = 1;
+ }
rx = (unsigned long) parameter;
- ry = (unsigned long) func;
- asm volatile(
+ ry = (unsigned long) *func;
+
#ifdef CONFIG_64BIT
- " sam31\n"
- " diag %0,%1,0x64\n"
- " sam64\n"
+ /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */
+ if (*func > DCSS_SEGEXT)
+ asm volatile(
+ " diag %0,%1,0x64\n"
+ " ipm %2\n"
+ " srl %2,28\n"
+ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+ /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */
+ else
+ asm volatile(
+ " sam31\n"
+ " diag %0,%1,0x64\n"
+ " sam64\n"
+ " ipm %2\n"
+ " srl %2,28\n"
+ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
#else
+ asm volatile(
" diag %0,%1,0x64\n"
-#endif
" ipm %2\n"
" srl %2,28\n"
: "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+#endif
*ret1 = rx;
*ret2 = ry;
return rc;
@@ -190,14 +279,45 @@ query_segment_type (struct dcss_segment *seg)
qin->qoutlen = sizeof(struct qout64);
memcpy (qin->qname, seg->dcss_name, 8);
- diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc);
+ diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc);
+ if (diag_cc < 0) {
+ rc = diag_cc;
+ goto out_free;
+ }
if (diag_cc > 1) {
PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc);
rc = dcss_diag_translate_rc (vmrc);
goto out_free;
}
+#ifdef CONFIG_64BIT
+ /* Only old format of output area of Diagnose x'64' is supported,
+ copy data for the new format. */
+ if (segext_scode == DCSS_SEGEXT) {
+ struct qout64_old *qout_old;
+ qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA);
+ if (qout_old == NULL) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+ memcpy(qout_old, qout, sizeof(struct qout64_old));
+ qout->segstart = (unsigned long) qout_old->segstart;
+ qout->segend = (unsigned long) qout_old->segend;
+ qout->segcnt = qout_old->segcnt;
+ qout->segrcnt = qout_old->segrcnt;
+
+ if (qout->segcnt > 6)
+ qout->segrcnt = 6;
+ for (i = 0; i < qout->segrcnt; i++) {
+ qout->range[i].start =
+ (unsigned long) qout_old->range[i].start;
+ qout->range[i].end =
+ (unsigned long) qout_old->range[i].end;
+ }
+ kfree(qout_old);
+ }
+#endif
if (qout->segcnt > 6) {
rc = -ENOTSUPP;
goto out_free;
@@ -269,6 +389,30 @@ segment_type (char* name)
}
/*
+ * check if segment collides with other segments that are currently loaded
+ * returns 1 if this is the case, 0 if no collision was found
+ */
+static int
+segment_overlaps_others (struct dcss_segment *seg)
+{
+ struct list_head *l;
+ struct dcss_segment *tmp;
+
+ BUG_ON(!mutex_is_locked(&dcss_lock));
+ list_for_each(l, &dcss_list) {
+ tmp = list_entry(l, struct dcss_segment, list);
+ if ((tmp->start_addr >> 20) > (seg->end >> 20))
+ continue;
+ if ((tmp->end >> 20) < (seg->start_addr >> 20))
+ continue;
+ if (seg == tmp)
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
+/*
* real segment loading function, called from segment_load
*/
static int
@@ -276,7 +420,8 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
{
struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
GFP_DMA);
- int dcss_command, rc, diag_cc;
+ int rc, diag_cc;
+ unsigned long start_addr, end_addr, dummy;
if (seg == NULL) {
rc = -ENOMEM;
@@ -287,6 +432,13 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
if (rc < 0)
goto out_free;
+ if (loadshr_scode == DCSS_LOADSHRX) {
+ if (segment_overlaps_others(seg)) {
+ rc = -EBUSY;
+ goto out_free;
+ }
+ }
+
rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
if (rc)
@@ -316,20 +468,28 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
}
if (do_nonshared)
- dcss_command = DCSS_LOADNSR;
+ diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
+ &start_addr, &end_addr);
else
- dcss_command = DCSS_LOADNOLY;
-
- diag_cc = dcss_diag(dcss_command, seg->dcss_name,
- &seg->start_addr, &seg->end);
+ diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
+ &start_addr, &end_addr);
+ if (diag_cc < 0) {
+ dcss_diag(&purgeseg_scode, seg->dcss_name,
+ &dummy, &dummy);
+ rc = diag_cc;
+ goto out_resource;
+ }
if (diag_cc > 1) {
PRINT_WARN ("segment_load: could not load segment %s - "
- "diag returned error (%ld)\n",name,seg->end);
- rc = dcss_diag_translate_rc (seg->end);
- dcss_diag(DCSS_PURGESEG, seg->dcss_name,
- &seg->start_addr, &seg->end);
+ "diag returned error (%ld)\n",
+ name, end_addr);
+ rc = dcss_diag_translate_rc(end_addr);
+ dcss_diag(&purgeseg_scode, seg->dcss_name,
+ &dummy, &dummy);
goto out_resource;
}
+ seg->start_addr = start_addr;
+ seg->end = end_addr;
seg->do_nonshared = do_nonshared;
atomic_set(&seg->ref_count, 1);
list_add(&seg->list, &dcss_list);
@@ -423,8 +583,8 @@ int
segment_modify_shared (char *name, int do_nonshared)
{
struct dcss_segment *seg;
- unsigned long dummy;
- int dcss_command, rc, diag_cc;
+ unsigned long start_addr, end_addr, dummy;
+ int rc, diag_cc;
mutex_lock(&dcss_lock);
seg = segment_by_name (name);
@@ -445,38 +605,51 @@ segment_modify_shared (char *name, int do_nonshared)
goto out_unlock;
}
release_resource(seg->res);
- if (do_nonshared) {
- dcss_command = DCSS_LOADNSR;
+ if (do_nonshared)
seg->res->flags &= ~IORESOURCE_READONLY;
- } else {
- dcss_command = DCSS_LOADNOLY;
+ else
if (seg->vm_segtype == SEG_TYPE_SR ||
seg->vm_segtype == SEG_TYPE_ER)
seg->res->flags |= IORESOURCE_READONLY;
- }
+
if (request_resource(&iomem_resource, seg->res)) {
PRINT_WARN("segment_modify_shared: could not reload segment %s"
" - overlapping resources\n", name);
rc = -EBUSY;
kfree(seg->res);
- goto out_del;
+ goto out_del_mem;
+ }
+
+ dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
+ if (do_nonshared)
+ diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
+ &start_addr, &end_addr);
+ else
+ diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
+ &start_addr, &end_addr);
+ if (diag_cc < 0) {
+ rc = diag_cc;
+ goto out_del_res;
}
- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
- diag_cc = dcss_diag(dcss_command, seg->dcss_name,
- &seg->start_addr, &seg->end);
if (diag_cc > 1) {
PRINT_WARN ("segment_modify_shared: could not reload segment %s"
- " - diag returned error (%ld)\n",name,seg->end);
- rc = dcss_diag_translate_rc (seg->end);
- goto out_del;
+ " - diag returned error (%ld)\n",
+ name, end_addr);
+ rc = dcss_diag_translate_rc(end_addr);
+ goto out_del_res;
}
+ seg->start_addr = start_addr;
+ seg->end = end_addr;
seg->do_nonshared = do_nonshared;
rc = 0;
goto out_unlock;
- out_del:
+ out_del_res:
+ release_resource(seg->res);
+ kfree(seg->res);
+ out_del_mem:
vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
kfree(seg);
out_unlock:
mutex_unlock(&dcss_lock);
@@ -510,7 +683,7 @@ segment_unload(char *name)
kfree(seg->res);
vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
kfree(seg);
out_unlock:
mutex_unlock(&dcss_lock);
@@ -545,7 +718,7 @@ segment_save(char *name)
endpfn = (seg->end) >> PAGE_SHIFT;
sprintf(cmd1, "DEFSEG %s", name);
for (i=0; i<seg->segcnt; i++) {
- sprintf(cmd1+strlen(cmd1), " %X-%X %s",
+ sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
seg->range[i].start >> PAGE_SHIFT,
seg->range[i].end >> PAGE_SHIFT,
segtype_string[seg->range[i].start & 0xff]);
diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
index 1b238ebae6b..70dabd1e065 100644
--- a/arch/um/Kconfig.char
+++ b/arch/um/Kconfig.char
@@ -203,6 +203,10 @@ config SOUND
tristate
default UML_SOUND
+config SOUND_OSS_CORE
+ bool
+ default UML_SOUND
+
config HOSTAUDIO
tristate
default UML_SOUND
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index dd097b83583..c24c4a487b7 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -256,7 +256,8 @@ static u32 get_cur_val(const cpumask_t *mask)
* Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
* no meaning should be associated with absolute values of these MSRs.
*/
-static unsigned int get_measured_perf(unsigned int cpu)
+static unsigned int get_measured_perf(struct cpufreq_policy *policy,
+ unsigned int cpu)
{
union {
struct {
@@ -326,7 +327,7 @@ static unsigned int get_measured_perf(unsigned int cpu)
#endif
- retval = per_cpu(drv_data, cpu)->max_freq * perf_percent / 100;
+ retval = per_cpu(drv_data, policy->cpu)->max_freq * perf_percent / 100;
put_cpu();
set_cpus_allowed_ptr(current, &saved_mask);
@@ -785,7 +786,11 @@ static int __init acpi_cpufreq_init(void)
if (ret)
return ret;
- return cpufreq_register_driver(&acpi_cpufreq_driver);
+ ret = cpufreq_register_driver(&acpi_cpufreq_driver);
+ if (ret)
+ free_percpu(acpi_perf_data);
+
+ return ret;
}
static void __exit acpi_cpufreq_exit(void)
@@ -795,8 +800,6 @@ static void __exit acpi_cpufreq_exit(void)
cpufreq_unregister_driver(&acpi_cpufreq_driver);
free_percpu(acpi_perf_data);
-
- return;
}
module_param(acpi_pstate_strict, uint, 0644);
diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
index e4a4bf870e9..fe613c93b36 100644
--- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
@@ -25,8 +25,8 @@
#include <linux/cpufreq.h>
#include <asm/msr.h>
-#include <asm/timex.h>
-#include <asm/io.h>
+#include <linux/timex.h>
+#include <linux/io.h>
#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */
#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */
@@ -82,7 +82,7 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
u8 clockspeed_reg; /* Clock Speed Register */
local_irq_disable();
- outb_p(0x80,REG_CSCIR);
+ outb_p(0x80, REG_CSCIR);
clockspeed_reg = inb_p(REG_CSCDR);
local_irq_enable();
@@ -98,10 +98,10 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
}
/* 33 MHz is not 32 MHz... */
- if ((clockspeed_reg & 0xE0)==0xA0)
+ if ((clockspeed_reg & 0xE0) == 0xA0)
return 33000;
- return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000);
+ return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000;
}
@@ -117,7 +117,7 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
* There is no return value.
*/
-static void elanfreq_set_cpu_state (unsigned int state)
+static void elanfreq_set_cpu_state(unsigned int state)
{
struct cpufreq_freqs freqs;
@@ -144,20 +144,20 @@ static void elanfreq_set_cpu_state (unsigned int state)
*/
local_irq_disable();
- outb_p(0x40,REG_CSCIR); /* Disable hyperspeed mode */
- outb_p(0x00,REG_CSCDR);
+ outb_p(0x40, REG_CSCIR); /* Disable hyperspeed mode */
+ outb_p(0x00, REG_CSCDR);
local_irq_enable(); /* wait till internal pipelines and */
udelay(1000); /* buffers have cleaned up */
local_irq_disable();
/* now, set the CPU clock speed register (0x80) */
- outb_p(0x80,REG_CSCIR);
- outb_p(elan_multiplier[state].val80h,REG_CSCDR);
+ outb_p(0x80, REG_CSCIR);
+ outb_p(elan_multiplier[state].val80h, REG_CSCDR);
/* now, the hyperspeed bit in PMU Force Mode Register (0x40) */
- outb_p(0x40,REG_CSCIR);
- outb_p(elan_multiplier[state].val40h,REG_CSCDR);
+ outb_p(0x40, REG_CSCIR);
+ outb_p(elan_multiplier[state].val40h, REG_CSCDR);
udelay(10000);
local_irq_enable();
@@ -173,12 +173,12 @@ static void elanfreq_set_cpu_state (unsigned int state)
* for the hardware supported by the driver.
*/
-static int elanfreq_verify (struct cpufreq_policy *policy)
+static int elanfreq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]);
}
-static int elanfreq_target (struct cpufreq_policy *policy,
+static int elanfreq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
@@ -205,7 +205,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
- (c->x86 != 4) || (c->x86_model!=10))
+ (c->x86 != 4) || (c->x86_model != 10))
return -ENODEV;
/* max freq */
@@ -213,7 +213,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
max_freq = elanfreq_get_cpu_frequency(0);
/* table init */
- for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
+ for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
@@ -224,7 +224,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table);
if (result)
- return (result);
+ return result;
cpufreq_frequency_table_get_attr(elanfreq_table, policy->cpu);
return 0;
@@ -260,7 +260,7 @@ __setup("elanfreq=", elanfreq_setup);
#endif
-static struct freq_attr* elanfreq_attr[] = {
+static struct freq_attr *elanfreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
@@ -284,9 +284,9 @@ static int __init elanfreq_init(void)
/* Test if we have the right hardware */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
- (c->x86 != 4) || (c->x86_model!=10)) {
+ (c->x86 != 4) || (c->x86_model != 10)) {
printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
- return -ENODEV;
+ return -ENODEV;
}
return cpufreq_register_driver(&elanfreq_driver);
}
@@ -298,7 +298,7 @@ static void __exit elanfreq_exit(void)
}
-module_param (max_freq, int, 0444);
+module_param(max_freq, int, 0444);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
index eb9b62b0830..b5ced806a31 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
@@ -15,12 +15,11 @@
#include <linux/slab.h>
#include <asm/msr.h>
-#include <asm/timex.h>
-#include <asm/io.h>
+#include <linux/timex.h>
+#include <linux/io.h>
-
-#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
- as it is unused */
+#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
+ as it is unused */
static unsigned int busfreq; /* FSB, in 10 kHz */
static unsigned int max_multiplier;
@@ -53,7 +52,7 @@ static int powernow_k6_get_cpu_multiplier(void)
msrval = POWERNOW_IOPORT + 0x1;
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
- invalue=inl(POWERNOW_IOPORT + 0x8);
+ invalue = inl(POWERNOW_IOPORT + 0x8);
msrval = POWERNOW_IOPORT + 0x0;
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
@@ -67,9 +66,9 @@ static int powernow_k6_get_cpu_multiplier(void)
*
* Tries to change the PowerNow! multiplier
*/
-static void powernow_k6_set_state (unsigned int best_i)
+static void powernow_k6_set_state(unsigned int best_i)
{
- unsigned long outvalue=0, invalue=0;
+ unsigned long outvalue = 0, invalue = 0;
unsigned long msrval;
struct cpufreq_freqs freqs;
@@ -90,10 +89,10 @@ static void powernow_k6_set_state (unsigned int best_i)
msrval = POWERNOW_IOPORT + 0x1;
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
- invalue=inl(POWERNOW_IOPORT + 0x8);
+ invalue = inl(POWERNOW_IOPORT + 0x8);
invalue = invalue & 0xf;
outvalue = outvalue | invalue;
- outl(outvalue ,(POWERNOW_IOPORT + 0x8));
+ outl(outvalue , (POWERNOW_IOPORT + 0x8));
msrval = POWERNOW_IOPORT + 0x0;
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
@@ -124,7 +123,7 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
*
* sets a new CPUFreq policy
*/
-static int powernow_k6_target (struct cpufreq_policy *policy,
+static int powernow_k6_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
@@ -152,7 +151,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
busfreq = cpu_khz / max_multiplier;
/* table init */
- for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
+ for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
if (clock_ratio[i].index > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
else
@@ -165,7 +164,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
if (result)
- return (result);
+ return result;
cpufreq_frequency_table_get_attr(clock_ratio, policy->cpu);
@@ -176,8 +175,8 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
{
unsigned int i;
- for (i=0; i<8; i++) {
- if (i==max_multiplier)
+ for (i = 0; i < 8; i++) {
+ if (i == max_multiplier)
powernow_k6_set_state(i);
}
cpufreq_frequency_table_put_attr(policy->cpu);
@@ -189,7 +188,7 @@ static unsigned int powernow_k6_get(unsigned int cpu)
return busfreq * powernow_k6_get_cpu_multiplier();
}
-static struct freq_attr* powernow_k6_attr[] = {
+static struct freq_attr *powernow_k6_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
@@ -227,7 +226,7 @@ static int __init powernow_k6_init(void)
}
if (cpufreq_register_driver(&powernow_k6_driver)) {
- release_region (POWERNOW_IOPORT, 16);
+ release_region(POWERNOW_IOPORT, 16);
return -EINVAL;
}
@@ -243,13 +242,13 @@ static int __init powernow_k6_init(void)
static void __exit powernow_k6_exit(void)
{
cpufreq_unregister_driver(&powernow_k6_driver);
- release_region (POWERNOW_IOPORT, 16);
+ release_region(POWERNOW_IOPORT, 16);
}
-MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
+MODULE_LICENSE("GPL");
module_init(powernow_k6_init);
module_exit(powernow_k6_exit);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8a67f16987d..31d6f535a79 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1467,25 +1467,27 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- int ret;
+ int ret = -EINVAL;
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
- return -EINVAL;
+ goto no_policy;
if (unlikely(lock_policy_rwsem_write(policy->cpu)))
- return -EINVAL;
+ goto fail;
ret = __cpufreq_driver_target(policy, target_freq, relation);
unlock_policy_rwsem_write(policy->cpu);
+fail:
cpufreq_cpu_put(policy);
+no_policy:
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
-int __cpufreq_driver_getavg(struct cpufreq_policy *policy)
+int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
{
int ret = 0;
@@ -1493,8 +1495,8 @@ int __cpufreq_driver_getavg(struct cpufreq_policy *policy)
if (!policy)
return -EINVAL;
- if (cpu_online(policy->cpu) && cpufreq_driver->getavg)
- ret = cpufreq_driver->getavg(policy->cpu);
+ if (cpu_online(cpu) && cpufreq_driver->getavg)
+ ret = cpufreq_driver->getavg(policy, cpu);
cpufreq_cpu_put(policy);
return ret;
@@ -1717,13 +1719,17 @@ int cpufreq_update_policy(unsigned int cpu)
{
struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
struct cpufreq_policy policy;
- int ret = 0;
+ int ret;
- if (!data)
- return -ENODEV;
+ if (!data) {
+ ret = -ENODEV;
+ goto no_policy;
+ }
- if (unlikely(lock_policy_rwsem_write(cpu)))
- return -EINVAL;
+ if (unlikely(lock_policy_rwsem_write(cpu))) {
+ ret = -EINVAL;
+ goto fail;
+ }
dprintk("updating policy for CPU %u\n", cpu);
memcpy(&policy, data, sizeof(struct cpufreq_policy));
@@ -1750,7 +1756,9 @@ int cpufreq_update_policy(unsigned int cpu)
unlock_policy_rwsem_write(cpu);
+fail:
cpufreq_cpu_put(data);
+no_policy:
return ret;
}
EXPORT_SYMBOL(cpufreq_update_policy);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index ac0bbf2d234..e2657837d95 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -460,6 +460,7 @@ static void do_dbs_timer(struct work_struct *work)
static inline void dbs_timer_init(void)
{
+ init_timer_deferrable(&dbs_work.timer);
schedule_delayed_work(&dbs_work,
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
return;
@@ -575,13 +576,15 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+static
+#endif
struct cpufreq_governor cpufreq_gov_conservative = {
.name = "conservative",
.governor = cpufreq_governor_dbs,
.max_transition_latency = TRANSITION_LATENCY_LIMIT,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_conservative);
static int __init cpufreq_gov_dbs_init(void)
{
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 33855cb3cf1..2ab3c12b88a 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -18,13 +18,19 @@
#include <linux/jiffies.h>
#include <linux/kernel_stat.h>
#include <linux/mutex.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/ktime.h>
/*
* dbs is used in this file as a shortform for demandbased switching
* It helps to keep variable names smaller, simpler
*/
+#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10)
#define DEF_FREQUENCY_UP_THRESHOLD (80)
+#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3)
+#define MICRO_FREQUENCY_UP_THRESHOLD (95)
#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
@@ -57,6 +63,7 @@ enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
struct cpu_dbs_info_s {
cputime64_t prev_cpu_idle;
cputime64_t prev_cpu_wall;
+ cputime64_t prev_cpu_nice;
struct cpufreq_policy *cur_policy;
struct delayed_work work;
struct cpufreq_frequency_table *freq_table;
@@ -86,21 +93,24 @@ static struct workqueue_struct *kondemand_wq;
static struct dbs_tuners {
unsigned int sampling_rate;
unsigned int up_threshold;
+ unsigned int down_differential;
unsigned int ignore_nice;
unsigned int powersave_bias;
} dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+ .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
.ignore_nice = 0,
.powersave_bias = 0,
};
-static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
+static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
+ cputime64_t *wall)
{
cputime64_t idle_time;
- cputime64_t cur_jiffies;
+ cputime64_t cur_wall_time;
cputime64_t busy_time;
- cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
+ cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
kstat_cpu(cpu).cpustat.system);
@@ -113,7 +123,37 @@ static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
kstat_cpu(cpu).cpustat.nice);
}
- idle_time = cputime64_sub(cur_jiffies, busy_time);
+ idle_time = cputime64_sub(cur_wall_time, busy_time);
+ if (wall)
+ *wall = cur_wall_time;
+
+ return idle_time;
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
+{
+ u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+
+ if (idle_time == -1ULL)
+ return get_cpu_idle_time_jiffy(cpu, wall);
+
+ if (dbs_tuners_ins.ignore_nice) {
+ cputime64_t cur_nice;
+ unsigned long cur_nice_jiffies;
+ struct cpu_dbs_info_s *dbs_info;
+
+ dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ cur_nice = cputime64_sub(kstat_cpu(cpu).cpustat.nice,
+ dbs_info->prev_cpu_nice);
+ /*
+ * Assumption: nice time between sampling periods will be
+ * less than 2^32 jiffies for 32 bit sys
+ */
+ cur_nice_jiffies = (unsigned long)
+ cputime64_to_jiffies64(cur_nice);
+ dbs_info->prev_cpu_nice = kstat_cpu(cpu).cpustat.nice;
+ return idle_time + jiffies_to_usecs(cur_nice_jiffies);
+ }
return idle_time;
}
@@ -277,8 +317,8 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
for_each_online_cpu(j) {
struct cpu_dbs_info_s *dbs_info;
dbs_info = &per_cpu(cpu_dbs_info, j);
- dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
- dbs_info->prev_cpu_wall = get_jiffies_64();
+ dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+ &dbs_info->prev_cpu_wall);
}
mutex_unlock(&dbs_mutex);
@@ -334,9 +374,7 @@ static struct attribute_group dbs_attr_group = {
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
{
- unsigned int idle_ticks, total_ticks;
- unsigned int load = 0;
- cputime64_t cur_jiffies;
+ unsigned int max_load_freq;
struct cpufreq_policy *policy;
unsigned int j;
@@ -346,13 +384,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
this_dbs_info->freq_lo = 0;
policy = this_dbs_info->cur_policy;
- cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
- total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
- this_dbs_info->prev_cpu_wall);
- this_dbs_info->prev_cpu_wall = get_jiffies_64();
- if (!total_ticks)
- return;
/*
* Every sampling_rate, we check, if current idle time is less
* than 20% (default), then we try to increase frequency
@@ -365,27 +397,44 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
* 5% (default) of current frequency
*/
- /* Get Idle Time */
- idle_ticks = UINT_MAX;
+ /* Get Absolute Load - in terms of freq */
+ max_load_freq = 0;
+
for_each_cpu_mask_nr(j, policy->cpus) {
- cputime64_t total_idle_ticks;
- unsigned int tmp_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
+ cputime64_t cur_wall_time, cur_idle_time;
+ unsigned int idle_time, wall_time;
+ unsigned int load, load_freq;
+ int freq_avg;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
- total_idle_ticks = get_cpu_idle_time(j);
- tmp_idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks,
+
+ cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+
+ wall_time = (unsigned int) cputime64_sub(cur_wall_time,
+ j_dbs_info->prev_cpu_wall);
+ j_dbs_info->prev_cpu_wall = cur_wall_time;
+
+ idle_time = (unsigned int) cputime64_sub(cur_idle_time,
j_dbs_info->prev_cpu_idle);
- j_dbs_info->prev_cpu_idle = total_idle_ticks;
+ j_dbs_info->prev_cpu_idle = cur_idle_time;
+
+ if (unlikely(!wall_time || wall_time < idle_time))
+ continue;
+
+ load = 100 * (wall_time - idle_time) / wall_time;
+
+ freq_avg = __cpufreq_driver_getavg(policy, j);
+ if (freq_avg <= 0)
+ freq_avg = policy->cur;
- if (tmp_idle_ticks < idle_ticks)
- idle_ticks = tmp_idle_ticks;
+ load_freq = load * freq_avg;
+ if (load_freq > max_load_freq)
+ max_load_freq = load_freq;
}
- if (likely(total_ticks > idle_ticks))
- load = (100 * (total_ticks - idle_ticks)) / total_ticks;
/* Check for frequency increase */
- if (load > dbs_tuners_ins.up_threshold) {
+ if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
/* if we are already at full speed then break out early */
if (!dbs_tuners_ins.powersave_bias) {
if (policy->cur == policy->max)
@@ -412,15 +461,13 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
* can support the current CPU usage without triggering the up
* policy. To be safe, we focus 10 points under the threshold.
*/
- if (load < (dbs_tuners_ins.up_threshold - 10)) {
- unsigned int freq_next, freq_cur;
-
- freq_cur = __cpufreq_driver_getavg(policy);
- if (!freq_cur)
- freq_cur = policy->cur;
-
- freq_next = (freq_cur * load) /
- (dbs_tuners_ins.up_threshold - 10);
+ if (max_load_freq <
+ (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) *
+ policy->cur) {
+ unsigned int freq_next;
+ freq_next = max_load_freq /
+ (dbs_tuners_ins.up_threshold -
+ dbs_tuners_ins.down_differential);
if (!dbs_tuners_ins.powersave_bias) {
__cpufreq_driver_target(policy, freq_next,
@@ -526,8 +573,8 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
- j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
- j_dbs_info->prev_cpu_wall = get_jiffies_64();
+ j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+ &j_dbs_info->prev_cpu_wall);
}
this_dbs_info->cpu = cpu;
/*
@@ -579,22 +626,42 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+static
+#endif
struct cpufreq_governor cpufreq_gov_ondemand = {
.name = "ondemand",
.governor = cpufreq_governor_dbs,
.max_transition_latency = TRANSITION_LATENCY_LIMIT,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_ondemand);
static int __init cpufreq_gov_dbs_init(void)
{
+ int err;
+ cputime64_t wall;
+ u64 idle_time;
+ int cpu = get_cpu();
+
+ idle_time = get_cpu_idle_time_us(cpu, &wall);
+ put_cpu();
+ if (idle_time != -1ULL) {
+ /* Idle micro accounting is supported. Use finer thresholds */
+ dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
+ dbs_tuners_ins.down_differential =
+ MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
+ }
+
kondemand_wq = create_workqueue("kondemand");
if (!kondemand_wq) {
printk(KERN_ERR "Creation of kondemand failed\n");
return -EFAULT;
}
- return cpufreq_register_governor(&cpufreq_gov_ondemand);
+ err = cpufreq_register_governor(&cpufreq_gov_ondemand);
+ if (err)
+ destroy_workqueue(kondemand_wq);
+
+ return err;
}
static void __exit cpufreq_gov_dbs_exit(void)
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index e8e1451ef1c..7e2e515087f 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -36,12 +36,14 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy,
return 0;
}
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE_MODULE
+static
+#endif
struct cpufreq_governor cpufreq_gov_performance = {
.name = "performance",
.governor = cpufreq_governor_performance,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_performance);
static int __init cpufreq_gov_performance_init(void)
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 88d2f44fba4..e6db5faf3eb 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -35,12 +35,14 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
return 0;
}
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE
+static
+#endif
struct cpufreq_governor cpufreq_gov_powersave = {
.name = "powersave",
.governor = cpufreq_governor_powersave,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_powersave);
static int __init cpufreq_gov_powersave_init(void)
{
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 32244aa7cc0..1442bbada05 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -187,6 +187,9 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
}
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
+static
+#endif
struct cpufreq_governor cpufreq_gov_userspace = {
.name = "userspace",
.governor = cpufreq_governor_userspace,
@@ -194,7 +197,6 @@ struct cpufreq_governor cpufreq_gov_userspace = {
.show_setspeed = show_speed,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_userspace);
static int __init cpufreq_gov_userspace_init(void)
{
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 9929d20320b..26194a0ce92 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -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++) {
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index acb78017e7d..0a225ccda02 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -215,7 +215,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
return rc;
}
/* register 'device' debug area, used for all DBF_DEV_XXX calls */
- device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
+ device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1,
8 * sizeof(long));
debug_register_view(device->debug_area, &debug_sprintf_view);
debug_set_level(device->debug_area, DBF_WARNING);
@@ -933,7 +933,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
MESSAGE(KERN_DEBUG,
"invalid status in handle_killed_request: "
"bus_id %s, status %02x",
- cdev->dev.bus_id, cqr->status);
+ dev_name(&cdev->dev), cqr->status);
return;
}
@@ -942,7 +942,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
device != dasd_device_from_cdev_locked(cdev) ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
return;
}
@@ -982,11 +982,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
break;
case -ETIMEDOUT:
printk(KERN_WARNING"%s(%s): request timed out\n",
- __func__, cdev->dev.bus_id);
+ __func__, dev_name(&cdev->dev));
break;
default:
printk(KERN_WARNING"%s(%s): unknown error %ld\n",
- __func__, cdev->dev.bus_id, PTR_ERR(irb));
+ __func__, dev_name(&cdev->dev), PTR_ERR(irb));
}
dasd_handle_killed_request(cdev, intparm);
return;
@@ -995,7 +995,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
now = get_clock();
DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x",
- cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) |
+ dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) |
irb->scsw.cmd.dstat), (unsigned int) intparm);
/* check for unsolicited interrupts */
@@ -1019,7 +1019,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
if (!device ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
return;
}
@@ -1037,7 +1037,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
if (cqr->status != DASD_CQR_IN_IO) {
MESSAGE(KERN_DEBUG,
"invalid status: bus_id %s, status %02x",
- cdev->dev.bus_id, cqr->status);
+ dev_name(&cdev->dev), cqr->status);
return;
}
DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
@@ -2134,14 +2134,14 @@ int dasd_generic_probe(struct ccw_device *cdev,
if (ret) {
printk(KERN_WARNING
"dasd_generic_probe: could not set ccw-device options "
- "for %s\n", cdev->dev.bus_id);
+ "for %s\n", dev_name(&cdev->dev));
return ret;
}
ret = dasd_add_sysfs_files(cdev);
if (ret) {
printk(KERN_WARNING
"dasd_generic_probe: could not add sysfs entries "
- "for %s\n", cdev->dev.bus_id);
+ "for %s\n", dev_name(&cdev->dev));
return ret;
}
cdev->handler = &dasd_int_handler;
@@ -2152,13 +2152,13 @@ int dasd_generic_probe(struct ccw_device *cdev,
* initial probe.
*/
if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
- (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
+ (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0))
ret = ccw_device_set_online(cdev);
if (ret)
printk(KERN_WARNING
"dasd_generic_probe: could not initially "
"online ccw-device %s; return code: %d\n",
- cdev->dev.bus_id, ret);
+ dev_name(&cdev->dev), ret);
return 0;
}
@@ -2224,7 +2224,7 @@ int dasd_generic_set_online(struct ccw_device *cdev,
printk (KERN_WARNING
"dasd_generic couldn't online device %s "
"- discipline DIAG not available\n",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
dasd_delete_device(device);
return -ENODEV;
}
@@ -2248,7 +2248,7 @@ int dasd_generic_set_online(struct ccw_device *cdev,
printk (KERN_WARNING
"dasd_generic couldn't online device %s "
"with discipline %s rc=%i\n",
- cdev->dev.bus_id, discipline->name, rc);
+ dev_name(&cdev->dev), discipline->name, rc);
module_put(discipline->owner);
module_put(base_discipline->owner);
dasd_delete_device(device);
@@ -2259,7 +2259,7 @@ int dasd_generic_set_online(struct ccw_device *cdev,
if (device->state <= DASD_STATE_KNOWN) {
printk (KERN_WARNING
"dasd_generic discipline not found for %s\n",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
rc = -ENODEV;
dasd_set_target_state(device, DASD_STATE_NEW);
if (device->block)
@@ -2267,7 +2267,7 @@ int dasd_generic_set_online(struct ccw_device *cdev,
dasd_delete_device(device);
} else
pr_debug("dasd_generic device %s found\n",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
/* FIXME: we have to wait for the root device but we don't want
* to wait for each single device but for all at once. */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 5c6e6f331cb..b8f9c00633f 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1397,7 +1397,7 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
DEV_MESSAGE(KERN_ERR, cqr->startdev,
"ERP on alias device for request %p,"
" recover on base device %s", cqr,
- cqr->block->base->cdev->dev.bus_id);
+ dev_name(&cqr->block->base->cdev->dev));
}
dasd_eckd_reset_ccw_to_base_io(cqr);
erp->startdev = cqr->block->base;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index cd3335c1c30..921443b01d1 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -515,9 +515,9 @@ dasd_devmap_from_cdev(struct ccw_device *cdev)
{
struct dasd_devmap *devmap;
- devmap = dasd_find_busid(cdev->dev.bus_id);
+ devmap = dasd_find_busid(dev_name(&cdev->dev));
if (IS_ERR(devmap))
- devmap = dasd_add_busid(cdev->dev.bus_id,
+ devmap = dasd_add_busid(dev_name(&cdev->dev),
DASD_FEATURE_DEFAULT);
return devmap;
}
@@ -584,7 +584,7 @@ dasd_delete_device(struct dasd_device *device)
unsigned long flags;
/* First remove device pointer from devmap. */
- devmap = dasd_find_busid(device->cdev->dev.bus_id);
+ devmap = dasd_find_busid(dev_name(&device->cdev->dev));
BUG_ON(IS_ERR(devmap));
spin_lock(&dasd_devmap_lock);
if (devmap->device != device) {
@@ -674,7 +674,7 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
struct dasd_devmap *devmap;
int ro_flag;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
if (!IS_ERR(devmap))
ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
else
@@ -723,7 +723,7 @@ dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf)
struct dasd_devmap *devmap;
int erplog;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
if (!IS_ERR(devmap))
erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0;
else
@@ -770,7 +770,7 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
struct dasd_devmap *devmap;
int use_diag;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
if (!IS_ERR(devmap))
use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
else
@@ -876,7 +876,7 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
struct dasd_devmap *devmap;
int alias;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
spin_lock(&dasd_devmap_lock);
if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
spin_unlock(&dasd_devmap_lock);
@@ -899,7 +899,7 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
struct dasd_devmap *devmap;
char *vendor;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
spin_lock(&dasd_devmap_lock);
if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
vendor = devmap->uid.vendor;
@@ -924,7 +924,7 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
char ua_string[3];
struct dasd_uid *uid;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
spin_lock(&dasd_devmap_lock);
if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
spin_unlock(&dasd_devmap_lock);
@@ -972,7 +972,7 @@ dasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf)
struct dasd_devmap *devmap;
int eer_flag;
- devmap = dasd_find_busid(dev->bus_id);
+ devmap = dasd_find_busid(dev_name(dev));
if (!IS_ERR(devmap) && devmap->device)
eer_flag = dasd_eer_enabled(devmap->device);
else
@@ -1034,7 +1034,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
{
struct dasd_devmap *devmap;
- devmap = dasd_find_busid(cdev->dev.bus_id);
+ devmap = dasd_find_busid(dev_name(&cdev->dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
spin_lock(&dasd_devmap_lock);
@@ -1057,7 +1057,7 @@ dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
{
struct dasd_devmap *devmap;
- devmap = dasd_find_busid(cdev->dev.bus_id);
+ devmap = dasd_find_busid(dev_name(&cdev->dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
@@ -1077,7 +1077,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature)
{
struct dasd_devmap *devmap;
- devmap = dasd_find_busid(cdev->dev.bus_id);
+ devmap = dasd_find_busid(dev_name(&cdev->dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
@@ -1093,7 +1093,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
{
struct dasd_devmap *devmap;
- devmap = dasd_find_busid(cdev->dev.bus_id);
+ devmap = dasd_find_busid(dev_name(&cdev->dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 773b3fe275b..49f9d221e23 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6,6 +6,8 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
*
*/
@@ -84,7 +86,7 @@ dasd_eckd_probe (struct ccw_device *cdev)
if (ret) {
printk(KERN_WARNING
"dasd_eckd_probe: could not set ccw-device options "
- "for %s\n", cdev->dev.bus_id);
+ "for %s\n", dev_name(&cdev->dev));
return ret;
}
ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
@@ -1501,12 +1503,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
return;
}
- /* just report other unsolicited interrupts */
- DEV_MESSAGE(KERN_DEBUG, device, "%s",
- "unsolicited interrupt received");
- device->discipline->dump_sense(device, NULL, irb);
- dasd_schedule_device_bh(device);
+ if ((irb->scsw.cmd.cc == 1) &&
+ (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
+ (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) &&
+ (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) {
+ /* fake irb do nothing, they are handled elsewhere */
+ dasd_schedule_device_bh(device);
+ return;
+ }
+
+ if (!(irb->esw.esw0.erw.cons)) {
+ /* just report other unsolicited interrupts */
+ DEV_MESSAGE(KERN_ERR, device, "%s",
+ "unsolicited interrupt received");
+ } else {
+ DEV_MESSAGE(KERN_ERR, device, "%s",
+ "unsolicited interrupt received "
+ "(sense available)");
+ device->discipline->dump_sense(device, NULL, irb);
+ }
+ dasd_schedule_device_bh(device);
return;
};
@@ -2068,6 +2085,103 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
return 0;
}
+/*
+ * Issue syscall I/O to EMC Symmetrix array.
+ * CCWs are PSF and RSSD
+ */
+static int dasd_symm_io(struct dasd_device *device, void __user *argp)
+{
+ struct dasd_symmio_parms usrparm;
+ char *psf_data, *rssd_result;
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+ int rc;
+
+ /* Copy parms from caller */
+ rc = -EFAULT;
+ if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
+ goto out;
+#ifndef CONFIG_64BIT
+ /* Make sure pointers are sane even on 31 bit. */
+ if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+#endif
+ /* alloc I/O data area */
+ psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA);
+ rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA);
+ if (!psf_data || !rssd_result) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+
+ /* get syscall header from user space */
+ rc = -EFAULT;
+ if (copy_from_user(psf_data,
+ (void __user *)(unsigned long) usrparm.psf_data,
+ usrparm.psf_data_len))
+ goto out_free;
+
+ /* sanity check on syscall header */
+ if (psf_data[0] != 0x17 && psf_data[1] != 0xce) {
+ rc = -EINVAL;
+ goto out_free;
+ }
+
+ /* setup CCWs for PSF + RSSD */
+ cqr = dasd_smalloc_request("ECKD", 2 , 0, device);
+ if (IS_ERR(cqr)) {
+ DEV_MESSAGE(KERN_WARNING, device, "%s",
+ "Could not allocate initialization request");
+ rc = PTR_ERR(cqr);
+ goto out_free;
+ }
+
+ cqr->startdev = device;
+ cqr->memdev = device;
+ cqr->retries = 3;
+ cqr->expires = 10 * HZ;
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+
+ /* Build the ccws */
+ ccw = cqr->cpaddr;
+
+ /* PSF ccw */
+ ccw->cmd_code = DASD_ECKD_CCW_PSF;
+ ccw->count = usrparm.psf_data_len;
+ ccw->flags |= CCW_FLAG_CC;
+ ccw->cda = (__u32)(addr_t) psf_data;
+
+ ccw++;
+
+ /* RSSD ccw */
+ ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+ ccw->count = usrparm.rssd_result_len;
+ ccw->flags = CCW_FLAG_SLI ;
+ ccw->cda = (__u32)(addr_t) rssd_result;
+
+ rc = dasd_sleep_on(cqr);
+ if (rc)
+ goto out_sfree;
+
+ rc = -EFAULT;
+ if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result,
+ rssd_result, usrparm.rssd_result_len))
+ goto out_sfree;
+ rc = 0;
+
+out_sfree:
+ dasd_sfree_request(cqr, cqr->memdev);
+out_free:
+ kfree(rssd_result);
+ kfree(psf_data);
+out:
+ DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc);
+ return rc;
+}
+
static int
dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
{
@@ -2086,6 +2200,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
return dasd_eckd_reserve(device);
case BIODASDSLCK:
return dasd_eckd_steal_lock(device);
+ case BIODASDSYMMIO:
+ return dasd_symm_io(device, argp);
default:
return -ENOIOCTLCMD;
}
@@ -2145,13 +2261,13 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
/* dump the sense data */
len = sprintf(page, KERN_ERR PRINTK_HEADER
" I/O status report for device %s:\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" in req: %p CS: 0x%02X DS: 0x%02X\n", req,
irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" device %s: Failing CCW: %p\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
(void *) (addr_t) irb->scsw.cmd.cpa);
if (irb->esw.esw0.erw.cons) {
for (sl = 0; sl < 4; sl++) {
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index bf512ac75b9..892e2878d61 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -309,7 +309,8 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,
do_gettimeofday(&tv);
header.tv_sec = tv.tv_sec;
header.tv_usec = tv.tv_usec;
- strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+ strncpy(header.busid, dev_name(&device->cdev->dev),
+ DASD_EER_BUSID_SIZE);
spin_lock_irqsave(&bufferlock, flags);
list_for_each_entry(eerb, &bufferlist, list) {
@@ -349,7 +350,8 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
do_gettimeofday(&tv);
header.tv_sec = tv.tv_sec;
header.tv_usec = tv.tv_usec;
- strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+ strncpy(header.busid, dev_name(&device->cdev->dev),
+ DASD_EER_BUSID_SIZE);
spin_lock_irqsave(&bufferlock, flags);
list_for_each_entry(eerb, &bufferlist, list) {
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index aa0c533423a..93d9b6452a9 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -451,13 +451,13 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
}
len = sprintf(page, KERN_ERR PRINTK_HEADER
" I/O status report for device %s:\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" in req: %p CS: 0x%02X DS: 0x%02X\n", req,
irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" device %s: Failing CCW: %p\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
(void *) (addr_t) irb->scsw.cmd.cpa);
if (irb->esw.esw0.erw.cons) {
for (sl = 0; sl < 4; sl++) {
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 31ecaa4a40e..489d5fe488f 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -126,7 +126,7 @@ do { \
#define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
do { \
printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \
- d_device->cdev->dev.bus_id, d_args); \
+ dev_name(&d_device->cdev->dev), d_args); \
DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \
} while(0)
@@ -140,7 +140,7 @@ do { \
#define DEV_MESSAGE_LOG(d_loglevel,d_device,d_string,d_args...)\
do { \
printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \
- d_device->cdev->dev.bus_id, d_args); \
+ dev_name(&d_device->cdev->dev), d_args); \
} while(0)
#define MESSAGE_LOG(d_loglevel,d_string,d_args...)\
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index e3b5c4d3036..9088de84b45 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -67,7 +67,7 @@ dasd_devices_show(struct seq_file *m, void *v)
return 0;
}
/* Print device number. */
- seq_printf(m, "%s", device->cdev->dev.bus_id);
+ seq_printf(m, "%s", dev_name(&device->cdev->dev));
/* Print discipline string. */
if (device != NULL && device->discipline != NULL)
seq_printf(m, "(%s)", device->discipline->name);
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 9481e4a3f76..a7ff167d5b8 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -31,7 +31,6 @@
#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x)
#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x)
-
static int dcssblk_open(struct inode *inode, struct file *filp);
static int dcssblk_release(struct inode *inode, struct file *filp);
static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
@@ -48,6 +47,30 @@ static struct block_device_operations dcssblk_devops = {
.direct_access = dcssblk_direct_access,
};
+struct dcssblk_dev_info {
+ struct list_head lh;
+ struct device dev;
+ char segment_name[BUS_ID_SIZE];
+ atomic_t use_count;
+ struct gendisk *gd;
+ unsigned long start;
+ unsigned long end;
+ int segment_type;
+ unsigned char save_pending;
+ unsigned char is_shared;
+ struct request_queue *dcssblk_queue;
+ int num_of_segments;
+ struct list_head seg_list;
+};
+
+struct segment_info {
+ struct list_head lh;
+ char segment_name[BUS_ID_SIZE];
+ unsigned long start;
+ unsigned long end;
+ int segment_type;
+};
+
static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
size_t count);
static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
@@ -58,30 +81,20 @@ static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *at
static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
size_t count);
static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t dcssblk_seglist_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
-static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show,
+static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
dcssblk_save_store);
-static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show,
+static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
dcssblk_shared_store);
+static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
static struct device *dcssblk_root_dev;
-struct dcssblk_dev_info {
- struct list_head lh;
- struct device dev;
- char segment_name[BUS_ID_SIZE];
- atomic_t use_count;
- struct gendisk *gd;
- unsigned long start;
- unsigned long end;
- int segment_type;
- unsigned char save_pending;
- unsigned char is_shared;
- struct request_queue *dcssblk_queue;
-};
-
static LIST_HEAD(dcssblk_devices);
static struct rw_semaphore dcssblk_devices_sem;
@@ -91,8 +104,15 @@ static struct rw_semaphore dcssblk_devices_sem;
static void
dcssblk_release_segment(struct device *dev)
{
- PRINT_DEBUG("segment release fn called for %s\n", dev->bus_id);
- kfree(container_of(dev, struct dcssblk_dev_info, dev));
+ struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry, *temp;
+
+ dev_info = container_of(dev, struct dcssblk_dev_info, dev);
+ list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) {
+ list_del(&entry->lh);
+ kfree(entry);
+ }
+ kfree(dev_info);
module_put(THIS_MODULE);
}
@@ -142,6 +162,169 @@ dcssblk_get_device_by_name(char *name)
return NULL;
}
+/*
+ * get the struct segment_info from seg_list
+ * for the given name.
+ * down_read(&dcssblk_devices_sem) must be held.
+ */
+static struct segment_info *
+dcssblk_get_segment_by_name(char *name)
+{
+ struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry;
+
+ list_for_each_entry(dev_info, &dcssblk_devices, lh) {
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ if (!strcmp(name, entry->segment_name))
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * get the highest address of the multi-segment block.
+ */
+static unsigned long
+dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info)
+{
+ unsigned long highest_addr;
+ struct segment_info *entry;
+
+ highest_addr = 0;
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ if (highest_addr < entry->end)
+ highest_addr = entry->end;
+ }
+ return highest_addr;
+}
+
+/*
+ * get the lowest address of the multi-segment block.
+ */
+static unsigned long
+dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info)
+{
+ int set_first;
+ unsigned long lowest_addr;
+ struct segment_info *entry;
+
+ set_first = 0;
+ lowest_addr = 0;
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ if (set_first == 0) {
+ lowest_addr = entry->start;
+ set_first = 1;
+ } else {
+ if (lowest_addr > entry->start)
+ lowest_addr = entry->start;
+ }
+ }
+ return lowest_addr;
+}
+
+/*
+ * Check continuity of segments.
+ */
+static int
+dcssblk_is_continuous(struct dcssblk_dev_info *dev_info)
+{
+ int i, j, rc;
+ struct segment_info *sort_list, *entry, temp;
+
+ if (dev_info->num_of_segments <= 1)
+ return 0;
+
+ sort_list = kzalloc(
+ sizeof(struct segment_info) * dev_info->num_of_segments,
+ GFP_KERNEL);
+ if (sort_list == NULL)
+ return -ENOMEM;
+ i = 0;
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ memcpy(&sort_list[i], entry, sizeof(struct segment_info));
+ i++;
+ }
+
+ /* sort segments */
+ for (i = 0; i < dev_info->num_of_segments; i++)
+ for (j = 0; j < dev_info->num_of_segments; j++)
+ if (sort_list[j].start > sort_list[i].start) {
+ memcpy(&temp, &sort_list[i],
+ sizeof(struct segment_info));
+ memcpy(&sort_list[i], &sort_list[j],
+ sizeof(struct segment_info));
+ memcpy(&sort_list[j], &temp,
+ sizeof(struct segment_info));
+ }
+
+ /* check continuity */
+ for (i = 0; i < dev_info->num_of_segments - 1; i++) {
+ if ((sort_list[i].end + 1) != sort_list[i+1].start) {
+ PRINT_ERR("Segment %s is not contiguous with "
+ "segment %s\n",
+ sort_list[i].segment_name,
+ sort_list[i+1].segment_name);
+ rc = -EINVAL;
+ goto out;
+ }
+ /* EN and EW are allowed in a block device */
+ if (sort_list[i].segment_type != sort_list[i+1].segment_type) {
+ if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) ||
+ (sort_list[i].segment_type == SEG_TYPE_ER) ||
+ !(sort_list[i+1].segment_type &
+ SEGMENT_EXCLUSIVE) ||
+ (sort_list[i+1].segment_type == SEG_TYPE_ER)) {
+ PRINT_ERR("Segment %s has different type from "
+ "segment %s\n",
+ sort_list[i].segment_name,
+ sort_list[i+1].segment_name);
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+ }
+ rc = 0;
+out:
+ kfree(sort_list);
+ return rc;
+}
+
+/*
+ * Load a segment
+ */
+static int
+dcssblk_load_segment(char *name, struct segment_info **seg_info)
+{
+ int rc;
+
+ /* already loaded? */
+ down_read(&dcssblk_devices_sem);
+ *seg_info = dcssblk_get_segment_by_name(name);
+ up_read(&dcssblk_devices_sem);
+ if (*seg_info != NULL)
+ return -EEXIST;
+
+ /* get a struct segment_info */
+ *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL);
+ if (*seg_info == NULL)
+ return -ENOMEM;
+
+ strcpy((*seg_info)->segment_name, name);
+
+ /* load the segment */
+ rc = segment_load(name, SEGMENT_SHARED,
+ &(*seg_info)->start, &(*seg_info)->end);
+ if (rc < 0) {
+ segment_warning(rc, (*seg_info)->segment_name);
+ kfree(*seg_info);
+ } else {
+ INIT_LIST_HEAD(&(*seg_info)->lh);
+ (*seg_info)->segment_type = rc;
+ }
+ return rc;
+}
+
static void dcssblk_unregister_callback(struct device *dev)
{
device_unregister(dev);
@@ -165,6 +348,7 @@ static ssize_t
dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
{
struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry, *temp;
int rc;
if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
@@ -172,46 +356,46 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
down_write(&dcssblk_devices_sem);
dev_info = container_of(dev, struct dcssblk_dev_info, dev);
if (atomic_read(&dev_info->use_count)) {
- PRINT_ERR("share: segment %s is busy!\n",
- dev_info->segment_name);
rc = -EBUSY;
goto out;
}
if (inbuf[0] == '1') {
- // reload segment in shared mode
- rc = segment_modify_shared(dev_info->segment_name,
- SEGMENT_SHARED);
- if (rc < 0) {
- BUG_ON(rc == -EINVAL);
- if (rc != -EAGAIN)
- goto removeseg;
- } else {
- dev_info->is_shared = 1;
- switch (dev_info->segment_type) {
- case SEG_TYPE_SR:
- case SEG_TYPE_ER:
- case SEG_TYPE_SC:
- set_disk_ro(dev_info->gd,1);
+ /* reload segments in shared mode */
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ rc = segment_modify_shared(entry->segment_name,
+ SEGMENT_SHARED);
+ if (rc < 0) {
+ BUG_ON(rc == -EINVAL);
+ if (rc != -EAGAIN)
+ goto removeseg;
}
}
+ dev_info->is_shared = 1;
+ switch (dev_info->segment_type) {
+ case SEG_TYPE_SR:
+ case SEG_TYPE_ER:
+ case SEG_TYPE_SC:
+ set_disk_ro(dev_info->gd, 1);
+ }
} else if (inbuf[0] == '0') {
- // reload segment in exclusive mode
+ /* reload segments in exclusive mode */
if (dev_info->segment_type == SEG_TYPE_SC) {
PRINT_ERR("Segment type SC (%s) cannot be loaded in "
- "non-shared mode\n", dev_info->segment_name);
+ "non-shared mode\n", dev_info->segment_name);
rc = -EINVAL;
goto out;
}
- rc = segment_modify_shared(dev_info->segment_name,
- SEGMENT_EXCLUSIVE);
- if (rc < 0) {
- BUG_ON(rc == -EINVAL);
- if (rc != -EAGAIN)
- goto removeseg;
- } else {
- dev_info->is_shared = 0;
- set_disk_ro(dev_info->gd, 0);
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ rc = segment_modify_shared(entry->segment_name,
+ SEGMENT_EXCLUSIVE);
+ if (rc < 0) {
+ BUG_ON(rc == -EINVAL);
+ if (rc != -EAGAIN)
+ goto removeseg;
+ }
}
+ dev_info->is_shared = 0;
+ set_disk_ro(dev_info->gd, 0);
} else {
rc = -EINVAL;
goto out;
@@ -220,8 +404,14 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
goto out;
removeseg:
- PRINT_ERR("Could not reload segment %s, removing it now!\n",
- dev_info->segment_name);
+ PRINT_ERR("Could not reload segment(s) of the device %s, removing "
+ "segment(s) now!\n",
+ dev_info->segment_name);
+ temp = entry;
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ if (entry != temp)
+ segment_unload(entry->segment_name);
+ }
list_del(&dev_info->lh);
del_gendisk(dev_info->gd);
@@ -254,6 +444,7 @@ static ssize_t
dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
{
struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry;
if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
return -EINVAL;
@@ -263,14 +454,16 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
if (inbuf[0] == '1') {
if (atomic_read(&dev_info->use_count) == 0) {
// device is idle => we save immediately
- PRINT_INFO("Saving segment %s\n",
+ PRINT_INFO("Saving segment(s) of the device %s\n",
dev_info->segment_name);
- segment_save(dev_info->segment_name);
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ segment_save(entry->segment_name);
+ }
} else {
// device is busy => we save it when it becomes
// idle in dcssblk_release
- PRINT_INFO("Segment %s is currently busy, it will "
- "be saved when it becomes idle...\n",
+ PRINT_INFO("Device %s is currently busy, segment(s) "
+ "will be saved when it becomes idle...\n",
dev_info->segment_name);
dev_info->save_pending = 1;
}
@@ -279,7 +472,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
// device is busy & the user wants to undo his save
// request
dev_info->save_pending = 0;
- PRINT_INFO("Pending save for segment %s deactivated\n",
+ PRINT_INFO("Pending save for segment(s) of the device "
+ "%s deactivated\n",
dev_info->segment_name);
}
} else {
@@ -291,66 +485,123 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
}
/*
+ * device attribute for showing all segments in a device
+ */
+static ssize_t
+dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+
+ struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry;
+
+ down_read(&dcssblk_devices_sem);
+ dev_info = container_of(dev, struct dcssblk_dev_info, dev);
+ i = 0;
+ buf[0] = '\0';
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ strcpy(&buf[i], entry->segment_name);
+ i += strlen(entry->segment_name);
+ buf[i] = '\n';
+ i++;
+ }
+ up_read(&dcssblk_devices_sem);
+ return i;
+}
+
+/*
* device attribute for adding devices
*/
static ssize_t
dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- int rc, i;
+ int rc, i, j, num_of_segments;
struct dcssblk_dev_info *dev_info;
+ struct segment_info *seg_info, *temp;
char *local_buf;
unsigned long seg_byte_size;
dev_info = NULL;
+ seg_info = NULL;
if (dev != dcssblk_root_dev) {
rc = -EINVAL;
goto out_nobuf;
}
+ if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) {
+ rc = -ENAMETOOLONG;
+ goto out_nobuf;
+ }
+
local_buf = kmalloc(count + 1, GFP_KERNEL);
if (local_buf == NULL) {
rc = -ENOMEM;
goto out_nobuf;
}
+
/*
* parse input
*/
+ num_of_segments = 0;
for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
- local_buf[i] = toupper(buf[i]);
+ for (j = i; (buf[j] != ':') &&
+ (buf[j] != '\0') &&
+ (buf[j] != '\n') &&
+ j < count; j++) {
+ local_buf[j-i] = toupper(buf[j]);
+ }
+ local_buf[j-i] = '\0';
+ if (((j - i) == 0) || ((j - i) > 8)) {
+ rc = -ENAMETOOLONG;
+ goto seg_list_del;
+ }
+
+ rc = dcssblk_load_segment(local_buf, &seg_info);
+ if (rc < 0)
+ goto seg_list_del;
+ /*
+ * get a struct dcssblk_dev_info
+ */
+ if (num_of_segments == 0) {
+ dev_info = kzalloc(sizeof(struct dcssblk_dev_info),
+ GFP_KERNEL);
+ if (dev_info == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ strcpy(dev_info->segment_name, local_buf);
+ dev_info->segment_type = seg_info->segment_type;
+ INIT_LIST_HEAD(&dev_info->seg_list);
+ }
+ list_add_tail(&seg_info->lh, &dev_info->seg_list);
+ num_of_segments++;
+ i = j;
+
+ if ((buf[j] == '\0') || (buf[j] == '\n'))
+ break;
}
- local_buf[i] = '\0';
- if ((i == 0) || (i > 8)) {
+
+ /* no trailing colon at the end of the input */
+ if ((i > 0) && (buf[i-1] == ':')) {
rc = -ENAMETOOLONG;
- goto out;
- }
- /*
- * already loaded?
- */
- down_read(&dcssblk_devices_sem);
- dev_info = dcssblk_get_device_by_name(local_buf);
- up_read(&dcssblk_devices_sem);
- if (dev_info != NULL) {
- PRINT_WARN("Segment %s already loaded!\n", local_buf);
- rc = -EEXIST;
- goto out;
- }
- /*
- * get a struct dcssblk_dev_info
- */
- dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL);
- if (dev_info == NULL) {
- rc = -ENOMEM;
- goto out;
+ goto seg_list_del;
}
+ strlcpy(local_buf, buf, i + 1);
+ dev_info->num_of_segments = num_of_segments;
+ rc = dcssblk_is_continuous(dev_info);
+ if (rc < 0)
+ goto seg_list_del;
+
+ dev_info->start = dcssblk_find_lowest_addr(dev_info);
+ dev_info->end = dcssblk_find_highest_addr(dev_info);
- strcpy(dev_info->segment_name, local_buf);
- strlcpy(dev_info->dev.bus_id, local_buf, BUS_ID_SIZE);
+ dev_set_name(&dev_info->dev, dev_info->segment_name);
dev_info->dev.release = dcssblk_release_segment;
INIT_LIST_HEAD(&dev_info->lh);
-
dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
if (dev_info->gd == NULL) {
rc = -ENOMEM;
- goto free_dev_info;
+ goto seg_list_del;
}
dev_info->gd->major = dcssblk_major;
dev_info->gd->fops = &dcssblk_devops;
@@ -360,59 +611,43 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
dev_info->gd->driverfs_dev = &dev_info->dev;
blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
- /*
- * load the segment
- */
- rc = segment_load(local_buf, SEGMENT_SHARED,
- &dev_info->start, &dev_info->end);
- if (rc < 0) {
- segment_warning(rc, dev_info->segment_name);
- goto dealloc_gendisk;
- }
+
seg_byte_size = (dev_info->end - dev_info->start + 1);
set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
- PRINT_INFO("Loaded segment %s, size = %lu Byte, "
+ PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, "
"capacity = %lu (512 Byte) sectors\n", local_buf,
seg_byte_size, seg_byte_size >> 9);
- dev_info->segment_type = rc;
dev_info->save_pending = 0;
dev_info->is_shared = 1;
dev_info->dev.parent = dcssblk_root_dev;
/*
- * get minor, add to list
+ *get minor, add to list
*/
down_write(&dcssblk_devices_sem);
- if (dcssblk_get_device_by_name(local_buf)) {
- up_write(&dcssblk_devices_sem);
+ if (dcssblk_get_segment_by_name(local_buf)) {
rc = -EEXIST;
- goto unload_seg;
+ goto release_gd;
}
rc = dcssblk_assign_free_minor(dev_info);
- if (rc) {
- up_write(&dcssblk_devices_sem);
- PRINT_ERR("No free minor number available! "
- "Unloading segment...\n");
- goto unload_seg;
- }
+ if (rc)
+ goto release_gd;
sprintf(dev_info->gd->disk_name, "dcssblk%d",
MINOR(disk_devt(dev_info->gd)));
list_add_tail(&dev_info->lh, &dcssblk_devices);
if (!try_module_get(THIS_MODULE)) {
rc = -ENODEV;
- goto list_del;
+ goto dev_list_del;
}
/*
* register the device
*/
rc = device_register(&dev_info->dev);
if (rc) {
- PRINT_ERR("Segment %s could not be registered RC=%d\n",
- local_buf, rc);
module_put(THIS_MODULE);
- goto list_del;
+ goto dev_list_del;
}
get_device(&dev_info->dev);
rc = device_create_file(&dev_info->dev, &dev_attr_shared);
@@ -421,6 +656,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
rc = device_create_file(&dev_info->dev, &dev_attr_save);
if (rc)
goto unregister_dev;
+ rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
+ if (rc)
+ goto unregister_dev;
add_disk(dev_info->gd);
@@ -434,7 +672,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
set_disk_ro(dev_info->gd,0);
break;
}
- PRINT_DEBUG("Segment %s loaded successfully\n", local_buf);
up_write(&dcssblk_devices_sem);
rc = count;
goto out;
@@ -445,20 +682,27 @@ unregister_dev:
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
device_unregister(&dev_info->dev);
- segment_unload(dev_info->segment_name);
+ list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
+ segment_unload(seg_info->segment_name);
+ }
put_device(&dev_info->dev);
up_write(&dcssblk_devices_sem);
goto out;
-list_del:
+dev_list_del:
list_del(&dev_info->lh);
- up_write(&dcssblk_devices_sem);
-unload_seg:
- segment_unload(local_buf);
-dealloc_gendisk:
+release_gd:
blk_cleanup_queue(dev_info->dcssblk_queue);
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
-free_dev_info:
+ up_write(&dcssblk_devices_sem);
+seg_list_del:
+ if (dev_info == NULL)
+ goto out;
+ list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) {
+ list_del(&seg_info->lh);
+ segment_unload(seg_info->segment_name);
+ kfree(seg_info);
+ }
kfree(dev_info);
out:
kfree(local_buf);
@@ -473,6 +717,7 @@ static ssize_t
dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry;
int rc, i;
char *local_buf;
@@ -499,26 +744,28 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
dev_info = dcssblk_get_device_by_name(local_buf);
if (dev_info == NULL) {
up_write(&dcssblk_devices_sem);
- PRINT_WARN("Segment %s is not loaded!\n", local_buf);
+ PRINT_WARN("Device %s is not loaded!\n", local_buf);
rc = -ENODEV;
goto out_buf;
}
if (atomic_read(&dev_info->use_count) != 0) {
up_write(&dcssblk_devices_sem);
- PRINT_WARN("Segment %s is in use!\n", local_buf);
+ PRINT_WARN("Device %s is in use!\n", local_buf);
rc = -EBUSY;
goto out_buf;
}
- list_del(&dev_info->lh);
+ list_del(&dev_info->lh);
del_gendisk(dev_info->gd);
blk_cleanup_queue(dev_info->dcssblk_queue);
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
device_unregister(&dev_info->dev);
- segment_unload(dev_info->segment_name);
- PRINT_DEBUG("Segment %s unloaded successfully\n",
- dev_info->segment_name);
+
+ /* unload all related segments */
+ list_for_each_entry(entry, &dev_info->seg_list, lh)
+ segment_unload(entry->segment_name);
+
put_device(&dev_info->dev);
up_write(&dcssblk_devices_sem);
@@ -550,6 +797,7 @@ static int
dcssblk_release(struct inode *inode, struct file *filp)
{
struct dcssblk_dev_info *dev_info;
+ struct segment_info *entry;
int rc;
dev_info = inode->i_bdev->bd_disk->private_data;
@@ -560,9 +808,11 @@ dcssblk_release(struct inode *inode, struct file *filp)
down_write(&dcssblk_devices_sem);
if (atomic_dec_and_test(&dev_info->use_count)
&& (dev_info->save_pending)) {
- PRINT_INFO("Segment %s became idle and is being saved now\n",
+ PRINT_INFO("Device %s became idle and is being saved now\n",
dev_info->segment_name);
- segment_save(dev_info->segment_name);
+ list_for_each_entry(entry, &dev_info->seg_list, lh) {
+ segment_save(entry->segment_name);
+ }
dev_info->save_pending = 0;
}
up_write(&dcssblk_devices_sem);
@@ -602,7 +852,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
case SEG_TYPE_SC:
/* cannot write to these segments */
if (bio_data_dir(bio) == WRITE) {
- PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
+ PRINT_WARN("rejecting write to ro device %s\n",
+ dev_name(&dev_info->dev));
goto fail;
}
}
@@ -657,7 +908,7 @@ static void
dcssblk_check_params(void)
{
int rc, i, j, k;
- char buf[9];
+ char buf[DCSSBLK_PARM_LEN + 1];
struct dcssblk_dev_info *dev_info;
for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
@@ -665,15 +916,16 @@ dcssblk_check_params(void)
for (j = i; (dcssblk_segments[j] != ',') &&
(dcssblk_segments[j] != '\0') &&
(dcssblk_segments[j] != '(') &&
- (j - i) < 8; j++)
+ (j < DCSSBLK_PARM_LEN); j++)
{
buf[j-i] = dcssblk_segments[j];
}
buf[j-i] = '\0';
rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
- for (k = 0; buf[k] != '\0'; k++)
+ for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++)
buf[k] = toupper(buf[k]);
+ buf[k] = '\0';
if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
down_read(&dcssblk_devices_sem);
dev_info = dcssblk_get_device_by_name(buf);
@@ -740,10 +992,12 @@ module_exit(dcssblk_exit);
module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
- "comma-separated list, each name max. 8 chars.\n"
- "Adding \"(local)\" to segment name equals echoing 0 to "
- "/sys/devices/dcssblk/<segment name>/shared after loading "
- "the segment - \n"
- "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\"");
+ "comma-separated list, names in each set separated "
+ "by commas are separated by colons, each set contains "
+ "names of contiguous segments and each name max. 8 chars.\n"
+ "Adding \"(local)\" to the end of each set equals echoing 0 "
+ "to /sys/devices/dcssblk/<device name>/shared after loading "
+ "the contiguous segments - \n"
+ "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");
MODULE_LICENSE("GPL");
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index dd9b986389a..03916989ed2 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -56,6 +56,7 @@ typedef struct {
static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
static unsigned int xpram_sizes[XPRAM_MAX_DEVS];
static struct gendisk *xpram_disks[XPRAM_MAX_DEVS];
+static struct request_queue *xpram_queues[XPRAM_MAX_DEVS];
static unsigned int xpram_pages;
static int xpram_devs;
@@ -330,18 +331,22 @@ static int __init xpram_setup_sizes(unsigned long pages)
return 0;
}
-static struct request_queue *xpram_queue;
-
static int __init xpram_setup_blkdev(void)
{
unsigned long offset;
int i, rc = -ENOMEM;
for (i = 0; i < xpram_devs; i++) {
- struct gendisk *disk = alloc_disk(1);
- if (!disk)
+ xpram_disks[i] = alloc_disk(1);
+ if (!xpram_disks[i])
+ goto out;
+ xpram_queues[i] = blk_alloc_queue(GFP_KERNEL);
+ if (!xpram_queues[i]) {
+ put_disk(xpram_disks[i]);
goto out;
- xpram_disks[i] = disk;
+ }
+ blk_queue_make_request(xpram_queues[i], xpram_make_request);
+ blk_queue_hardsect_size(xpram_queues[i], 4096);
}
/*
@@ -352,18 +357,6 @@ static int __init xpram_setup_blkdev(void)
goto out;
/*
- * Assign the other needed values: make request function, sizes and
- * hardsect size. All the minor devices feature the same value.
- */
- xpram_queue = blk_alloc_queue(GFP_KERNEL);
- if (!xpram_queue) {
- rc = -ENOMEM;
- goto out_unreg;
- }
- blk_queue_make_request(xpram_queue, xpram_make_request);
- blk_queue_hardsect_size(xpram_queue, 4096);
-
- /*
* Setup device structures.
*/
offset = 0;
@@ -377,18 +370,18 @@ static int __init xpram_setup_blkdev(void)
disk->first_minor = i;
disk->fops = &xpram_devops;
disk->private_data = &xpram_devices[i];
- disk->queue = xpram_queue;
+ disk->queue = xpram_queues[i];
sprintf(disk->disk_name, "slram%d", i);
set_capacity(disk, xpram_sizes[i] << 1);
add_disk(disk);
}
return 0;
-out_unreg:
- unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
out:
- while (i--)
+ while (i--) {
+ blk_cleanup_queue(xpram_queues[i]);
put_disk(xpram_disks[i]);
+ }
return rc;
}
@@ -400,10 +393,10 @@ static void __exit xpram_exit(void)
int i;
for (i = 0; i < xpram_devs; i++) {
del_gendisk(xpram_disks[i]);
+ blk_cleanup_queue(xpram_queues[i]);
put_disk(xpram_disks[i]);
}
unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
- blk_cleanup_queue(xpram_queue);
}
static int __init xpram_init(void)
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index d3ec9b55ab3..9ab06e0dad4 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -21,6 +21,7 @@
#include <linux/console.h>
#include <linux/interrupt.h>
#include <linux/err.h>
+#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/bootmem.h>
@@ -88,7 +89,6 @@ struct raw3215_info {
int count; /* number of bytes in output buffer */
int written; /* number of bytes in write requests */
struct tty_struct *tty; /* pointer to tty structure if present */
- struct tasklet_struct tasklet;
struct raw3215_req *queued_read; /* pointer to queued read requests */
struct raw3215_req *queued_write;/* pointer to queued write requests */
wait_queue_head_t empty_wait; /* wait queue for flushing */
@@ -341,21 +341,14 @@ raw3215_try_io(struct raw3215_info *raw)
}
/*
- * The bottom half handler routine for 3215 devices. It tries to start
- * the next IO and wakes up processes waiting on the tty.
+ * Try to start the next IO and wake up processes waiting on the tty.
*/
-static void
-raw3215_tasklet(void *data)
+static void raw3215_next_io(struct raw3215_info *raw)
{
- struct raw3215_info *raw;
struct tty_struct *tty;
- unsigned long flags;
- raw = (struct raw3215_info *) data;
- spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_mk_write_req(raw);
raw3215_try_io(raw);
- spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
tty = raw->tty;
if (tty != NULL &&
RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
@@ -380,7 +373,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
if (cstat != 0)
- tasklet_schedule(&raw->tasklet);
+ raw3215_next_io(raw);
if (dstat & 0x01) { /* we got a unit exception */
dstat &= ~0x01; /* we can ignore it */
}
@@ -390,7 +383,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
break;
/* Attention interrupt, someone hit the enter key */
raw3215_mk_read_req(raw);
- tasklet_schedule(&raw->tasklet);
+ raw3215_next_io(raw);
break;
case 0x08:
case 0x0C:
@@ -448,7 +441,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
raw->queued_read == NULL) {
wake_up_interruptible(&raw->empty_wait);
}
- tasklet_schedule(&raw->tasklet);
+ raw3215_next_io(raw);
break;
default:
/* Strange interrupt, I'll do my best to clean up */
@@ -460,7 +453,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
}
- tasklet_schedule(&raw->tasklet);
+ raw3215_next_io(raw);
}
return;
}
@@ -674,9 +667,6 @@ raw3215_probe (struct ccw_device *cdev)
kfree(raw);
return -ENOMEM;
}
- tasklet_init(&raw->tasklet,
- (void (*)(unsigned long)) raw3215_tasklet,
- (unsigned long) raw);
init_waitqueue_head(&raw->empty_wait);
cdev->dev.driver_data = raw;
@@ -775,11 +765,11 @@ static struct tty_driver *con3215_device(struct console *c, int *index)
}
/*
- * panic() calls console_unblank before the system enters a
- * disabled, endless loop.
+ * panic() calls con3215_flush through a panic_notifier
+ * before the system enters a disabled, endless loop.
*/
static void
-con3215_unblank(void)
+con3215_flush(void)
{
struct raw3215_info *raw;
unsigned long flags;
@@ -790,6 +780,23 @@ con3215_unblank(void)
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
+static int con3215_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ con3215_flush();
+ return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+ .notifier_call = con3215_notify,
+ .priority = 0,
+};
+
+static struct notifier_block on_reboot_nb = {
+ .notifier_call = con3215_notify,
+ .priority = 0,
+};
+
/*
* The console structure for the 3215 console
*/
@@ -797,7 +804,6 @@ static struct console con3215 = {
.name = "ttyS",
.write = con3215_write,
.device = con3215_device,
- .unblank = con3215_unblank,
.flags = CON_PRINTBUFFER,
};
@@ -846,9 +852,6 @@ con3215_init(void)
cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED;
- tasklet_init(&raw->tasklet,
- (void (*)(unsigned long)) raw3215_tasklet,
- (unsigned long) raw);
init_waitqueue_head(&raw->empty_wait);
/* Request the console irq */
@@ -859,6 +862,8 @@ con3215_init(void)
raw3215[0] = NULL;
return -ENODEV;
}
+ atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+ register_reboot_notifier(&on_reboot_nb);
register_console(&con3215);
return 0;
}
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 3c07974886e..d028d2ee83d 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/types.h>
#include <linux/err.h>
+#include <linux/reboot.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -528,11 +529,11 @@ con3270_wait_write(struct con3270 *cp)
}
/*
- * panic() calls console_unblank before the system enters a
- * disabled, endless loop.
+ * panic() calls con3270_flush through a panic_notifier
+ * before the system enters a disabled, endless loop.
*/
static void
-con3270_unblank(void)
+con3270_flush(void)
{
struct con3270 *cp;
unsigned long flags;
@@ -554,6 +555,23 @@ con3270_unblank(void)
spin_unlock_irqrestore(&cp->view.lock, flags);
}
+static int con3270_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ con3270_flush();
+ return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+ .notifier_call = con3270_notify,
+ .priority = 0,
+};
+
+static struct notifier_block on_reboot_nb = {
+ .notifier_call = con3270_notify,
+ .priority = 0,
+};
+
/*
* The console structure for the 3270 console
*/
@@ -561,7 +579,6 @@ static struct console con3270 = {
.name = "tty3270",
.write = con3270_write,
.device = con3270_device,
- .unblank = con3270_unblank,
.flags = CON_PRINTBUFFER,
};
@@ -623,6 +640,8 @@ con3270_init(void)
condev->cline->len = 0;
con3270_create_status(condev);
condev->input = alloc_string(&condev->freemem, 80);
+ atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+ register_reboot_notifier(&on_reboot_nb);
register_console(&con3270);
return 0;
}
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index c3dee900a5c..1792b2c0130 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -1171,7 +1171,7 @@ static int raw3270_create_attributes(struct raw3270 *rp)
rp->clttydev = device_create_drvdata(class3270, &rp->cdev->dev,
MKDEV(IBM_TTY3270_MAJOR, rp->minor),
NULL,
- "tty%s", rp->cdev->dev.bus_id);
+ "tty%s", dev_name(&rp->cdev->dev));
if (IS_ERR(rp->clttydev)) {
rc = PTR_ERR(rp->clttydev);
goto out_ttydev;
@@ -1180,7 +1180,7 @@ static int raw3270_create_attributes(struct raw3270 *rp)
rp->cltubdev = device_create_drvdata(class3270, &rp->cdev->dev,
MKDEV(IBM_FS3270_MAJOR, rp->minor),
NULL,
- "tub%s", rp->cdev->dev.bus_id);
+ "tub%s", dev_name(&rp->cdev->dev));
if (!IS_ERR(rp->cltubdev))
goto out;
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 7e619c534bf..9a25c4bd142 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -16,6 +16,7 @@
#include <linux/bootmem.h>
#include <linux/termios.h>
#include <linux/err.h>
+#include <linux/reboot.h>
#include "sclp.h"
#include "sclp_rw.h"
@@ -172,7 +173,7 @@ sclp_console_device(struct console *c, int *index)
* will be flushed to the SCLP.
*/
static void
-sclp_console_unblank(void)
+sclp_console_flush(void)
{
unsigned long flags;
@@ -188,6 +189,24 @@ sclp_console_unblank(void)
spin_unlock_irqrestore(&sclp_con_lock, flags);
}
+static int
+sclp_console_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ sclp_console_flush();
+ return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+ .notifier_call = sclp_console_notify,
+ .priority = 1,
+};
+
+static struct notifier_block on_reboot_nb = {
+ .notifier_call = sclp_console_notify,
+ .priority = 1,
+};
+
/*
* used to register the SCLP console to the kernel and to
* give printk necessary information
@@ -197,7 +216,6 @@ static struct console sclp_console =
.name = sclp_console_name,
.write = sclp_console_write,
.device = sclp_console_device,
- .unblank = sclp_console_unblank,
.flags = CON_PRINTBUFFER,
.index = 0 /* ttyS0 */
};
@@ -241,6 +259,8 @@ sclp_console_init(void)
sclp_con_width_htab = 8;
/* enable printk-access to this driver */
+ atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+ register_reboot_notifier(&on_reboot_nb);
register_console(&sclp_console);
return 0;
}
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index ad51738c426..9854f19f5e6 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -24,6 +24,8 @@
#include <linux/bootmem.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/reboot.h>
+
#include <asm/uaccess.h>
#include "sclp.h"
@@ -743,24 +745,30 @@ sclp_vt220_con_device(struct console *c, int *index)
return sclp_vt220_driver;
}
-/*
- * This routine is called from panic when the kernel is going to give up.
- * We have to make sure that all buffers will be flushed to the SCLP.
- * Note that this function may be called from within an interrupt context.
- */
-static void
-sclp_vt220_con_unblank(void)
+static int
+sclp_vt220_notify(struct notifier_block *self,
+ unsigned long event, void *data)
{
__sclp_vt220_flush_buffer();
+ return NOTIFY_OK;
}
+static struct notifier_block on_panic_nb = {
+ .notifier_call = sclp_vt220_notify,
+ .priority = 1,
+};
+
+static struct notifier_block on_reboot_nb = {
+ .notifier_call = sclp_vt220_notify,
+ .priority = 1,
+};
+
/* Structure needed to register with printk */
static struct console sclp_vt220_console =
{
.name = SCLP_VT220_CONSOLE_NAME,
.write = sclp_vt220_con_write,
.device = sclp_vt220_con_device,
- .unblank = sclp_vt220_con_unblank,
.flags = CON_PRINTBUFFER,
.index = SCLP_VT220_CONSOLE_INDEX
};
@@ -776,6 +784,8 @@ sclp_vt220_con_init(void)
if (rc)
return rc;
/* Attach linux console */
+ atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+ register_reboot_notifier(&on_reboot_nb);
register_console(&sclp_vt220_console);
return 0;
}
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 839987618ff..4005c44a404 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -910,7 +910,7 @@ tape_3590_erp_swap(struct tape_device *device, struct tape_request *request,
* should proceed with the new tape... this
* should probably be done in user space!
*/
- PRINT_WARN("(%s): Swap Tape Device!\n", device->cdev->dev.bus_id);
+ PRINT_WARN("(%s): Swap Tape Device!\n", dev_name(&device->cdev->dev));
return tape_3590_erp_basic(device, request, irb, -EIO);
}
@@ -1003,40 +1003,43 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
/* Exception Message */
switch (sense->fmt.f70.emc) {
case 0x02:
- PRINT_WARN("(%s): Data degraded\n", device->cdev->dev.bus_id);
+ PRINT_WARN("(%s): Data degraded\n",
+ dev_name(&device->cdev->dev));
break;
case 0x03:
PRINT_WARN("(%s): Data degraded in partion %i\n",
- device->cdev->dev.bus_id, sense->fmt.f70.mp);
+ dev_name(&device->cdev->dev), sense->fmt.f70.mp);
break;
case 0x04:
- PRINT_WARN("(%s): Medium degraded\n", device->cdev->dev.bus_id);
+ PRINT_WARN("(%s): Medium degraded\n",
+ dev_name(&device->cdev->dev));
break;
case 0x05:
PRINT_WARN("(%s): Medium degraded in partition %i\n",
- device->cdev->dev.bus_id, sense->fmt.f70.mp);
+ dev_name(&device->cdev->dev), sense->fmt.f70.mp);
break;
case 0x06:
- PRINT_WARN("(%s): Block 0 Error\n", device->cdev->dev.bus_id);
+ PRINT_WARN("(%s): Block 0 Error\n",
+ dev_name(&device->cdev->dev));
break;
case 0x07:
PRINT_WARN("(%s): Medium Exception 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f70.md);
+ dev_name(&device->cdev->dev), sense->fmt.f70.md);
break;
default:
PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f70.emc);
+ dev_name(&device->cdev->dev), sense->fmt.f70.emc);
break;
}
/* Service Message */
switch (sense->fmt.f70.smc) {
case 0x02:
PRINT_WARN("(%s): Reference Media maintenance procedure %i\n",
- device->cdev->dev.bus_id, sense->fmt.f70.md);
+ dev_name(&device->cdev->dev), sense->fmt.f70.md);
break;
default:
PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f70.smc);
+ dev_name(&device->cdev->dev), sense->fmt.f70.smc);
break;
}
}
@@ -1054,101 +1057,101 @@ tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb)
switch (sense->fmt.f71.emc) {
case 0x01:
PRINT_WARN("(%s): Effect of failure is unknown\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x02:
PRINT_WARN("(%s): CU Exception - no performance impact\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x03:
PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x04:
PRINT_WARN("(%s): CU Exception on device path 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x05:
PRINT_WARN("(%s): CU Exception on library path 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x06:
PRINT_WARN("(%s): CU Exception on node 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x07:
PRINT_WARN("(%s): CU Exception on partition 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
default:
PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.emc);
+ dev_name(&device->cdev->dev), sense->fmt.f71.emc);
}
/* Service Message */
switch (sense->fmt.f71.smc) {
case 0x01:
PRINT_WARN("(%s): Repair impact is unknown\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x02:
PRINT_WARN("(%s): Repair will not impact cu performance\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x03:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable node "
"0x%x on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable nodes "
"(0x%x-0x%x) on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x04:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable cannel path "
"0x%x on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable cannel paths "
"(0x%x-0x%x) on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x05:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable device path "
"0x%x on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable device paths "
"(0x%x-0x%x) on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x06:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable library path "
"0x%x on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable library paths "
"(0x%x-0x%x) on CU\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x07:
PRINT_WARN("(%s): Repair will disable access to CU\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
default:
PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.smc);
+ dev_name(&device->cdev->dev), sense->fmt.f71.smc);
}
}
@@ -1165,104 +1168,104 @@ tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb)
switch (sense->fmt.f71.emc) {
case 0x01:
PRINT_WARN("(%s): Effect of failure is unknown\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x02:
PRINT_WARN("(%s): DV Exception - no performance impact\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x03:
PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x04:
PRINT_WARN("(%s): DV Exception on loader 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x05:
PRINT_WARN("(%s): DV Exception on message display 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
break;
case 0x06:
PRINT_WARN("(%s): DV Exception in tape path\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x07:
PRINT_WARN("(%s): DV Exception in drive\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
default:
PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.emc);
+ dev_name(&device->cdev->dev), sense->fmt.f71.emc);
}
/* Service Message */
switch (sense->fmt.f71.smc) {
case 0x01:
PRINT_WARN("(%s): Repair impact is unknown\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x02:
PRINT_WARN("(%s): Repair will not impact device performance\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x03:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable channel path "
"0x%x on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable channel path "
"(0x%x-0x%x) on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x04:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable interface 0x%x "
"on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable interfaces "
"(0x%x-0x%x) on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x05:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable loader 0x%x "
"on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable loader "
"(0x%x-0x%x) on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x07:
PRINT_WARN("(%s): Repair will disable access to DV\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case 0x08:
if (sense->fmt.f71.mdf == 0)
PRINT_WARN("(%s): Repair will disable message "
"display 0x%x on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1]);
else
PRINT_WARN("(%s): Repair will disable message "
"displays (0x%x-0x%x) on DV\n",
- device->cdev->dev.bus_id,
+ dev_name(&device->cdev->dev),
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
break;
case 0x09:
- PRINT_WARN("(%s): Clean DV\n", device->cdev->dev.bus_id);
+ PRINT_WARN("(%s): Clean DV\n", dev_name(&device->cdev->dev));
break;
default:
PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.smc);
+ dev_name(&device->cdev->dev), sense->fmt.f71.smc);
}
}
@@ -1279,18 +1282,18 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
return;
if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) {
if (tape_3590_msg[sense->mc] != NULL)
- PRINT_WARN("(%s): %s\n", device->cdev->dev.bus_id,
+ PRINT_WARN("(%s): %s\n", dev_name(&device->cdev->dev),
tape_3590_msg[sense->mc]);
else {
PRINT_WARN("(%s): Message Code 0x%x\n",
- device->cdev->dev.bus_id, sense->mc);
+ dev_name(&device->cdev->dev), sense->mc);
}
return;
}
if (sense->mc == 0xf0) {
/* Standard Media Information Message */
PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, "
- "RC=%02x-%04x-%02x\n", device->cdev->dev.bus_id,
+ "RC=%02x-%04x-%02x\n", dev_name(&device->cdev->dev),
sense->fmt.f70.sev, sense->mc,
sense->fmt.f70.emc, sense->fmt.f70.smc,
sense->fmt.f70.refcode, sense->fmt.f70.mid,
@@ -1302,7 +1305,7 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
/* Standard I/O Subsystem Service Information Message */
PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, "
"MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.sev,
+ dev_name(&device->cdev->dev), sense->fmt.f71.sev,
device->cdev->id.dev_model,
sense->mc, sense->fmt.f71.emc,
sense->fmt.f71.smc, sense->fmt.f71.refcode1,
@@ -1314,7 +1317,7 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
/* Standard Device Service Information Message */
PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, "
"MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
- device->cdev->dev.bus_id, sense->fmt.f71.sev,
+ dev_name(&device->cdev->dev), sense->fmt.f71.sev,
device->cdev->id.dev_model,
sense->mc, sense->fmt.f71.emc,
sense->fmt.f71.smc, sense->fmt.f71.refcode1,
@@ -1327,7 +1330,7 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
return;
}
PRINT_WARN("(%s): Device Message(%x)\n",
- device->cdev->dev.bus_id, sense->mc);
+ dev_name(&device->cdev->dev), sense->mc);
}
static int tape_3590_crypt_error(struct tape_device *device,
@@ -1336,10 +1339,11 @@ static int tape_3590_crypt_error(struct tape_device *device,
u8 cu_rc, ekm_rc1;
u16 ekm_rc2;
u32 drv_rc;
- char *bus_id, *sense;
+ const char *bus_id;
+ char *sense;
sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
- bus_id = device->cdev->dev.bus_id;
+ bus_id = dev_name(&device->cdev->dev);
cu_rc = sense[0];
drv_rc = *((u32*) &sense[5]) & 0xffffff;
ekm_rc1 = sense[9];
@@ -1440,7 +1444,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
* "device intervention" is not very meaningfull
*/
PRINT_WARN("(%s): Tape operation when medium not loaded\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
tape_med_state_set(device, MS_UNLOADED);
tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
@@ -1487,18 +1491,18 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x6020:
PRINT_WARN("(%s): Cartridge of wrong type ?\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);
case 0x8011:
PRINT_WARN("(%s): Another host has reserved the tape device\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
return tape_3590_erp_basic(device, request, irb, -EPERM);
case 0x8013:
PRINT_WARN("(%s): Another host has privileged access to the "
- "tape device\n", device->cdev->dev.bus_id);
+ "tape device\n", dev_name(&device->cdev->dev));
PRINT_WARN("(%s): To solve the problem unload the current "
- "cartridge!\n", device->cdev->dev.bus_id);
+ "cartridge!\n", dev_name(&device->cdev->dev));
return tape_3590_erp_basic(device, request, irb, -EPERM);
default:
return tape_3590_erp_basic(device, request, irb, -EIO);
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 95da72bc17e..a25b8bf54f4 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -278,7 +278,7 @@ tapeblock_cleanup_device(struct tape_device *device)
if (!device->blk_data.disk) {
PRINT_ERR("(%s): No gendisk to clean up!\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
goto cleanup_queue;
}
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 181a5441af1..d7073dbf825 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -215,12 +215,12 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
case MS_UNLOADED:
device->tape_generic_status |= GMT_DR_OPEN(~0);
PRINT_INFO("(%s): Tape is unloaded\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
case MS_LOADED:
device->tape_generic_status &= ~GMT_DR_OPEN(~0);
PRINT_INFO("(%s): Tape has been mounted\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
break;
default:
// print nothing
@@ -415,7 +415,7 @@ tape_generic_offline(struct tape_device *device)
device->cdev_id);
PRINT_WARN("(%s): Set offline failed "
"- drive in use.\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return -EBUSY;
}
@@ -538,7 +538,8 @@ tape_generic_probe(struct ccw_device *cdev)
ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
if (ret) {
tape_put_device(device);
- PRINT_ERR("probe failed for tape device %s\n", cdev->dev.bus_id);
+ PRINT_ERR("probe failed for tape device %s\n",
+ dev_name(&cdev->dev));
return ret;
}
cdev->dev.driver_data = device;
@@ -546,7 +547,7 @@ tape_generic_probe(struct ccw_device *cdev)
device->cdev = cdev;
ccw_device_get_id(cdev, &dev_id);
device->cdev_id = devid_to_int(&dev_id);
- PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
+ PRINT_INFO("tape device %s found\n", dev_name(&cdev->dev));
return ret;
}
@@ -616,7 +617,7 @@ tape_generic_remove(struct ccw_device *cdev)
device->cdev_id);
PRINT_WARN("(%s): Drive in use vanished - "
"expect trouble!\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
PRINT_WARN("State was %i\n", device->tape_state);
tape_state_set(device, TS_NOT_OPER);
__tape_discard_requests(device);
@@ -840,7 +841,7 @@ tape_dump_sense(struct tape_device* device, struct tape_request *request,
PRINT_INFO("-------------------------------------------------\n");
PRINT_INFO("DSTAT : %02x CSTAT: %02x CPA: %04x\n",
irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa);
- PRINT_INFO("DEVICE: %s\n", device->cdev->dev.bus_id);
+ PRINT_INFO("DEVICE: %s\n", dev_name(&device->cdev->dev));
if (request != NULL)
PRINT_INFO("OP : %s\n", tape_op_verbose[request->op]);
@@ -1051,7 +1052,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
device = (struct tape_device *) cdev->dev.driver_data;
if (device == NULL) {
PRINT_ERR("could not get device structure for %s "
- "in interrupt\n", cdev->dev.bus_id);
+ "in interrupt\n", dev_name(&cdev->dev));
return;
}
request = (struct tape_request *) intparm;
@@ -1064,13 +1065,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
switch (PTR_ERR(irb)) {
case -ETIMEDOUT:
PRINT_WARN("(%s): Request timed out\n",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
case -EIO:
__tape_end_request(device, request, -EIO);
break;
default:
PRINT_ERR("(%s): Unexpected i/o error %li\n",
- cdev->dev.bus_id,
+ dev_name(&cdev->dev),
PTR_ERR(irb));
}
return;
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index e7c888c14e7..8a376af926a 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -52,7 +52,7 @@ static int tape_proc_show(struct seq_file *m, void *v)
return 0;
spin_lock_irq(get_ccwdev_lock(device->cdev));
seq_printf(m, "%d\t", (int) n);
- seq_printf(m, "%-10.10s ", device->cdev->dev.bus_id);
+ seq_printf(m, "%-10.10s ", dev_name(&device->cdev->dev));
seq_printf(m, "%04X/", device->cdev->id.cu_type);
seq_printf(m, "%02X\t", device->cdev->id.cu_model);
seq_printf(m, "%04X/", device->cdev->id.dev_type);
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index cc8fd781ee2..5bd573d144d 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -47,7 +47,7 @@ tape_std_assign_timeout(unsigned long data)
rc = tape_cancel_io(device, request);
if(rc)
PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n",
- device->cdev->dev.bus_id, rc);
+ dev_name(&device->cdev->dev), rc);
}
@@ -83,7 +83,7 @@ tape_std_assign(struct tape_device *device)
if (rc != 0) {
PRINT_WARN("%s: assign failed - device might be busy\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
device->cdev_id);
} else {
@@ -106,7 +106,7 @@ tape_std_unassign (struct tape_device *device)
DBF_EVENT(3, "(%08x): Can't unassign device\n",
device->cdev_id);
PRINT_WARN("(%s): Can't unassign device - device gone\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
return -EIO;
}
@@ -120,7 +120,8 @@ tape_std_unassign (struct tape_device *device)
if ((rc = tape_do_io(device, request)) != 0) {
DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
- PRINT_WARN("%s: Unassign failed\n", device->cdev->dev.bus_id);
+ PRINT_WARN("%s: Unassign failed\n",
+ dev_name(&device->cdev->dev));
} else {
DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
}
@@ -634,10 +635,10 @@ tape_std_mtcompression(struct tape_device *device, int mt_count)
DBF_EXCEPTION(6, "xcom parm\n");
if (*device->modeset_byte & 0x08)
PRINT_INFO("(%s) Compression is currently on\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
else
PRINT_INFO("(%s) Compression is currently off\n",
- device->cdev->dev.bus_id);
+ dev_name(&device->cdev->dev));
PRINT_INFO("Use 1 to switch compression on, 0 to "
"switch it off\n");
return -EINVAL;
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index c31faefa2b3..42173cc3461 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -724,8 +724,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
dev = kzalloc(sizeof(struct device), GFP_KERNEL);
if (dev) {
- snprintf(dev->bus_id, BUS_ID_SIZE, "%s",
- priv->internal_name);
+ dev_set_name(dev, priv->internal_name);
dev->bus = &iucv_bus;
dev->parent = iucv_root;
dev->driver = &vmlogrdr_driver;
@@ -751,7 +750,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
priv->class_device = device_create_drvdata(vmlogrdr_class, dev,
MKDEV(vmlogrdr_major,
priv->minor_num),
- priv, "%s", dev->bus_id);
+ priv, "%s", dev_name(dev));
if (IS_ERR(priv->class_device)) {
ret = PTR_ERR(priv->class_device);
priv->class_device=NULL;
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index c1f352b8486..6fdfa5ddeca 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -886,11 +886,11 @@ static int ur_set_online(struct ccw_device *cdev)
goto fail_free_cdev;
if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {
if (urd->class == DEV_CLASS_UR_I)
- sprintf(node_id, "vmrdr-%s", cdev->dev.bus_id);
+ sprintf(node_id, "vmrdr-%s", dev_name(&cdev->dev));
if (urd->class == DEV_CLASS_UR_O)
- sprintf(node_id, "vmpun-%s", cdev->dev.bus_id);
+ sprintf(node_id, "vmpun-%s", dev_name(&cdev->dev));
} else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) {
- sprintf(node_id, "vmprt-%s", cdev->dev.bus_id);
+ sprintf(node_id, "vmprt-%s", dev_name(&cdev->dev));
} else {
rc = -EOPNOTSUPP;
goto fail_free_cdev;
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 0bfcbbe375c..2f547b840ef 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -24,6 +24,7 @@
#include "cio.h"
#include "cio_debug.h"
#include "css.h"
+#include "device.h"
/*
* "Blacklisting" of certain devices:
@@ -191,9 +192,9 @@ static int blacklist_parse_parameters(char *str, range_action action,
rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
msgtrigger);
if (rc)
- totalrc = 1;
+ totalrc = -EINVAL;
} else
- totalrc = 1;
+ totalrc = -EINVAL;
}
return totalrc;
@@ -240,8 +241,10 @@ static int blacklist_parse_proc_parameters(char *buf)
rc = blacklist_parse_parameters(buf, free, 0);
else if (strcmp("add", parm) == 0)
rc = blacklist_parse_parameters(buf, add, 0);
+ else if (strcmp("purge", parm) == 0)
+ return ccw_purge_blacklisted();
else
- return 1;
+ return -EINVAL;
css_schedule_reprobe();
@@ -353,7 +356,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
}
ret = blacklist_parse_proc_parameters(buf);
if (ret)
- rc = -EINVAL;
+ rc = ret;
else
rc = user_len;
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 9a50f245774..3ac2c2019f5 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -269,8 +269,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
goto error;
}
- snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
- gdev->cdev[0]->dev.bus_id);
+ dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
rc = device_add(&gdev->dev);
if (rc)
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index f1216cf6fa8..1246f61a533 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -393,8 +393,7 @@ int chp_new(struct chp_id chpid)
chp->state = 1;
chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
chp->dev.release = chp_release;
- snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
- chpid.id);
+ dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id);
/* Obtain channel path description and fill it in. */
ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 91ca87aa9f9..f49f0e502b8 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -261,7 +261,7 @@ static int chsc_examine_irb(struct chsc_request *request)
{
int backed_up;
- if (!scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND)
+ if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND))
return -EIO;
backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK;
request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 326f4cc7f92..3db2c386546 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -114,6 +114,7 @@ cio_tpi(void)
struct tpi_info *tpi_info;
struct subchannel *sch;
struct irb *irb;
+ int irq_context;
tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
if (tpi (NULL) != 1)
@@ -126,7 +127,9 @@ cio_tpi(void)
sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
if (!sch)
return 1;
- local_bh_disable();
+ irq_context = in_interrupt();
+ if (!irq_context)
+ local_bh_disable();
irq_enter ();
spin_lock(sch->lock);
memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
@@ -134,7 +137,8 @@ cio_tpi(void)
sch->driver->irq(sch);
spin_unlock(sch->lock);
irq_exit ();
- _local_bh_enable();
+ if (!irq_context)
+ _local_bh_enable();
return 1;
}
@@ -153,7 +157,7 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
"subchannel 0.%x.%04x!\n", sch->schid.ssid,
sch->schid.sch_no);
- sprintf(dbf_text, "no%s", sch->dev.bus_id);
+ sprintf(dbf_text, "no%s", dev_name(&sch->dev));
CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
@@ -171,7 +175,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
union orb *orb;
CIO_TRACE_EVENT(4, "stIO");
- CIO_TRACE_EVENT(4, sch->dev.bus_id);
+ CIO_TRACE_EVENT(4, dev_name(&sch->dev));
orb = &to_io_private(sch)->orb;
memset(orb, 0, sizeof(union orb));
@@ -232,7 +236,7 @@ cio_resume (struct subchannel *sch)
int ccode;
CIO_TRACE_EVENT (4, "resIO");
- CIO_TRACE_EVENT (4, sch->dev.bus_id);
+ CIO_TRACE_EVENT(4, dev_name(&sch->dev));
ccode = rsch (sch->schid);
@@ -269,7 +273,7 @@ cio_halt(struct subchannel *sch)
return -ENODEV;
CIO_TRACE_EVENT (2, "haltIO");
- CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&sch->dev));
/*
* Issue "Halt subchannel" and process condition code
@@ -304,7 +308,7 @@ cio_clear(struct subchannel *sch)
return -ENODEV;
CIO_TRACE_EVENT (2, "clearIO");
- CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&sch->dev));
/*
* Issue "Clear subchannel" and process condition code
@@ -340,7 +344,7 @@ cio_cancel (struct subchannel *sch)
return -ENODEV;
CIO_TRACE_EVENT (2, "cancelIO");
- CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&sch->dev));
ccode = xsch (sch->schid);
@@ -404,7 +408,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
int ret;
CIO_TRACE_EVENT (2, "ensch");
- CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&sch->dev));
if (sch_is_pseudo_sch(sch))
return -EINVAL;
@@ -454,7 +458,7 @@ int cio_disable_subchannel(struct subchannel *sch)
int ret;
CIO_TRACE_EVENT (2, "dissch");
- CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&sch->dev));
if (sch_is_pseudo_sch(sch))
return 0;
@@ -571,8 +575,10 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
}
mutex_init(&sch->reg_mutex);
/* Set a name for the subchannel */
- snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
- schid.sch_no);
+ if (cio_is_console(schid))
+ sch->dev.init_name = cio_get_console_sch_name(schid);
+ else
+ dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no);
/*
* The first subchannel that is not-operational (ccode==3)
@@ -677,6 +683,7 @@ do_IRQ (struct pt_regs *regs)
#ifdef CONFIG_CCW_CONSOLE
static struct subchannel console_subchannel;
+static char console_sch_name[10] = "0.x.xxxx";
static struct io_subchannel_private console_priv;
static int console_subchannel_in_use;
@@ -827,6 +834,12 @@ cio_get_console_subchannel(void)
return &console_subchannel;
}
+const char *cio_get_console_sch_name(struct subchannel_id schid)
+{
+ snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no);
+ return (const char *)console_sch_name;
+}
+
#endif
static int
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
@@ -846,19 +859,6 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
return -EBUSY; /* uhm... */
}
-/* we can't use the normal udelay here, since it enables external interrupts */
-
-static void udelay_reset(unsigned long usecs)
-{
- uint64_t start_cc, end_cc;
-
- asm volatile ("STCK %0" : "=m" (start_cc));
- do {
- cpu_relax();
- asm volatile ("STCK %0" : "=m" (end_cc));
- } while (((end_cc - start_cc)/4096) < usecs);
-}
-
static int
__clear_io_subchannel_easy(struct subchannel_id schid)
{
@@ -874,7 +874,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid)
if (schid_equal(&ti.schid, &schid))
return 0;
}
- udelay_reset(100);
+ udelay_simple(100);
}
return -EBUSY;
}
@@ -882,7 +882,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid)
static void __clear_chsc_subchannel_easy(void)
{
/* It seems we can only wait for a bit here :/ */
- udelay_reset(100);
+ udelay_simple(100);
}
static int pgm_check_occured;
@@ -892,7 +892,7 @@ static void cio_reset_pgm_check_handler(void)
pgm_check_occured = 1;
}
-static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
+static int stsch_reset(struct subchannel_id schid, struct schib *addr)
{
int rc;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 3b236d20e83..0fb24784e92 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -117,11 +117,15 @@ extern int cio_is_console(struct subchannel_id);
extern struct subchannel *cio_get_console_subchannel(void);
extern spinlock_t * cio_get_console_lock(void);
extern void *cio_get_console_priv(void);
+extern const char *cio_get_console_sch_name(struct subchannel_id schid);
+extern const char *cio_get_console_cdev_name(struct subchannel *sch);
#else
#define cio_is_console(schid) 0
#define cio_get_console_subchannel() NULL
#define cio_get_console_lock() NULL
#define cio_get_console_priv() NULL
+#define cio_get_console_sch_name(schid) NULL
+#define cio_get_console_cdev_name(sch) NULL
#endif
#endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 1261e1a9e8c..76bbb1e74c2 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -698,7 +698,7 @@ static int __init setup_css(int nr)
return -ENOMEM;
css->pseudo_subchannel->dev.parent = &css->device;
css->pseudo_subchannel->dev.release = css_subchannel_release;
- sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+ dev_set_name(&css->pseudo_subchannel->dev, "defunct");
ret = cio_create_sch_lock(css->pseudo_subchannel);
if (ret) {
kfree(css->pseudo_subchannel);
@@ -707,7 +707,7 @@ static int __init setup_css(int nr)
mutex_init(&css->mutex);
css->valid = 1;
css->cssid = nr;
- sprintf(css->device.bus_id, "css%x", nr);
+ dev_set_name(&css->device, "css%x", nr);
css->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
css_generate_pgid(css, tod_high);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 28221030b88..4e78c82194b 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -31,6 +31,7 @@
#include "device.h"
#include "ioasm.h"
#include "io_sch.h"
+#include "blacklist.h"
static struct timer_list recovery_timer;
static DEFINE_SPINLOCK(recovery_lock);
@@ -296,36 +297,33 @@ static void ccw_device_unregister(struct ccw_device *cdev)
device_del(&cdev->dev);
}
-static void ccw_device_remove_orphan_cb(struct device *dev)
+static void ccw_device_remove_orphan_cb(struct work_struct *work)
{
- struct ccw_device *cdev = to_ccwdev(dev);
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
ccw_device_unregister(cdev);
put_device(&cdev->dev);
+ /* Release cdev reference for workqueue processing. */
+ put_device(&cdev->dev);
}
-static void ccw_device_remove_sch_cb(struct device *dev)
-{
- struct subchannel *sch;
-
- sch = to_subchannel(dev);
- css_sch_device_unregister(sch);
- /* Reset intparm to zeroes. */
- sch->schib.pmcw.intparm = 0;
- cio_modify(sch);
- put_device(&sch->dev);
-}
+static void ccw_device_call_sch_unregister(struct work_struct *work);
static void
ccw_device_remove_disconnected(struct ccw_device *cdev)
{
unsigned long flags;
- int rc;
/*
* Forced offline in disconnected state means
* 'throw away device'.
*/
+ /* Get cdev reference for workqueue processing. */
+ if (!get_device(&cdev->dev))
+ return;
if (ccw_device_is_orphan(cdev)) {
/*
* Deregister ccw device.
@@ -335,23 +333,13 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
spin_lock_irqsave(cdev->ccwlock, flags);
cdev->private->state = DEV_STATE_NOT_OPER;
spin_unlock_irqrestore(cdev->ccwlock, flags);
- rc = device_schedule_callback(&cdev->dev,
- ccw_device_remove_orphan_cb);
- if (rc)
- CIO_MSG_EVENT(0, "Couldn't unregister orphan "
- "0.%x.%04x\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno);
- return;
- }
- /* Deregister subchannel, which will kill the ccw device. */
- rc = device_schedule_callback(cdev->dev.parent,
- ccw_device_remove_sch_cb);
- if (rc)
- CIO_MSG_EVENT(0, "Couldn't unregister disconnected device "
- "0.%x.%04x\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno);
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_remove_orphan_cb);
+ } else
+ /* Deregister subchannel, which will kill the ccw device. */
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister);
+ queue_work(slow_path_wq, &cdev->private->kick_work);
}
/**
@@ -970,12 +958,17 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
priv = container_of(work, struct ccw_device_private, kick_work);
cdev = priv->cdev;
+ /* Get subchannel reference for local processing. */
+ if (!get_device(cdev->dev.parent))
+ return;
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
+ /* Release cdev reference for workqueue processing.*/
put_device(&cdev->dev);
+ /* Release subchannel reference for local processing. */
put_device(&sch->dev);
}
@@ -1001,6 +994,8 @@ io_subchannel_recog_done(struct ccw_device *cdev)
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_call_sch_unregister);
queue_work(slow_path_wq, &cdev->private->kick_work);
+ /* Release subchannel reference for asynchronous recognition. */
+ put_device(&sch->dev);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
break;
@@ -1040,8 +1035,11 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
init_timer(&priv->timer);
/* Set an initial name for the device. */
- snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
- sch->schid.ssid, sch->schib.pmcw.dev);
+ if (cio_is_console(sch->schid))
+ cdev->dev.init_name = cio_get_console_cdev_name(sch);
+ else
+ dev_set_name(&cdev->dev, "0.%x.%04x",
+ sch->schid.ssid, sch->schib.pmcw.dev);
/* Increase counter of devices currently in recognition. */
atomic_inc(&ccw_device_init_count);
@@ -1106,7 +1104,7 @@ static void io_subchannel_irq(struct subchannel *sch)
cdev = sch_get_cdev(sch);
CIO_TRACE_EVENT(3, "IRQ");
- CIO_TRACE_EVENT(3, sch->dev.bus_id);
+ CIO_TRACE_EVENT(3, dev_name(&sch->dev));
if (cdev)
dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
}
@@ -1476,6 +1474,45 @@ static void ccw_device_schedule_recovery(void)
spin_unlock_irqrestore(&recovery_lock, flags);
}
+static int purge_fn(struct device *dev, void *data)
+{
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct ccw_device_private *priv = cdev->private;
+ int unreg;
+
+ spin_lock_irq(cdev->ccwlock);
+ unreg = is_blacklisted(priv->dev_id.ssid, priv->dev_id.devno) &&
+ (priv->state == DEV_STATE_OFFLINE);
+ spin_unlock_irq(cdev->ccwlock);
+ if (!unreg)
+ goto out;
+ if (!get_device(&cdev->dev))
+ goto out;
+ CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
+ priv->dev_id.devno);
+ PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister);
+ queue_work(slow_path_wq, &cdev->private->kick_work);
+
+out:
+ /* Abort loop in case of pending signal. */
+ if (signal_pending(current))
+ return -EINTR;
+
+ return 0;
+}
+
+/**
+ * ccw_purge_blacklisted - purge unused, blacklisted devices
+ *
+ * Unregister all ccw devices that are offline and on the blacklist.
+ */
+int ccw_purge_blacklisted(void)
+{
+ CIO_MSG_EVENT(2, "ccw: purging blacklisted devices\n");
+ bus_for_each_dev(&ccw_bus_type, NULL, NULL, purge_fn);
+ return 0;
+}
+
static void device_set_disconnected(struct ccw_device *cdev)
{
if (!cdev)
@@ -1492,7 +1529,7 @@ void ccw_device_set_notoper(struct ccw_device *cdev)
struct subchannel *sch = to_subchannel(cdev->dev.parent);
CIO_TRACE_EVENT(2, "notoper");
- CIO_TRACE_EVENT(2, sch->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&sch->dev));
ccw_device_set_timeout(cdev, 0);
cio_disable_subchannel(sch);
cdev->private->state = DEV_STATE_NOT_OPER;
@@ -1591,6 +1628,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow)
#ifdef CONFIG_CCW_CONSOLE
static struct ccw_device console_cdev;
+static char console_cdev_name[10] = "0.x.xxxx";
static struct ccw_device_private console_private;
static int console_cdev_in_use;
@@ -1661,6 +1699,14 @@ ccw_device_probe_console(void)
console_cdev.online = 1;
return &console_cdev;
}
+
+
+const char *cio_get_console_cdev_name(struct subchannel *sch)
+{
+ snprintf(console_cdev_name, 10, "0.%x.%04x",
+ sch->schid.ssid, sch->schib.pmcw.dev);
+ return (const char *)console_cdev_name;
+}
#endif
/*
@@ -1673,7 +1719,7 @@ __ccwdev_check_busid(struct device *dev, void *id)
bus_id = id;
- return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0);
+ return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0);
}
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 6f5c3f2b358..104ed669db4 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -86,6 +86,7 @@ int ccw_device_is_orphan(struct ccw_device *);
int ccw_device_recognition(struct ccw_device *);
int ccw_device_online(struct ccw_device *);
int ccw_device_offline(struct ccw_device *);
+int ccw_purge_blacklisted(void);
/* Function prototypes for device status and basic sense stuff. */
void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 84cc9ea346d..10bc03940fb 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -52,8 +52,10 @@ static void ccw_timeout_log(struct ccw_device *cdev)
printk(KERN_WARNING "cio: orb:\n");
print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
orb, sizeof(*orb), 0);
- printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
- printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
+ printk(KERN_WARNING "cio: ccw device bus id: %s\n",
+ dev_name(&cdev->dev));
+ printk(KERN_WARNING "cio: subchannel bus id: %s\n",
+ dev_name(&sch->dev));
printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
"vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index ee1a28310fb..eabcc42d63d 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -498,7 +498,7 @@ ccw_device_stlck(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
CIO_TRACE_EVENT(2, "stl lock");
- CIO_TRACE_EVENT(2, cdev->dev.bus_id);
+ CIO_TRACE_EVENT(2, dev_name(&cdev->dev));
buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
if (!buf)
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 3f8f1cf69c7..c4f3e7c9a85 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -123,7 +123,7 @@ struct ccw_device_private {
void *cmb_wait; /* deferred cmb enable/disable */
};
-static inline int ssch(struct subchannel_id schid, volatile union orb *addr)
+static inline int ssch(struct subchannel_id schid, union orb *addr)
{
register struct subchannel_id reg1 asm("1") = schid;
int ccode = -EIO;
@@ -134,7 +134,9 @@ static inline int ssch(struct subchannel_id schid, volatile union orb *addr)
" srl %0,28\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc", "memory");
return ccode;
}
@@ -147,7 +149,9 @@ static inline int rsch(struct subchannel_id schid)
" rsch\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc", "memory");
return ccode;
}
@@ -160,7 +164,9 @@ static inline int csch(struct subchannel_id schid)
" csch\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
return ccode;
}
@@ -173,7 +179,9 @@ static inline int hsch(struct subchannel_id schid)
" hsch\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
return ccode;
}
@@ -186,7 +194,9 @@ static inline int xsch(struct subchannel_id schid)
" .insn rre,0xb2760000,%1,0\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
return ccode;
}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 9fa2ac13ac8..75926279263 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -23,38 +23,39 @@ struct tpi_info {
* Some S390 specific IO instructions as inline
*/
-static inline int stsch(struct subchannel_id schid,
- volatile struct schib *addr)
+static inline int stsch(struct subchannel_id schid, struct schib *addr)
{
register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
asm volatile(
- " stsch 0(%2)\n"
+ " stsch 0(%3)\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ : "=d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
return ccode;
}
-static inline int stsch_err(struct subchannel_id schid,
- volatile struct schib *addr)
+static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
{
register struct subchannel_id reg1 asm ("1") = schid;
int ccode = -EIO;
asm volatile(
- " stsch 0(%2)\n"
+ " stsch 0(%3)\n"
"0: ipm %0\n"
" srl %0,28\n"
"1:\n"
EX_TABLE(0b,1b)
- : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ : "+d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
return ccode;
}
-static inline int msch(struct subchannel_id schid,
- volatile struct schib *addr)
+static inline int msch(struct subchannel_id schid, struct schib *addr)
{
register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
@@ -63,12 +64,13 @@ static inline int msch(struct subchannel_id schid,
" msch 0(%2)\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ : "=d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc");
return ccode;
}
-static inline int msch_err(struct subchannel_id schid,
- volatile struct schib *addr)
+static inline int msch_err(struct subchannel_id schid, struct schib *addr)
{
register struct subchannel_id reg1 asm ("1") = schid;
int ccode = -EIO;
@@ -79,33 +81,38 @@ static inline int msch_err(struct subchannel_id schid,
" srl %0,28\n"
"1:\n"
EX_TABLE(0b,1b)
- : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc");
return ccode;
}
-static inline int tsch(struct subchannel_id schid,
- volatile struct irb *addr)
+static inline int tsch(struct subchannel_id schid, struct irb *addr)
{
register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
asm volatile(
- " tsch 0(%2)\n"
+ " tsch 0(%3)\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+ : "=d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
return ccode;
}
-static inline int tpi( volatile struct tpi_info *addr)
+static inline int tpi(struct tpi_info *addr)
{
int ccode;
asm volatile(
- " tpi 0(%1)\n"
+ " tpi 0(%2)\n"
" ipm %0\n"
" srl %0,28"
- : "=d" (ccode) : "a" (addr), "m" (*addr) : "cc");
+ : "=d" (ccode), "=m" (*addr)
+ : "a" (addr)
+ : "cc");
return ccode;
}
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index c1a70985abf..e3ea1d5f281 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -16,6 +16,14 @@
#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */
#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */
+/*
+ * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait
+ * till next initiative to give transmitted skbs back to the stack is too long.
+ * Therefore polling is started in case of multicast queue is filled more
+ * than 50 percent.
+ */
+#define QDIO_IQDIO_POLL_LVL 65 /* HS multicast queue */
+
enum qdio_irq_states {
QDIO_IRQ_STATE_INACTIVE,
QDIO_IRQ_STATE_ESTABLISHED,
@@ -195,6 +203,9 @@ struct qdio_output_q {
/* PCIs are enabled for the queue */
int pci_out_enabled;
+ /* IQDIO: output multiple buffers (enhanced SIGA) */
+ int use_enh_siga;
+
/* timer to check for more outbound work */
struct timer_list timer;
};
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 337aa3087a7..b5390821434 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -155,7 +155,7 @@ static int qstat_seq_open(struct inode *inode, struct file *filp)
static void get_queue_name(struct qdio_q *q, struct ccw_device *cdev, char *name)
{
memset(name, 0, sizeof(name));
- sprintf(name, "%s", cdev->dev.bus_id);
+ sprintf(name, "%s", dev_name(&cdev->dev));
if (q->is_input_q)
sprintf(name + strlen(name), "_input");
else
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index e6eabc85342..a50682d2a0f 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -316,6 +316,9 @@ static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
unsigned int fc = 0;
unsigned long schid;
+ if (q->u.out.use_enh_siga) {
+ fc = 3;
+ }
if (!is_qebsm(q))
schid = *((u32 *)&q->irq_ptr->schid);
else {
@@ -851,6 +854,12 @@ static void __qdio_outbound_processing(struct qdio_q *q)
if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q))
return;
+ if ((queue_type(q) == QDIO_IQDIO_QFMT) &&
+ (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) {
+ tasklet_schedule(&q->tasklet);
+ return;
+ }
+
if (q->u.out.pci_out_enabled)
return;
@@ -956,7 +965,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev,
char dbf_text[15];
QDIO_DBF_TEXT2(1, trace, "ick2");
- sprintf(dbf_text, "%s", cdev->dev.bus_id);
+ sprintf(dbf_text, "%s", dev_name(&cdev->dev));
QDIO_DBF_TEXT2(1, trace, dbf_text);
QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int));
QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int));
@@ -1443,6 +1452,8 @@ int qdio_establish(struct qdio_initialize *init_data)
}
qdio_setup_ssqd_info(irq_ptr);
+ sprintf(dbf_text, "qDmmwc%2x", irq_ptr->ssqd_desc.mmwc);
+ QDIO_DBF_TEXT2(0, setup, dbf_text);
sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac);
QDIO_DBF_TEXT2(0, setup, dbf_text);
@@ -1615,12 +1626,21 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
if (multicast_outbound(q))
qdio_kick_outbound_q(q);
else
- /*
- * One siga-w per buffer required for unicast
- * HiperSockets.
- */
- while (count--)
+ if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
+ (count > 1) &&
+ (count <= q->irq_ptr->ssqd_desc.mmwc)) {
+ /* exploit enhanced SIGA */
+ q->u.out.use_enh_siga = 1;
qdio_kick_outbound_q(q);
+ } else {
+ /*
+ * One siga-w per buffer required for unicast
+ * HiperSockets.
+ */
+ q->u.out.use_enh_siga = 0;
+ while (count--)
+ qdio_kick_outbound_q(q);
+ }
goto out;
}
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 62b6b55230d..326db1e827c 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -892,8 +892,8 @@ static void ap_scan_bus(struct work_struct *unused)
ap_dev->device.bus = &ap_bus_type;
ap_dev->device.parent = ap_root_device;
- snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x",
- AP_QID_DEVICE(ap_dev->qid));
+ dev_set_name(&ap_dev->device, "card%02x",
+ AP_QID_DEVICE(ap_dev->qid));
ap_dev->device.release = ap_device_release;
rc = device_register(&ap_dev->device);
if (rc) {
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 292b60da6dc..ff4a6931bb8 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -24,6 +24,7 @@
#include <asm/kvm_virtio.h>
#include <asm/setup.h>
#include <asm/s390_ext.h>
+#include <asm/s390_rdev.h>
#define VIRTIO_SUBCODE_64 0x0D00
@@ -241,10 +242,7 @@ static struct virtio_config_ops kvm_vq_configspace_ops = {
* The root device for the kvm virtio devices.
* This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2.
*/
-static struct device kvm_root = {
- .parent = NULL,
- .bus_id = "kvm_s390",
-};
+static struct device *kvm_root;
/*
* adds a new device and register it with virtio
@@ -261,7 +259,7 @@ static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset)
return;
}
- kdev->vdev.dev.parent = &kvm_root;
+ kdev->vdev.dev.parent = kvm_root;
kdev->vdev.id.device = d->type;
kdev->vdev.config = &kvm_vq_configspace_ops;
kdev->desc = d;
@@ -317,15 +315,16 @@ static int __init kvm_devices_init(void)
if (!MACHINE_IS_KVM)
return -ENODEV;
- rc = device_register(&kvm_root);
- if (rc) {
+ kvm_root = s390_root_dev_register("kvm_s390");
+ if (IS_ERR(kvm_root)) {
+ rc = PTR_ERR(kvm_root);
printk(KERN_ERR "Could not register kvm_s390 root device");
return rc;
}
rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE);
if (rc) {
- device_unregister(&kvm_root);
+ s390_root_dev_unregister(kvm_root);
return rc;
}
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index e10ac9ab2d4..8f83fc994f5 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -299,7 +299,7 @@ claw_probe(struct ccwgroup_device *cgdev)
probe_error(cgdev);
put_device(&cgdev->dev);
printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n",
- cgdev->cdev[0]->dev.bus_id,__func__,__LINE__);
+ dev_name(&cgdev->cdev[0]->dev), __func__, __LINE__);
CLAW_DBF_TEXT_(2, setup, "probex%d", rc);
return rc;
}
@@ -584,7 +584,7 @@ claw_irq_handler(struct ccw_device *cdev,
if (!cdev->dev.driver_data) {
printk(KERN_WARNING "claw: unsolicited interrupt for device:"
"%s received c-%02x d-%02x\n",
- cdev->dev.bus_id, irb->scsw.cmd.cstat,
+ dev_name(&cdev->dev), irb->scsw.cmd.cstat,
irb->scsw.cmd.dstat);
CLAW_DBF_TEXT(2, trace, "badirq");
return;
@@ -598,7 +598,7 @@ claw_irq_handler(struct ccw_device *cdev,
p_ch = &privptr->channel[WRITE];
else {
printk(KERN_WARNING "claw: Can't determine channel for "
- "interrupt, device %s\n", cdev->dev.bus_id);
+ "interrupt, device %s\n", dev_name(&cdev->dev));
CLAW_DBF_TEXT(2, trace, "badchan");
return;
}
@@ -662,7 +662,7 @@ claw_irq_handler(struct ccw_device *cdev,
printk(KERN_WARNING "claw: unsolicited "
"interrupt for device:"
"%s received c-%02x d-%02x\n",
- cdev->dev.bus_id,
+ dev_name(&cdev->dev),
irb->scsw.cmd.cstat,
irb->scsw.cmd.dstat);
return;
@@ -1136,19 +1136,20 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code)
break;
case -ENODEV:
printk(KERN_EMERG "%s: Missing device called "
- "for IO ENODEV\n", cdev->dev.bus_id);
+ "for IO ENODEV\n", dev_name(&cdev->dev));
break;
case -EIO:
printk(KERN_EMERG "%s: Status pending... EIO \n",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
break;
case -EINVAL:
printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n",
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
break;
default:
printk(KERN_EMERG "%s: Unknown error in "
- "Do_IO %d\n",cdev->dev.bus_id, return_code);
+ "Do_IO %d\n", dev_name(&cdev->dev),
+ return_code);
}
}
CLAW_DBF_TEXT(4, trace, "ccwret");
@@ -2848,11 +2849,11 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
struct chbk *p_ch;
struct ccw_dev_id dev_id;
- CLAW_DBF_TEXT_(2, setup, "%s", cdev->dev.bus_id);
+ CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cdev->dev));
privptr->channel[i].flag = i+1; /* Read is 1 Write is 2 */
p_ch = &privptr->channel[i];
p_ch->cdev = cdev;
- snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
+ snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", dev_name(&cdev->dev));
ccw_device_get_id(cdev, &dev_id);
p_ch->devno = dev_id.devno;
if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
@@ -2879,7 +2880,8 @@ claw_new_device(struct ccwgroup_device *cgdev)
int ret;
struct ccw_dev_id dev_id;
- printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id);
+ printk(KERN_INFO "claw: add for %s\n",
+ dev_name(&cgdev->cdev[READ]->dev));
CLAW_DBF_TEXT(2, setup, "new_dev");
privptr = cgdev->dev.driver_data;
cgdev->cdev[READ]->dev.driver_data = privptr;
@@ -2903,14 +2905,16 @@ claw_new_device(struct ccwgroup_device *cgdev)
if (ret != 0) {
printk(KERN_WARNING
"claw: ccw_device_set_online %s READ failed "
- "with ret = %d\n",cgdev->cdev[READ]->dev.bus_id,ret);
+ "with ret = %d\n", dev_name(&cgdev->cdev[READ]->dev),
+ ret);
goto out;
}
ret = ccw_device_set_online(cgdev->cdev[WRITE]);
if (ret != 0) {
printk(KERN_WARNING
"claw: ccw_device_set_online %s WRITE failed "
- "with ret = %d\n",cgdev->cdev[WRITE]->dev.bus_id, ret);
+ "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev)
+ ret);
goto out;
}
dev = alloc_netdev(0,"claw%d",claw_init_netdevice);
@@ -2986,7 +2990,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev)
struct net_device *ndev;
int ret;
- CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id);
+ CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
priv = cgdev->dev.driver_data;
if (!priv)
return -ENODEV;
@@ -3016,11 +3020,11 @@ claw_remove_device(struct ccwgroup_device *cgdev)
struct claw_privbk *priv;
BUG_ON(!cgdev);
- CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id);
+ CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
priv = cgdev->dev.driver_data;
BUG_ON(!priv);
printk(KERN_INFO "claw: %s() called %s will be removed.\n",
- __func__,cgdev->cdev[0]->dev.bus_id);
+ __func__, dev_name(&cgdev->cdev[0]->dev));
if (cgdev->state == CCWGROUP_ONLINE)
claw_shutdown_device(cgdev);
claw_remove_files(&cgdev->dev);
diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h
index 1a89d989f34..005072c420d 100644
--- a/drivers/s390/net/claw.h
+++ b/drivers/s390/net/claw.h
@@ -85,7 +85,7 @@
#define CLAW_MAX_DEV 256 /* max claw devices */
#define MAX_NAME_LEN 8 /* host name, adapter name length */
#define CLAW_FRAME_SIZE 4096
-#define CLAW_ID_SIZE BUS_ID_SIZE+3
+#define CLAW_ID_SIZE 20+3
/* state machine codes used in claw_irq_handler */
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index b11fec24c7d..a4e29836a2a 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -277,18 +277,18 @@ static long ctcm_check_irb_error(struct ccw_device *cdev, struct irb *irb)
CTCM_DBF_TEXT_(ERROR, CTC_DBF_WARN,
"irb error %ld on device %s\n",
- PTR_ERR(irb), cdev->dev.bus_id);
+ PTR_ERR(irb), dev_name(&cdev->dev));
switch (PTR_ERR(irb)) {
case -EIO:
- ctcm_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id);
+ ctcm_pr_warn("i/o-error on device %s\n", dev_name(&cdev->dev));
break;
case -ETIMEDOUT:
- ctcm_pr_warn("timeout on device %s\n", cdev->dev.bus_id);
+ ctcm_pr_warn("timeout on device %s\n", dev_name(&cdev->dev));
break;
default:
ctcm_pr_warn("unknown error %ld on device %s\n",
- PTR_ERR(irb), cdev->dev.bus_id);
+ PTR_ERR(irb), dev_name(&cdev->dev));
}
return PTR_ERR(irb);
}
@@ -1182,7 +1182,7 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
int dstat;
CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
- "Enter %s(%s)", CTCM_FUNTAIL, &cdev->dev.bus_id);
+ "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev));
if (ctcm_check_irb_error(cdev, irb))
return;
@@ -1208,14 +1208,14 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
ch = priv->channel[WRITE];
else {
ctcm_pr_err("ctcm: Can't determine channel for interrupt, "
- "device %s\n", cdev->dev.bus_id);
+ "device %s\n", dev_name(&cdev->dev));
return;
}
dev = ch->netdev;
if (dev == NULL) {
ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n",
- __func__, cdev->dev.bus_id, ch);
+ __func__, dev_name(&cdev->dev), ch);
return;
}
@@ -1329,7 +1329,7 @@ static int add_channel(struct ccw_device *cdev, enum channel_types type,
CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO,
"%s(%s), type %d, proto %d",
- __func__, cdev->dev.bus_id, type, priv->protocol);
+ __func__, dev_name(&cdev->dev), type, priv->protocol);
ch = kzalloc(sizeof(struct channel), GFP_KERNEL);
if (ch == NULL)
@@ -1358,7 +1358,7 @@ static int add_channel(struct ccw_device *cdev, enum channel_types type,
goto nomem_return;
ch->cdev = cdev;
- snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", cdev->dev.bus_id);
+ snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev));
ch->type = type;
/**
@@ -1518,8 +1518,8 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
type = get_channel_type(&cdev0->id);
- snprintf(read_id, CTCM_ID_SIZE, "ch-%s", cdev0->dev.bus_id);
- snprintf(write_id, CTCM_ID_SIZE, "ch-%s", cdev1->dev.bus_id);
+ snprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev));
+ snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev));
ret = add_channel(cdev0, type, priv);
if (ret)
diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h
index 8e10ee86a5e..d77cce3fe4d 100644
--- a/drivers/s390/net/ctcm_main.h
+++ b/drivers/s390/net/ctcm_main.h
@@ -104,7 +104,7 @@
#define READ 0
#define WRITE 1
-#define CTCM_ID_SIZE BUS_ID_SIZE+3
+#define CTCM_ID_SIZE 20+3
struct ctcm_profile {
unsigned long maxmulti;
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 9bcfa04d863..0825be87e5a 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -492,7 +492,7 @@ lcs_start_channel(struct lcs_channel *channel)
unsigned long flags;
int rc;
- LCS_DBF_TEXT_(4,trace,"ssch%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4, trace,"ssch%s", dev_name(&channel->ccwdev->dev));
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_start(channel->ccwdev,
channel->ccws + channel->io_idx, 0, 0,
@@ -501,7 +501,8 @@ lcs_start_channel(struct lcs_channel *channel)
channel->state = LCS_CH_STATE_RUNNING;
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) {
- LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4,trace,"essh%s",
+ dev_name(&channel->ccwdev->dev));
PRINT_ERR("Error in starting channel, rc=%d!\n", rc);
}
return rc;
@@ -514,12 +515,13 @@ lcs_clear_channel(struct lcs_channel *channel)
int rc;
LCS_DBF_TEXT(4,trace,"clearch");
- LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4, trace, "%s", dev_name(&channel->ccwdev->dev));
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_clear(channel->ccwdev, (addr_t) channel);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) {
- LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4, trace, "ecsc%s",
+ dev_name(&channel->ccwdev->dev));
return rc;
}
wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_CLEARED));
@@ -540,13 +542,14 @@ lcs_stop_channel(struct lcs_channel *channel)
if (channel->state == LCS_CH_STATE_STOPPED)
return 0;
LCS_DBF_TEXT(4,trace,"haltsch");
- LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4, trace, "%s", dev_name(&channel->ccwdev->dev));
channel->state = LCS_CH_STATE_INIT;
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_halt(channel->ccwdev, (addr_t) channel);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) {
- LCS_DBF_TEXT_(4,trace,"ehsc%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4, trace, "ehsc%s",
+ dev_name(&channel->ccwdev->dev));
return rc;
}
/* Asynchronous halt initialted. Wait for its completion. */
@@ -632,10 +635,11 @@ __lcs_resume_channel(struct lcs_channel *channel)
return 0;
if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND)
return 0;
- LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(5, trace, "rsch%s", dev_name(&channel->ccwdev->dev));
rc = ccw_device_resume(channel->ccwdev);
if (rc) {
- LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(4, trace, "ersc%s",
+ dev_name(&channel->ccwdev->dev));
PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc);
} else
channel->state = LCS_CH_STATE_RUNNING;
@@ -1302,18 +1306,18 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb)
switch (PTR_ERR(irb)) {
case -EIO:
- PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
+ PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev));
LCS_DBF_TEXT(2, trace, "ckirberr");
LCS_DBF_TEXT_(2, trace, " rc%d", -EIO);
break;
case -ETIMEDOUT:
- PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
+ PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev));
LCS_DBF_TEXT(2, trace, "ckirberr");
LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT);
break;
default:
PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
LCS_DBF_TEXT(2, trace, "ckirberr");
LCS_DBF_TEXT(2, trace, " rc???");
}
@@ -1390,7 +1394,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
- LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id);
+ LCS_DBF_TEXT_(5, trace, "Rint%s", dev_name(&cdev->dev));
LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.cstat,
irb->scsw.cmd.dstat);
LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.fctl,
@@ -1400,7 +1404,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
rc = lcs_get_problem(cdev, irb);
if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) {
PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
- cdev->dev.bus_id, dstat, cstat);
+ dev_name(&cdev->dev), dstat, cstat);
if (rc) {
channel->state = LCS_CH_STATE_ERROR;
}
@@ -1463,7 +1467,7 @@ lcs_tasklet(unsigned long data)
int rc;
channel = (struct lcs_channel *) data;
- LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id);
+ LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev));
/* Check for processed buffers. */
iob = channel->iob;
@@ -2244,7 +2248,7 @@ lcs_recovery(void *ptr)
return 0;
LCS_DBF_TEXT(4, trace, "recover2");
gdev = card->gdev;
- PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id);
+ PRINT_WARN("Recovery of device %s started...\n", dev_name(&gdev->dev));
rc = __lcs_shutdown_device(gdev, 1);
rc = lcs_new_device(gdev);
if (!rc)
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 9242b5acc66..0fea51e34b5 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1724,7 +1724,7 @@ static int netiucv_register_device(struct net_device *ndev)
IUCV_DBF_TEXT(trace, 3, __func__);
if (dev) {
- snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name);
+ dev_set_name(dev, "net%s", ndev->name);
dev->bus = &iucv_bus;
dev->parent = iucv_root;
/*
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index bf8a75c92f2..af6d6045851 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -90,11 +90,11 @@ struct qeth_dbf_info {
#define CARD_RDEV(card) card->read.ccwdev
#define CARD_WDEV(card) card->write.ccwdev
#define CARD_DDEV(card) card->data.ccwdev
-#define CARD_BUS_ID(card) card->gdev->dev.bus_id
-#define CARD_RDEV_ID(card) card->read.ccwdev->dev.bus_id
-#define CARD_WDEV_ID(card) card->write.ccwdev->dev.bus_id
-#define CARD_DDEV_ID(card) card->data.ccwdev->dev.bus_id
-#define CHANNEL_ID(channel) channel->ccwdev->dev.bus_id
+#define CARD_BUS_ID(card) dev_name(&card->gdev->dev)
+#define CARD_RDEV_ID(card) dev_name(&card->read.ccwdev->dev)
+#define CARD_WDEV_ID(card) dev_name(&card->write.ccwdev->dev)
+#define CARD_DDEV_ID(card) dev_name(&card->data.ccwdev->dev)
+#define CHANNEL_ID(channel) dev_name(&channel->ccwdev->dev)
/**
* card stuff
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index c7ab1b86451..141b2bb7b3c 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -745,7 +745,7 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ",
- cdev->dev.bus_id, dstat, cstat);
+ dev_name(&cdev->dev), dstat, cstat);
print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
16, 1, irb, 64, 1);
return 1;
@@ -784,12 +784,12 @@ static long __qeth_check_irb_error(struct ccw_device *cdev,
switch (PTR_ERR(irb)) {
case -EIO:
- PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
+ PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev));
QETH_DBF_TEXT(TRACE, 2, "ckirberr");
QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO);
break;
case -ETIMEDOUT:
- PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
+ PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev));
QETH_DBF_TEXT(TRACE, 2, "ckirberr");
QETH_DBF_TEXT_(TRACE, 2, " rc%d", -ETIMEDOUT);
if (intparm == QETH_RCD_PARM) {
@@ -803,7 +803,7 @@ static long __qeth_check_irb_error(struct ccw_device *cdev,
break;
default:
PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
- cdev->dev.bus_id);
+ dev_name(&cdev->dev));
QETH_DBF_TEXT(TRACE, 2, "ckirberr");
QETH_DBF_TEXT(TRACE, 2, " rc???");
}
@@ -4081,7 +4081,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
if (!get_device(dev))
return -ENODEV;
- QETH_DBF_TEXT_(SETUP, 2, "%s", gdev->dev.bus_id);
+ QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev));
card = qeth_alloc_card();
if (!card) {
diff --git a/drivers/s390/s390_rdev.c b/drivers/s390/s390_rdev.c
index 3c7145d9f9a..64371c05a3b 100644
--- a/drivers/s390/s390_rdev.c
+++ b/drivers/s390/s390_rdev.c
@@ -30,7 +30,7 @@ s390_root_dev_register(const char *name)
dev = kzalloc(sizeof(struct device), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
- strncpy(dev->bus_id, name, min(strlen(name), (size_t)BUS_ID_SIZE));
+ dev_set_name(dev, name);
dev->release = s390_root_dev_release;
ret = device_register(dev);
if (ret) {
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 24255e42dc3..3b56220fb90 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -283,8 +283,8 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
unit->port = port;
unit->fcp_lun = fcp_lun;
- snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx",
- (unsigned long long) fcp_lun);
+ dev_set_name(&unit->sysfs_device, "0x%016llx",
+ (unsigned long long) fcp_lun);
unit->sysfs_device.parent = &port->sysfs_device;
unit->sysfs_device.release = zfcp_sysfs_unit_release;
dev_set_drvdata(&unit->sysfs_device, unit);
@@ -610,8 +610,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set(&port->refcount, 0);
- snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx",
- (unsigned long long) wwpn);
+ dev_set_name(&port->sysfs_device, "0x%016llx", wwpn);
port->sysfs_device.parent = &adapter->ccw_device->dev;
port->sysfs_device.release = zfcp_sysfs_port_release;
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 73eb41580f2..8a13071c444 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -596,7 +596,7 @@ struct zfcp_data {
struct semaphore config_sema; /* serialises configuration
changes */
atomic_t loglevel; /* current loglevel */
- char init_busid[BUS_ID_SIZE];
+ char init_busid[20];
u64 init_wwpn;
u64 init_fcp_lun;
struct kmem_cache *fsf_req_qtcb_cache;
@@ -619,7 +619,7 @@ struct zfcp_fsf_req_qtcb {
#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200
-#define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id)
+#define zfcp_get_busid_by_adapter(adapter) (dev_name(&adapter->ccw_device->dev))
/*
* Helper functions for request ID management.
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 78231313187..9040f738ff3 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1376,7 +1376,7 @@ static int zfcp_erp_thread(void *data)
struct zfcp_erp_action *act;
unsigned long flags;
- daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id);
+ daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
/* Block all signals */
siginitsetinv(&current->blocked, 0);
atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 2809d789b55..ca9293ba176 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -381,7 +381,7 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \
static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
- unit->port->adapter->ccw_device->dev.bus_id);
+ dev_name(&unit->port->adapter->ccw_device->dev));
ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
(unsigned long long) unit->port->wwpn);
ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n",
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index f9575c40912..9c32063a0c2 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -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/linux/cpufreq.h b/include/linux/cpufreq.h
index 6fd5668aa57..1ee608fd7b7 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -187,7 +187,8 @@ extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int relation);
-extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy);
+extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
+ unsigned int cpu);
int cpufreq_register_governor(struct cpufreq_governor *governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor);
@@ -226,7 +227,9 @@ struct cpufreq_driver {
unsigned int (*get) (unsigned int cpu);
/* optional */
- unsigned int (*getavg) (unsigned int cpu);
+ unsigned int (*getavg) (struct cpufreq_policy *policy,
+ unsigned int cpu);
+
int (*exit) (struct cpufreq_policy *policy);
int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);
int (*resume) (struct cpufreq_policy *policy);
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 8cf8cfe2cc9..98921a3e1aa 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -126,7 +126,7 @@ static inline ktime_t tick_nohz_get_sleep_length(void)
return len;
}
static inline void tick_nohz_stop_idle(int cpu) { }
-static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return 0; }
+static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
# endif /* !NO_HZ */
#endif
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
deleted file mode 100644
index d9aebdf6db6..00000000000
--- a/include/sound/ad1848.h
+++ /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 */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 3eaf155b850..2c4dc908a54 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -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;
diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h
index a6e0facf8a3..20ebf3298eb 100644
--- a/include/sound/asoundef.h
+++ b/include/sound/asoundef.h
@@ -60,35 +60,56 @@
#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 */
@@ -106,8 +127,16 @@
#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 */
@@ -120,6 +149,26 @@
#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 */
/*****************************************************************************
* *
diff --git a/include/sound/core.h b/include/sound/core.h
index 558b96284bd..e5eec5f7350 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -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
index f0785f9f4ae..00000000000
--- a/include/sound/cs4231.h
+++ /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
index 00000000000..b1b2b8b59ad
--- /dev/null
+++ b/include/sound/jack.h
@@ -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
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index ae2921d9ddc..d787a6b4a10 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -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,
diff --git a/include/sound/minors.h b/include/sound/minors.h
index 46bcd2023ed..a81798ab73e 100644
--- a/include/sound/minors.h
+++ b/include/sound/minors.h
@@ -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)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 51d58ccda2d..40c5a6fa6bc 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -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
index 00000000000..2fd3d251d9a
--- /dev/null
+++ b/include/sound/pxa2xx-lib.h
@@ -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
diff --git a/include/sound/sb.h b/include/sound/sb.h
index d0c9ed3546c..85f93c5fe1e 100644
--- a/include/sound/sb.h
+++ b/include/sound/sb.h
@@ -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
diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h
index 9688d4be918..fa149ca77e4 100644
--- a/include/sound/snd_wavefront.h
+++ b/include/sound/snd_wavefront.h
@@ -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
index 00000000000..a064e1934a5
--- /dev/null
+++ b/include/sound/soc-of-simple.h
@@ -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_ */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 1890d87c520..a1e0357a84d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -26,10 +26,12 @@
/*
* 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,\
@@ -43,64 +45,68 @@
.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 |\
@@ -108,7 +114,7 @@
.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;
};
diff --git a/include/sound/version.h b/include/sound/version.h
index 6b78aff273a..4aafeda8863 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -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 ""
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index 4830651cc4c..5456343ebe4 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -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
index 00000000000..fd01f22825c
--- /dev/null
+++ b/include/sound/wss.h
@@ -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 */
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index cb02324bdb8..a4d21939816 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -20,6 +20,7 @@
#include <linux/profile.h>
#include <linux/sched.h>
#include <linux/tick.h>
+#include <linux/module.h>
#include <asm/irq_regs.h>
@@ -190,9 +191,17 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
{
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
- *last_update_time = ktime_to_us(ts->idle_lastupdate);
+ if (!tick_nohz_enabled)
+ return -1;
+
+ if (ts->idle_active)
+ *last_update_time = ktime_to_us(ts->idle_lastupdate);
+ else
+ *last_update_time = ktime_to_us(ktime_get());
+
return ktime_to_us(ts->idle_sleeptime);
}
+EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);
/**
* tick_nohz_stop_sched_tick - stop the idle tick from the idle task
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index 3eca62566d6..f7e8e93ff30 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -81,7 +81,10 @@ my (@stack, $re, $dre, $x, $xs);
$re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
} elsif ($arch =~ /^s390x?$/) {
# 11160: a7 fb ff 60 aghi %r15,-160
- $re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+ # or
+ # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15)
+ $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
+ (?:\(\%r15\))?$/ox;
} elsif ($arch =~ /^sh64$/) {
#XXX: we only check for the immediate case presently,
# though we will want to check for the movi/sub
diff --git a/sound/Kconfig b/sound/Kconfig
index 8ebf512ced6..200aca1faa7 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -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.
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 7a16a3331f7..6c515b2b8bb 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -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,
},
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 351e19ea378..f8e6de48d81 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -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.
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 4ef6dd00c6e..2054de11de8 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -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
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index b0a47449496..89096e811a4 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -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
index 00000000000..99026dfb81e
--- /dev/null
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -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");
+
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 199cca3366d..cba71d86754 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -12,198 +12,27 @@
#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
index 00000000000..1c93eb77cb9
--- /dev/null
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -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");
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index 381094aab23..535704f7749 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -10,183 +10,20 @@
* 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,
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
index b79f1e80378..5c4a4d38a08 100644
--- a/sound/arm/pxa2xx-pcm.h
+++ b/sound/arm/pxa2xx-pcm.h
@@ -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;
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
index b9c51bf8cd7..1dcd51d81d1 100644
--- a/sound/arm/sa11xx-uda1341.c
+++ b/sound/arm/sa11xx-uda1341.c
@@ -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;
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 335d45ecde6..66348c92f88 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -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
diff --git a/sound/core/Makefile b/sound/core/Makefile
index da8e685eef9..d57125a5687 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -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
diff --git a/sound/core/control.c b/sound/core/control.c
index 281b2e2ef0e..6d71f9a7ccb 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -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);
}
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 6101259ad86..368dc9c4aef 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -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:
diff --git a/sound/core/device.c b/sound/core/device.c
index 202dac0e4d8..c58d8227254 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -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:
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 6d6589f9389..195cafc5a55 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -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);
diff --git a/sound/core/info.c b/sound/core/info.c
index c67773ad929..527b207462b 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -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);
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index e35789a9275..e4af138d651 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -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) {
diff --git a/sound/core/init.c b/sound/core/init.c
index df46bbc25dc..8af467df924 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -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
index 00000000000..8133a2b173a
--- /dev/null
+++ b/sound/core/jack.c
@@ -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");
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index f5d6d8d1297..a7b46ec72f3 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -46,14 +46,6 @@ 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);
-
-/*
- */
-
static DEFINE_MUTEX(list_mutex);
static LIST_HEAD(mem_list_head);
@@ -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;
diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c
index 9ded30d0e97..05b58d4fc2b 100644
--- a/sound/core/oss/copy.c
+++ b/sound/core/oss/copy.c
@@ -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);
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c
index f874f6ca365..6faa1d71920 100644
--- a/sound/core/oss/io.c
+++ b/sound/core/oss/io.c
@@ -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);
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index da3dbd41669..4c1d1682719 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -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,
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 581aa2c60e6..4690b8b5681 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -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];
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index 77f96194a0e..f7649d4d950 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -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,
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 4c601b192dd..1af62b8b86c 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -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
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index bec94138205..6751daa3bb5 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -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;
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 14dfb3175d8..a466443c4a2 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -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,
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
index da7ab7a3e82..0dcc2870d53 100644
--- a/sound/core/oss/route.c
+++ b/sound/core/oss/route.c
@@ -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);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index ece25c718e9..192a433a240 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -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);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 49aa693fba8..36d7a599823 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -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) ||
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 1533f0379e9..6ea5cfb8399 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -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;
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index ff07b4a9992..a6d42808828 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -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) {
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c487025d345..e61e12506de 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -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,
}
};
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index 033a024d153..2c89c04f291 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -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;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index b917a9f981c..c4995c9f573 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -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;
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 97b30fb4c36..51e64e30dd3 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -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;
}
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 777796e9449..f25e3cc7ddf 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -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);
}
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index e024e4588b8..945a27c34a9 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -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;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 7a1545d2d95..8ca2be339f3 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -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;
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
index 9628c06e4ea..38693f47c26 100644
--- a/sound/core/seq/seq_compat.c
+++ b/sound/core/seq/seq_compat.c
@@ -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:
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 05410e536a4..1f997675c89 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -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)
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 3a94ed021bd..0d75afa786b 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -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);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 0cf6ac47731..7fb55436287 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -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);
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 99b35360c50..4d26146a62c 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -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;
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 1c32a53d6bd..3bf7d73ac52 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -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));
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 85969db576c..0101a8b99b7 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -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);
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 4a48c6ee8ee..e7a8e9e4edb 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -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)
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index d8fcd62e400..f745c317d6a 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -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)
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index cefd228cd2a..d4564edd61d 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -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:
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 1003ae375d4..c0685e2f0af 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -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;
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 7be51546eb9..7fe12264ff8 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -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;
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 0af337efc64..e582face89d 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -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 ||
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 5512f5373c5..e05802ae6e1 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -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);
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 4e4c69e6cb4..e5e749f3e0e 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -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;
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index b5e1a71bb64..5b89c0883d6 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -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);
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index ebe4359047c..780582340fe 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -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);
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index cebcb8b78ac..16feafa2c51 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -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)
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 239347f2615..9a2271dc046 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -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;
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index fb64c890109..962bb9c8b9c 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -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 */
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 74f6e53eae0..49b9e240915 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -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);
}
diff --git a/sound/drivers/vx/vx_cmd.c b/sound/drivers/vx/vx_cmd.c
index 9529e3bf286..23f4857f02c 100644
--- a/sound/drivers/vx/vx_cmd.c
+++ b/sound/drivers/vx/vx_cmd.c
@@ -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;
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 585af2eb143..473b07f6ae8 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -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) {
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index efd22e92bce..8d6362e2d4c 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -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) {
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 5a347321f8c..c71b8d148d7 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -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;
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index fdbf86571b1..27de574c08f 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -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);
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index fb8932af888..0e1ba9b4790 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -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;
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index 9c3d361accf..020a5d51247 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -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);
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index b1e74e40cba..5c0c77dd01c 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -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;
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c
index 1f4942ea141..9840eb43648 100644
--- a/sound/i2c/l3/uda1341.c
+++ b/sound/i2c/l3/uda1341.c
@@ -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)
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index d20d893b3b6..0341451f814 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -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++) {
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index f350835ade9..2cad2d61251 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -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);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 288926d2e20..ee47abab764 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -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 */
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 5769a13c1d9..660beb41f76 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -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.
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index c0ce7db2a1b..63af13d901a 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -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/
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 68f1260b560..77524244a84 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -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 */
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 4b8dfe2e3dc..3bfca7c59ba 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -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;
diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile
index ae23331e920..3d6dea3ff92 100644
--- a/sound/isa/ad1848/Makefile
+++ b/sound/isa/ad1848/Makefile
@@ -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
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 5f5271efdc5..b68d20edc20 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -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
index 630c90f9ee5..00000000000
--- a/sound/isa/ad1848/ad1848_lib.c
+++ /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)
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index 154e728f592..3e74d1a3928 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -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);
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 4d198ec71e9..e49aec700a5 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -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");
diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile
index 5067ee00193..5870ca21ab5 100644
--- a/sound/isa/cs423x/Makefile
+++ b/sound/isa/cs423x/Makefile
@@ -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
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index e9462b9944b..ddd289120aa 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -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
index 521db705d17..00000000000
--- a/sound/isa/cs423x/cs4231_lib.c
+++ /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)
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 4d4b8ddc26b..91f9c15d3e3 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -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) {
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index de71910401e..6a85fdc53b6 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -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;
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 1e1e575b1db..4fbb508a817 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -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;
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index cccc16c8113..12eb98f2f93 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -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 */
diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c
index ebdb3346930..0dd43414016 100644
--- a/sound/isa/gus/gus_mixer.c
+++ b/sound/isa/gus/gus_mixer.c
@@ -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");
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 99731dc9732..38510aeb21c 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -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);
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index f87c6236661..f94c1976e63 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -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;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index ca0d7ace0c7..5faecfb602d 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -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;
}
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 854a9f74b46..58c972b2af0 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -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],
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 2a1e2f5d12c..440755cc001 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -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;
}
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 0797ca441a3..19706b0d849 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -33,11 +33,7 @@
#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,14 +698,10 @@ 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;
struct snd_hwdep *synth;
@@ -731,38 +719,46 @@ 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) {
@@ -770,16 +766,6 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
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);
#if defined(CS4231) || defined(OPTi93X)
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index b35be7d9a9f..96678d5d383 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -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);
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 1be16c9700f..c99c6078be3 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -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;
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 35f3d7b1653..49037d074c7 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -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;
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index f7e8192270a..2a6cc1cfe94 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -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) {
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
index fe03bb82053..658d55769c9 100644
--- a/sound/isa/sb/sb8_main.c
+++ b/sound/isa/sb/sb8_main.c
@@ -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;
}
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index b432d9ae874..27a65150225 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -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)
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 73d4572d136..406a431af91 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -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++);
}
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index da3d152bcad..ca35924dc3b 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -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);
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index a07274ecb14..2c7503bf127 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -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;
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 06ad7863dff..48a16d86583 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -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");
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 3a6c6fe1ec4..4c095bc7c72 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -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;
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 2efaa7f205a..dfc449a2194 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -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;
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index a33384a55b0..f14a7c0b699 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -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);
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 0bb9b925660..4c410820a99 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -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
index 00000000000..454fee769a3
--- /dev/null
+++ b/sound/isa/wss/Makefile
@@ -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
index 00000000000..3d6c5f2838a
--- /dev/null
+++ b/sound/isa/wss/wss_lib.c
@@ -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);
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index fbef38a9604..1881cec11e7 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -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) {
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index d4fafb6eec6..1ca7427c4b6 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -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)
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index c611514f7ff..e0ae4d4d6a5 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -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
diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c
index 51e1fde62e8..a0274f3dac0 100644
--- a/sound/oss/aedsp16.c
+++ b/sound/oss/aedsp16.c
@@ -29,14 +29,6 @@
#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
diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig
index 3eb782720e5..f456574a964 100644
--- a/sound/oss/dmasound/Kconfig
+++ b/sound/oss/dmasound/Kconfig
@@ -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
index a94b9df489d..00000000000
--- a/sound/oss/hal2.c
+++ /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
index 2bd3b52d8a3..00000000000
--- a/sound/oss/hal2.h
+++ /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 */
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index a690ca57adb..6c0a770ed05 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -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)
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 99f5483abf2..41f870f8a11 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -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++) {
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 31f52d3fc21..7003711f4fc 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -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.
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 8c49a00a5e3..6704acbca8c 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -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);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index f4fbc795ee8..6ce3cbe98a6 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -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)
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 39ec55b57b1..92f3a976ef2 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -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);
}
diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c
index 33d37b1c42f..0f819ddb3eb 100644
--- a/sound/pci/ak4531_codec.c
+++ b/sound/pci/ak4531_codec.c
@@ -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;
}
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 27ce6136ab0..ba570053d4d 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -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.
*
@@ -27,8 +27,10 @@
* 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 = {
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 457228fb22a..085a52b8c80 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -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);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index d457a32a793..2f106306c7f 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -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);
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index 4aad35bba11..cf46bba563c 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -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);
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 333c62de862..b070e571451 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -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));
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index f9a58b4a30e..b9d2f202cf9 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -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,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 22f18f3cfbc..333007c523a 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -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);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 4ecdd635ed1..3aa8d973540 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -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);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 6abe8a3bd36..a7d89662acf 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -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".
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
index 893ee4f1ea7..c7885117da3 100644
--- a/sound/pci/ca0106/ca_midi.c
+++ b/sound/pci/ca0106/ca_midi.c
@@ -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;
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 9971b5b7735..1a74ca62c31 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -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;
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 7556fd90d0e..ef9308f7c45 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -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);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index e214e567dec..fb6dc398025 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -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,9 +3545,25 @@ 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,
.name = "Terratec SiXPack 5.1",
},
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index ccc8bedb5b1..f4f0c8f5dad 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -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);
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 2873cfe48c3..dd7c41b037b 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -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;
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c
index 4159e3bc186..29043301ebb 100644
--- a/sound/pci/echoaudio/darla20_dsp.c
+++ b/sound/pci/echoaudio/darla20_dsp.c
@@ -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"));
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c
index 79938eed7e9..60228731841 100644
--- a/sound/pci/echoaudio/darla24_dsp.c
+++ b/sound/pci/echoaudio/darla24_dsp.c
@@ -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);
}
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index 48eb7c59911..417e25add82 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -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"));
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index e16dc92e82f..8dbc5c4ba42 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -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;
}
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index 52a93318957..c3736bbd819 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -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);
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index e6c10077039..be0e18192de 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -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);
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c
index 3aa37e76eba..afa273330e8 100644
--- a/sound/pci/echoaudio/echoaudio_gml.c
+++ b/sound/pci/echoaudio/echoaudio_gml.c
@@ -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);
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c
index 2757c896084..db6c952e9d7 100644
--- a/sound/pci/echoaudio/gina20_dsp.c
+++ b/sound/pci/echoaudio/gina20_dsp.c
@@ -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;
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c
index 144fc567bec..2fef37a2a5b 100644
--- a/sound/pci/echoaudio/gina24_dsp.c
+++ b/sound/pci/echoaudio/gina24_dsp.c
@@ -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) {
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c
index d6ac7734609..f05e39f7aad 100644
--- a/sound/pci/echoaudio/indigo_dsp.c
+++ b/sound/pci/echoaudio/indigo_dsp.c
@@ -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;
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c
index 500e150b49f..90730a5ecb4 100644
--- a/sound/pci/echoaudio/indigodj_dsp.c
+++ b/sound/pci/echoaudio/indigodj_dsp.c
@@ -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;
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c
index f3ad13d06be..a7e09ec2107 100644
--- a/sound/pci/echoaudio/indigoio_dsp.c
+++ b/sound/pci/echoaudio/indigoio_dsp.c
@@ -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;
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
index 990c9a60a0a..ede75c6ca0f 100644
--- a/sound/pci/echoaudio/layla20_dsp.c
+++ b/sound/pci/echoaudio/layla20_dsp.c
@@ -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;
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index 97e42e11514..d61b5cbccca 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -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) {
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c
index 891c7051909..227386602f9 100644
--- a/sound/pci/echoaudio/mia_dsp.c
+++ b/sound/pci/echoaudio/mia_dsp.c
@@ -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;
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index 91f5bff66d3..77bf2a83d99 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -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;
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c
index c0b4bf0be7d..eaa619bd2a0 100644
--- a/sound/pci/echoaudio/mona_dsp.c
+++ b/sound/pci/echoaudio/mona_dsp.c
@@ -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"));
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index 45088ebcce5..0e649dcdbf6 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -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;
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 42bae6f7e9a..e10f027bde0 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -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);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 491a4a50f86..5ff4dbb62da 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -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;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 71dc4c8865b..7dba08f0ab8 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -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);
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index c4d76d16661..8578c70c61f 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -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;
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 7d379f5131f..6a47672f930 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -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);
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 958cb2a65a4..d7300a1aa26 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -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;
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 84fac1fbf10..4cd9a1faaec 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -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;
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 1bf298d214b..20ee7599600 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -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);
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index ab0c726d648..1980c6d207e 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -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
index 00000000000..9b77b3e0fa9
--- /dev/null
+++ b/sound/pci/hda/hda_beep.c
@@ -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
index 00000000000..de4036e6e71
--- /dev/null
+++ b/sound/pci/hda/hda_beep.h
@@ -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
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d2e1093f8e9..6447754ae56 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -94,6 +94,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
#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)
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index efc682888b3..60468f56240 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -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 */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 59e4389c94a..0ca30894f7c 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -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);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1c53e337ecb..9f316c1b279 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -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) {
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5c9e578f7f2..7957fefda73 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -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 */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 2fdf2358dbc..dfbcfa88da4 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -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[];
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 1e5aff5c48d..743d77922bc 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -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
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index e8003d99f0b..2b00c4afdf9 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -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 */
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 12272508b11..ba61575983f 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -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
index 00000000000..1a65775d28e
--- /dev/null
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -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 */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 66025161bd6..0b6e682c46d 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -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,6 +8155,105 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
{ } /* end */
};
+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 */
+};
+
+static void alc883_nb_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_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
@@ -7927,6 +8283,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
[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)
{
@@ -8948,6 +9450,41 @@ static void alc262_hippo1_unsol_event(struct hda_codec *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,
* 0x1b = port replicator headphone out
@@ -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,6 +10525,43 @@ static struct alc_config_preset alc262_presets[] = {
.input_mux = &alc262_fujitsu_capture_source,
.unsol_event = alc262_lenovo_3000_unsol_event,
},
+ [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)
@@ -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,6 +11969,76 @@ static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
alc269_eeepc_amic_automute(codec);
}
+/*
+ * 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)},
+
+ /* 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)
@@ -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 },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index f3da621f25c..c461baa83c2 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -33,10 +33,12 @@
#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,
@@ -71,9 +73,15 @@ enum {
};
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 },
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index e7e43524f8c..63e4871e5d8 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -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
@@ -29,6 +29,13 @@
/* 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
@@ -64,12 +74,64 @@
#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[0];
- spec->input_mux = &spec->private_imux;
+ 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 */
};
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c
index dab31b2756a..03391da8c8c 100644
--- a/sound/pci/ice1712/ak4xxx.c
+++ b/sound/pci/ice1712/ak4xxx.c
@@ -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;
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 868ae291b96..110d16e5273 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -44,10 +44,9 @@
* 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 */
},
{
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 0ed96c17805..d216362626d 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -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)
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index ea7116c304c..f7f14df81f2 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -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},"
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 013fc4f0482..6fe35b81204 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -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);
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 29d449d73c9..5b442383fcd 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -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;
}
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 762fbd7a750..fdae6deba16 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -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>
@@ -112,7 +112,7 @@
*/
#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 */
@@ -121,7 +121,7 @@
/*
* 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 */
@@ -138,7 +138,7 @@
#define ICE1712_DSC_RATE 0x05 /* dword - rate */
#define ICE1712_DSC_VOLUME 0x06 /* word - volume control */
-/*
+/*
* Professional multi-track direct control registers
*/
@@ -214,7 +214,7 @@
/*
- *
+ *
*/
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;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index e596d777d9d..1b3f1170271 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -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;
}
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index b4e0c16852a..c51659b9caf 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -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>
@@ -34,9 +34,10 @@
#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;
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index 5a158b73dca..de29be8c965 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -22,15 +22,24 @@
*/
/* 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 */
};
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h
index 13e841b5548..7fc22d9d442 100644
--- a/sound/pci/ice1712/phase.h
+++ b/sound/pci/ice1712/phase.h
@@ -22,13 +22,15 @@
* 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[];
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 203cdc1bf8d..6bc3f91b728 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -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 */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 4d2631434dc..b508bb360b9 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -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;
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
index a08d17c7e65..5af9e84456d 100644
--- a/sound/pci/ice1712/wtm.c
+++ b/sound/pci/ice1712/wtm.c
@@ -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
@@ -20,12 +20,12 @@
* 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;
diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h
index 03a394e442f..423c1a204c0 100644
--- a/sound/pci/ice1712/wtm.h
+++ b/sound/pci/ice1712/wtm.h
@@ -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[];
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 048d99e25ab..c88d1eace1c 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -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);
@@ -1957,6 +1963,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x10cf,
+ .subdevice = 0x127d,
+ .name = "Fujitsu Lifebook P7010",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x10cf,
.subdevice = 0x127e,
.name = "Fujitsu Lifebook C1211D",
.type = AC97_TUNE_HP_ONLY
@@ -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);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index faf674e671a..93449e46456 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -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];
}
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 4a44c0f20f7..5f8006b4275 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -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
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 0037be74fde..9ff3f9e3440 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -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);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 3dd0c796327..2d0dce649a6 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -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;
}
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 785085e4835..b9a06c27939 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -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);
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index f9860314613..3782b52bc0e 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -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);
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 6fdda1f70b2..3ba6174c3df 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -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)
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 06d13e71711..50c9f8a0508 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -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);
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
index dad393ae040..1ab833f843e 100644
--- a/sound/pci/oxygen/hifier.c
+++ b/sound/pci/oxygen/hifier.c
@@ -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;
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index c5829d30ef8..b60f6212745 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -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;
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 74a64488007..19107c6307e 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -19,14 +19,19 @@
#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)
{
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 83f135f80df..3126c4b403d 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -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);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 22f37851045..84f481d41ef 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -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);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 05eb8994c14..304da169bfd 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -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;
}
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index c4ad65a3406..c262049961e 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -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",
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 01d7b75f918..98c6a8c65d8 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -62,14 +62,66 @@
* 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;
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 2c7e2533679..0e06c6c9fcc 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -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;
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 000e6fed6e3..7143259cfe3 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -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;
}
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index d2f043278cf..96640d9c227 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -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 */
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 6a359624734..e9f0706ed3e 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -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);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 4d6fbb36ab8..d723543bead 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -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;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index ab423bc8234..98762f909d6 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -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 ---------------------------- */
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index a123f0e6ba2..2570907134d 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -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;
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 0d3d305b0a0..cd408b86c83 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -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");
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index a69b4206c69..c612b435ca2 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -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]) {
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index 3fd7f1b29b0..f9779e23fe5 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -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);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 6781be9e307..1aafe956ee2 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -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;
}
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 31f64ee3988..5bd79d2a5a1 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -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;
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 631f3a63999..7e87f398ff0 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -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;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 92d49aadf57..90d0d62bd0b 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -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);
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 99bf2a65a6f..989e04abb52 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -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;
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 106c48225bb..7bd33e6552a 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -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;
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
index baa2a723737..89f5c328acf 100644
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -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)
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 009df8dd37a..f746e15b848 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -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",
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 54df8baf916..7c920f3e7fe 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -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},
};
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index f743530add8..4dfda6674be 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -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"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 933a66d3080..d849349f2c6 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -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/
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c
index 3f326219f1e..98a2d5826a8 100644
--- a/sound/soc/at32/playpaq_wm8510.c
+++ b/sound/soc/at32/playpaq_wm8510.c
@@ -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;
}
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
index 5d44515e62e..a5b1a79ebff 100644
--- a/sound/soc/at91/at91-ssc.c
+++ b/sound/soc/at91/at91-ssc.c
@@ -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;
}
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
index b81d6b2cfa1..684781e4088 100644
--- a/sound/soc/at91/eti_b1_wm8731.c
+++ b/sound/soc/at91/eti_b1_wm8731.c
@@ -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
index 00000000000..f98331d099e
--- /dev/null
+++ b/sound/soc/blackfin/Kconfig
@@ -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
index 00000000000..9ea8bd9e0ba
--- /dev/null
+++ b/sound/soc/blackfin/Makefile
@@ -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
index 00000000000..51f4907c483
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -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
index 00000000000..350125a0ae2
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.h
@@ -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
index 00000000000..c782e311fd5
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -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
index 00000000000..3f77cc558dc
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -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
index 00000000000..124425d2232
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -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
index 00000000000..61fccf92519
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -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
index 00000000000..4d4609a97c5
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h
@@ -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
index 00000000000..43a4092eeb8
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -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
index 00000000000..7107d1a0b06
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-i2s.h
@@ -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
index 00000000000..3b99e484d55
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -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
index 00000000000..4c163454bbf
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -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
index 00000000000..e15f67fd776
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -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");
+
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1db04a28a53..e0b9869df0f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -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
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d7b97abcf72..f977978a340 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -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
index 00000000000..4e09c1f2c06
--- /dev/null
+++ b/sound/soc/codecs/ad1980.c
@@ -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
index 00000000000..db6c8500d66
--- /dev/null
+++ b/sound/soc/codecs/ad1980.h
@@ -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
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 7da9f467b7b..088cf992772 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -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);
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
index e9fe30e2c05..c7a58703ea3 100644
--- a/sound/soc/codecs/ak4535.h
+++ b/sound/soc/codecs/ak4535.h
@@ -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
index 00000000000..940ce1c3522
--- /dev/null
+++ b/sound/soc/codecs/ssm2602.c
@@ -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
index 00000000000..f344e6d76e3
--- /dev/null
+++ b/sound/soc/codecs/ssm2602.h
@@ -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
index 00000000000..bed8a9e63dd
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -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
index 00000000000..786ba16c945
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -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_ */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5f9abb19943..566a427c928 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -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);
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index d76c079b86e..00a195aa02e 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -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];
};
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 807318fbdc8..d206d7f892b 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -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);
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index 50c603e2c9f..c55c17a52a1 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -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
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 3d998e6a997..9a37c8d95ed 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -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);
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
index f5d2e42eb3f..c5368396045 100644
--- a/sound/soc/codecs/wm8510.h
+++ b/sound/soc/codecs/wm8510.h
@@ -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
index 00000000000..df1ffbe305b
--- /dev/null
+++ b/sound/soc/codecs/wm8580.c
@@ -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
index 00000000000..589ddaba21d
--- /dev/null
+++ b/sound/soc/codecs/wm8580.h
@@ -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
+
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 9402fcaf04f..7b64d9a7ff7 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -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,8 +773,12 @@ 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);
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
index 99f2e3c60e3..95190e9c0c1 100644
--- a/sound/soc/codecs/wm8731.h
+++ b/sound/soc/codecs/wm8731.h
@@ -35,6 +35,8 @@
#define WM8731_DAI 0
struct wm8731_setup_data {
+ int spi;
+ int i2c_bus;
unsigned short i2c_address;
};
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index dd1f55404b2..4892e398a59 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -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,8 +1067,12 @@ 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);
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
index 8ef30e628b2..1dc100e19cf 100644
--- a/sound/soc/codecs/wm8750.h
+++ b/sound/soc/codecs/wm8750.h
@@ -58,6 +58,8 @@
#define WM8750_SYSCLK 0
struct wm8750_setup_data {
+ int spi;
+ int i2c_bus;
unsigned short i2c_address;
};
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index e873414840c..8c4df44f334 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -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);
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 44f5f1ff0cc..7defde069f1 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -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
index 00000000000..0b8c6d38b48
--- /dev/null
+++ b/sound/soc/codecs/wm8900.c
@@ -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
index 00000000000..ba450d99e90
--- /dev/null
+++ b/sound/soc/codecs/wm8900.h
@@ -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
index 00000000000..a3f54ec4226
--- /dev/null
+++ b/sound/soc/codecs/wm8903.c
@@ -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
index 00000000000..cec622f2f66
--- /dev/null
+++ b/sound/soc/codecs/wm8903.h
@@ -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
index 00000000000..974a4cd0f3f
--- /dev/null
+++ b/sound/soc/codecs/wm8971.c
@@ -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
index 00000000000..ef4f08f9f34
--- /dev/null
+++ b/sound/soc/codecs/wm8971.h
@@ -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
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index dd995ef448b..63410d7b5ef 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -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);
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
index 0a08325d544..0e192f3b078 100644
--- a/sound/soc/codecs/wm8990.h
+++ b/sound/soc/codecs/wm8990.h
@@ -827,6 +827,7 @@
#define WM8990_AINRMUX_PWR_BIT 3
struct wm8990_setup_data {
+ unsigned i2c_bus;
unsigned short i2c_address;
};
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 38d1fe0971f..441d0580db1 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -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)
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 65fdbd81a37..9e6062cd6b5 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -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,
};
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 5ebf1ff71c4..abb5fedb0b1 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -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;
}
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
index c5b091807ee..241648ce887 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -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
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 6a5e56a782b..76feaa65737 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -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
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 8d6a45e75a6..62cb4eb07e3 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -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
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3368ace6097..bba9546ba5f 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -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.
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 62f680a4a77..035da4afec3 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -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
index 00000000000..86923299bc1
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -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);
+
+
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 4bdc9d8fc90..94f89debde1 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -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
index 00000000000..0382fdac51c
--- /dev/null
+++ b/sound/soc/fsl/soc-of-simple.c
@@ -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);
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 87d0ed01f65..d166b6b2a60 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -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,
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 9212c37a33b..f8c1cdd940a 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -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
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 0a53f72077f..72b7a5140bf 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -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,
};
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index a4697f7e292..f84f7d8db09 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -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,
};
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index d94a495bd6b..a80ae074b09 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -13,225 +13,30 @@
#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,
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index c796b188277..39d19212f6d 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -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>
@@ -30,6 +31,15 @@
#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);
}
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 4345f387fe4..afcd892cd2f 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -10,64 +10,14 @@
* 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);
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
index 54c9c755e50..60c3b20aeeb 100644
--- a/sound/soc/pxa/pxa2xx-pcm.h
+++ b/sound/soc/pxa/pxa2xx-pcm.h
@@ -13,21 +13,6 @@
#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;
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 37cb768fc93..3d4738c06e7 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -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,
};
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 8089f8ee05c..73a50e93a9a 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -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);
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 83f1190293a..ad381138fc2 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -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;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index f9d100bc847..9ca9c08610f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -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,
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 1b04259a432..4ae07e236b3 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -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>
*
@@ -34,21 +90,17 @@
* 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 */
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 0c63e0585b1..49acee0c484 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -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);
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 1c4797be72e..791d2fb821d 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -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);
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index ee2e1b4f355..c534a2a849f 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -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);
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index c89d2ea594b..f16a3fce459 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -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);
diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c
index c6917ba2c93..00fc005ecf6 100644
--- a/sound/synth/emux/emux_nrpn.c
+++ b/sound/synth/emux/emux_nrpn.c
@@ -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) {
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index f60a98ef7de..5c47b6c0926 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -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);
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index d176cc01742..335aa2ce257 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -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);
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index b343818dbb9..2cc6f6f7906 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -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++) {
diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c
index deabe5f899c..c85522e3808 100644
--- a/sound/synth/util_mem.c
+++ b/sound/synth/util_mem.c
@@ -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);
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index ffcdc8f4ef6..4f0eac9bff1 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -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
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index aa252ef2ebf..abb288bfe35 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -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/
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index b8cfb7c2276..bbd70d5814a 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -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;
}
}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 7cf18c38dc4..36e4f7a29ad 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -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,
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 6676a177c99..5962e4b8442 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -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));
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 89c63d073cc..a49246113e7 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -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);
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 9ea726c049c..69689e79bf7 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -62,6 +62,13 @@
.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
@@ -1338,6 +1345,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+{
+ /*
+ * 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 */
{
USB_DEVICE(0x582, 0x00a6),
@@ -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 */
{
diff --git a/sound/usb/usx2y/Makefile b/sound/usb/usx2y/Makefile
index 9ac22bce112..748933054b6 100644
--- a/sound/usb/usx2y/Makefile
+++ b/sound/usb/usx2y/Makefile
@@ -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
index 00000000000..b441fe2cd19
--- /dev/null
+++ b/sound/usb/usx2y/us122l.c
@@ -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
index 00000000000..3d10c4b2a0f
--- /dev/null
+++ b/sound/usb/usx2y/us122l.h
@@ -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
index 00000000000..ff23cc1ce3b
--- /dev/null
+++ b/sound/usb/usx2y/usb_stream.c
@@ -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
index 00000000000..4dd74ab1e9c
--- /dev/null
+++ b/sound/usb/usx2y/usb_stream.h
@@ -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