GIT 0217b9195be8453536b31753c0129b4e9d6f151d git+ssh://master.kernel.org/pub/scm/linux/kernel/git/perex/alsa.git#mm commit Author: Andrew Morton Date: Fri Sep 21 23:25:00 2007 +0200 [ALSA] git-alsa kconfig fix Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ac58c010f68e03797159d1ebb3674f1cc0228f03 Author: Randy Dunlap Date: Fri Sep 21 18:25:40 2007 +0200 [ALSA] sound/hda: fix help text Fix hda help text typo. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 77fdffd71de92015a693b39c83e89867ae758ccd Author: Peer Chen Date: Fri Sep 21 18:20:25 2007 +0200 [ALSA] alsa: Add the MCP79 support to hda_intel driver Add the MCP79 support to hda driver. The patch base on kernel 2.6.23-rc7 Signed-off-by: Peer Chen Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c415f7ae708cbc8be4062c3334a45dd595505e27 Author: Takashi Iwai Date: Thu Sep 20 17:34:57 2007 +0200 [ALSA] Workaround for invalid signature read of CS8427 Reading the signature of CS8427 over SPI/I2C fails on some devices by mysterious reason. In most cases, however, it succeeds at the sequential read. So, let's give a second chance to check the signature again. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f7bdc8d77cc5d096f0659eac39272d76e48d77e4 Author: Kailang Yang Date: Thu Sep 20 12:51:39 2007 +0200 [ALSA] hda-codec - Missing support ASUS A7J Added the missing support for ASUS A7J [0x1043 0x1243] Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4e075a2f2093aac39dbf9b054562cae0e5928a48 Author: Kailang Yang Date: Thu Sep 20 12:50:29 2007 +0200 [ALSA] hda-codec - Fix ALC662 codec support * Fixed ALC662 init verbs (wrong NIDs) * Fixed ALC662 auto model issue (wrong DAC index) Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ef8d674bef5ab196dbcd976244225ad1b6bd3d74 Author: Trent Piepho Date: Wed Sep 19 21:20:17 2007 +0200 [ALSA] ad1848: simplify MCE down code The polling loop to check for ACI to go down was more convoluted than it needed to be. New loop should be more efficient and it is a lot simpler. The old loop checked for a timeout before checking for ACI down, which could result in an erroneous timeout. It's only a failure if the timeout expires _and_ ACI is still high. There is nothing wrong with the timeout expiring while the task is sleeping if ACI went low. A polling loop to check for the device to leaving INIT mode is removed. The device must have already left init for the previous ACI loop to have finished. Acked-by: Rene Herman Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d9f6f1b70c2ee550c242cf329a34b1147adfddb4 Author: Trent Piepho Date: Wed Sep 19 21:19:57 2007 +0200 [ALSA] ad1848: Fix msleep while atomic Simplest fix. Acked-by: Rene Herman Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2b825fa94b65e532ebcaca8d5e173929664c9c29 Author: Keita Maehara Date: Wed Sep 19 14:29:37 2007 +0200 [ALSA] ac97: YMF743 missing controls support (2/2) These patches enable a few YMF743 controls (Tone/3D/IEC958) that won't be detected with the current version of ALSA. The second one contains following changes: - A chip-specific SPDIF support for YMF743 (It doesn't have AC97 standard SPDIF registers seen on YMF753). - The implementation for 'IEC958 Playback Source' and 'IEC958 Mute' are identical to the ones for YMF753. But there is no 'IEC958 Output Pin' for YMF743. Signed-off-by: Keita Maehara Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9de12ee1123308b4306fcfced21dc53d7f90e890 Author: Keita Maehara Date: Wed Sep 19 14:27:38 2007 +0200 [ALSA] ac97: YMF743 missing controls support (1/2) These patches enable some YMF743 controls (Tone/3D/IEC958) that won't be detected with the current version of ALSA. The first one contains only cosmetic changes to share a few YMF753-specific symbols with YMF743. Signed-off-by: Keita Maehara Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ac36be7f8c89d5e4218b6486f46c9378f0fec23c Author: Rene Herman Date: Tue Sep 18 18:33:15 2007 +0200 [ALSA] schedule_timeout() fix for core/seq/seq_instr.c Replace schedule_timeout() with schedule_timeout_uninterruptible() to avoid signals in loop. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a02d45a417700905d030c3174a55e1a050cf578d Author: Rene Herman Date: Tue Sep 18 18:10:49 2007 +0200 [ALSA] alsa-kernel: schedule_timeout() fixes Fix schedule_timeout() use in alsa-kernel. Mostly just schedule_timeout(1) --> schedule_timeout_uninterruptible(1) The wavefront_synth one fixes the surrounding loop as well. In ymfpci_main, delete a superfluous set_current_state() and in soc/soc-dapm.c replace an _interruptible with _uninterruptible in some debug code; it's not waiting for signals. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8732e852ee6e04bfcc07012e6d5e0e517145f5e5 Author: Matthew Ranostay Date: Tue Sep 18 00:52:38 2007 +0200 [ALSA] hda: More subsystem id BIOS changes More laptop BIOS changes the subsystem id for STAC9205 cards if the microphone is toggled on/off in the settings. The patch removes the old STAC_9205_M43xx and use STAC_9205_DELL_M43. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4b42fcfd6d9d70b4b32bd386f5ff9f791e9464e7 Author: Takashi Iwai Date: Mon Sep 17 19:08:32 2007 +0200 [ALSA] Add description about power-saving mode Added the description about power-saving mode on AC97 and HD-audio drivers. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6b1a1da5432c269413ca08b4a0c94ea1535bae57 Author: Takashi Iwai Date: Mon Sep 17 19:07:46 2007 +0200 [ALSA] Add default values for power-saving as Kconfig options Added CONFIG_SND_AC97_POWER_SAVE_DEFAULT and CONFIG_SND_HDA_POWER_SAVE_DEFAULT Kconfig options as the default values for power-saving mode of AC97 and HD-audio drivers, respectively. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f10e6e1fd71a02334ec6e51eac832d2954d92e8e Author: Krzysztof Helt Date: Mon Sep 17 17:57:37 2007 +0200 [ALSA] sscape: support for audio part of VIVO cards This patch adds support for audio part of the Ensoniq SoundScape VIVO cards. The MIDI part is not supported. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 87a03e161af91b402534c640d6176588cf4034dd Author: Takashi Iwai Date: Mon Sep 17 16:44:06 2007 +0200 [ALSA] opti9xx: adjust OPL3 FM resource value The OPTi ISA-PnP chips advertise their OPL4 base at 0x380 (to 0x3f0) through pnp and put their on-chip OPL3 at +8. The driver assumes the provided value is the ALBase (OPL3 address) though and checks for an OPL4 at -8, which means that simply adding 8 to the pnp provides value works to fix detection of both OPL3 and OPL4. Problem spotted on 931 and 933 by Krzysztof Helt and confirmed on 924 and 925 (together all OPTi ISA-PnP chips) by me. Signed-off-by; Rene Herman Acked-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9b2ef8dd7d6b4f1e019bf95798ed50fb2d248440 Author: Takashi Iwai Date: Mon Sep 17 16:26:16 2007 +0200 [ALSA] Add descriptions for new module options of snd-sscape driver Add descriptions for new module options of snd-sscape driver, wss_port and dma2. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 96192ff09091b3682e151dd023bc2df496ec0057 Author: Krzysztof Helt Date: Mon Sep 17 16:23:13 2007 +0200 [ALSA] sscape: driver extension to 2nd DMA and WSS port This patch adds second DMA channel and WSS port settings to the sscape driver. Also, it adds internal card type setting. The Ensoniq SoundScape VIVO PnP id is added but not handled yet. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 60441f9e89a8953fab3b34d4c0753fafe1f5162d Author: Daniel Mack Date: Mon Sep 17 14:45:14 2007 +0200 [ALSA] caiaq - support for Native Instrument's RigKontrol3 This patch adds support for Native Instrument's upcoming RigKontrol3 sound interface. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 920d83464b6521f82adc70a55477b6802f80067c Author: Krzysztof Helt Date: Mon Sep 17 14:43:14 2007 +0200 [ALSA] sc6000: 2 minor fixes This patch zeroes buffer for the card name and fixes incorrect jump in the probe function. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c7f6b247d2f070df2a3be67c9b6c7ed41af793e0 Author: Krzysztof Helt Date: Mon Sep 17 14:42:49 2007 +0200 [ALSA] sc6000: documentation fix This patch fixes MPU-401 irq values list in documentation. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 42cefaca7e27882d96ed76b57184cc14566a665e Author: Matthias Kaehlcke Date: Mon Sep 17 14:41:16 2007 +0200 [ALSA] Routines for effect processor FX8010: Use list_for_each_entry Routines for effect processor FX8010: Use list_for_each_entry instead of list_for_each Signed-off-by: Matthias Kaehlcke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit eea3d81a4d5da2c5d0acc22cbd848b2279c7b1bf Author: Matthias Kaehlcke Date: Mon Sep 17 14:40:04 2007 +0200 [ALSA] Intel HD Audio: Use list_for_each_entry(_safe) Intel HD Audio: Use list_for_each_entry(_safe) instead of list_for_each(_safe) Signed-off-by: Matthias Kaehlcke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a941a77981c24d2277384c3a2b35ce4d6cb81501 Author: Matthias Kaehlcke Date: Mon Sep 17 14:39:05 2007 +0200 [ALSA] ESS Maestro 1/2/2E Sound Card: Use list_for_each_entry ESS Maestro 1/2/2E Sound Card: Use list_for_each_entry instead of list_for_each Signed-off-by: Matthias Kaehlcke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a3e1070f58da3f82dbd925ed2344ff8a8be43780 Author: Krzysztof Helt Date: Mon Sep 17 12:52:43 2007 +0200 [ALSA] ad1848_lib: waiting loops done after cs4231_lib This patch fixes ad1848_lib waiting loops to be the same as in the cs4231_lib. Acked-by: Rene Herman Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ffbcbb3cbe1ff2b38ac973fd4bb9688a2cac0e6b Author: Andrew Morton Date: Mon Sep 17 12:50:38 2007 +0200 [ALSA] sc6000 build fix sound/isa/sc6000.c: In function 'sc6000_dsp_reset': sound/isa/sc6000.c:270: error: implicit declaration of function 'udelay' sound/isa/sc6000.c: In function 'sc6000_init_mss': sound/isa/sc6000.c:327: error: implicit declaration of function 'msleep' {standard input}: Assembler messages: Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 15c872dae12351c0862ffe29e372259c7fc5d0e3 Author: Giuliano Pochini Date: Mon Sep 17 12:49:40 2007 +0200 [ALSA] echoaudio - Add barrier() to prevent compiler optimization This patch adds a barrier() to prevent the compiler from moving the read outside of the loop. It also fixes a comment. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit de7f4f1677429ad9362388abee0f996a292c914b Author: Tobin Davis Date: Mon Sep 17 12:46:12 2007 +0200 [ALSA] hda-codec: Add two new systems to ALC883 This patch adds support for the Asus M2A-VM HDMI and Abit IP35-PRO motherboards. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9ace8ec64c3c15776138e09c2f938aa719e76d36 Author: Tobin Davis Date: Mon Sep 17 12:45:11 2007 +0200 [ALSA] hda-codec: Add 4 channel support for Realtek ALC883 I had a request for a 4 channel mode. This should implement front and surround outputs, leaving the 3rd plug for mic input. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 49933a8b5a5d6737105b328ae0772a3e14fcf91c Author: Clemens Ladisch Date: Mon Sep 17 09:41:36 2007 +0200 [ALSA] cmipci: fix distortion on rear channels When playing multichannel data, the rear channels can get distorted if the last sample of the last played stereo stream was not zero. To avoid this, add a hack to play a few silence samples after the stream is stopped. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit c2dc394dbd543d1132e7df13d44a476c45f08ecd Author: Clemens Ladisch Date: Mon Sep 17 09:40:57 2007 +0200 [ALSA] cmipci: clean up struct cmipci_pcm Remove some unused field from the struct cmipci_pcm, and change the type of some others to save some space. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 40af7ae913fc71bae06d1056587df4784cc8557b Author: Clemens Ladisch Date: Mon Sep 17 09:40:24 2007 +0200 [ALSA] cmipci: fix lookup of double rates When using one of the double sampling rates, use half the sample rate to look up in the rates[] table, otherwise we stumble over the BUG(). Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 4870a0dbc771f03e2884a1a88965a5891bf19434 Author: Clemens Ladisch Date: Mon Sep 17 09:39:51 2007 +0200 [ALSA] cmipci: reorganize set_dac_channels() By reorganizing the code that sets the CHB3DxC bits we can not only simplify this code but also fix the bug where the CHB3D8C bit was not reset when playing a stereo stream after a 7.1 stream. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 2fcaaa42442220a322d84a2f0b53b708fe25db73 Author: Clemens Ladisch Date: Mon Sep 17 09:39:10 2007 +0200 [ALSA] cmipci: remove 5.0 format Disallow playback of five channels because the hardware does not support it (or nobody knows how to do it). Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit b9246eb8f00a41151c273809c183bc51a76f3bd1 Author: Clemens Ladisch Date: Mon Sep 17 09:37:47 2007 +0200 [ALSA] cmipci: allow 96 kHz playback on non-multichannel rear Move the code that enables 96 kHz out of the if() that checks for availability of both DMA channels so that it is enabled even when another stream is playing on the front channels. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 2662469b473f5562878018451e386ab31e6d95e5 Author: Clemens Ladisch Date: Mon Sep 17 09:37:19 2007 +0200 [ALSA] cmipci: initialize 0x90 registers Initialize the registers at 0x90 and 0x91 with some undocumented values. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 8ad48f5ed8e5f765ed1f4a743d9a95e1c43315ad Author: Clemens Ladisch Date: Mon Sep 17 09:36:49 2007 +0200 [ALSA] cmipci: reset the chip when initializing When the chip is initialized, reset it. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 13e0b497ece53a51562ae06945bb4b89c7b64d69 Author: Clemens Ladisch Date: Mon Sep 17 09:36:16 2007 +0200 [ALSA] cmipci: show more registers in proc file Show a dump of all registers in the 0x00-0x27 and 0x90-0x93 ranges in the 'cmipci' proc file. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit af718c9f38b56357dd2cc0637e4a6538f937ac33 Author: Clemens Ladisch Date: Mon Sep 17 09:35:46 2007 +0200 [ALSA] cmipci: update register definitions Update comments for many register symbols, add some new register symbols, and rename a few ones. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 202e798109ad04c9445ec58c7859f89f6ac2f57c Author: Clemens Ladisch Date: Mon Sep 17 09:34:59 2007 +0200 [ALSA] cmipci: fix version 37 detection Use the proper value for the bit that identifies chip version 37. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit fad38ad074bcbd7ae4aec06e3a1e1edb8996f34b Author: Clemens Ladisch Date: Mon Sep 17 09:33:37 2007 +0200 [ALSA] bt87x: fix detection of generic boards Add an 'unknown' board type so that it is possible to differentiate between unknown and generic boards. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 9489b012d136443c29cb8730e59594506bc1afb8 Author: Clemens Ladisch Date: Mon Sep 17 09:33:17 2007 +0200 [ALSA] usb-audio: add Ozone Academic support Add a quirk to detect the MIDI port on the M-Audio Ozone Academic. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 0890e792e7fde62ef94cbc5236207ff0bdf883df Author: Jaroslav Kysela Date: Wed Sep 12 13:29:51 2007 +0200 [ALSA] SC6000 driver - add HAS_IOPORT dependency Signed-off-by: Jaroslav Kysela commit 781ab74bff4ad49d32b0f35f31f9d52c7dec9f68 Author: Takashi Iwai Date: Tue Sep 11 22:11:08 2007 +0200 [ALSA] echoaudio - Remove superfluous volatile prefix Remove superfluous volatile prefix in the communication struct definition. This eventually fixes the compile warnings with the recent gcc, too. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e2197be3cd50e7bb2e31a91ab8e71303f14cd1f8 Author: Takashi Iwai Date: Tue Sep 11 22:10:14 2007 +0200 [ALSA] Add description of sc6000 driver Added the description of the new sc6000 driver to ALSA-Configuration.txt. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 89fc2cb264ef06832fce6721024ee5dcd1c27f4c Author: Krzysztof Helt Date: Tue Sep 11 21:53:05 2007 +0200 [ALSA] Gallant SC-6000 driver This is port of the Gallant SC-6000 driver from the OSS aedsp16 driver. This card was also sold as AudioExcel DSP 16 and Zoltrix AV302 (Audio Plus True 16). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5c153d46ff61fb4364848cb3f370c8da9bad48c8 Author: Danny Tholen Date: Tue Sep 11 21:41:56 2007 +0200 [ALSA] hda-intel - Improve HD-audio codec probing robustness When modem is disabled in the BIOS, detection of the number of codecs always fails after booting if STATESTS is not cleared first. This patch fixes this problem and also adds an error check in a place where a read error would lead to a very large number of pointless loops. Signed-off-by: Danny Tholen Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ed0b3ee3fcf4a697606bb23ea2eb003217974977 Author: Takashi Iwai Date: Tue Sep 11 21:28:50 2007 +0200 [ALSA] pcxhr - Fix trigger start with non-linked streams The non-linked streams couldn't be started properly due to missing setting of stream->status. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1805b64fbda3401738fb4e5d33bbe3caaa15f3e0 Author: Takashi Iwai Date: Tue Sep 11 10:12:14 2007 +0200 [ALSA] Fix thinko in cs4231 mce down check The last patches to replace with schedule_timeout() don't work as expected. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 42100e8c17ab277d2480348c503698d5787373ce Author: Krzysztof Helt Date: Tue Sep 11 00:55:46 2007 +0200 [ALSA] sun-cs4231: improved waiting after MCE down This patch sync sparc driver with x86 isa cs4231 driver patches. It fixes wrong waiting for the auto calibration bit and makes further waiting use much finer granularity. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 835717cf517b7ad9d152239e53f41c15f5bb7301 Author: Timur Tabi Date: Tue Sep 11 00:45:50 2007 +0200 [ALSA] Fix CS4270 volume control and optimize I2C operations The volume control for the CS4270 ASoC driver was inverted - raising the volume level with alsamixer would decrease the actual volume. This patch also improves the performance of the I2C code (used to change register settings) by only performing an I2C write if the new value is different from the value that's in the register cache. Signed-off-by: Timur Tabi Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7fa0e977cdc5d486cf685ee69b850f2dd781bf14 Author: Krzysztof Helt Date: Tue Sep 11 00:40:42 2007 +0200 [ALSA] cs4231-lib: improved waiting after mce_down This patch replaces long msleeps in waiting loops with schedule_timeout() calls. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1926f16f9029db437c2032ebc9a446befb2a59a0 Author: Takashi Iwai Date: Tue Sep 11 00:35:06 2007 +0200 [ALSA] Kill useless volatile in pcm.h The volatile prefix is just useless there. Let's kill them, and then gcc will be happier, too. sound/acore/pcm.c:867: warning: passing argument 1 of ‘__constant_c_and_count_memset’ discards qualifiers from pointer target type Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6c62d4036e39168ccf3f82680c87a94633a6a159 Author: Takashi Iwai Date: Tue Sep 11 00:33:48 2007 +0200 [ALSA] Fix 'discards qualifiers' compile warnings in pcm.h Fixed cast messes in pcm.h. include/sound/pcm.h: In function ‘hw_param_interval_c’: include/sound/pcm.h:800: warning: passing argument 1 of ‘hw_param_interval’ discards qualifiers from pointer target type Simply redefine the inline functions again for const pointers. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9a543c456add552b7c7f6482e6b52685adb2f2f2 Author: Rene Herman Date: Mon Sep 10 23:22:55 2007 +0200 [ALSA] ad1848/cs4231: replace commented out debug code with snd-printd{,d} While I'm at it another 'while I'm there' -- replace commented out debug code with snd-printd{,d}. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 97f01cd10a91ba24b5c43b788c3393160f8c380e Author: Rene Herman Date: Mon Sep 10 23:20:34 2007 +0200 [ALSA] ad1848: replace HZ calculus with msecs_to_jiffies() If I'm not mistaken, any (new) use of HZ these days is considered a bug so while I'm there... Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 62eb73d5346a22a243914b5bfde855b6713e4de2 Author: Rene Herman Date: Mon Sep 10 23:19:55 2007 +0200 [ALSA] ad1838/cs4231 - fix MCE timeout upon initial load When the ad1848/cs2431 is first being initialized, auto-calibration may not be set causing a timeout waiting for it in snd_ad1848/cs4231_mce_down(). This has no dire consequences other than an alarming printk, but since what we need to wait for is for the calibration to _finish_, let's just check for that instead. The early chips need a slight delay (as commented -- 5 sample periods) to be sure that _if_ calibration is going to happen, it has started when we check While the CS4231A datasheet implies it'll happen immediately on downing MCE, some testing is showing that there's a window there as well, so just do the delay everywhere. Thanks to Krysztof Helt for pinpointing this problem. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c0b7f06c8174ee5a8a041d887ecb086b96c3ae51 Author: Adrian Bunk Date: Mon Sep 10 23:15:50 2007 +0200 [ALSA] au88x0_synth.c bugfix This patch fixes the code in vortex_wt_SetFrequency() to what seems to have been intended. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bcebf61669279db8bc4cc55ef9a3b189002ac8d9 Author: Rene Herman Date: Mon Sep 10 23:13:26 2007 +0200 [ALSA] ad1848: fix AD1848P macro Consistent variable naming is a good thing, but let's be a little less sneaky about enforcing it... ;-/ Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e133d76d179f1188deb358476236d46b5be282fd Author: Matthew Ranostay Date: Mon Sep 10 23:09:42 2007 +0200 [ALSA] hda: BIOS changing subsystem id Some laptop BIOS change the subsystem id for STAC9205 cards if the microphone isn't toggled on/off in the settings. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1ee1c655940014bad66dea634f2b9b88dd87818a Author: Adrian Bunk Date: Mon Sep 10 23:08:34 2007 +0200 [ALSA] unexport snd_ctl_elem_{read,write} snd_ctl_elem_{read,write} no longer have any modular users Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d8a1496f3d7832a7dca7968c4c5415d6e4822fcd Author: Krzysztof Helt Date: Mon Sep 10 23:06:55 2007 +0200 [ALSA] sun-cs4231: checkpatch fixes This patch fixes white spaces and issues pointed by the checkpatch.pl script. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 675241a203364f35361ba1c35456b4e795201cca Author: Clemens Ladisch Date: Mon Sep 10 08:05:19 2007 +0200 [ALSA] document basic TLV stuff Add documentation about how to define dB scale information for mixer controls. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 4534af84502ecd0ff6136e710fad733015efb919 Author: Trent Piepho Date: Fri Sep 7 13:18:50 2007 +0200 [ALSA] snd-bt87x: Power down audio ADC when not in use Sets a bit to power down the Bt87x's internal audio ADC when the ALSA device isn't open, or when it is in 'digital mode' using an external ADC. Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 65010d0bfec70230934ea5ae0bba88778f594a35 Author: Clemens Ladisch Date: Fri Sep 7 10:44:13 2007 +0200 [ALSA] cmipci: add msbits constraint for 24-bit format Add a msbits constraint to the SPDIF output device to indicate that S32_LE samples use only 24 bits for data. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 9321649b7a54ab7d2e03618841c26d9a44dfa185 Author: Takashi Iwai Date: Fri Sep 7 10:58:58 2007 +0200 [ALSA] hda-codec - Add support for Toshiba A305 Added the proper model=toshiba for Toshiba A305 with ALC268 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 63319d30394c6aa18816e28a7b90e6e6ac928e4a Author: Takashi Iwai Date: Fri Sep 7 10:57:44 2007 +0200 [ALSA] hda-codec - Add missing Mic Boost for some ALC882 models Mic Boost mixer volume was missing in some ALC882 models. Added now. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 91f5a6406fa2ee48421e704d21366de077f22476 Author: Trent Piepho Date: Thu Sep 6 15:06:44 2007 +0200 [ALSA] snd-bt87x: Improve support for different board types Different cards have different audio configurations, but the driver didn't support this. The only setting it had was the digital rate. This patch adds a board configuration list. Currently, configurable items are the digital rate and the digital data format (for cards with an external ADC), a flag for the absence of an external ADC, and a flag for no connection to the Bt87x internal ADC. This allows cards that don't use the internal ADC to omit the ALSA 'Bt87x analog' device and related controls. Cards without an external ADC can omit the 'Bt87x digital' device. In order to support the CS5331A ADC used on the Osprey 440 and 2x0 cards, the digital format needs to be different than the default. Support could be added for defining: The connections or lack of them to the Bt87x's internal ADC mux Multiple sample rates for an external ADC (e.g. Osprey) Control of an external mux for an external ADC (e.g. Osprey) The card definitions for cards other than the Ospreys are kept equivalent to their old values. This is likely inaccurate for most cards, as it is doubtful that both an external and the internal ADC would be used. Lacking information on those cards, the behavior is left unchanged. Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e75e05af2f851282df88026e9867a07d35c6e94f Author: Krzysztof Helt Date: Thu Sep 6 15:03:59 2007 +0200 [ALSA] cs4231-lib: replace common delay loop by function This patch replaces a common delay loop by a function. It also uses ARRAY_SIZE macro for the rates table. Acked-by: Rene Herman Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f39edaddf15892e4d1284a9d7228bf29239b5c33 Author: Krzysztof Helt Date: Thu Sep 6 15:03:22 2007 +0200 [ALSA] ad1848_lib: replace common delay loop by function This patch replaces a common delay loop by a function. It also uses ARRAY_SIZE macro for the rates table. Acked-by: Rene Herman Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7f9d14c7630c81b47b6e9b778a982f1d21499fc5 Author: Krzysztof Helt Date: Thu Sep 6 15:02:33 2007 +0200 [ALSA] dbri - Use linux/of.h instead of asm/prom.h The linux/of.h header should be used instead of asm/prom.h. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8d0ed788b36d39096b216003fc7b52417f45cb62 Author: Takashi Iwai Date: Thu Sep 6 15:00:27 2007 +0200 [ALSA] hda-codec - Add quirk entry for Casper CPR2000 Added the quirk entry for Casper CPR2000 (model=acer) with ALC268 codec (ALSA bug#3343). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f4d3e79c6204de3d6a64cd79063f001824a49c29 Author: Takashi Iwai Date: Thu Sep 6 14:54:11 2007 +0200 [ALSA] hda-codec - Add missing model names for ALC882 codecs Added the missing model option strings for ALC882 codecs. Also added the corresponding description in ALSA-Configuration.txt. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4734acaa8048adc71b7935dc06ea34fa56d90d96 Author: Takashi Iwai Date: Thu Sep 6 14:52:04 2007 +0200 [ALSA] hda-codec - Add support for ASUS A7M Added the support for ASUS A7M with ALC882 codec. It's slightly different from ASUS A7J. The patch taken from ALSA bug#3000 https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3000 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d46e33f15e0577293e248483268f47eaa3c411c9 Author: Takashi Iwai Date: Thu Sep 6 14:29:53 2007 +0200 [ALSA] hda-codec - Add laptop-automute model for AD1986A Added a new model laptop-automute for AD1986A, which has the HP jack detection and auto-muting of the speaker. Currently, it's used for Lenovo N100. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8c3f9c7494e524db78dbcd85fb4134890fa8ec8b Author: Takashi Iwai Date: Wed Sep 5 23:48:45 2007 +0200 [ALSA] Add missing models for Dell with STAC9200 codec Added the missing description of models for Dell machines with STAC9200 HD-audio codec chip. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 49822d0db60af949aeef39ba316f6dd1568a857c Author: Takashi Iwai Date: Wed Sep 5 23:46:03 2007 +0200 [ALSA] hda-codec - Fix wrong pin config order in STAC92xx dell models The last patch to change/add Dell models have wrong pin config orders. This patch fixes the pin positions. Taken from ALSA bug#3319, https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3319 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 43dabd9f7fc1ae4ca42382e774338c9f601f78e8 Author: Takashi Iwai Date: Wed Sep 5 19:14:38 2007 +0200 [ALSA] hda-codec - Add support for Acer Aspire 9303 Add the entry for Acer Aspire 9303 (model=acer-aspire) with ALC883 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 845e5381ee849ffcd38fe8118fe1c4ff423e3042 Author: Krzysztof Helt Date: Wed Sep 5 15:08:23 2007 +0200 [ALSA] sun-cs4231: use cs4231-regs.h This patch replaces cs4231 registers definitions with common include. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 54aa89ef8d3ec202bbd9a8a0e0bf52fe646db181 Author: Krzysztof Helt Date: Wed Sep 5 15:07:57 2007 +0200 [ALSA] sun-cs4231: memory management fix The chip structure is now allocated by snd_card_new() and it must not be released by separate kfree(). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 00a34c14a9a3531ba2bed02fae14c69aadfdabc4 Author: Krzysztof Helt Date: Wed Sep 5 15:05:08 2007 +0200 [ALSA] dbri: conversion to OpenFirmware framework This patch converts the dbri driver to use OF framework. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 118eaa6e631b9c4077cdd37890f03fcfa0975e06 Author: Krzysztof Helt Date: Tue Sep 4 13:24:14 2007 +0200 [ALSA] cs4231 header split This patch splits the cs4231.h file into two parts: - cs4231-regs.h which contain register constants and macros - cs4231.h which includes the above and contain rest of the definitions This will allow to share register definitions between x86 ISA cs4231 and SPARC cs4231. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7f6a6dcdbafa5e63815fd0087c6b463e42092a68 Author: Krzysztof Helt Date: Tue Sep 4 13:09:20 2007 +0200 [ALSA] dbri: more cleanups This patch: - removes redundant constant suffices - removes redundant parentheses - removes redundant curly brackets - removes check if a spinlock is locked inside method which is only called with the spinlock locked - moves few functions to the __init section - removes line which appears twice after the previous patch - minor comments improvements Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 59210f4e78dedb6d28d19826972697c42c7d3c87 Author: Krzysztof Helt Date: Tue Sep 4 13:08:24 2007 +0200 [ALSA] sun-cs4231: code improvements This patch does some code improvements to make driver (both code and binary) shorter. It also make use of card->private_data pointer to store chip information. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit de8ca0ad89479fa6b0dded9ba1ba7049908e22d8 Author: Andres Salomon Date: Mon Sep 3 15:43:43 2007 +0200 [ALSA] cs5535audio: drop unused bus master stuff We really only care about the first two bus masters (playback and capture). There's no need to have unused BM code lying around, so let's get rid of it. If for some reason we trigger an IRQ for some BM that we're not using.. well, that warrants spitting out an error message (imo). Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 65b8e9cf1fae5cec3eb63ad7772d48346ae5fdb8 Author: Andres Salomon Date: Mon Sep 3 15:43:18 2007 +0200 [ALSA] cs5535audio: fix ACC_BM[x]_CMD register handling According to 6.3.2.7 of the cs5535/cs5536 data sheets, the ACC_BM[x]_CMD registers are only 8 bits wide. This driver treats them as 32 bits wide, and also has bits in the wrong place. Simple fix to the definitions. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ab73ca96293785d9b317f3be00fe9389d1c1250e Author: Andres Salomon Date: Mon Sep 3 15:42:52 2007 +0200 [ALSA] cs5535audio: update PCI device handling in suspend/resume Save the PCI state before disabling the device, and add some error checking. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ab14e9d48c8794507fbcd6c267726139b3686e14 Author: Andres Salomon Date: Mon Sep 3 15:42:16 2007 +0200 [ALSA] cs5535audio: fix PRD register save/restore power management race In the suspend path, we currently save the PRD registers and then disable DMA. This is racy; the sound hardware might update the PRD register as it finishes processing some DMA pages between when we've saved the PRD registers and when DMA actually gets disabled. Furthermore, we actively check whether or not DMA is enabled before saving PRD registers; there's no reason to do that, as the PRD registers should not update when we twiddle the ACC_BM[x]_CMD register(s). Worst case, we save the PRD registers twice; even powering down the ACC shouldn't mess with the PRD registers (according to the 5536 data sheet, section 5.3.7.4, power-down procedure). This patch reworks all that to first disable DMA, and then save PRD registers. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d5d409e258b2a4536bf2ce4f29e4385922f87021 Author: Andres Salomon Date: Mon Sep 3 15:41:47 2007 +0200 [ALSA] cs5535audio: correctly set dma->substream We're never actually setting dma->substream to the current substream; that means the dma->substream checks that we do in the suspend/resume path are never satisfied, and the PRD registers are never correctly managed. This changes it so that we set the substream when constructing the specific bus master DMA, and unsetting it when we tear down the BM's DMA. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7231b1623d9b7d2e9f6b1eb4dfc8c4a2bd0efb10 Author: Maxim Levitsky Date: Mon Sep 3 15:31:02 2007 +0200 [ALSA] hda-codec - Fix support for sigmatel codecs that have 2 or more ADCs 1) Create seperate mixer controls for each ADC 2) Make number of substreams of capture PCM device be equal to number of ADCs Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9f7c25f0229d8f604baa5c143e6e94308c620a8f Author: Maxim Levitsky Date: Mon Sep 3 15:30:26 2007 +0200 [ALSA] hda-codec - make volume knob, the master volume for sigmatel codecs VolumeKnob is present on most sigmatel codecs, it allows to decrease volume of all DACs at once, it is a kind of post-procesing volume. Note that all output amps of sigmatel only decrease volume, and all input amps only increase volume. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 615a34a283aa35bd5e4dd70ebc6ac3182ccb0a7a Author: Maxim Levitsky Date: Mon Sep 3 15:29:37 2007 +0200 [ALSA] hda-codec - add support for analog loopback to STAC9204/9205/922x/927x The analog loopback routes the sound just before it enters ADC0 to output of DAC0. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9a5db959c57a74c0d774b6abe3c8e82177ef7cef Author: Maxim Levitsky Date: Mon Sep 3 15:29:04 2007 +0200 [ALSA] hda-codec - add support for swapping center/LFE channels to STAC codecs Center/LFE channels are located on same jack, so it can be usefull to swap them. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c8d00095544610fe552de110c479545d7270abe8 Author: Maxim Levitsky Date: Mon Sep 3 15:28:04 2007 +0200 [ALSA] hda-intel - Fix resume logic, when dynamic power managment is on Comment in hda_intel.c states that 'the explicit resume is needed only when POWER_SAVE isn't set', but this is not true. There is no code that will automaticly power up the codec on resume, but only code that powers it up when user accesses it. So if user leaves a sound playing, codec will not be powered To fix that I check if there are any codecs that should be powered codec->power_count, and if so I power them up together with main controller. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6462b3d60d9c253e626de4f36ddf5ff5836d1740 Author: Maxim Levitsky Date: Mon Sep 3 15:26:57 2007 +0200 [ALSA] hda-intel - fix a race in dynamic power managment codec->power_transition is supposed to be true while codec is going to be shut off if in the mean time somebody calls snd_hda_power_up, hda_power_work will not shut down the codec, but nether will clear codec->power_transition, thus it stays on forever. Fix this. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8d0f1f2a759aa00a45e8430f3a50b445c31ab265 Author: Clemens Ladisch Date: Mon Sep 3 09:56:45 2007 +0200 [ALSA] cmipci: show real chip name in card name The '-MCx' suffix that is expected by alsa-lib is only needed in the card driver string, so we can show the actual chip name in the shortname. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 156a14fb0872e0a6cd1544cbbe2dbd440d3d11c1 Author: Clemens Ladisch Date: Mon Sep 3 09:56:23 2007 +0200 [ALSA] cmipci: check that the legacy MIDI port works Check that the UART_EN bit actually enabled the MPU-401 port. Apparently, C-Media thinks that it is a good idea to be paranoid here. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 867c9c13ccd55d40d4d866391a8c1abaf0816788 Author: Clemens Ladisch Date: Mon Sep 3 09:55:49 2007 +0200 [ALSA] cmipci: do not check for integrated FM/MIDI ports with chip version 37 Integrated MPU-401/OPL3 ports are available with chip version 39 and later, so we do not test for the port with version 37. Now that the test is known to work, we can again enable the MIDI port by default. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit c7cdfe6c6792c42433cf5d851ea515ac200fd733 Author: Clemens Ladisch Date: Mon Sep 3 09:54:55 2007 +0200 [ALSA] cmipci: add 96 kHz support Add support for 88.2 kHz and 96 kHz analog and digital playback on CMI8768/CMI8770 chips. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 020660f0265271a07dd4ca6b301cd02750d8fc88 Author: Clemens Ladisch Date: Mon Sep 3 09:54:27 2007 +0200 [ALSA] cmipci: remove invalid channels constraint Remove the constraint that sets the channel limit for the first playback device to that of the second one; the first device supports only stereo. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 0ab815cb2fc4bbfc0cacd1c6876ece304381b2af Author: Takashi Iwai Date: Mon Sep 3 09:43:38 2007 +0200 [ALSA] hda-codec - Avoid zero NID in line_out_pins[] of STAC codecs The STAC codes adds line_out_pins[] for shared mic/line-inputs accordingly. But, the current code may give a hole with NID=0 in some setting, which results in an error at probe. This patch fixes the problem. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 67fe3c1cd6311098bf95c8c351d0f62a5cdfad90 Author: Takashi Iwai Date: Mon Sep 3 09:36:36 2007 +0200 [ALSA] hda-codec - Fix wrong pin-setup at resume of STAC codecs The resume procedure for STAC codecs overrides the cached values and results in the wrong (reset) PIN state. The patch gets rid of the overriding part and simplifies the resume. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 148a26edeebbc238df7e038e751eb1a54af20f66 Author: Mark Hills Date: Mon Sep 3 08:20:09 2007 +0200 [ALSA] usb-audio: update quirk for Rane SL 1 (aka. Serato Scratch Live) Allow the interface's mixer to be used, and give the interface its correct name. Signed-off-by: Mark Hills Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit d9068563e8df73bdb81fe10b44612db10fc915aa Author: Maxim Levitsky Date: Fri Aug 31 12:52:19 2007 +0200 [ALSA] hda-codec - code cleanups in patch_sigmatel.c Clean up the mixer entries for Input Source using a macro. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c7f3c840450fc0e0dbe1ba1843c7756b27507fbc Author: zhejiang Date: Fri Aug 31 12:36:05 2007 +0200 [ALSA] hda-codec - Fix capture on ALC262 HP machines Fix the index for Front Mic capture source on ALC262 HP machines. Also, added the new capture source list for HP BPC DC7000 series to work properly. From: zhejiang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2dad44bd8a6fd7351f779341c27bac0a1e9bfec3 Author: Remy Bruno Date: Fri Aug 31 12:33:54 2007 +0200 [ALSA] hdsp - Add support for latset RME9632 revisions added support for the latest revision of the 9632 (and hopefully a few following ones). The DSP matrix was not working because of wrong identification of the card in this part of the code. Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f3c80d5260065eaad77f7b8ab8e04430495dc65c Author: Remy Bruno Date: Fri Aug 31 12:21:08 2007 +0200 [ALSA] hdspm - Fix autosync bug * better report of speed mode change failures * autosync_ref control bugfix (was reporting pref_sync_ref instead) (changed HDSPM_AES32_AUTOSYNC_FROM_NONE value to comply with array indexing in snd_hdspm_info_autosync_ref()) * added support for master modes up to 192kHz (clock source control value was restricted up to 96kHz) Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b727868bd7c5ff7bcd562e34122b56afee0775ba Author: Oliver Neukum Date: Fri Aug 31 12:15:27 2007 +0200 [ALSA] missing error check in usb sound driver usb_set_interface() can fail, even for altsetting 0 Signed-off-by: Oliver Neukum Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 753290389a3a139ce30209adb3fc75ce979fa6f4 Author: Clemens Ladisch Date: Wed Aug 29 17:38:14 2007 +0200 [ALSA] usb-audio: add quirk for Serato Scratch Live DJ Box Add a quirk to detect the Serato Scratch Live DJ Box. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit b28cf3bccee78a922ae83076da0aeb048b8f5442 Author: Takashi Iwai Date: Wed Aug 29 15:12:46 2007 +0200 [ALSA] ac97 - Suppress the reset of audio-codec from modem-codec at resume On codec chips with both audio and modem functions (e.g. Conexant one), performing AC97_RESET resets the whole registers. When both audio and modem drivers are resumed at the same time, the modem one often is resumed after the audio, and it results in the reset of audio registers (ALSA bug#3333). This patch fixes such a problem. Since the modem codec basically doesn't need AC97_RESET, skip this initialization unless specified as audio. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a380b25c6dc904df7cd0b744697bf1d8ae13bfa4 Author: Takashi Iwai Date: Wed Aug 29 15:07:11 2007 +0200 [ALSA] hda-codec - Add Mic Boost control with auto-configuration Some codecs need Mic Boost mixer controls for obtaining a proper recording level, but the auto-configuration doesn't create them. This patch adds the creation of mic-boost controls on corresponding codecs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 79b741fca846dca9c7982eb14f059df54fb0c78a Author: Takashi Iwai Date: Wed Aug 29 12:54:25 2007 +0200 [ALSA] Allow shared IRQ for CS5530 device CS5530 is a PCI device and often shares the IRQ although the SB common routine tries to allocate it exclusively. This patch allows shared IRQ for CS5530. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f2542f492131b02179a9d89010a270d2fe2c26df Author: Jesper Juhl Date: Tue Aug 28 15:21:33 2007 +0200 [ALSA] emu10k1: There's no need to cast vmalloc() return value in snd_emu10k1_create() vmalloc() returns void *. no need to cast. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2de5b501803bee471f6cfb86d0e088107cc05084 Author: Clemens Ladisch Date: Mon Aug 27 09:22:31 2007 +0200 [ALSA] cmipci: show actual chip name in card longname Show the actual name of CMI8762/CMI8768/CMI8769/CMI8770 chips in the card longname instead of just using 'CMI8738' for all of them. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 45f1270db8dc7d842624e18d3764de1fd4d0a969 Author: Clemens Ladisch Date: Mon Aug 27 09:21:02 2007 +0200 [ALSA] cmipci: remove has_dual_dac Remove the has_dual_dac variable because it was always set. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 31908ce73f083193b288bba81e0bc5d9ec19ffbd Author: Clemens Ladisch Date: Mon Aug 27 09:20:31 2007 +0200 [ALSA] cmipci: reorganize chip version detection Add a case for chip version 39 where no bit is set in register 0Ch, and move the detection of version 39 before that of 8768. This makes the logic more compatible with the driver on that other OS. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit b9e755752e6c20331170857f1abf8a9bb75c1785 Author: Clemens Ladisch Date: Fri Aug 24 09:18:04 2007 +0200 [ALSA] cmipci: make the test for integrated MIDI port address more robust Unused bytes in the I/O register range are likely to have the value 0x00 instead of 0xff, so test against both values when checking for the presence of the integrated MIDI port. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 28a7d823cc9b1333f0c6f0fc061adb852946364d Author: Takashi Iwai Date: Thu Aug 23 19:04:28 2007 +0200 [ALSA] hda-codec - Fix Dell laptops support with STAC codecs Fixed Dell laptops support with STAC92xx codecs. Many pin-config models are introduced. See ALSA-Configuration.txt for details. The patch taken from ALSA bug#3319, originally by Jorg Prante: https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3319 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d962017d7b5229d2c812f46c7da70a4909f3dccd Author: Takashi Iwai Date: Thu Aug 23 18:56:52 2007 +0200 [ALSA] hda-codec - Fix ALC268 unsol event The unsol event of ALC268 is in the standard bit 26. Also, fixed the Acer master controls, and added Extensa 5210 to the quirk list. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ef8577e68d5ae2d09db945b30f714502feb04d68 Author: Takashi Iwai Date: Thu Aug 23 00:31:43 2007 +0200 [ALSA] hda-codec - Fix mater mixer switch of ALC262 sony-amd model Fixed the master mixer switch of ALC272 sony-amd model. It used a simple bind-control, but it resulted in unexpected unmute of speaker output. Now the control checks the HP jack state apropriately, just like fujitsu model. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ba71d61c47f83d5358ce0439dd41a0edf2abd2fa Author: Takashi Iwai Date: Thu Aug 23 00:01:09 2007 +0200 [ALSA] hda-intel - Fix compile with gcc-3.x gcc-3.x doesn't like forward inlining: CC [M] sound/pci/hda/hda_codec.o sound/pci/hda/hda_codec.c: In function 'snd_hda_codec_free': sound/pci/hda/hda_codec.c:517: sorry, unimplemented: inlining failed in call to 'free_hda_cache': function body not available sound/pci/hda/hda_codec.c:534: sorry, unimplemented: called from here sound/pci/hda/hda_codec.c:517: sorry, unimplemented: inlining failed in call to 'free_hda_cache': function body not available sound/pci/hda/hda_codec.c:535: sorry, unimplemented: called from here Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6e49357e60ce946e46432edc632cd8a720158e25 Author: Takashi Iwai Date: Wed Aug 22 14:19:45 2007 +0200 [ALSA] bt87x - Add known PCI ID entries Added the PCI ID entries for known working devices - Prolink PixelView PV-M4900 - Pinnacle Studio PCTV rave Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 587268752ca7aeae75f26212ff6bc13c0465b55b Author: Clemens Ladisch Date: Wed Aug 22 09:45:03 2007 +0200 [ALSA] cmipci: fix handling of FM/MIDI port addresses Make sure that the MPU-401 MIDI and OPL-3 FM devices are used only on those chips where they are supported, and that the correct port addresses are used. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 26e90a2057f986bf7b0196ee7aee1dee069e7cd6 Author: Takashi Iwai Date: Tue Aug 21 15:20:26 2007 +0200 [ALSA] wavefront - Use standard firmware loader Use the standard firmware loader for loading ICS2115 OS firmware file. This is the last old bad guy that is still using sys_open() and sys_read() calls, and now all should be gone. The patch also adds the missing description of module options related with wavefront_synth.c. Due to this rewrite, user will have to copy or make symlink the firmware file appropriately to the standard firmware path such as /lib/firmware. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9010d513c6ab7c6fd16f8f1e1d44ff288a8e999f Author: Takashi Iwai Date: Tue Aug 21 11:51:42 2007 +0200 [ALSA] hda-codec - Add missing capture boost for ALC268 Added missing capture boost controls for ALC268 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5dd3d368c1fda4a1b074cee60bbd436d8a6da20b Author: Clemens Ladisch Date: Tue Aug 21 08:58:35 2007 +0200 [ALSA] cmipci: fix MIDI device name Initialize card->shortname early enough so that the MIDI device can pick it up and does not need to have a generic name. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 7d7cc179214eefc16ee9db79cea0a7a0c48bbd0b Author: Clemens Ladisch Date: Tue Aug 21 08:57:34 2007 +0200 [ALSA] usb-audio: add workaround for ESI MIDI Mate/RomIO II Force low speed USB MIDI devices like the ESI MIDI Mate and RomIO II to use interrupt transfers because the USB core would not be happy about low speed bulk transfers. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 99ef655f4d2025dfd0b26749194f088193d78cad Author: Clemens Ladisch Date: Tue Aug 21 08:56:54 2007 +0200 [ALSA] usb-audio: allow low speed MIDI devices Allow low speed MIDI devices because newer devices from ESI do not support full speed. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 9edfffdcdcf466ec3c2128b77d7cb073e66f02f2 Author: Clemens Ladisch Date: Tue Aug 21 08:56:08 2007 +0200 [ALSA] usb-audio: allow output interrupt transfers for MIDI Allow output interrupt transfers for some MIDI devices that require them. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 2c4b2e6898df669193808fa94a190a645a411de0 Author: Takashi Iwai Date: Mon Aug 20 15:20:02 2007 +0200 [ALSA] hda-codec - Add SPDIF support on ALC880 fujitsu model Some Fujitsu laptops have SPDIF output jack (ALSA bug#3009). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit dc07a159ba88ef9eecb7b753cba49b774e6cb653 Author: Krzysztof Helt Date: Mon Aug 20 12:30:54 2007 +0200 [ALSA] dbri: driver cleanup This patch fixes white spaces, spelling and formatting to conform closer to the coding standard of the kernel. It contains few fixes pointed out by the checkpatch.pl script. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 150a60674e59b11bc13599a9cf7ce29fc880fd12 Author: Kailang Yang Date: Mon Aug 20 11:31:23 2007 +0200 [ALSA] hda-codec - Add support for Haier W66 1. Support Lenovo 420A (PCI SSID: 0x17aa 0x3bfc) 2. Support Haier W66 (PCI SSID: 0x1991 0x5625) Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a52e47cd77565323de3d3270604e75125f9f2773 Author: Takashi Iwai Date: Fri Aug 17 09:17:36 2007 +0200 [ALSA] hda-intel - Add probe_mask blacklist Added the black-list of probe_mask option to set the default value for known non-working devices. Currently, Thinkpad *60 and *61 series are set. I'm afraid more will be added to the list in near future... Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9e76eb93fad72675f69975fd1a1b9d2df34a0ff8 Author: Takashi Iwai Date: Fri Aug 17 09:02:12 2007 +0200 [ALSA] hda-codec - Fix ALC268 acer model ALC268 has different NIDs from ALC262. Acer model should use NID 0x02 and 0x03 instead of 0x0c and 0x0d for the master volume. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 456d248fcc5d30802eea2e18d62937daeb627a88 Author: Takashi Iwai Date: Thu Aug 16 19:32:16 2007 +0200 [ALSA] emu10k1 - Fix memory corruption The number of mixer elements for SPDIF control don't match with the actual array size (3). This may result in a memory corruption that overwrites the i2c_capture_source field (ALSA bug#3095). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5b51abc7543404b5c74c403b74ba511f273926a7 Author: Takashi Iwai Date: Thu Aug 16 18:57:30 2007 +0200 [ALSA] hda-codec - Add support for Toshiba Satellite P205 Add model=lenovo for Toshiba Satellite P205 with ALC861VD codec chip. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2cc986ba782e00f69a255a7dbc3bc4f8aa962e20 Author: Takashi Iwai Date: Thu Aug 16 18:19:38 2007 +0200 [ALSA] hda-codec - Add support for Macbook Pro rev3 Added the support for Macbook Pro rev3 with ALC885 codec chip. The patch taken from ALSA bug#3242. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1dd87b266043bbcb8a7e81ffc5173dbccb7eec98 Author: Takashi Iwai Date: Thu Aug 16 17:52:43 2007 +0200 [ALSA] hda-codec - Fix Toshiba A135 model selection Fixed the double entries in the model presets. Toshib A135 prefers model=lenovo rather than dallas. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 168731e87eaf8de660626b7460b6ec1ad229ca1f Author: Takashi Iwai Date: Thu Aug 16 17:33:55 2007 +0200 [ALSA] hda-codec - Add auto-mute function to Sony VAIO with STAC9872 Added auto-mute function with HP jack to Sony VAIO laptop with STAC9872 codec. The patch taken from ALSA bug#3275. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c1ae96644f814c55a8baa95f7878e26c4527a3bc Author: Takashi Iwai Date: Thu Aug 16 17:23:32 2007 +0200 [ALSA] hda-codec - Add model for MSI m673x Added model=targa-dig for MSI m673x with ALC883 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 03770262961fedbe008abe50c85ea8547468ab9d Author: Takashi Iwai Date: Thu Aug 16 16:35:33 2007 +0200 [ALSA] hda-intel - Avoid unnecessary work scheduling Avoid unnecessary work scheduling for power-off. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8ab5cde63f5fe3148c8e560779b858811c02bcf6 Author: Takashi Iwai Date: Thu Aug 16 15:23:35 2007 +0200 [ALSA] hda-codec - Add unsol_event to ALC883 Acer Aspire Added unsol_event handling to ALC883 Acer Aspire codes. Also, removed unneeded channel-mode mixer control from 2-ch only presets. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9341e3af6a9800d168bbb59289262065df1d0297 Author: Takashi Iwai Date: Thu Aug 16 15:02:16 2007 +0200 [ALSA] hda-codec - Remove superfluous code Remove the superfluous code that's actually not used at all. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 463ddc9dfe837481eba44e7e8d38663de98794ac Author: Takashi Iwai Date: Thu Aug 16 15:01:03 2007 +0200 [ALSA] hda-codec - Fix PM on ALC885 Intel Macs Fix power-management on ALC885 Intel Macs. It fixes the problem with power-saving mode, too. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0c79c08e52e5c9f17746dd4f57b14396ac0ddacf Author: Takashi Iwai Date: Thu Aug 16 14:59:45 2007 +0200 [ALSA] hda-codec - Add ALC268 acer model Added model=acer for ALC268 codec support. The configuration is: headphone = 0x14, speaker = 0x15 needs hp-jack auto-detection. The same routine as alc262-fujitsu model is used. Also, added the auto-muting routine for ALC268 model=toshiba. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 67039447d6d2bfb5fc50e7d496a289299b2b0134 Author: Takashi Iwai Date: Thu Aug 16 12:32:45 2007 +0200 [ALSA] hda-intel - Add position_fix quirk for Dell Precision 390 Dell Precision 390 needs position_fix=1 as default (ALSA bug#3295). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bfd68f992b4479742a55622c76c44bf0468b0d09 Author: Clemens Ladisch Date: Thu Aug 16 08:44:51 2007 +0200 [ALSA] usb-audio: fix parsing of SysEx messages from CME keyboards When CME keyboards send a SysEx message (e.g. master volume), the USB packet uses a format different from the standard format. Parsing this packet according to the specification corrupts the SysEx message itself and can cause the following MIDI messages to be misinterpreted, too. This patch adds a workaround for this case. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit f2e161fc27dc98733270c7a9826103148e36cdd0 Author: Takashi Iwai Date: Wed Aug 15 22:20:45 2007 +0200 [ALSA] hda-codec - Fix Master volume with AD1986A laptop model Use the bind-control for NID 0x1a and 0x1b as Master volume control on AD1986 model=laptop as well as model=laptop-eapd. This will fix the missing output on some devices. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 84bec1883d67bd3c83e127ad595e3ac0a4b57060 Author: Takashi Iwai Date: Wed Aug 15 22:18:22 2007 +0200 [ALSA] hda-intel - Add flush_scheduled_work() in snd_hda_codec_free() Added flush_scheduled_work() in snd_hda_codec_free() to make sure that the all work is gone. Also, optimized the condition to schedule the delayed work in snd_hda_power_down(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b1029b8f22b14393a227f32ea80bd2717694c536 Author: Takashi Iwai Date: Wed Aug 15 16:44:04 2007 +0200 [ALSA] hda-codec - Add option texts and descriptions for new Realtek models Added the missing text entries and descriptions for the newly added model values for Realtek codec chips. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bd2e0da21d1fa4ffcc275894eeea2ad30ed75543 Author: Takashi Iwai Date: Wed Aug 15 16:24:17 2007 +0200 [ALSA] hda-codec - Add support for Biostar NF61S SE mobo Added the support for Biostar NF61S SE mobo with ALC861VD codec, model=6stack-digout (ALSA bug#3190). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 926a83ca779e2511248393563f69445512097966 Author: Kailang Yang Date: Wed Aug 15 16:21:59 2007 +0200 [ALSA] hda-codec - Update realtek codec support 1. Support Acer Aspire 9810 2. Support TOSHIBA A205 3. Support HP TX1000 Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8002eb71466e40be19d8d343bb15402d4a7ef33f Author: Takashi Iwai Date: Wed Aug 15 15:43:06 2007 +0200 [ALSA] hda-codec - Remove conflicting capture mixers for ALC861VD Removed conflicting capture mixers for ALC861VD model=dallas. It fixes the ALSA bug#3236. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 64867bf151283c0e8af14ab458eb1753e816f738 Author: Takashi Iwai Date: Tue Aug 14 15:18:26 2007 +0200 [ALSA] hda-intel - Don't do suspend if already powered down In the power-saving mode, the suspend is done dynamically at power-down. So we don't have to call suspend stuff explicitly if it's already powered down. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cb5f2abcff7744408df419803085b89103257245 Author: Takashi Iwai Date: Tue Aug 14 15:15:52 2007 +0200 [ALSA] hda-intel - Fix NULL dereference in resume codec->patch_ops.init can be NULL. Check before calling it. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a0e8e2af27f155a5c75c96319688dbdfd1282390 Author: Clemens Ladisch Date: Mon Aug 13 17:40:54 2007 +0200 [ALSA] pcm: add snd_pcm_rate_to_rate_bit() helper Add a snd_pcm_rate_to_rate_bit() function to factor out common code used by several drivers. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 47bb004655ffea0268d0fd8175e45513851ce98f Author: Clemens Ladisch Date: Mon Aug 13 17:38:54 2007 +0200 [ALSA] pcm: merge rates[] from pcm_misc.c and pcm_native.c Merge the rates[] arrays from pcm_misc.c and pcm_native.c because they are both the same. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit c159550e9aafe899a71291964063d1d467648d9f Author: Clemens Ladisch Date: Mon Aug 13 17:37:55 2007 +0200 [ALSA] remove incorrect usage of SNDRV_PCM_INFO_SYNC_START and snd_pcm_set_sync() Set the SNDRV_PCM_INFO_SYNC_START flag and the substream's sync ID (only) if the substream actually can be linked to another one. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 08365977858d1d0fc8364d28b08ccbc6c5c85559 Author: Takashi Iwai Date: Mon Aug 13 16:16:53 2007 +0200 [ALSA] mixart - Check ioremap error Check ioremap error and handle properly at initialization. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f5cd03ef3e28402319defa099ba334d1eb8be543 Author: Takashi Iwai Date: Mon Aug 13 16:10:30 2007 +0200 [ALSA] hda-intel - Add power_save_controller module option Add power_save_controller module option instead of define flag. Also, added descriptions of new module options in ALSA-Configuration.txt. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9551ff6d3d74409a57936c74071a9378cc94abae Author: Tobin Davis Date: Mon Aug 13 15:50:29 2007 +0200 [ALSA] This patch adds more support for Dell systems with Stac9205 codecs. Tested against a couple of different systems (with different pin configs), but the others should also work. Also cleaned up some of the 9205 patch code. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit fae1787592d507125d9d84b06c7df5094f4a2192 Author: Takashi Iwai Date: Mon Aug 13 15:29:04 2007 +0200 [ALSA] hda-intel - Fix resume with power save The controller power wasn't turned on properly at resume due to the power-saving patch. Now fixed. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ee200bc8640dfb95eed6185b4036f9f8169f38fd Author: Mariusz Kozlowski Date: Sat Aug 11 11:06:09 2007 +0200 [ALSA] This patch removes memset() from snd_emu10k1_fx8010_info() which apparently isn't needed there. Upatched code uses: memset(info, 0, sizeof(info)); where 'info' is a pointer and therefore only first 4 bytes of 'info' gets cleared on a 32bit machine. Anyway looking at the code zeoring this memory region isn't needed at all because the snd_emu10k1_fx8010_info() function initializes all the 'info' fields on its own. So that's why this code works at all in its original form. This patch removes this redundant code. Also snd_emu10k1_fx8010_info() can't fail so lets save some bytes and change its return type to void. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 90f8b06197b4eee4c9c82505978beffb5abd1cb4 Author: Takashi Iwai Date: Fri Aug 10 17:22:34 2007 +0200 [ALSA] hda-codec - update of documentation Update the documentation to reflect the last changes regarding the power-saving mode and register caches. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0f9a661ee62f06bfd2d2f06bd069686efa1e1723 Author: Takashi Iwai Date: Fri Aug 10 17:21:45 2007 +0200 [ALSA] hda-intel - Add POWER_SAVE option Added CONFIG_SND_HDA_POWER_SAVE kconfig. It's an experimental option to achieve an aggressive power-saving. With this option, the driver will turn on/off the power of each codec and controller chip dynamically on demand. The patch introduces a new module option 'power_save'. It specifies the second of time-out for automatic power-down. As default, it's 10 seconds. Setting 0 means to suppress the power-saving feature. The codec may have analog-input loopbacks, which are usually represented by mixer elements such as 'Mic Playback Switch' or 'CD Playback Switch'. When these are on, we cannot turn off the mixer and the codec chip has to be kept on. For bookkeeping these states, a new codec-callback is introduced. For the bus-controller side, a new callback pm_notify is introduced, which can be used to turn on/off the contoller appropriately. Note that this power-saving might cause slight click-noise at power-on/off. Also, it might take some time to wake up the codec, and might even drop some tones at the very beginning. This seems to be the side-effect of turning off the controller chip. This turn-off of the controller can be disabled by undefining HDA_POWER_SAVE_RESET_CONTOLLER in hda_intel.c. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit de72e8c2476250888dd9d1b56f8b5eb052bebf04 Author: Takashi Iwai Date: Fri Aug 10 17:12:15 2007 +0200 [ALSA] hda-codec - Clean up bind-controls We have already a generic bind-control helper, so let's clean up the codes using it. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 18c2c77fd398f7b6170e25e2b7dd036111c70ad4 Author: Takashi Iwai Date: Fri Aug 10 17:11:07 2007 +0200 [ALSA] hda-codec - add snd_hda_codec_stereo() function Added snd_hda_codec_amp_stereo() function that changes both of stereo channels with the same mask and value bits. It simplifies most of amp-handling codes. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 13c288ff6f43bcb6802f0b5cf0feadbc3dbdd8b5 Author: Takashi Iwai Date: Fri Aug 10 17:09:26 2007 +0200 [ALSA] hda-codec - optimize resume using caches So far, the driver looked the table of snd_kcontrol_new used for creating mixer elements and forces to call each of its put callbacks in PM resume code. This is too ugly and hackish. Now, the resume is simplified using the codec amp and command register caches. The driver simply restores the values that have been written in the cache table. With this simplification, most codec support codes don't require any special resume callback. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 205b34a7f173b56af7cb5b48abb5b248209c7a61 Author: Takashi Iwai Date: Fri Aug 10 17:03:40 2007 +0200 [ALSA] hda-codec - introduce command register cache This patch adds the cache for codec command registers. snd_hda_codec_write_cache() and snd_hda_sequence_write_cache() do the write operations with caching, which values can be resumed via snd_hda_codec_resume_cache(). The patch introduces only the framework, and no codec code is using this cache yet. It'll be implemented in the following patch. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 736d85ab6d200defb252e6acb64bc609c2503313 Author: Takashi Iwai Date: Fri Aug 10 16:59:39 2007 +0200 [ALSA] hda-codec - rewrite amp cache more generic Rewrite the code to handle amp cache and hash tables to be more generic. This routine will be used by the register caches in the next patch. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7458a7d1a943a7d1dc57740495dde316cf556425 Author: Takashi Iwai Date: Fri Aug 10 16:50:37 2007 +0200 [ALSA] Use msecs_to_jiffies() in ac97_codec.c Replace the direct calculation of jiffies with msecs_to_jiffies(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e0944d8cedad77816254c369bb14f28183695d08 Author: Takashi Iwai Date: Fri Aug 10 15:07:06 2007 +0200 [ALSA] usb-audio - Add advanced mode support for Edirol UA-1EX Add the quirk to support Advanced mode of Edirol UA-1EX. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 62803c6f69fec9cacd85e08cb1370aa803b9dcff Author: Krzysztof Helt Date: Fri Aug 10 12:04:42 2007 +0200 [ALSA] isa libs Makefiles cleanup This patch uses the Kconfig parameters SND_AD1848_LIB and SND_CS4231_LIB instead of mentioning each driver that requires the ad1848-lib or cs4231-lib separately in the Makefiles. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 70fd98f917418d3e2698166082692d6c22698559 Author: Clemens Ladisch Date: Fri Aug 10 09:41:07 2007 +0200 [ALSA] seq_midi_event: fix parsing of F9/FD bytes Check for a valid event type when encoding a system real-time message to prevent the bytes F9 or FD resulting in an empty sequencer message. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 0b0f208930a9d994dda0fd243ed3b857c521a39a Author: Clemens Ladisch Date: Fri Aug 10 09:40:09 2007 +0200 [ALSA] seq_midi_event: fix parsing of missing data bytes Reorganize the encoder logic to prevent status bytes that appear where data bytes are expected from being interpreted as data bytes. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 68e142773088cdc8315685968e894e06eef0dab0 Author: Clemens Ladisch Date: Fri Aug 10 09:39:14 2007 +0200 [ALSA] seq_midi_event: prevent running status after system messages Reset the event type after encoding a system message to prevent any following data bytes from being interpreted as data for a running status system message, which is not allowed in MIDI. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit abfb2f79bafa69546f27eb872ec7d68d3f29f3cd Author: Clemens Ladisch Date: Fri Aug 10 09:38:36 2007 +0200 [ALSA] seq_midi_event: fix encoding of data bytes after end of sysex Create a new state ST_INVALID for the encoder to prevent data bytes at the beginning of a stream or after a sysex message being interpreted as note-off parameters. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit f711c916a03c9dcbbda1b3c1c657653a5a01f0ac Author: Mark Hills Date: Fri Aug 10 08:01:54 2007 +0200 [ALSA] This patch is a USB quirk to ensure the Stanton Scratchamp v1 is detected (bugtrack #2932). The interface is two USB devices in the same physical box. Note that this is the USB ScratchAmp v1 and not the later v2 (firewire) model. Signed-off-by: Mark Hills Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 0c21a94741e8e54ec29d6cd17cf7bb311332541d Author: Takashi Iwai Date: Wed Aug 8 17:00:32 2007 +0200 [ALSA] Add new AFMT_* formats for OSS emulation The recent OSS includes the support for 32bit and other formats, which we already have, too. Let's define and map them. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit fb17277b0c5d6a134a0190d6568b177be72314da Author: Takashi Iwai Date: Wed Aug 8 16:58:45 2007 +0200 [ALSA] Fix OSS documentation about 3bytes format Now the OSS emulation supports 3bytes format, too. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1cd769391ea77f88dcdaac66f27d264c73a0c6bc Author: Takashi Iwai Date: Wed Aug 8 16:49:08 2007 +0200 [ALSA] Support 3-bytes 24bit format in PCM OSS emulation Add the support of 3-bytes 24bit formats in PCM OSS emulation. Also removed snd_pcm_build_linear_format() function. It's exported just for OSS emulation, and now the code was changed without calling this function. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b5b290af1e6371acd2debcbfde869e54d11f5a75 Author: Takashi Iwai Date: Wed Aug 8 15:50:58 2007 +0200 [ALSA] Simplify the format conversion in PCM OSS emulation Simplify the format conversion code in PCM OSS emulation. This patch also adds the support of 3bytes 24bit formats with linear and mulaw, but they are not enabled in pcm_plugin.c yet. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0bb2fbed9b18a934e2523e0c83627bc902d03575 Author: Takashi Iwai Date: Wed Aug 8 15:20:48 2007 +0200 [ALSA] Remove ifdefs from OSS PCM emulation codes Fix Makefile to compile files conditionally to CONFIG_SND_PCM_OSS_PLUGINS, and remove unneeded ifdefs in these files. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 09870ed3e63a6c163322337c912df0651524fe0e Author: Takashi Iwai Date: Tue Aug 7 16:16:07 2007 +0200 [ALSA] doc - Remove IRQF_DISABLED from the example description Remove the bogus IRQF_DISBLAED together with IRQF_SHARED from the example code in the document. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit be38c01c16ea55394c4e26d50de814807874f74b Author: Eugene Teo Date: Tue Aug 7 14:34:23 2007 +0200 [ALSA] seq: resource leak fix and various code cleanups This patch fixes: 1) a resource leak (CID: 1817) 2) various code cleanups Signed-off-by: Eugene Teo Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4e9e9ac849349d4c47efbb204cbcc57af289c08f Author: Tobin Davis Date: Tue Aug 7 11:50:26 2007 +0200 [ALSA] hda-codec - Add support for Acer Aspire laptops This patch adds support for some Acer Aspire systems. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7879d0039d0105e6bbfea2d7af354e5c7df46cf1 Author: Tobin Davis Date: Tue Aug 7 11:48:12 2007 +0200 [ALSA] hda-codec - Add more Dell systems This patch adds support for Dell E520 and a couple of other 965 based systems. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0c747626d9e795f8e42d8e7333e8ba856e123210 Author: Russ Cox Date: Mon Aug 6 15:37:58 2007 +0200 [ALSA] fix selector unit bug affecting some USB speakerphones Following the suggestion in this thread: https://bugs.launchpad.net/ubuntu/+source/alsa-lib/+bug/26683 the correct upper bound on desc[0] is 5 + num_ins not 6 + num_ins, because the index used later is 5+i, not 6+i. This change makes my Vosky Chatterbox speakerphone work. Apparently it also helps with the Minivox MV100. Signed-off-by: Russ Cox Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c49c2600d54dd10a7e703801ab32c082d46ffe81 Author: Jesper Juhl Date: Mon Aug 6 14:05:27 2007 +0200 [ALSA] au88x0: mem leak fix in snd_vortex_create() In sound/pci/au88x0/au88x0.c::snd_vortex_create() : The Coverity checker found that if we allocate storage for 'chip' but then leave via the regions_out: label, then we end up leaking the storage allocated for 'chip'. I believe simply freeing 'chip' before the 'return err;' line is all we need to fix this, but please double-check me :) Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a6d29cf6f97ecb5b4e3e3f0b418d4970459c6932 Author: Takashi Iwai Date: Thu Aug 2 15:51:59 2007 +0200 [ALSA] hda-intel - Remove invalid __devinit Some functions in hda_codec.c are called from patch ops, which are kept in the codec instance even after initialization. Thus they shouldn't be marked as __devinit. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 590e85f95a83cb08f9a8708088d4056483cf309d Author: Michal Piotrowski Date: Thu Aug 2 14:26:43 2007 +0200 [ALSA] Get rid of dead code in sound/arm/sa11xx-uda1341.c File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 82 Unknown CONFIG option! CONFIG_H3600_HAL File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 103 Unknown CONFIG option! CONFIG_H3600_HAL File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 241 Unknown CONFIG option! CONFIG_H3600_HAL File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 310 Unknown CONFIG option! CONFIG_H3600_HAL File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 334 Unknown CONFIG option! CONFIG_H3600_HAL File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 344 Unknown CONFIG option! CONFIG_H3600_HAL File /home/devel/linux-rdc/sound/arm/sa11xx-uda1341.c line 357 Unknown CONFIG option! CONFIG_H3600_HAL Signed-off-by: Michal Piotrowski Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c2ec21e2682a329f5fc1efe8d7c320b1166a3eb5 Author: Michal Piotrowski Date: Thu Aug 2 14:15:05 2007 +0200 [ALSA] Coding style fix sound/pci/ca0106/ca_midi.h Coding style fix Signed-off-by: Michal Piotrowski Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 09ad94e48d6ba98c2a9f39e26913275002b1313b Author: Takashi Iwai Date: Thu Aug 2 00:01:43 2007 +0200 [ALSA] hda-intel - Fix a typo in Kconfig Fix a typo in Kconfig help text for CONFIG_SND_HDA_HWDEP. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 588974588f396cb6c516d64c1ec3d86f3dff6cb6 Author: Rene Herman Date: Wed Aug 1 23:50:21 2007 +0200 [ALSA] add the ESS1879 pnpbios ID to the es18xx driver As reported by Troy Heidner, the 'Gateway Solo 5150' laptop (for one) has an onboard ESS1879 that identifies itself through PNPBIOS as just that. He also confirmed that other than not knowing about it, snd-es18xx drives the chip fine, so this adds the ID to the driver. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit eb02ad96693b5f93653ffa13d6941d0d6292b95f Author: Scott Thompson Date: Wed Aug 1 13:38:59 2007 +0200 [ALSA] sound/soc ioremap/iounmap balancing ioremap / iounmap balancing in sound/soc tree Signed-off-by: Scott Thompson hushmail.com> Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ea48dd02369b668ca90f600abb0ba84d34303325 Author: Timur Tabi Date: Wed Aug 1 12:22:07 2007 +0200 [ALSA] CS4270 driver does not compile with I2C disabled Fix compilation errors with the CS4270 when I2C is not enabled. Updated some comments to indicate that that stand-alone mode is not fully implemented, because there is no mechanism for the CS4270 driver and the machine driver to communicate the values of various input pins. Signed-off-by: Timur Tabi Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 92eaf323b79458ded27d5b6bd165ec7ef8442c6e Author: Timur Tabi Date: Tue Jul 31 18:18:44 2007 +0200 [ALSA] ASoC CS4270 codec device driver This patch adds ALSA SoC support for the Cirrus Logic CS4270 codec. The following features are suppored: 1) Stand-alone and software mode 2) Software mode via I2C only 3) Master mode, not Slave 4) No power management Signed-off-by: Timur Tabi Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 15b50c7a48708ca78a6fe3d8272df7fc5245c28d Author: Takashi Iwai Date: Tue Jul 31 15:56:24 2007 +0200 [ALSA] hda-codec - Fix GPIO in resume Reinitialize GPIO in resume callback if necessary. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 35a3469d1e49eecd824e067158cf9112c5b3a316 Author: Takashi Iwai Date: Tue Jul 31 11:09:16 2007 +0200 [ALSA] hda-intel - Fix a typo in Makefile Fixed a typo of CONFIG_SND_HDA_GENERIC. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b9b5cdffa45ba50363bd9536a0de7a30bd369084 Author: Takashi Iwai Date: Tue Jul 31 11:08:10 2007 +0200 [ALSA] hda-intel - Fix compile warning in snd_hwdep_ioctl_compat() Fix missing cast: sound/pci/hda/hda_hwdep.c:86: warning: passing argument 4 of 'hda_hwdep_ioctl' makes integer from pointer without a cast Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 202da1813ca7f5e5eb2f1de50c86bd1ecc1e0b00 Author: Tobin Davis Date: Mon Jul 30 21:42:10 2007 +0200 [ALSA] hda-codec - Add support for the ASRock K8NF6G-VSTA motherboard This patch adds ALC861VD support for the ASRock K8NF6G-VSTA motherboard. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6eb9b4e13c5eb463954445c596323f2d8aa4933e Author: Adrian Bunk Date: Mon Jul 30 15:40:43 2007 +0200 [ALSA] sound/synth/util_mem.c: remove pointless check The Coverity checker spotted that if anyone would call this function with 'prev == NULL', he would still get an Oops a few lines below. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d6699026782e62477b62ca8f861188038368cf2d Author: Takashi Iwai Date: Mon Jul 30 14:52:41 2007 +0200 [ALSA] Add missing static in ac97_codec.c Added missing static to snd_ac97_restore_status() and snd_ac97_restore_iec958() functions. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1591b0ec7d1d25fbd2fff877e14170d2d2220828 Author: James Courtier-Dutton Date: Thu Jul 26 18:44:49 2007 +0100 [ALSA] snd-emu10k1:Unmute the Audio/Micro Dock after firmware load. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit a9b28ca01ab792261e541f7dc56aca72bfc7de85 Author: James Courtier-Dutton Date: Thu Jul 26 18:31:39 2007 +0100 [ALSA] snd-emu10k1:Implement SPDIF/ADAT status. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 6c9badf749fc0e25f9378113944ad2ee99343012 Author: James Courtier-Dutton Date: Mon Jul 23 14:01:46 2007 +0100 [ALSA] snd-emu10k1: Add support for E-Mu 1616 PCI, 1616M PCI, 0404 PCI, E-Mu Notebook. Description: The .device=0x0008 chips have new, but different EMU32 in/out channels. Driver updated to make use of these EMU32 channels. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit fadce3d83ef480726536c96f35517609e0ed34e5 Author: James Courtier-Dutton Date: Mon Jul 23 18:12:41 2007 +0100 [ALSA] snd-ca0106:Add recognition for new variant. Fixes ALSA bug#3251 Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 838cdf444c86f3b19461b844c905c634a605f8c7 Author: James Courtier-Dutton Date: Mon Jul 23 20:30:22 2007 +0100 [ALSA] snd-emu10k1:Support for ADAT and S/PDIF. Patch submitted by Ctirad Fertr Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 55ec24ff37fa91750675b766ded74766e55f797d Author: James Courtier-Dutton Date: Mon Jul 23 17:52:27 2007 +0100 [ALSA] snd-emu10k1:Improves firmware loading for E-Mu cards. Details: Fixes http://bugzilla.kernel.org/show_bug.cgi?id=8176 Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit f5ce0354d33a302e2435d503fab4da15487e8c42 Author: Clemens Ladisch Date: Mon Jul 30 08:14:31 2007 +0200 [ALSA] check for linked substreams of different cards It is possible to have linked substreams that belong to different cards and/or different drivers. This patch changes some drivers to make sure that they do not incorrectly try to handle substreams of a different card. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit ac71a8c0acfecd74c65df95920221171b70c317f Author: Takashi Iwai Date: Fri Jul 27 19:15:54 2007 +0200 [ALSA] hda-codec - kernel config for each codec Create kernel configs to choose the codec support codes to build. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f11396e551da6bdd0a8860c34505ad1b5f7218f1 Author: Takashi Iwai Date: Fri Jul 27 19:02:40 2007 +0200 [ALSA] hda-codec - Add a generic bind-control helper Added callbacks for a generic bind-control of mixer elements. This can be used for creating a mixer element controlling multiple widgets at the same time. Two macros, HDA_BIND_VOL() and HDA_BIND_SW(), are introduced for creating bind-volume and bind-switch, respectively. It taks the mixer element name and struct hda_bind_ctls pointer, which contains the real control callbacks in ops field and long array for private_value of each bound widget. All widgets have to be the same type (i.e. the same amp capability). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cd28fdc7f53877178da0029aadec28ce5d327561 Author: Takashi Iwai Date: Fri Jul 27 18:58:06 2007 +0200 [ALSA] hda-intel - Add hwdep interface Added a hwdep interface for each codec (enabled per kconfig). This interface can be used for reading/writing HD-audio verbs and other purposes as future extensions. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f58cf256adfc9cb543e4d46b2474f78c81152672 Author: Takashi Iwai Date: Fri Jul 27 16:52:46 2007 +0200 [ALSA] hdspm - Coding style fixes Fix codes to follow more to the standard kernel coding style. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit db633264a1b973f449d6ec0161bf238088de82c3 Author: Takashi Iwai Date: Fri Jul 27 16:52:19 2007 +0200 [ALSA] hda-intel - Coding style fixes Fix codes to follow more to the standard kernel coding style. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b84a9022357f00a58e36677001a49361a46493f4 Author: Paul Vojta Date: Fri Jul 27 12:20:38 2007 +0200 [ALSA] Fix bugs in mode change/recalibration for opl3sa2 driver The mode change / recalibration doesn't work always with opl3sa2 devices, e.g. the first time it's played back. The patch fixes the problem. Signed-off-by: Paul Vojta Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit af6388e5351ee651efdb346888f35f9b4987a1f5 Author: Karsten Wiese Date: Fri Jul 27 12:15:42 2007 +0200 [ALSA] snd_usb_caiaq_input_free() fix input_free_device()'s comment says: input_free_device() should only be used if input_register_device() was not called yet or if it failed. Once device was registered use input_unregister_device() and memory will be freed once last refrence to the device is dropped. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6d11c1d25afdb5ce126152b7e1730b9cda621b47 Author: Takashi Iwai Date: Thu Jul 26 19:10:47 2007 +0200 [ALSA] Clean up Makefile Clean up Makefile using xxx- style instead of ifeq(CONFIG_XXX,y). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 128e729281a132ce40deb2077b5303b4b45190b5 Author: Takashi Iwai Date: Thu Jul 26 18:59:36 2007 +0200 [ALSA] Fix build error without CONFIG_HAS_DMA The recent change of include/asm-generic/dma-mapping-broken.h breaks the build without CONFIG_HAS_DMA. This patch is an ad hoc fix. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 70fefbef927f0e5c1635ddd7b9186c94805ef5a4 Author: Takashi Iwai Date: Thu Jul 26 16:50:09 2007 +0200 [ALSA] Fixes to follow the standard coding style Fixed the tutorial to follow the standard kernel coding style. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7bb2446d62df030ebdcc0f12b2c3d77321fde437 Author: Takashi Iwai Date: Thu Jul 26 11:49:22 2007 +0200 [ALSA] hda-codec - Fix the initial mixer state of ALC262 sony-assamd model Many of ALC262 codes don't call the automute function at the beginning, which may keep the silence until the HP jack is replugged. Now proper init_hook is added. Also, sony-assamd model doesn't handle the widget 0x14 properly, thus calling automute isn't enough. Now Front switch handles both widgets. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 551f23f82b80ec4814686a25df64b6003e5b37ce Author: Trent Piepho Date: Wed Jul 25 18:41:17 2007 +0200 [ALSA] ca0106: remove extra commands in SPI DAC init sequence The init sequence set a number of registers more than once to different values. It's only necessary to set them once to their final values. It also never actually updated the digital attenuation settings. Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 367d19e386b5cafbb05da55df64e13ab72b76774 Author: Trent Piepho Date: Wed Jul 25 18:40:39 2007 +0200 [ALSA] ca0106: Add more symbol SPI register names and use them Add more symbol name for SPI register values. Change the SPI_XXX_BIT defines from the bit number to a mask. Saves having to write (1< Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 17c84d69e36f0cd648ca1192d216d725aa58908a Author: Trent Piepho Date: Wed Jul 25 18:39:59 2007 +0200 [ALSA] ca0106: power down SPI DAC channels when not in use For cards with an SPI DAC (SB Live 24-bit / Audigy SE), power down channels 0-2 when not in use. They are powered up on PCM open and down again on PCM close. Channel 4 (== Front) is not powered down, as it is used for capture feedback. Powering it down would effectively kill line in pass-through. Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b5ff9c8b4fcacebdfb406de926ae3636c9c6b1ce Author: Takashi Iwai Date: Tue Jul 24 18:04:05 2007 +0200 [ALSA] hda-codec - Fix AD1988 SPDIF output The SPDIF output on AD1988 had some problems due to the wrongly routed analog loopback to SPDIF. This patch fixes the implementation of 'IEC958 Playback Source' mixer to handle the amp bits of mixer widget 0x1d correctly. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0d886580048cd8ce3328921218d2c739a95eb4f2 Author: Harald Welte Date: Tue Jul 24 12:49:39 2007 +0200 [ALSA] s3c24xx-pcm: fix hw_params dma handling Since the PCM emulation can call multiple times to hw_setup(), but we can only once allocate/request the DMA channel, we have to handle this gracefully. Signed-off-by: Harald Welte Signed-off-by: Arnaud Patard Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4a5fa19436478f0d362512f71687414ae0f0bfc3 Author: Trent Piepho Date: Tue Jul 24 12:10:34 2007 +0200 [ALSA] ca0106: replaced control add sequences with macro Turn a rather long lined for loop that is duplicated multiple times into a macro. Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d87a2676b3c7fe162268fb5ffea975de61d33c33 Author: Trent Piepho Date: Tue Jul 24 12:06:16 2007 +0200 [ALSA] ca0106: Add analog mute controls for cards with SPI DAC Add four mute controls for the analog output channels for cards that use an SPI DAC, like the SB0570 SB Live! 24-bit / Audigy SE. The Wolfson DAC doesn't support muting left/right so the controls are mono. The chip state struct gets a 32-byte array to act as a shadow of the spi dac registers. Only two registers are used for mute, but more would be needed for analog gain, de-emphasis, DAC power down, phase inversion, and other features. Signed-off-by: Trent Piepho Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cb9750ac507649e7a9fa308cac14e19dac5b103c Author: Adrian Bunk Date: Tue Jul 24 11:56:45 2007 +0200 [ALSA] sound/pci/cs46xx/: fix an off-by-one This patch fixes an off-by-one in a snd_assert() spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5fa1f30bb2eb1424edfb4bddc1bcb1aae0e54c39 Author: Takashi Iwai Date: Tue Jul 24 11:21:21 2007 +0200 [ALSA] ice1712 - Fix missing replacement to snd_ctl_boolean_mono_info There were some places I forgot to replace with snd_ctl_boolean_mono_info. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f90d7cd3ec54359c79527b14deeb34d7732972de Author: Clemens Ladisch Date: Mon Jul 23 17:38:44 2007 +0200 [ALSA] ymfpci: fix volume handling of the 44.1 kHz slot The existing code for handling the 44.1 slot's volume has two problems: the volume is not affected by the 'Wave Playback Volume' mixer control, and the BUF441OUTVOL register, which is used to control the per- substream volume for this slot, uses a different scale than the gain fields of the other slots. This patch makes the BUF441OUTVOL register a shadow of the NATIVEDACOUTVOL register so that the Wave volume is consistent for all substreams. As a consequence of this, the per-substream PCM volume control gets no longer activated for the substream using this slot. The code for (de)activating the mixer control is moved from the open/close to the prepare/trigger_stop callbacks so that it is able to determine the substream's slot. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 5dc80dabaa74e138d5a881e2945992c132f1e5d2 Author: Hans-Christian Egtvedt Date: Mon Jul 23 16:01:38 2007 +0200 [ALSA] ALSA sound driver for the AT73C213 DAC using Atmel SSC driver This patch adds support for the AT73C213 DAC using the misc Atmel SSC driver in I2S mode. The driver also requires a SPI to setup the registers and control volume. It has been tested with an AT32AP7000 on the ATSTK1000 development board. The driver should also work with any Atmel device with an SSC module supported by the Atmel SSC driver (atmel-ssc). The atmel-ssc driver is just submitted to the Linux kernel. Please see mail thread http://lkml.org/lkml/2007/7/16/32 Signed-off-by: Hans-Christian Egtvedt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 51ed5da767cdef179f8dd999ede6cca052251c60 Author: Hans-Christian Egtvedt Date: Mon Jul 23 15:52:42 2007 +0200 [ALSA] Add SPI devices to ALSA Kconfig and Makefile This patch adds SPI devices in the ALSA diretory, including the Kconfig and Makefile. Signed-off-by: Hans-Christian Egtvedt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9c8cf13b6b33f8ffc2f63965e6397e809bac6fd6 Author: Arnaud Patard Date: Mon Jul 23 15:43:37 2007 +0200 [ALSA] Fix Kconfig entry for SND_S3C24XX_SOC_NEO1973_WM8753 SND_S3C24XX_SOC_NEO1973_WM8753 depends on MACH_GTA01 but the Kconfig entry which is going to be merged is MACH_NEO1973_GTA01. Signed-off-by: Arnaud Patard Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 98836bb6906e7f7f0dc983289bbf99552589cd58 Author: Takashi Iwai Date: Mon Jul 23 15:42:26 2007 +0200 [ALSA] Clean up with common snd_ctl_boolean_*_info callbacks Clean up codes using the new common snd_ctl_boolean_*_info() callbacks. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f13b7d7c745586cc568fbdbf85946bddb6c1a9ac Author: Takashi Iwai Date: Mon Jul 23 15:41:34 2007 +0200 [ALSA] Add helper functions for frequently used callbacks Added helper functions for frequenty used callbacks: snd_ctl_boolean_mono_info() and snd_ctl_boolean_stereo_info() Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1c4e64d6686c0a9d8cb2f6bafc3fae536c7fb7ef Author: Jesper Juhl Date: Mon Jul 23 12:15:42 2007 +0200 [ALSA] Clean up duplicate includes in sound/core/ This patch cleans up duplicate includes in sound/core/ Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 3dbc8377d1b6bd4bed831121bede22109128ebd3 Author: Jesper Juhl Date: Mon Jul 23 12:15:16 2007 +0200 [ALSA] Clean up duplicate includes in sound/soc/ This patch cleans up duplicate includes in sound/soc/ Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4cdd0fdaf7d3f539b7732cc83563f6ba2fbb8d0a Author: Jesper Juhl Date: Mon Jul 23 12:14:53 2007 +0200 [ALSA] Clean up duplicate includes in sound/ppc/ This patch cleans up duplicate includes in sound/ppc/ Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c4cda455059cd47cf0896f576076ab1c5cd6cb4b Author: Stephen Rothwell Date: Mon Jul 23 12:10:07 2007 +0200 [ALSA] Fix tas_suspend/resume build warning sound/aoa/codecs/snd-aoa-codec-tas.c:750: warning: 'tas_suspend' defined but not used sound/aoa/codecs/snd-aoa-codec-tas.c:760: warning: 'tas_resume' defined but not used Acked-by: Johannes Berg Signed-off-by: Stephen Rothwell Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela Documentation/sound/alsa/ALSA-Configuration.txt | 113 + Documentation/sound/alsa/CMIPCI.txt | 17 .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 184 ++- Documentation/sound/alsa/OSS-Emulation.txt | 7 Documentation/sound/alsa/hda_codec.txt | 49 - Documentation/sound/alsa/powersave.txt | 41 + include/linux/i2c-id.h | 1 include/linux/spi/at73c213.h | 25 include/sound/ac97_codec.h | 6 include/sound/ad1848.h | 2 include/sound/asound.h | 1 include/sound/control.h | 8 include/sound/cs4231-regs.h | 180 ++ include/sound/cs4231.h | 157 -- include/sound/emu10k1.h | 13 include/sound/hda_hwdep.h | 44 + include/sound/hdspm.h | 16 include/sound/pcm.h | 11 include/sound/soc.h | 3 sound/Kconfig | 4 sound/Makefile | 3 sound/aoa/codecs/snd-aoa-codec-onyx.c | 20 sound/aoa/codecs/snd-aoa-codec-tas.c | 29 sound/aoa/fabrics/snd-aoa-fabric-layout.c | 10 sound/arm/sa11xx-uda1341.c | 35 sound/core/Makefile | 13 sound/core/control.c | 31 sound/core/memalloc.c | 6 sound/core/oss/Makefile | 5 sound/core/oss/copy.c | 5 sound/core/oss/io.c | 5 sound/core/oss/linear.c | 89 + sound/core/oss/mulaw.c | 88 + sound/core/oss/pcm_oss.c | 35 sound/core/oss/pcm_plugin.c | 61 - sound/core/oss/plugin_ops.h | 370 ----- sound/core/oss/rate.c | 5 sound/core/oss/route.c | 5 sound/core/pcm_misc.c | 63 - sound/core/pcm_native.c | 8 sound/core/rawmidi.c | 1 sound/core/seq/oss/seq_oss_init.c | 40 - sound/core/seq/oss/seq_oss_writeq.c | 6 sound/core/seq/seq_instr.c | 10 sound/core/seq/seq_midi_event.c | 97 + sound/drivers/dummy.c | 10 sound/drivers/mts64.c | 10 sound/drivers/opl3/Makefile | 6 sound/drivers/vx/vx_mixer.c | 18 sound/i2c/Makefile | 4 sound/i2c/cs8427.c | 6 sound/i2c/other/ak4114.c | 10 sound/i2c/other/ak4117.c | 10 sound/i2c/other/ak4xxx-adda.c | 10 sound/i2c/other/pt2258.c | 10 sound/i2c/tea6330t.c | 10 sound/isa/Kconfig | 22 sound/isa/Makefile | 2 sound/isa/ad1816a/ad1816a_lib.c | 2 sound/isa/ad1848/Makefile | 7 sound/isa/ad1848/ad1848_lib.c | 122 +- sound/isa/cs423x/Makefile | 17 sound/isa/cs423x/cs4231_lib.c | 110 + sound/isa/es18xx.c | 19 sound/isa/gus/gus_mixer.c | 9 sound/isa/opl3sa2.c | 1 sound/isa/opti9xx/miro.c | 18 sound/isa/opti9xx/opti92x-ad1848.c | 4 sound/isa/sb/sb16_csp.c | 9 sound/isa/sb/sb_common.c | 4 sound/isa/sc6000.c | 656 +++++++++ sound/isa/sscape.c | 354 +++-- sound/isa/wavefront/wavefront_synth.c | 130 +- sound/pci/Kconfig | 111 + sound/pci/ac97/ac97_codec.c | 36 sound/pci/ac97/ac97_id.h | 1 sound/pci/ac97/ac97_patch.c | 160 +- sound/pci/ac97/ac97_proc.c | 8 sound/pci/ali5451/ali5451.c | 10 sound/pci/au88x0/au88x0.c | 1 sound/pci/au88x0/au88x0_eq.c | 10 sound/pci/au88x0/au88x0_synth.c | 4 sound/pci/bt87x.c | 217 ++- sound/pci/ca0106/ca0106.h | 98 + sound/pci/ca0106/ca0106_main.c | 103 + sound/pci/ca0106/ca0106_mixer.c | 98 + sound/pci/ca0106/ca_midi.h | 6 sound/pci/cmipci.c | 537 +++++-- sound/pci/cs4281.c | 24 sound/pci/cs46xx/Makefile | 6 sound/pci/cs46xx/cs46xx_lib.c | 10 sound/pci/cs46xx/dsp_spos_scb_lib.c | 2 sound/pci/cs5535audio/Makefile | 7 sound/pci/cs5535audio/cs5535audio.c | 24 sound/pci/cs5535audio/cs5535audio.h | 42 - sound/pci/cs5535audio/cs5535audio_pcm.c | 10 sound/pci/cs5535audio/cs5535audio_pm.c | 26 sound/pci/echoaudio/echoaudio.c | 33 sound/pci/echoaudio/echoaudio_dsp.c | 4 sound/pci/echoaudio/echoaudio_dsp.h | 15 sound/pci/emu10k1/emu10k1_main.c | 128 +- sound/pci/emu10k1/emu10k1x.c | 9 sound/pci/emu10k1/emufx.c | 249 ++- sound/pci/emu10k1/emumixer.c | 84 + sound/pci/emu10k1/emuproc.c | 56 + sound/pci/emu10k1/io.c | 10 sound/pci/emu10k1/p16v.c | 19 sound/pci/ens1370.c | 40 - sound/pci/es1938.c | 20 sound/pci/es1968.c | 28 sound/pci/hda/Makefile | 27 sound/pci/hda/hda_codec.c | 715 +++++++-- sound/pci/hda/hda_codec.h | 113 + sound/pci/hda/hda_generic.c | 100 + sound/pci/hda/hda_hwdep.c | 122 ++ sound/pci/hda/hda_intel.c | 382 ++++- sound/pci/hda/hda_local.h | 193 ++- sound/pci/hda/hda_patch.h | 16 sound/pci/hda/hda_proc.c | 30 sound/pci/hda/patch_analog.c | 524 ++++--- sound/pci/hda/patch_atihdmi.c | 16 sound/pci/hda/patch_cmedia.c | 24 sound/pci/hda/patch_conexant.c | 156 +- sound/pci/hda/patch_realtek.c | 1538 ++++++++++++++------ sound/pci/hda/patch_si3054.c | 20 sound/pci/hda/patch_sigmatel.c | 959 +++++++++--- sound/pci/hda/patch_via.c | 80 + sound/pci/ice1712/aureon.c | 45 - sound/pci/ice1712/delta.c | 11 sound/pci/ice1712/ews.c | 18 sound/pci/ice1712/ice1712.c | 48 - sound/pci/ice1712/ice1712.h | 3 sound/pci/ice1712/ice1724.c | 50 - sound/pci/ice1712/phase.c | 23 sound/pci/ice1712/pontis.c | 27 sound/pci/ice1712/prodigy192.c | 27 sound/pci/ice1712/wtm.c | 29 sound/pci/korg1212/korg1212.c | 4 sound/pci/maestro3.c | 2 sound/pci/mixart/mixart.c | 10 sound/pci/mixart/mixart_mixer.c | 9 sound/pci/nm256/nm256.c | 1 sound/pci/pcxhr/pcxhr.c | 5 sound/pci/pcxhr/pcxhr_mixer.c | 9 sound/pci/rme32.c | 33 sound/pci/rme96.c | 41 - sound/pci/rme9652/hdsp.c | 87 - sound/pci/rme9652/hdspm.c | 723 +++++---- sound/pci/rme9652/rme9652.c | 27 sound/pci/trident/trident_main.c | 20 sound/pci/via82xx.c | 14 sound/pci/via82xx_modem.c | 4 sound/pci/ymfpci/ymfpci_main.c | 106 + sound/pcmcia/vx/vxp_mixer.c | 9 sound/ppc/daca.c | 10 sound/ppc/pmac.c | 57 - sound/ppc/pmac.h | 4 sound/ppc/snd_ps3.c | 1 sound/sh/aica.c | 10 sound/soc/codecs/Kconfig | 20 sound/soc/codecs/Makefile | 2 sound/soc/codecs/cs4270.c | 805 ++++++++++ sound/soc/codecs/cs4270.h | 28 sound/soc/pxa/spitz.c | 1 sound/soc/s3c24xx/Kconfig | 2 sound/soc/s3c24xx/s3c24xx-i2s.c | 1 sound/soc/s3c24xx/s3c24xx-pcm.c | 22 sound/soc/soc-core.c | 20 sound/soc/soc-dapm.c | 2 sound/sparc/cs4231.c | 208 +-- sound/sparc/dbri.c | 581 ++++---- sound/spi/Kconfig | 31 sound/spi/Makefile | 5 sound/spi/at73c213.c | 1129 +++++++++++++++ sound/spi/at73c213.h | 119 ++ sound/synth/util_mem.c | 2 sound/usb/Kconfig | 2 sound/usb/caiaq/caiaq-audio.c | 1 sound/usb/caiaq/caiaq-device.c | 18 sound/usb/caiaq/caiaq-device.h | 1 sound/usb/caiaq/caiaq-input.c | 28 sound/usb/usbaudio.c | 46 - sound/usb/usbmidi.c | 46 + sound/usb/usbmixer.c | 11 sound/usb/usbquirks.h | 86 + 185 files changed, 10199 insertions(+), 5258 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 241e26c..9268925 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -365,13 +365,14 @@ Prior to version 0.9.0rc4 options had a Module snd-cmipci ----------------- - Module for C-Media CMI8338 and 8738 PCI sound cards. + Module for C-Media CMI8338/8738/8768/8770 PCI sound cards. - mpu_port - 0x300,0x310,0x320,0x330 = legacy port, - 1 = integrated PCI port, + mpu_port - port address of MIDI interface (8338 only): + 0x300,0x310,0x320,0x330 = legacy port, 0 = disable (default) - fm_port - 0x388 = legacy port, - 1 = integrated PCI port (default), + fm_port - port address of OPL-3 FM synthesizer (8x38 only): + 0x388 = legacy port, + 1 = integrated PCI port (default on 8738), 0 = disable soft_ac3 - Software-conversion of raw SPDIF packets (model 033 only) (default = 1) @@ -768,6 +769,10 @@ Prior to version 0.9.0rc4 options had a single_cmd - Use single immediate commands to communicate with codecs (for debugging only) enable_msi - Enable Message Signaled Interrupt (MSI) (default = off) + power_save - Automatic power-saving timtout (in second, 0 = + disable) + power_save_controller - Reset HD-audio controller in power-saving mode + (default = on) This module supports one card and autoprobe. @@ -828,6 +833,8 @@ Prior to version 0.9.0rc4 options had a ALC268 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops auto auto-config reading BIOS (default) ALC662 @@ -842,7 +849,11 @@ Prior to version 0.9.0rc4 options had a 3stack-dig 3-jack with SPDIF I/O 6stack-dig 6-jack digital with SPDIF I/O arima Arima W820Di1 + targa Targa T8, MSI-1049 T8 + asus-a7j ASUS A7J + asus-a7m ASUS A7M macpro MacPro support + mbp3 Macbook Pro rev3 imac24 iMac 24'' with jack detection w2jc ASUS W2JC auto auto-config reading BIOS (default) @@ -854,6 +865,7 @@ Prior to version 0.9.0rc4 options had a 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + acer-aspire Acer Aspire 9810 medion Medion Laptops medion-md2 Medion MD2 targa-dig Targa/MSI @@ -862,6 +874,7 @@ Prior to version 0.9.0rc4 options had a lenovo-101e Lenovo 101E lenovo-nb0763 Lenovo NB0763 lenovo-ms7195-dig Lenovo MS7195 + haier-w66 Haier W66 6stack-hp HP machines with 6stack (Nettle boards) 3stack-hp HP machines with 3stack (Lucknow, Samba boards) auto auto-config reading BIOS (default) @@ -885,6 +898,7 @@ Prior to version 0.9.0rc4 options had a 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) lenovo Lenovo 3000 C200 dallas Dallas laptops + hp HP TX1000 auto auto-config reading BIOS (default) CMI9880 @@ -920,6 +934,7 @@ Prior to version 0.9.0rc4 options had a 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) ultra 2-channel with EAPD (Samsung Ultra tablet PC) AD1988 @@ -945,14 +960,29 @@ Prior to version 0.9.0rc4 options had a can be adjusted. Appearing only when compiled with $CONFIG_SND_DEBUG=y - STAC9200/9205/9254 + STAC9200 ref Reference board + dell-d21 Dell (unknown) + dell-d22 Dell (unknown) + dell-d23 Dell (unknown) + dell-m21 Dell Inspiron 630m, Dell Inspiron 640m + dell-m22 Dell Latitude D620, Dell Latitude D820 + dell-m23 Dell XPS M1710, Dell Precision M90 + dell-m24 Dell Latitude 120L + dell-m25 Dell Inspiron E1505n + dell-m26 Dell Inspiron 1501 + dell-m27 Dell Inspiron E1705/9400 + + STAC9205/9254 + ref Reference board + dell-m42 Dell (unknown) + dell-m43 Dell Precision + dell-m44 Dell Inspiron STAC9220/9221 ref Reference board 3stack D945 3stack 5stack D945 5stack + SPDIF - dell Dell XPS M1210 intel-mac-v1 Intel Mac Type 1 intel-mac-v2 Intel Mac Type 2 intel-mac-v3 Intel Mac Type 3 @@ -964,6 +994,10 @@ Prior to version 0.9.0rc4 options had a macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) imac-intel Intel iMac (eq. type 2) imac-intel-20 Intel iMac (newer version) (eq. type 3) + dell-d81 Dell (unknown) + dell-d82 Dell (unknown) + dell-m81 Dell (unknown) + dell-m82 Dell XPS M1210 STAC9202/9250/9251 ref Reference board, base config @@ -975,6 +1009,7 @@ Prior to version 0.9.0rc4 options had a ref Reference board 3stack D965 3stack 5stack D965 5stack + SPDIF + dell-3stack Dell Dimension E520 STAC9872 vaio Setup for VAIO FE550G/SZ110 @@ -989,6 +1024,9 @@ Prior to version 0.9.0rc4 options had a subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel ML (see the section "Links and Addresses"). + power_save and power_save_controller options are for power-saving + mode. See powersave.txt for details. + Note 2: If you get click noises on output, try the module option position_fix=1 or 2. position_fix=1 will use the SD_LPIB register value without FIFO size correction as the current @@ -1630,6 +1668,21 @@ Prior to version 0.9.0rc4 options had a The power-management is supported. + Module snd-sc6000 + ----------------- + + Module for Gallant SC-6000 soundcard. + + port - Port # (0x220 or 0x240) + mss_port - MSS Port # (0x530 or 0xe80) + irq - IRQ # (5,7,9,10,11) + mpu_irq - MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq + dma - DMA # (1,3,0) + + This module supports multiple cards. + + This card is also known as Audio Excel DSP 16 or Zoltrix AV302. + Module snd-sgalaxy ------------------ @@ -1650,9 +1703,11 @@ Prior to version 0.9.0rc4 options had a Module for ENSONIQ SoundScape PnP cards. port - Port # (PnP setup) + wss_port - WSS Port # (PnP setup) irq - IRQ # (PnP setup) mpu_irq - MPU-401 IRQ # (PnP setup) dma - DMA # (PnP setup) + dma2 - 2nd DMA # (PnP setup, -1 to disable) This module supports multiple cards. ISA PnP must be enabled. You need sscape_ctl tool in alsa-tools package for loading @@ -1697,8 +1752,52 @@ Prior to version 0.9.0rc4 options had a dma2 - DMA2 # for CS4232 PCM interface. isapnp - ISA PnP detection - 0 = disable, 1 = enable (default) + The below are options for wavefront_synth features: + wf_raw - Assume that we need to boot the OS (default:no) + If yes, then during driver loading, the state of the board is + ignored, and we reset the board and load the firmware anyway. + fx_raw - Assume that the FX process needs help (default:yes) + If false, we'll leave the FX processor in whatever state it is + when the driver is loaded. The default is to download the + microprogram and associated coefficients to set it up for + "default" operation, whatever that means. + debug_default - Debug parameters for card initialization + wait_usecs - How long to wait without sleeping, usecs + (default:150) + This magic number seems to give pretty optimal throughput + based on my limited experimentation. + If you want to play around with it and find a better value, be + my guest. Remember, the idea is to get a number that causes us + to just busy wait for as many WaveFront commands as possible, + without coming up with a number so large that we hog the whole + CPU. + Specifically, with this number, out of about 134,000 status + waits, only about 250 result in a sleep. + sleep_interval - How long to sleep when waiting for reply + (default: 100) + sleep_tries - How many times to try sleeping during a wait + (default: 50) + ospath - Pathname to processed ICS2115 OS firmware + (default:wavefront.os) + The path name of the ISC2115 OS firmware. In the recent + version, it's handled via firmware loader framework, so it + must be installed in the proper path, typically, + /lib/firmware. + reset_time - How long to wait for a reset to take effect + (default:2) + ramcheck_time - How many seconds to wait for the RAM test + (default:20) + osrun_time - How many seconds to wait for the ICS2115 OS + (default:10) + This module supports multiple cards and ISA PnP. + Note: the firmware file "wavefront.os" was located in the earlier + version in /etc. Now it's loaded via firmware loader, and + must be in the proper firmware path, such as /lib/firmware. + Copy (or symlink) the file appropriately if you get an error + regarding firmware downloading after upgrading the kernel. + Module snd-sonicvibes --------------------- diff --git a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt index 4b2b153..16935c8 100644 --- a/Documentation/sound/alsa/CMIPCI.txt +++ b/Documentation/sound/alsa/CMIPCI.txt @@ -1,5 +1,5 @@ - Brief Notes on C-Media 8738/8338 Driver - ======================================= + Brief Notes on C-Media 8338/8738/8768/8770 Driver + ================================================= Takashi Iwai @@ -209,10 +209,13 @@ In addition to the standard SB mixer, CM MIDI CONTROLLER --------------- -The MPU401-UART interface is disabled as default. You need to set -module option "mpu_port" with a valid I/O port address to enable the -MIDI support. The valid I/O ports are 0x300, 0x310, 0x320 and 0x330. -Choose the value which doesn't conflict with other cards. +With CMI8338 chips, the MPU401-UART interface is disabled as default. +You need to set the module option "mpu_port" to a valid I/O port address +to enable MIDI support. Valid I/O ports are 0x300, 0x310, 0x320 and +0x330. Choose a value that doesn't conflict with other cards. + +With CMI8738 and newer chips, the MIDI interface is enabled by default +and the driver automatically chooses a port address. There is _no_ hardware wavetable function on this chip (except for OPL3 synth below). @@ -230,6 +233,8 @@ Set "fm_port" module option for more car The output quality of FM OPL/3 is, however, very weird. I don't know why.. +CMI8768 and newer chips do not have the FM synth. + Joystick and Modem ------------------ diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 74d3a35..2c3fc3c 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -18,8 +18,8 @@ - November 17, 2005 - 0.3.6 + September 10, 2007 + 0.3.7 @@ -405,8 +405,9 @@ /* definition of the chip-specific record */ struct mychip { struct snd_card *card; - // rest of implementation will be in the section - // "PCI Resource Managements" + /* rest of implementation will be in the section + * "PCI Resource Managements" + */ }; /* chip-specific destructor @@ -414,7 +415,7 @@ */ static int snd_mychip_free(struct mychip *chip) { - .... // will be implemented later... + .... /* will be implemented later... */ } /* component-destructor @@ -440,8 +441,9 @@ *rchip = NULL; - // check PCI availability here - // (see "PCI Resource Managements") + /* check PCI availability here + * (see "PCI Resource Managements") + */ .... /* allocate a chip-specific data with zero filled */ @@ -451,12 +453,13 @@ chip->card = card; - // rest of initialization here; will be implemented - // later, see "PCI Resource Managements" + /* rest of initialization here; will be implemented + * later, see "PCI Resource Managements" + */ .... - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_mychip_free(chip); return err; } @@ -490,7 +493,8 @@ return -ENOMEM; /* (3) */ - if ((err = snd_mychip_create(card, pci, &chip)) < 0) { + err = snd_mychip_create(card, pci, &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -502,10 +506,11 @@ card->shortname, chip->ioport, chip->irq); /* (5) */ - .... // implemented later + .... /* implemented later */ /* (6) */ - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } @@ -605,7 +610,8 @@ irq >= 0) @@ -1119,7 +1126,8 @@ *rchip = NULL; /* initialize the PCI entry */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; /* check PCI availability (28bit DMA) */ if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || @@ -1141,7 +1149,8 @@ chip->irq = -1; /* (1) PCI resource allocation */ - if ((err = pci_request_regions(pci, "My Chip")) < 0) { + err = pci_request_regions(pci, "My Chip"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -1156,10 +1165,10 @@ chip->irq = pci->irq; /* (2) initialization of the chip hardware */ - .... // (not implemented in this document) + .... /* (not implemented in this document) */ - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_mychip_free(chip); return err; } @@ -1233,7 +1242,8 @@ irq, snd_mychip_interrupt, - IRQF_DISABLED|IRQF_SHARED, "My Chip", chip)) { + IRQF_SHARED, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1773,7 +1784,8 @@ struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_mychip_playback_hw; - // more hardware-initialization will be done here + /* more hardware-initialization will be done here */ + .... return 0; } @@ -1781,7 +1793,8 @@ static int snd_mychip_playback_close(struct snd_pcm_substream *substream) { struct mychip *chip = snd_pcm_substream_chip(substream); - // the hardware-specific codes will be here + /* the hardware-specific codes will be here */ + .... return 0; } @@ -1793,7 +1806,8 @@ struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_mychip_capture_hw; - // more hardware-initialization will be done here + /* more hardware-initialization will be done here */ + .... return 0; } @@ -1801,7 +1815,8 @@ static int snd_mychip_capture_close(struct snd_pcm_substream *substream) { struct mychip *chip = snd_pcm_substream_chip(substream); - // the hardware-specific codes will be here + /* the hardware-specific codes will be here */ + .... return 0; } @@ -1844,10 +1859,12 @@ { switch (cmd) { case SNDRV_PCM_TRIGGER_START: - // do something to start the PCM engine + /* do something to start the PCM engine */ + .... break; case SNDRV_PCM_TRIGGER_STOP: - // do something to stop the PCM engine + /* do something to stop the PCM engine */ + .... break; default: return -EINVAL; @@ -1900,8 +1917,8 @@ struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, - &pcm)) < 0) + err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, &pcm); + if (err < 0) return err; pcm->private_data = chip; strcpy(pcm->name, "My Chip"); @@ -1939,8 +1956,8 @@ struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, - &pcm)) < 0) + err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, &pcm); + if (err < 0) return err; pcm->private_data = chip; strcpy(pcm->name, "My Chip"); @@ -2097,7 +2114,7 @@ struct mychip *chip = snd_pcm_chip(pcm); /* free your own data */ kfree(chip->my_private_pcm_data); - // do what you like else + /* do what you like else */ .... } @@ -2884,10 +2901,10 @@ #endif lock); snd_pcm_period_elapsed(chip->substream); spin_lock(&chip->lock); - // acknowledge the interrupt if necessary + /* acknowledge the interrupt if necessary */ } .... spin_unlock(&chip->lock); @@ -3134,7 +3151,7 @@ #endif snd_pcm_period_elapsed(substream); spin_lock(&chip->lock); } - // acknowledge the interrupt if necessary + /* acknowledge the interrupt if necessary */ } .... spin_unlock(&chip->lock); @@ -3456,6 +3473,13 @@ #endif + The tlv field can be used to provide + metadata about the control; see the + + Metadata subsection. + + + The other three are callback functions. @@ -3604,7 +3628,7 @@ #endif Example of info callback type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; @@ -3639,7 +3663,7 @@ #endif + + + Some common info callbacks are prepared for easy use: + snd_ctl_boolean_mono_info() and + snd_ctl_boolean_stereo_info(). + Obviously, the former is an info callback for a mono channel + boolean item, just like snd_myctl_mono_info + above, and the latter is for a stereo channel boolean item. + +
@@ -3794,7 +3828,8 @@ #endif @@ -3843,6 +3878,56 @@ #endif
+
+ Metadata + + To provide information about the dB values of a mixer control, use + on of the DECLARE_TLV_xxx macros from + <sound/tlv.h> to define a variable + containing this information, set thetlv.p + field to point to this variable, and include the + SNDRV_CTL_ELEM_ACCESS_TLV_READ flag in the + access field; like this: + + + + + + + + + The DECLARE_TLV_DB_SCALE macro defines + information about a mixer control where each step in the control's + value changes the dB value by a constant dB amount. + The first parameter is the name of the variable to be defined. + The second parameter is the minimum value, in units of 0.01 dB. + The third parameter is the step size, in units of 0.01 dB. + Set the fourth parameter to 1 if the minimum value actually mutes + the control. + + + + The DECLARE_TLV_DB_LINEAR macro defines + information about a mixer control where the control's value affects + the output linearly. + The first parameter is the name of the variable to be defined. + The second parameter is the minimum value, in units of 0.01 dB. + The third parameter is the maximum value, in units of 0.01 dB. + If the minimum value mutes the control, set the second parameter to + TLV_DB_GAIN_MUTE. + +
+ @@ -3880,7 +3965,7 @@ #endif { struct mychip *chip = ac97->private_data; .... - // read a register value here from the codec + /* read a register value here from the codec */ return the_register_value; } @@ -3889,7 +3974,7 @@ #endif { struct mychip *chip = ac97->private_data; .... - // write the given register value to the codec + /* write the given register value to the codec */ } static int snd_mychip_ac97(struct mychip *chip) @@ -3902,7 +3987,8 @@ #endif .read = snd_mychip_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; @@ -4447,10 +4533,10 @@ #endif streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, + list { sprintf(substream->name, "My MIDI Port %d", substream->number + 1); } /* same for SNDRV_RAWMIDI_STREAM_INPUT */ diff --git a/Documentation/sound/alsa/OSS-Emulation.txt b/Documentation/sound/alsa/OSS-Emulation.txt index bfa0c9a..022aaeb 100644 --- a/Documentation/sound/alsa/OSS-Emulation.txt +++ b/Documentation/sound/alsa/OSS-Emulation.txt @@ -303,10 +303,3 @@ ICE1712 supports only the unconventional the buffer as the conventional (mono or 2-channels, 8 or 16bit) format on OSS. -USB devices ------------ -Some USB devices support only 24bit format packed in 3bytes. This -format is not supported by OSS and no conversion is provided by kernel -OSS emulation. You can use the user-space OSS emulation via libaoss -instead. - diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt index 4eaae2a..8e1b025 100644 --- a/Documentation/sound/alsa/hda_codec.txt +++ b/Documentation/sound/alsa/hda_codec.txt @@ -49,6 +49,9 @@ struct hda_bus_ops { unsigned int verb, unsigned int parm); unsigned int (*get_response)(struct hda_codec *codec); void (*private_free)(struct hda_bus *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + void (*pm_notify)(struct hda_codec *codec); +#endif }; The command callback is called when the codec module needs to send a @@ -56,9 +59,16 @@ VERB to the controller. It's always a s The get_response callback is called when the codec requires the answer for the last command. These two callbacks are mandatory and have to be given. -The last, private_free callback, is optional. It's called in the +The third, private_free callback, is optional. It's called in the destructor to release any necessary data in the lowlevel driver. +The pm_notify callback is available only with +CONFIG_SND_HDA_POWER_SAVE kconfig. It's called when the codec needs +to power up or may power down. The controller should check the all +belonging codecs on the bus whether they are actually powered off +(check codec->power_on), and optionally the driver may power down the +contoller side, too. + The bus instance is created via snd_hda_bus_new(). You need to pass the card instance, the template, and the pointer to store the resultant bus instance. @@ -86,10 +96,8 @@ resultant codec instance (can be NULL if The codec is stored in a linked list of bus instance. You can follow the codec list like: - struct list_head *p; struct hda_codec *codec; - list_for_each(p, &bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &bus->codec_list, list) { ... } @@ -100,10 +108,15 @@ initialization sequence is called when t Codec Access ============ -To access codec, use snd_codec_read() and snd_codec_write(). +To access codec, use snd_hda_codec_read() and snd_hda_codec_write(). snd_hda_param_read() is for reading parameters. For writing a sequence of verbs, use snd_hda_sequence_write(). +There are variants of cached read/write, snd_hda_codec_write_cache(), +snd_hda_sequence_write_cache(). These are used for recording the +register states for the power-mangement resume. When no PM is needed, +these are equivalent with non-cached version. + To retrieve the number of sub nodes connected to the given node, use snd_hda_get_sub_nodes(). The connection list can be obtained via snd_hda_get_connections() call. @@ -239,6 +252,10 @@ set the codec->patch_ops field. This is int (*suspend)(struct hda_codec *codec, pm_message_t state); int (*resume)(struct hda_codec *codec); #endif + #ifdef CONFIG_SND_HDA_POWER_SAVE + int (*check_power_status)(struct hda_codec *codec, + hda_nid_t nid); + #endif }; The build_controls callback is called from snd_hda_build_controls(). @@ -251,6 +268,18 @@ The unsol_event callback is called when received. The suspend and resume callbacks are for power management. +They can be NULL if no special sequence is required. When the resume +callback is NULL, the driver calls the init callback and resumes the +registers from the cache. If other handling is needed, you'd need to +write your own resume callback. There, the amp values can be resumed +via + void snd_hda_codec_resume_amp(struct hda_codec *codec); +and the other codec registers via + void snd_hda_codec_resume_cache(struct hda_codec *codec); + +The check_power_status callback is called when the amp value of the +given widget NID is changed. The codec code can turn on/off the power +appropriately from this information. Each entry can be NULL if not necessary to be called. @@ -267,8 +296,7 @@ Digital I/O =========== Call snd_hda_create_spdif_out_ctls() from the patch to create controls -related with SPDIF out. In the patch resume callback, call -snd_hda_resume_spdif(). +related with SPDIF out. Helper Functions @@ -284,12 +312,7 @@ as a module parameter, and PCI subsystem is found, it returns the config field value. snd_hda_add_new_ctls() can be used to create and add control entries. -Pass the zero-terminated array of struct snd_kcontrol_new. The same array -can be passed to snd_hda_resume_ctls() for resume. -Note that this will call control->put callback of these entries. So, -put callback should check codec->in_resume and force to restore the -given value if it's non-zero even if the value is identical with the -cached value. +Pass the zero-terminated array of struct snd_kcontrol_new Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be used for the entry of struct snd_kcontrol_new. diff --git a/Documentation/sound/alsa/powersave.txt b/Documentation/sound/alsa/powersave.txt new file mode 100644 index 0000000..9657e80 --- /dev/null +++ b/Documentation/sound/alsa/powersave.txt @@ -0,0 +1,41 @@ +Notes on Power-Saving Mode +========================== + +AC97 and HD-audio drivers have the automatic power-saving mode. +This feature is enabled via Kconfig CONFIG_SND_AC97_POWER_SAVE +and CONFIG_SND_HDA_POWER_SAVE options, respectively. + +With the automatic power-saving, the driver turns off the codec power +appropriately when no operation is required. When no applications use +the device and/or no analog loopback is set, the power disablement is +done fully or partially. It'll save a certain power consumption, thus +good for laptops (even for desktops). + +The time-out for automatic power-off can be specified via power_save +module option of snd-ac97-codec and snd-hda-intel modules. Specify +the time-out value in seconds. 0 means to disable the automatic +power-saving. The default value of timeout is given via +CONFIG_SND_AC97_POWER_SAVE_DEFAULT and +CONFIG_SND_HDA_POWER_SAVE_DEFAULT Kconfig options. Setting this to 1 +(the minimum value) isn't recommended because many applications try to +reopen the device frequently. 10 would be a good choice for normal +operations. + +The power_save option is exported as writable. This means you can +adjust the value via sysfs on the fly. For example, to turn on the +automatic power-save mode with 10 seconds, write to +/sys/modules/snd_ac97_codec/parameters/power_save (usually as root): + + # echo 10 > /sys/modules/snd_ac97_codec/parameters/power_save + + +Note that you might hear click noise/pop when changing the power +state. Also, it often takes certain time to wake up from the +power-down to the active state. These are often hardly to fix, so +don't report extra bug reports unless you have a fix patch ;-) + +For HD-audio interface, there is another module option, +power_save_controller. This enables/disables the power-save mode of +the controller side. Setting this on may reduce a bit more power +consumption, but might result in longer wake-up time and click noise. +Try to turn it off when you experience such a thing too often. diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index b690148..c4aadc6 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -119,6 +119,7 @@ #define I2C_DRIVERID_WM8731 89 /* Wolfso #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ +#define I2C_DRIVERID_CS4270 93 /* Cirrus Logic 4270 audio codec */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/linux/spi/at73c213.h b/include/linux/spi/at73c213.h new file mode 100644 index 0000000..0f20a70 --- /dev/null +++ b/include/linux/spi/at73c213.h @@ -0,0 +1,25 @@ +/* + * Board-specific data used to set up AT73c213 audio DAC driver. + */ + +#ifndef __LINUX_SPI_AT73C213_H +#define __LINUX_SPI_AT73C213_H + +/** + * at73c213_board_info - how the external DAC is wired to the device. + * + * @ssc_id: SSC platform_driver id the DAC shall use to stream the audio. + * @dac_clk: the external clock used to provide master clock to the DAC. + * @shortname: a short discription for the DAC, seen by userspace tools. + * + * This struct contains the configuration of the hardware connection to the + * external DAC. The DAC needs a master clock and a I2S audio stream. It also + * provides a name which is used to identify it in userspace tools. + */ +struct at73c213_board_info { + int ssc_id; + struct clk *dac_clk; + char shortname[32]; +}; + +#endif /* __LINUX_SPI_AT73C213_H */ diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 246ac23..3b9eed7 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -345,9 +345,9 @@ #define AC97_ALC650_GPIO_SETUP 0x76 #define AC97_ALC650_GPIO_STATUS 0x78 #define AC97_ALC650_CLOCK 0x7a -/* specific - Yamaha YMF753 */ -#define AC97_YMF753_DIT_CTRL2 0x66 /* DIT Control 2 */ -#define AC97_YMF753_3D_MODE_SEL 0x68 /* 3D Mode Select */ +/* specific - Yamaha YMF7x3 */ +#define AC97_YMF7X3_DIT_CTRL 0x66 /* DIT Control (YMF743) / 2 (YMF753) */ +#define AC97_YMF7X3_3D_MODE_SEL 0x68 /* 3D Mode Select */ /* specific - C-Media */ #define AC97_CM9738_VENDOR_CTRL 0x5a diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h index b2c3f00..ca0b6c3 100644 --- a/include/sound/ad1848.h +++ b/include/sound/ad1848.h @@ -27,7 +27,7 @@ #include /* IO ports */ -#define AD1848P( codec, x ) ( (chip) -> port + c_d_c_AD1848##x ) +#define AD1848P( chip, x ) ( (chip) -> port + c_d_c_AD1848##x ) #define c_d_c_AD1848REGSEL 0 #define c_d_c_AD1848REG 1 diff --git a/include/sound/asound.h b/include/sound/asound.h index c1621c6..0a108ae 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -92,6 +92,7 @@ enum { SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ + SNDRV_HWDEP_IFACE_HDA, /* HD-audio */ /* Don't forget to change the following: */ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC diff --git a/include/sound/control.h b/include/sound/control.h index 72e759f..b26d463 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -161,4 +161,12 @@ static inline struct snd_ctl_elem_id *sn return dst_id; } +/* + * Frequently used control callbacks + */ +int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); + #endif /* __SOUND_CONTROL_H */ diff --git a/include/sound/cs4231-regs.h b/include/sound/cs4231-regs.h new file mode 100644 index 0000000..80872e8 --- /dev/null +++ b/include/sound/cs4231-regs.h @@ -0,0 +1,180 @@ +#ifndef __SOUND_CS4231_REGS_H +#define __SOUND_CS4231_REGS_H + +/* + * Copyright (c) by Jaroslav Kysela + * Definitions for CS4231 & InterWave chips & compatible chips registers + * + * + * 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 + * + */ + +/* IO ports */ + +#define CS4231P(x) (c_d_c_CS4231##x) + +#define c_d_c_CS4231REGSEL 0 +#define c_d_c_CS4231REG 1 +#define c_d_c_CS4231STATUS 2 +#define c_d_c_CS4231PIO 3 + +/* codec registers */ + +#define CS4231_LEFT_INPUT 0x00 /* left input control */ +#define CS4231_RIGHT_INPUT 0x01 /* right input control */ +#define CS4231_AUX1_LEFT_INPUT 0x02 /* left AUX1 input control */ +#define CS4231_AUX1_RIGHT_INPUT 0x03 /* right AUX1 input control */ +#define CS4231_AUX2_LEFT_INPUT 0x04 /* left AUX2 input control */ +#define CS4231_AUX2_RIGHT_INPUT 0x05 /* right AUX2 input control */ +#define CS4231_LEFT_OUTPUT 0x06 /* left output control register */ +#define CS4231_RIGHT_OUTPUT 0x07 /* right output control register */ +#define CS4231_PLAYBK_FORMAT 0x08 /* clock and data format - playback - bits 7-0 MCE */ +#define CS4231_IFACE_CTRL 0x09 /* interface control - bits 7-2 MCE */ +#define CS4231_PIN_CTRL 0x0a /* pin control */ +#define CS4231_TEST_INIT 0x0b /* test and initialization */ +#define CS4231_MISC_INFO 0x0c /* miscellaneaous information */ +#define CS4231_LOOPBACK 0x0d /* loopback control */ +#define CS4231_PLY_UPR_CNT 0x0e /* playback upper base count */ +#define CS4231_PLY_LWR_CNT 0x0f /* playback lower base count */ +#define CS4231_ALT_FEATURE_1 0x10 /* alternate #1 feature enable */ +#define AD1845_AF1_MIC_LEFT 0x10 /* alternate #1 feature + MIC left */ +#define CS4231_ALT_FEATURE_2 0x11 /* alternate #2 feature enable */ +#define AD1845_AF2_MIC_RIGHT 0x11 /* alternate #2 feature + MIC right */ +#define CS4231_LEFT_LINE_IN 0x12 /* left line input control */ +#define CS4231_RIGHT_LINE_IN 0x13 /* right line input control */ +#define CS4231_TIMER_LOW 0x14 /* timer low byte */ +#define CS4231_TIMER_HIGH 0x15 /* timer high byte */ +#define CS4231_LEFT_MIC_INPUT 0x16 /* left MIC input control register (InterWave only) */ +#define AD1845_UPR_FREQ_SEL 0x16 /* upper byte of frequency select */ +#define CS4231_RIGHT_MIC_INPUT 0x17 /* right MIC input control register (InterWave only) */ +#define AD1845_LWR_FREQ_SEL 0x17 /* lower byte of frequency select */ +#define CS4236_EXT_REG 0x17 /* extended register access */ +#define CS4231_IRQ_STATUS 0x18 /* irq status register */ +#define CS4231_LINE_LEFT_OUTPUT 0x19 /* left line output control register (InterWave only) */ +#define CS4231_VERSION 0x19 /* CS4231(A) - version values */ +#define CS4231_MONO_CTRL 0x1a /* mono input/output control */ +#define CS4231_LINE_RIGHT_OUTPUT 0x1b /* right line output control register (InterWave only) */ +#define AD1845_PWR_DOWN 0x1b /* power down control */ +#define CS4235_LEFT_MASTER 0x1b /* left master output control */ +#define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */ +#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */ +#define AD1845_CLOCK 0x1d /* crystal clock select and total power down */ +#define CS4235_RIGHT_MASTER 0x1d /* right master output control */ +#define CS4231_REC_UPR_CNT 0x1e /* record upper count */ +#define CS4231_REC_LWR_CNT 0x1f /* record lower count */ + +/* definitions for codec register select port - CODECP( REGSEL ) */ + +#define CS4231_INIT 0x80 /* CODEC is initializing */ +#define CS4231_MCE 0x40 /* mode change enable */ +#define CS4231_TRD 0x20 /* transfer request disable */ + +/* definitions for codec status register - CODECP( STATUS ) */ + +#define CS4231_GLOBALIRQ 0x01 /* IRQ is active */ + +/* definitions for codec irq status */ + +#define CS4231_PLAYBACK_IRQ 0x10 +#define CS4231_RECORD_IRQ 0x20 +#define CS4231_TIMER_IRQ 0x40 +#define CS4231_ALL_IRQS 0x70 +#define CS4231_REC_UNDERRUN 0x08 +#define CS4231_REC_OVERRUN 0x04 +#define CS4231_PLY_OVERRUN 0x02 +#define CS4231_PLY_UNDERRUN 0x01 + +/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */ + +#define CS4231_ENABLE_MIC_GAIN 0x20 + +#define CS4231_MIXS_LINE 0x00 +#define CS4231_MIXS_AUX1 0x40 +#define CS4231_MIXS_MIC 0x80 +#define CS4231_MIXS_ALL 0xc0 + +/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */ + +#define CS4231_LINEAR_8 0x00 /* 8-bit unsigned data */ +#define CS4231_ALAW_8 0x60 /* 8-bit A-law companded */ +#define CS4231_ULAW_8 0x20 /* 8-bit U-law companded */ +#define CS4231_LINEAR_16 0x40 /* 16-bit twos complement data - little endian */ +#define CS4231_LINEAR_16_BIG 0xc0 /* 16-bit twos complement data - big endian */ +#define CS4231_ADPCM_16 0xa0 /* 16-bit ADPCM */ +#define CS4231_STEREO 0x10 /* stereo mode */ +/* bits 3-1 define frequency divisor */ +#define CS4231_XTAL1 0x00 /* 24.576 crystal */ +#define CS4231_XTAL2 0x01 /* 16.9344 crystal */ + +/* definitions for interface control register - CS4231_IFACE_CTRL */ + +#define CS4231_RECORD_PIO 0x80 /* record PIO enable */ +#define CS4231_PLAYBACK_PIO 0x40 /* playback PIO enable */ +#define CS4231_CALIB_MODE 0x18 /* calibration mode bits */ +#define CS4231_AUTOCALIB 0x08 /* auto calibrate */ +#define CS4231_SINGLE_DMA 0x04 /* use single DMA channel */ +#define CS4231_RECORD_ENABLE 0x02 /* record enable */ +#define CS4231_PLAYBACK_ENABLE 0x01 /* playback enable */ + +/* definitions for pin control register - CS4231_PIN_CTRL */ + +#define CS4231_IRQ_ENABLE 0x02 /* enable IRQ */ +#define CS4231_XCTL1 0x40 /* external control #1 */ +#define CS4231_XCTL0 0x80 /* external control #0 */ + +/* definitions for test and init register - CS4231_TEST_INIT */ + +#define CS4231_CALIB_IN_PROGRESS 0x20 /* auto calibrate in progress */ +#define CS4231_DMA_REQUEST 0x10 /* DMA request in progress */ + +/* definitions for misc control register - CS4231_MISC_INFO */ + +#define CS4231_MODE2 0x40 /* MODE 2 */ +#define CS4231_IW_MODE3 0x6c /* MODE 3 - InterWave enhanced mode */ +#define CS4231_4236_MODE3 0xe0 /* MODE 3 - CS4236+ enhanced mode */ + +/* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */ + +#define CS4231_DACZ 0x01 /* zero DAC when underrun */ +#define CS4231_TIMER_ENABLE 0x40 /* codec timer enable */ +#define CS4231_OLB 0x80 /* output level bit */ + +/* definitions for Extended Registers - CS4236+ */ + +#define CS4236_REG(i23val) (((i23val << 2) & 0x10) | ((i23val >> 4) & 0x0f)) +#define CS4236_I23VAL(reg) ((((reg)&0xf) << 4) | (((reg)&0x10) >> 2) | 0x8) + +#define CS4236_LEFT_LINE 0x08 /* left LINE alternate volume */ +#define CS4236_RIGHT_LINE 0x18 /* right LINE alternate volume */ +#define CS4236_LEFT_MIC 0x28 /* left MIC volume */ +#define CS4236_RIGHT_MIC 0x38 /* right MIC volume */ +#define CS4236_LEFT_MIX_CTRL 0x48 /* synthesis and left input mixer control */ +#define CS4236_RIGHT_MIX_CTRL 0x58 /* right input mixer control */ +#define CS4236_LEFT_FM 0x68 /* left FM volume */ +#define CS4236_RIGHT_FM 0x78 /* right FM volume */ +#define CS4236_LEFT_DSP 0x88 /* left DSP serial port volume */ +#define CS4236_RIGHT_DSP 0x98 /* right DSP serial port volume */ +#define CS4236_RIGHT_LOOPBACK 0xa8 /* right loopback monitor volume */ +#define CS4236_DAC_MUTE 0xb8 /* DAC mute and IFSE enable */ +#define CS4236_ADC_RATE 0xc8 /* indenpendent ADC sample frequency */ +#define CS4236_DAC_RATE 0xd8 /* indenpendent DAC sample frequency */ +#define CS4236_LEFT_MASTER 0xe8 /* left master digital audio volume */ +#define CS4236_RIGHT_MASTER 0xf8 /* right master digital audio volume */ +#define CS4236_LEFT_WAVE 0x0c /* left wavetable serial port volume */ +#define CS4236_RIGHT_WAVE 0x1c /* right wavetable serial port volume */ +#define CS4236_VERSION 0x9c /* chip version and ID */ + +#endif /* __SOUND_CS4231_REGS_H */ diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h index ab51ce1..4d0e3bc 100644 --- a/include/sound/cs4231.h +++ b/include/sound/cs4231.h @@ -26,160 +26,7 @@ #include "control.h" #include "pcm.h" #include "timer.h" -/* IO ports */ - -#define CS4231P(x) (c_d_c_CS4231##x) - -#define c_d_c_CS4231REGSEL 0 -#define c_d_c_CS4231REG 1 -#define c_d_c_CS4231STATUS 2 -#define c_d_c_CS4231PIO 3 - -/* codec registers */ - -#define CS4231_LEFT_INPUT 0x00 /* left input control */ -#define CS4231_RIGHT_INPUT 0x01 /* right input control */ -#define CS4231_AUX1_LEFT_INPUT 0x02 /* left AUX1 input control */ -#define CS4231_AUX1_RIGHT_INPUT 0x03 /* right AUX1 input control */ -#define CS4231_AUX2_LEFT_INPUT 0x04 /* left AUX2 input control */ -#define CS4231_AUX2_RIGHT_INPUT 0x05 /* right AUX2 input control */ -#define CS4231_LEFT_OUTPUT 0x06 /* left output control register */ -#define CS4231_RIGHT_OUTPUT 0x07 /* right output control register */ -#define CS4231_PLAYBK_FORMAT 0x08 /* clock and data format - playback - bits 7-0 MCE */ -#define CS4231_IFACE_CTRL 0x09 /* interface control - bits 7-2 MCE */ -#define CS4231_PIN_CTRL 0x0a /* pin control */ -#define CS4231_TEST_INIT 0x0b /* test and initialization */ -#define CS4231_MISC_INFO 0x0c /* miscellaneaous information */ -#define CS4231_LOOPBACK 0x0d /* loopback control */ -#define CS4231_PLY_UPR_CNT 0x0e /* playback upper base count */ -#define CS4231_PLY_LWR_CNT 0x0f /* playback lower base count */ -#define CS4231_ALT_FEATURE_1 0x10 /* alternate #1 feature enable */ -#define AD1845_AF1_MIC_LEFT 0x10 /* alternate #1 feature + MIC left */ -#define CS4231_ALT_FEATURE_2 0x11 /* alternate #2 feature enable */ -#define AD1845_AF2_MIC_RIGHT 0x11 /* alternate #2 feature + MIC right */ -#define CS4231_LEFT_LINE_IN 0x12 /* left line input control */ -#define CS4231_RIGHT_LINE_IN 0x13 /* right line input control */ -#define CS4231_TIMER_LOW 0x14 /* timer low byte */ -#define CS4231_TIMER_HIGH 0x15 /* timer high byte */ -#define CS4231_LEFT_MIC_INPUT 0x16 /* left MIC input control register (InterWave only) */ -#define AD1845_UPR_FREQ_SEL 0x16 /* upper byte of frequency select */ -#define CS4231_RIGHT_MIC_INPUT 0x17 /* right MIC input control register (InterWave only) */ -#define AD1845_LWR_FREQ_SEL 0x17 /* lower byte of frequency select */ -#define CS4236_EXT_REG 0x17 /* extended register access */ -#define CS4231_IRQ_STATUS 0x18 /* irq status register */ -#define CS4231_LINE_LEFT_OUTPUT 0x19 /* left line output control register (InterWave only) */ -#define CS4231_VERSION 0x19 /* CS4231(A) - version values */ -#define CS4231_MONO_CTRL 0x1a /* mono input/output control */ -#define CS4231_LINE_RIGHT_OUTPUT 0x1b /* right line output control register (InterWave only) */ -#define AD1845_PWR_DOWN 0x1b /* power down control */ -#define CS4235_LEFT_MASTER 0x1b /* left master output control */ -#define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */ -#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */ -#define AD1845_CLOCK 0x1d /* crystal clock select and total power down */ -#define CS4235_RIGHT_MASTER 0x1d /* right master output control */ -#define CS4231_REC_UPR_CNT 0x1e /* record upper count */ -#define CS4231_REC_LWR_CNT 0x1f /* record lower count */ - -/* definitions for codec register select port - CODECP( REGSEL ) */ - -#define CS4231_INIT 0x80 /* CODEC is initializing */ -#define CS4231_MCE 0x40 /* mode change enable */ -#define CS4231_TRD 0x20 /* transfer request disable */ - -/* definitions for codec status register - CODECP( STATUS ) */ - -#define CS4231_GLOBALIRQ 0x01 /* IRQ is active */ - -/* definitions for codec irq status */ - -#define CS4231_PLAYBACK_IRQ 0x10 -#define CS4231_RECORD_IRQ 0x20 -#define CS4231_TIMER_IRQ 0x40 -#define CS4231_ALL_IRQS 0x70 -#define CS4231_REC_UNDERRUN 0x08 -#define CS4231_REC_OVERRUN 0x04 -#define CS4231_PLY_OVERRUN 0x02 -#define CS4231_PLY_UNDERRUN 0x01 - -/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */ - -#define CS4231_ENABLE_MIC_GAIN 0x20 - -#define CS4231_MIXS_LINE 0x00 -#define CS4231_MIXS_AUX1 0x40 -#define CS4231_MIXS_MIC 0x80 -#define CS4231_MIXS_ALL 0xc0 - -/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */ - -#define CS4231_LINEAR_8 0x00 /* 8-bit unsigned data */ -#define CS4231_ALAW_8 0x60 /* 8-bit A-law companded */ -#define CS4231_ULAW_8 0x20 /* 8-bit U-law companded */ -#define CS4231_LINEAR_16 0x40 /* 16-bit twos complement data - little endian */ -#define CS4231_LINEAR_16_BIG 0xc0 /* 16-bit twos complement data - big endian */ -#define CS4231_ADPCM_16 0xa0 /* 16-bit ADPCM */ -#define CS4231_STEREO 0x10 /* stereo mode */ -/* bits 3-1 define frequency divisor */ -#define CS4231_XTAL1 0x00 /* 24.576 crystal */ -#define CS4231_XTAL2 0x01 /* 16.9344 crystal */ - -/* definitions for interface control register - CS4231_IFACE_CTRL */ - -#define CS4231_RECORD_PIO 0x80 /* record PIO enable */ -#define CS4231_PLAYBACK_PIO 0x40 /* playback PIO enable */ -#define CS4231_CALIB_MODE 0x18 /* calibration mode bits */ -#define CS4231_AUTOCALIB 0x08 /* auto calibrate */ -#define CS4231_SINGLE_DMA 0x04 /* use single DMA channel */ -#define CS4231_RECORD_ENABLE 0x02 /* record enable */ -#define CS4231_PLAYBACK_ENABLE 0x01 /* playback enable */ - -/* definitions for pin control register - CS4231_PIN_CTRL */ - -#define CS4231_IRQ_ENABLE 0x02 /* enable IRQ */ -#define CS4231_XCTL1 0x40 /* external control #1 */ -#define CS4231_XCTL0 0x80 /* external control #0 */ - -/* definitions for test and init register - CS4231_TEST_INIT */ - -#define CS4231_CALIB_IN_PROGRESS 0x20 /* auto calibrate in progress */ -#define CS4231_DMA_REQUEST 0x10 /* DMA request in progress */ - -/* definitions for misc control register - CS4231_MISC_INFO */ - -#define CS4231_MODE2 0x40 /* MODE 2 */ -#define CS4231_IW_MODE3 0x6c /* MODE 3 - InterWave enhanced mode */ -#define CS4231_4236_MODE3 0xe0 /* MODE 3 - CS4236+ enhanced mode */ - -/* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */ - -#define CS4231_DACZ 0x01 /* zero DAC when underrun */ -#define CS4231_TIMER_ENABLE 0x40 /* codec timer enable */ -#define CS4231_OLB 0x80 /* output level bit */ - -/* definitions for Extended Registers - CS4236+ */ - -#define CS4236_REG(i23val) (((i23val << 2) & 0x10) | ((i23val >> 4) & 0x0f)) -#define CS4236_I23VAL(reg) ((((reg)&0xf) << 4) | (((reg)&0x10) >> 2) | 0x8) - -#define CS4236_LEFT_LINE 0x08 /* left LINE alternate volume */ -#define CS4236_RIGHT_LINE 0x18 /* right LINE alternate volume */ -#define CS4236_LEFT_MIC 0x28 /* left MIC volume */ -#define CS4236_RIGHT_MIC 0x38 /* right MIC volume */ -#define CS4236_LEFT_MIX_CTRL 0x48 /* synthesis and left input mixer control */ -#define CS4236_RIGHT_MIX_CTRL 0x58 /* right input mixer control */ -#define CS4236_LEFT_FM 0x68 /* left FM volume */ -#define CS4236_RIGHT_FM 0x78 /* right FM volume */ -#define CS4236_LEFT_DSP 0x88 /* left DSP serial port volume */ -#define CS4236_RIGHT_DSP 0x98 /* right DSP serial port volume */ -#define CS4236_RIGHT_LOOPBACK 0xa8 /* right loopback monitor volume */ -#define CS4236_DAC_MUTE 0xb8 /* DAC mute and IFSE enable */ -#define CS4236_ADC_RATE 0xc8 /* indenpendent ADC sample frequency */ -#define CS4236_DAC_RATE 0xd8 /* indenpendent DAC sample frequency */ -#define CS4236_LEFT_MASTER 0xe8 /* left master digital audio volume */ -#define CS4236_RIGHT_MASTER 0xf8 /* right master digital audio volume */ -#define CS4236_LEFT_WAVE 0x0c /* left wavetable serial port volume */ -#define CS4236_RIGHT_WAVE 0x1c /* right wavetable serial port volume */ -#define CS4236_VERSION 0x9c /* chip version and ID */ +#include "cs4231-regs.h" /* defines for codec.mode */ @@ -210,7 +57,7 @@ #define CS4231_HW_CS4238B 0x0403 /* CS42 #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 0x1001 /* OPL3-SA2 chip */ +#define CS4231_HW_OPL3SA2 0x1101 /* OPL3-SA2 chip, similar to cs4231 */ /* defines for codec.hwshare */ #define CS4231_HWSHARE_IRQ (1<<0) diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 529d0a5..1f72319 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1408,8 +1408,6 @@ struct snd_emu10k1_fx8010 { struct snd_emu10k1_fx8010_irq *irq_handlers; }; -#define emu10k1_gpr_ctl(n) list_entry(n, struct snd_emu10k1_fx8010_ctl, list) - struct snd_emu10k1_midi { struct snd_emu10k1 *emu; struct snd_rawmidi *rmidi; @@ -1456,6 +1454,9 @@ struct snd_emu1010 { unsigned int adc_pads; /* bit mask */ unsigned int dac_pads; /* bit mask */ unsigned int internal_clock; /* 44100 or 48000 */ + unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ + unsigned int optical_out; /* 0:SPDIF, 1:ADAT */ + struct task_struct *firmware_thread; }; struct snd_emu10k1 { @@ -1599,9 +1600,9 @@ unsigned int snd_emu10k1_ptr20_read(stru void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data); int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value); -int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value); -int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value); -int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src); +int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value); +int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value); +int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src); unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb); void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb); @@ -1746,6 +1747,8 @@ #define A_EXTOUT(x) (0x60 + (x)) /* x = #define A_FXBUS2(x) (0x80 + (x)) /* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */ #define A_EMU32OUTH(x) (0xa0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */ #define A_EMU32OUTL(x) (0xb0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */ +#define A3_EMU32IN(x) (0x160 + (x)) /* x = 0x00 - 0x3f "EMU32_IN_00 - _3F" - Only when .device = 0x0008 */ +#define A3_EMU32OUT(x) (0x1E0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_00 - _3F" - Only when .device = 0x0008 */ #define A_GPR(x) (A_FXGPREGBASE + (x)) /* cc_reg constants */ diff --git a/include/sound/hda_hwdep.h b/include/sound/hda_hwdep.h new file mode 100644 index 0000000..1c0034e --- /dev/null +++ b/include/sound/hda_hwdep.h @@ -0,0 +1,44 @@ +/* + * HWDEP Interface for HD-audio codec + * + * Copyright (c) 2007 Takashi Iwai + * + * 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_HWDEP_H +#define __SOUND_HDA_HWDEP_H + +#define HDA_HWDEP_VERSION ((1 << 16) | (0 << 8) | (0 << 0)) /* 1.0.0 */ + +/* verb */ +#define HDA_REG_NID_SHIFT 24 +#define HDA_REG_VERB_SHIFT 8 +#define HDA_REG_VAL_SHIFT 0 +#define HDA_VERB(nid,verb,param) ((nid)<<24 | (verb)<<8 | (param)) + +struct hda_verb_ioctl { + u32 verb; /* HDA_VERB() */ + u32 res; /* response */ +}; + +/* + * ioctls + */ +#define HDA_IOCTL_PVERSION _IOR('H', 0x10, int) +#define HDA_IOCTL_VERB_WRITE _IOWR('H', 0x11, struct hda_verb_ioctl) +#define HDA_IOCTL_GET_WCAP _IOWR('H', 0x12, struct hda_verb_ioctl) + +#endif diff --git a/include/sound/hdspm.h b/include/sound/hdspm.h index c3c854d..81990b2 100644 --- a/include/sound/hdspm.h +++ b/include/sound/hdspm.h @@ -1,4 +1,4 @@ -#ifndef __SOUND_HDSPM_H /* -*- linux-c -*- */ +#ifndef __SOUND_HDSPM_H #define __SOUND_HDSPM_H /* * Copyright (C) 2003 Winfried Ritsch (IEM) @@ -61,7 +61,8 @@ struct hdspm_peak_rms_ioctl { }; /* use indirect access due to the limit of ioctl bit size */ -#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct hdspm_peak_rms_ioctl) +#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS \ + _IOR('H', 0x40, struct hdspm_peak_rms_ioctl) /* ------------ CONFIG block IOCTL ---------------------- */ @@ -79,7 +80,8 @@ struct hdspm_config_info { unsigned int analog_out; }; -#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, struct hdspm_config_info) +#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO \ + _IOR('H', 0x41, struct hdspm_config_info) /* get Soundcard Version */ @@ -93,10 +95,14 @@ #define SNDRV_HDSPM_IOCTL_GET_VERSION _I /* ------------- get Matrix Mixer IOCTL --------------- */ -/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */ +/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = + * 32768 Bytes + */ /* organisation is 64 channelfader in a continous memory block */ -/* equivalent to hardware definition, maybe for future feature of mmap of them */ +/* equivalent to hardware definition, maybe for future feature of mmap of + * them + */ /* each of 64 outputs has 64 infader and 64 outfader: Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 73334e0..805d720 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -301,8 +301,8 @@ struct snd_pcm_runtime { union snd_pcm_sync_id sync; /* hardware synchronization ID */ /* -- mmap -- */ - volatile struct snd_pcm_mmap_status *status; - volatile struct snd_pcm_mmap_control *control; + struct snd_pcm_mmap_status *status; + struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ wait_queue_head_t sleep; @@ -791,13 +791,13 @@ static inline struct snd_interval *hw_pa static inline const struct snd_mask *hw_param_mask_c(const struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var) { - return (const struct snd_mask *)hw_param_mask((struct snd_pcm_hw_params*) params, var); + return ¶ms->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK]; } static inline const struct snd_interval *hw_param_interval_c(const struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var) { - return (const struct snd_interval *)hw_param_interval((struct snd_pcm_hw_params*) params, var); + return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; } #define params_access(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS)) @@ -922,7 +922,10 @@ snd_pcm_sframes_t snd_pcm_lib_writev(str snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames); +extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; + int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); +unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate); static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream, struct snd_dma_buffer *bufp) diff --git a/include/sound/soc.h b/include/sound/soc.h index db6edba..f47ef1f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -201,8 +201,7 @@ int snd_soc_info_volsw(struct snd_kcontr struct snd_ctl_elem_info *uinfo); int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); +#define snd_soc_info_bool_ext snd_ctl_boolean_mono int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, diff --git a/sound/Kconfig b/sound/Kconfig index e48b9b3..b2a2db4 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -63,6 +63,10 @@ source "sound/aoa/Kconfig" source "sound/arm/Kconfig" +if SPI +source "sound/spi/Kconfig" +endif + source "sound/mips/Kconfig" source "sound/sh/Kconfig" diff --git a/sound/Makefile b/sound/Makefile index 3ead922..c76d707 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ -obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/ +obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ + sparc/ spi/ parisc/ pcmcia/ mips/ soc/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 0288523..71e3f93 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c @@ -297,15 +297,7 @@ static struct snd_kcontrol_new capture_s .put = onyx_snd_capture_source_put, }; -static int onyx_snd_mute_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define onyx_snd_mute_info snd_ctl_boolean_stereo_info static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -359,15 +351,7 @@ static struct snd_kcontrol_new mute_cont }; -static int onyx_snd_single_bit_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define onyx_snd_single_bit_info snd_ctl_boolean_mono_info #define FLAG_POLARITY_INVERT 1 #define FLAG_SPDIFLOCK 2 diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 2f771f5..70c3416 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -272,15 +272,7 @@ static struct snd_kcontrol_new volume_co .put = tas_snd_vol_put, }; -static int tas_snd_mute_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define tas_snd_mute_info snd_ctl_boolean_stereo_info static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -431,15 +423,7 @@ static struct snd_kcontrol_new drc_range .put = tas_snd_drc_range_put, }; -static int tas_snd_drc_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define tas_snd_drc_switch_info snd_ctl_boolean_mono_info static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -743,6 +727,7 @@ static int tas_switch_clock(struct codec return 0; } +#ifdef CONFIG_PM /* we are controlled via i2c and assume that is always up * If that wasn't the case, we'd have to suspend once * our i2c device is suspended, and then take note of that! */ @@ -768,7 +753,6 @@ static int tas_resume(struct tas *tas) return 0; } -#ifdef CONFIG_PM static int _tas_suspend(struct codec_info_item *cii, pm_message_t state) { return tas_suspend(cii->codec_data); @@ -778,7 +762,10 @@ static int _tas_resume(struct codec_info { return tas_resume(cii->codec_data); } -#endif +#else /* CONFIG_PM */ +#define _tas_suspend NULL +#define _tas_resume NULL +#endif /* CONFIG_PM */ static struct codec_info tas_codec_info = { .transfers = tas_transfers, @@ -791,10 +778,8 @@ static struct codec_info tas_codec_info .owner = THIS_MODULE, .usable = tas_usable, .switch_clock = tas_switch_clock, -#ifdef CONFIG_PM .suspend = _tas_suspend, .resume = _tas_resume, -#endif }; static int tas_init_codec(struct aoa_codec *codec) diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 9880628..8b2ba99 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -582,15 +582,7 @@ static int layouts_list_items; * make the fabric handle all the card stuff, etc... */ static struct layout_dev *layout_device; -static int control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define control_info snd_ctl_boolean_mono_info #define AMP_CONTROL(n, description) \ static int n##_control_get(struct snd_kcontrol *kcontrol, \ diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index e7ed868..81c64b0 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c @@ -79,12 +79,6 @@ #include #include #include -#ifdef CONFIG_H3600_HAL -#include -#include -#include -#endif - #include #include #include @@ -100,9 +94,6 @@ #include * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this * module for Familiar 0.6.1 */ -#ifdef CONFIG_H3600_HAL -#define HH_VERSION 1 -#endif /* {{{ Type definitions */ @@ -238,11 +229,8 @@ static void sa11xx_uda1341_set_samplerat rate = 8000; /* Set the external clock generator */ -#ifdef CONFIG_H3600_HAL - h3600_audio_clock(rate); -#else + sa11xx_uda1341_set_audio_clock(rate); -#endif /* Select the clock divisor */ switch (rate) { @@ -307,13 +295,10 @@ static void sa11xx_uda1341_audio_init(st local_irq_restore(flags); /* Enable the audio power */ -#ifdef CONFIG_H3600_HAL - h3600_audio_power(AUDIO_RATE_DEFAULT); -#else + clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif /* Wait for the UDA1341 to wake up */ mdelay(1); //FIXME - was removed by Perex - Why? @@ -331,21 +316,13 @@ #endif /* make the left and right channels unswapped (flip the WS latch) */ Ser4SSDR = 0; -#ifdef CONFIG_H3600_HAL - h3600_audio_mute(0); -#else - clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif + clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); } static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341) { /* mute on */ -#ifdef CONFIG_H3600_HAL - h3600_audio_mute(1); -#else set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif /* disable the audio power and all signals leading to the audio chip */ l3_close(sa11xx_uda1341->uda1341); @@ -354,13 +331,9 @@ #endif /* power off and mute off */ /* FIXME - is muting off necesary??? */ -#ifdef CONFIG_H3600_HAL - h3600_audio_power(0); - h3600_audio_mute(0); -#else + clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif } /* }}} */ diff --git a/sound/core/Makefile b/sound/core/Makefile index 5a01c76..3ec303d 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -3,18 +3,15 @@ # Makefile for ALSA # Copyright (c) 1999,2001 by Jaroslav Kysela # -snd-objs := sound.o init.o memory.o info.o control.o misc.o device.o -ifeq ($(CONFIG_ISA_DMA_API),y) -snd-objs += isadma.o -endif -ifeq ($(CONFIG_SND_OSSEMUL),y) -snd-objs += sound_oss.o info_oss.o -endif +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-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o -snd-page-alloc-objs := memalloc.o sgbuf.o +snd-page-alloc-y := memalloc.o +snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o diff --git a/sound/core/control.c b/sound/core/control.c index 1f1ab9c..6144d8a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -716,8 +716,6 @@ int snd_ctl_elem_read(struct snd_card *c return result; } -EXPORT_SYMBOL(snd_ctl_elem_read); - static int snd_ctl_elem_read_user(struct snd_card *card, struct snd_ctl_elem_value __user *_control) { @@ -781,8 +779,6 @@ int snd_ctl_elem_write(struct snd_card * return result; } -EXPORT_SYMBOL(snd_ctl_elem_write); - static int snd_ctl_elem_write_user(struct snd_ctl_file *file, struct snd_ctl_elem_value __user *_control) { @@ -1486,3 +1482,30 @@ int snd_ctl_create(struct snd_card *card snd_assert(card != NULL, return -ENXIO); return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); } + +/* + * Frequently used control callbacks + */ +int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +EXPORT_SYMBOL(snd_ctl_boolean_mono_info); + +int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index f057430..d00dcfc 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -205,6 +205,7 @@ void snd_free_pages(void *ptr, size_t si * */ +#ifdef CONFIG_HAS_DMA /* allocate the coherent DMA pages */ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) { @@ -238,6 +239,7 @@ static void snd_free_dev_pages(struct de dec_snd_pages(pg); dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); } +#endif /* CONFIG_HAS_DMA */ #ifdef CONFIG_SBUS @@ -311,12 +313,14 @@ #ifdef CONFIG_SBUS dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr); break; #endif +#ifdef CONFIG_HAS_DMA case SNDRV_DMA_TYPE_DEV: dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); break; case SNDRV_DMA_TYPE_DEV_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; +#endif default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", type); dmab->area = NULL; @@ -382,12 +386,14 @@ #ifdef CONFIG_SBUS snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; #endif +#ifdef CONFIG_HAS_DMA case SNDRV_DMA_TYPE_DEV: snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; case SNDRV_DMA_TYPE_DEV_SG: snd_free_sgbuf_pages(dmab); break; +#endif default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type); } diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile index e6d5a04..5780525 100644 --- a/sound/core/oss/Makefile +++ b/sound/core/oss/Makefile @@ -5,8 +5,9 @@ # snd-mixer-oss-objs := mixer_oss.o -snd-pcm-oss-objs := pcm_oss.o pcm_plugin.o \ - io.o copy.o linear.o mulaw.o route.o rate.o +snd-pcm-oss-y := pcm_oss.o +snd-pcm-oss-$(CONFIG_SND_PCM_OSS_PLUGINS) += pcm_plugin.o \ + io.o copy.o linear.o mulaw.o route.o rate.o obj-$(CONFIG_SND_MIXER_OSS) += snd-mixer-oss.o obj-$(CONFIG_SND_PCM_OSS) += snd-pcm-oss.o diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c index 6658fac..d6a04c2 100644 --- a/sound/core/oss/copy.c +++ b/sound/core/oss/copy.c @@ -20,9 +20,6 @@ */ #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -88,5 +85,3 @@ int snd_pcm_plugin_build_copy(struct snd *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index b6e7ce3..322702e 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c @@ -20,9 +20,6 @@ */ #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -135,5 +132,3 @@ int snd_pcm_plugin_build_io(struct snd_p *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c index 5b1bcdc..41b2885 100644 --- a/sound/core/oss/linear.c +++ b/sound/core/oss/linear.c @@ -21,9 +21,6 @@ */ #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -34,19 +31,34 @@ #include "pcm_plugin.h" */ struct linear_priv { - int conv; + int cvt_endian; /* need endian conversion? */ + unsigned int src_ofs; /* byte offset in source format */ + unsigned int dst_ofs; /* byte soffset in destination format */ + unsigned int copy_ofs; /* byte offset in temporary u32 data */ + unsigned int dst_bytes; /* byte size of destination format */ + unsigned int copy_bytes; /* bytes to copy per conversion */ + unsigned int flip; /* MSB flip for signeness, done after endian conv */ }; +static inline void do_convert(struct linear_priv *data, + unsigned char *dst, unsigned char *src) +{ + unsigned int tmp = 0; + unsigned char *p = (unsigned char *)&tmp; + + memcpy(p + data->copy_ofs, src + data->src_ofs, data->copy_bytes); + if (data->cvt_endian) + tmp = swab32(tmp); + tmp ^= data->flip; + memcpy(dst, p + data->dst_ofs, data->dst_bytes); +} + static void convert(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { -#define CONV_LABELS -#include "plugin_ops.h" -#undef CONV_LABELS struct linear_priv *data = (struct linear_priv *)plugin->extra_data; - void *conv = conv_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; for (channel = 0; channel < nchannels; ++channel) { @@ -67,11 +79,7 @@ #undef CONV_LABELS dst_step = dst_channels[channel].area.step / 8; frames1 = frames; while (frames1-- > 0) { - goto *conv; -#define CONV_END after -#include "plugin_ops.h" -#undef CONV_END - after: + do_convert(data, dst, src); src += src_step; dst += dst_step; } @@ -106,29 +114,36 @@ #endif return frames; } -static int conv_index(int src_format, int dst_format) +static void init_data(struct linear_priv *data, int src_format, int dst_format) { - int src_endian, dst_endian, sign, src_width, dst_width; - - sign = (snd_pcm_format_signed(src_format) != - snd_pcm_format_signed(dst_format)); -#ifdef SNDRV_LITTLE_ENDIAN - src_endian = snd_pcm_format_big_endian(src_format); - dst_endian = snd_pcm_format_big_endian(dst_format); -#else - src_endian = snd_pcm_format_little_endian(src_format); - dst_endian = snd_pcm_format_little_endian(dst_format); -#endif - - if (src_endian < 0) - src_endian = 0; - if (dst_endian < 0) - dst_endian = 0; - - src_width = snd_pcm_format_width(src_format) / 8 - 1; - dst_width = snd_pcm_format_width(dst_format) / 8 - 1; - - return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; + int src_le, dst_le, src_bytes, dst_bytes; + + src_bytes = snd_pcm_format_width(src_format) / 8; + dst_bytes = snd_pcm_format_width(dst_format) / 8; + src_le = snd_pcm_format_little_endian(src_format) > 0; + dst_le = snd_pcm_format_little_endian(dst_format) > 0; + + data->dst_bytes = dst_bytes; + data->cvt_endian = src_le != dst_le; + data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes; + if (src_le) { + data->copy_ofs = 4 - data->copy_bytes; + data->src_ofs = src_bytes - data->copy_bytes; + } else + data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 - + src_bytes; + if (dst_le) + data->dst_ofs = 4 - data->dst_bytes; + else + data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 - + dst_bytes; + if (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)) { + if (dst_le) + data->flip = cpu_to_le32(0x80000000); + else + data->flip = cpu_to_be32(0x80000000); + } } int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, @@ -154,10 +169,8 @@ int snd_pcm_plugin_build_linear(struct s if (err < 0) return err; data = (struct linear_priv *)plugin->extra_data; - data->conv = conv_index(src_format->format, dst_format->format); + init_data(data, src_format->format, dst_format->format); plugin->transfer = linear_transfer; *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c index 2eb1880..3da3b81 100644 --- a/sound/core/oss/mulaw.c +++ b/sound/core/oss/mulaw.c @@ -22,9 +22,6 @@ */ #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -149,19 +146,32 @@ typedef void (*mulaw_f)(struct snd_pcm_p struct mulaw_priv { mulaw_f func; - int conv; + int cvt_endian; /* need endian conversion? */ + unsigned int native_ofs; /* byte offset in native format */ + unsigned int copy_ofs; /* byte offset in s16 format */ + unsigned int native_bytes; /* byte size of the native format */ + unsigned int copy_bytes; /* bytes to copy per conversion */ + u16 flip; /* MSB flip for signedness, done after endian conversion */ }; +static inline void cvt_s16_to_native(struct mulaw_priv *data, + unsigned char *dst, u16 sample) +{ + sample ^= data->flip; + if (data->cvt_endian) + sample = swab16(sample); + if (data->native_bytes > data->copy_bytes) + memset(dst, 0, data->native_bytes); + memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs, + data->copy_bytes); +} + static void mulaw_decode(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { -#define PUT_S16_LABELS -#include "plugin_ops.h" -#undef PUT_S16_LABELS struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; - void *put = put_s16_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; for (channel = 0; channel < nchannels; ++channel) { @@ -183,30 +193,33 @@ #undef PUT_S16_LABELS frames1 = frames; while (frames1-- > 0) { signed short sample = ulaw2linear(*src); - goto *put; -#define PUT_S16_END after -#include "plugin_ops.h" -#undef PUT_S16_END - after: + cvt_s16_to_native(data, dst, sample); src += src_step; dst += dst_step; } } } +static inline signed short cvt_native_to_s16(struct mulaw_priv *data, + unsigned char *src) +{ + u16 sample = 0; + memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs, + data->copy_bytes); + if (data->cvt_endian) + sample = swab16(sample); + sample ^= data->flip; + return (signed short)sample; +} + static void mulaw_encode(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { -#define GET_S16_LABELS -#include "plugin_ops.h" -#undef GET_S16_LABELS struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; - void *get = get_s16_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; - signed short sample = 0; for (channel = 0; channel < nchannels; ++channel) { char *src; char *dst; @@ -225,11 +238,7 @@ #undef GET_S16_LABELS dst_step = dst_channels[channel].area.step / 8; frames1 = frames; while (frames1-- > 0) { - goto *get; -#define GET_S16_END after -#include "plugin_ops.h" -#undef GET_S16_END - after: + signed short sample = cvt_native_to_s16(data, src); *dst = linear2ulaw(sample); src += src_step; dst += dst_step; @@ -265,23 +274,25 @@ #endif return frames; } -static int getput_index(int format) +static void init_data(struct mulaw_priv *data, int format) { - int sign, width, endian; - sign = !snd_pcm_format_signed(format); - width = snd_pcm_format_width(format) / 8 - 1; - if (width < 0 || width > 3) { - snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format); - width = 0; - } #ifdef SNDRV_LITTLE_ENDIAN - endian = snd_pcm_format_big_endian(format); + data->cvt_endian = snd_pcm_format_big_endian(format) > 0; #else - endian = snd_pcm_format_little_endian(format); + data->cvt_endian = snd_pcm_format_little_endian(format) > 0; #endif - if (endian < 0) - endian = 0; - return width * 4 + endian * 2 + sign; + if (!snd_pcm_format_signed(format)) + data->flip = 0x8000; + data->native_bytes = snd_pcm_format_physical_width(format) / 8; + data->copy_bytes = data->native_bytes < 2 ? 1 : 2; + if (snd_pcm_format_little_endian(format)) { + data->native_ofs = data->native_bytes - data->copy_bytes; + data->copy_ofs = 2 - data->copy_bytes; + } else { + /* S24 in 4bytes need an 1 byte offset */ + data->native_ofs = data->native_bytes - + snd_pcm_format_width(format) / 8; + } } int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, @@ -322,11 +333,8 @@ int snd_pcm_plugin_build_mulaw(struct sn return err; data = (struct mulaw_priv *)plugin->extra_data; data->func = func; - data->conv = getput_index(format->format); - snd_assert(data->conv >= 0 && data->conv < 4*2*2, return -EINVAL); + init_data(data, format->format); plugin->transfer = mulaw_transfer; *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index fc11572..c058713 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -633,6 +633,22 @@ static long snd_pcm_alsa_frames(struct s return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); } +/* define extended formats in the recent OSS versions (if any) */ +/* linear formats */ +#define AFMT_S32_LE 0x00001000 +#define AFMT_S32_BE 0x00002000 +#define AFMT_S24_LE 0x00008000 +#define AFMT_S24_BE 0x00010000 +#define AFMT_S24_PACKED 0x00040000 + +/* other supported formats */ +#define AFMT_FLOAT 0x00004000 +#define AFMT_SPDIF_RAW 0x00020000 + +/* unsupported formats */ +#define AFMT_AC3 0x00000400 +#define AFMT_VORBIS 0x00000800 + static int snd_pcm_oss_format_from(int format) { switch (format) { @@ -646,6 +662,13 @@ static int snd_pcm_oss_format_from(int f case AFMT_U16_LE: return SNDRV_PCM_FORMAT_U16_LE; case AFMT_U16_BE: return SNDRV_PCM_FORMAT_U16_BE; case AFMT_MPEG: return SNDRV_PCM_FORMAT_MPEG; + case AFMT_S32_LE: return SNDRV_PCM_FORMAT_S32_LE; + case AFMT_S32_BE: return SNDRV_PCM_FORMAT_S32_BE; + case AFMT_S24_LE: return SNDRV_PCM_FORMAT_S24_LE; + case AFMT_S24_BE: return SNDRV_PCM_FORMAT_S24_BE; + case AFMT_S24_PACKED: return SNDRV_PCM_FORMAT_S24_3LE; + case AFMT_FLOAT: return SNDRV_PCM_FORMAT_FLOAT; + case AFMT_SPDIF_RAW: return SNDRV_PCM_FORMAT_IEC958_SUBFRAME; default: return SNDRV_PCM_FORMAT_U8; } } @@ -663,6 +686,13 @@ static int snd_pcm_oss_format_to(int for case SNDRV_PCM_FORMAT_U16_LE: return AFMT_U16_LE; case SNDRV_PCM_FORMAT_U16_BE: return AFMT_U16_BE; case SNDRV_PCM_FORMAT_MPEG: return AFMT_MPEG; + case SNDRV_PCM_FORMAT_S32_LE: return AFMT_S32_LE; + case SNDRV_PCM_FORMAT_S32_BE: return AFMT_S32_BE; + case SNDRV_PCM_FORMAT_S24_LE: return AFMT_S24_LE; + case SNDRV_PCM_FORMAT_S24_BE: return AFMT_S24_BE; + case SNDRV_PCM_FORMAT_S24_3LE: return AFMT_S24_PACKED; + case SNDRV_PCM_FORMAT_FLOAT: return AFMT_FLOAT; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW; default: return -EINVAL; } } @@ -1725,7 +1755,10 @@ static int snd_pcm_oss_get_formats(struc return AFMT_MU_LAW | AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | AFMT_U16_LE | - AFMT_U16_BE; + AFMT_U16_BE | + AFMT_S32_LE | AFMT_S32_BE | + AFMT_S24_LE | AFMT_S24_LE | + AFMT_S24_PACKED; params = kmalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 0e67dd2..25dcf96 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -25,9 +25,6 @@ #define PLUGIN_DEBUG #endif #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -267,6 +264,8 @@ static int snd_pcm_plug_formats(struct s SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE | + SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW); @@ -283,6 +282,10 @@ static int preferred_formats[] = { SNDRV_PCM_FORMAT_S16_BE, SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24_3LE, + SNDRV_PCM_FORMAT_S24_3BE, + SNDRV_PCM_FORMAT_U24_3LE, + SNDRV_PCM_FORMAT_U24_3BE, SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE, SNDRV_PCM_FORMAT_U24_LE, @@ -297,41 +300,37 @@ static int preferred_formats[] = { int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { + int i; + if (snd_mask_test(format_mask, format)) return format; if (! snd_pcm_plug_formats(format_mask, format)) return -EINVAL; if (snd_pcm_format_linear(format)) { - int width = snd_pcm_format_width(format); - int unsignd = snd_pcm_format_unsigned(format); - int big = snd_pcm_format_big_endian(format); - int format1; - int wid, width1=width; - int dwidth1 = 8; - for (wid = 0; wid < 4; ++wid) { - int end, big1 = big; - for (end = 0; end < 2; ++end) { - int sgn, unsignd1 = unsignd; - for (sgn = 0; sgn < 2; ++sgn) { - format1 = snd_pcm_build_linear_format(width1, unsignd1, big1); - if (format1 >= 0 && - snd_mask_test(format_mask, format1)) - goto _found; - unsignd1 = !unsignd1; - } - big1 = !big1; - } - if (width1 == 32) { - dwidth1 = -dwidth1; - width1 = width; + unsigned int width = snd_pcm_format_width(format); + int unsignd = snd_pcm_format_unsigned(format) > 0; + int big = snd_pcm_format_big_endian(format) > 0; + unsigned int badness, best = -1; + int best_format = -1; + for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) { + int f = preferred_formats[i]; + unsigned int w; + if (!snd_mask_test(format_mask, f)) + continue; + w = snd_pcm_format_width(f); + if (w >= width) + badness = w - width; + else + badness = width - w + 32; + badness += snd_pcm_format_unsigned(f) != unsignd; + badness += snd_pcm_format_big_endian(f) != big; + if (badness < best) { + best_format = f; + best = badness; } - width1 += dwidth1; } - return -EINVAL; - _found: - return format1; + return best_format >= 0 ? best_format : -EINVAL; } else { - unsigned int i; switch (format) { case SNDRV_PCM_FORMAT_MU_LAW: for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { @@ -740,5 +739,3 @@ int snd_pcm_area_copy(const struct snd_p } return 0; } - -#endif diff --git a/sound/core/oss/plugin_ops.h b/sound/core/oss/plugin_ops.h deleted file mode 100644 index 1f5bde4..0000000 --- a/sound/core/oss/plugin_ops.h +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Plugin sample operators with fast switch - * Copyright (c) 2000 by Jaroslav Kysela - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library 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 Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#define as_u8(ptr) (*(u_int8_t*)(ptr)) -#define as_u16(ptr) (*(u_int16_t*)(ptr)) -#define as_u32(ptr) (*(u_int32_t*)(ptr)) -#define as_u64(ptr) (*(u_int64_t*)(ptr)) -#define as_s8(ptr) (*(int8_t*)(ptr)) -#define as_s16(ptr) (*(int16_t*)(ptr)) -#define as_s32(ptr) (*(int32_t*)(ptr)) -#define as_s64(ptr) (*(int64_t*)(ptr)) - -#ifdef COPY_LABELS -static void *copy_labels[4] = { - &©_8, - &©_16, - &©_32, - &©_64 -}; -#endif - -#ifdef COPY_END -while(0) { -copy_8: as_s8(dst) = as_s8(src); goto COPY_END; -copy_16: as_s16(dst) = as_s16(src); goto COPY_END; -copy_32: as_s32(dst) = as_s32(src); goto COPY_END; -copy_64: as_s64(dst) = as_s64(src); goto COPY_END; -} -#endif - -#ifdef CONV_LABELS -/* src_wid src_endswap sign_toggle dst_wid dst_endswap */ -static void *conv_labels[4 * 2 * 2 * 4 * 2] = { - &&conv_xxx1_xxx1, /* 8h -> 8h */ - &&conv_xxx1_xxx1, /* 8h -> 8s */ - &&conv_xxx1_xx10, /* 8h -> 16h */ - &&conv_xxx1_xx01, /* 8h -> 16s */ - &&conv_xxx1_x100, /* 8h -> 24h */ - &&conv_xxx1_001x, /* 8h -> 24s */ - &&conv_xxx1_1000, /* 8h -> 32h */ - &&conv_xxx1_0001, /* 8h -> 32s */ - &&conv_xxx1_xxx9, /* 8h ^> 8h */ - &&conv_xxx1_xxx9, /* 8h ^> 8s */ - &&conv_xxx1_xx90, /* 8h ^> 16h */ - &&conv_xxx1_xx09, /* 8h ^> 16s */ - &&conv_xxx1_x900, /* 8h ^> 24h */ - &&conv_xxx1_009x, /* 8h ^> 24s */ - &&conv_xxx1_9000, /* 8h ^> 32h */ - &&conv_xxx1_0009, /* 8h ^> 32s */ - &&conv_xxx1_xxx1, /* 8s -> 8h */ - &&conv_xxx1_xxx1, /* 8s -> 8s */ - &&conv_xxx1_xx10, /* 8s -> 16h */ - &&conv_xxx1_xx01, /* 8s -> 16s */ - &&conv_xxx1_x100, /* 8s -> 24h */ - &&conv_xxx1_001x, /* 8s -> 24s */ - &&conv_xxx1_1000, /* 8s -> 32h */ - &&conv_xxx1_0001, /* 8s -> 32s */ - &&conv_xxx1_xxx9, /* 8s ^> 8h */ - &&conv_xxx1_xxx9, /* 8s ^> 8s */ - &&conv_xxx1_xx90, /* 8s ^> 16h */ - &&conv_xxx1_xx09, /* 8s ^> 16s */ - &&conv_xxx1_x900, /* 8s ^> 24h */ - &&conv_xxx1_009x, /* 8s ^> 24s */ - &&conv_xxx1_9000, /* 8s ^> 32h */ - &&conv_xxx1_0009, /* 8s ^> 32s */ - &&conv_xx12_xxx1, /* 16h -> 8h */ - &&conv_xx12_xxx1, /* 16h -> 8s */ - &&conv_xx12_xx12, /* 16h -> 16h */ - &&conv_xx12_xx21, /* 16h -> 16s */ - &&conv_xx12_x120, /* 16h -> 24h */ - &&conv_xx12_021x, /* 16h -> 24s */ - &&conv_xx12_1200, /* 16h -> 32h */ - &&conv_xx12_0021, /* 16h -> 32s */ - &&conv_xx12_xxx9, /* 16h ^> 8h */ - &&conv_xx12_xxx9, /* 16h ^> 8s */ - &&conv_xx12_xx92, /* 16h ^> 16h */ - &&conv_xx12_xx29, /* 16h ^> 16s */ - &&conv_xx12_x920, /* 16h ^> 24h */ - &&conv_xx12_029x, /* 16h ^> 24s */ - &&conv_xx12_9200, /* 16h ^> 32h */ - &&conv_xx12_0029, /* 16h ^> 32s */ - &&conv_xx12_xxx2, /* 16s -> 8h */ - &&conv_xx12_xxx2, /* 16s -> 8s */ - &&conv_xx12_xx21, /* 16s -> 16h */ - &&conv_xx12_xx12, /* 16s -> 16s */ - &&conv_xx12_x210, /* 16s -> 24h */ - &&conv_xx12_012x, /* 16s -> 24s */ - &&conv_xx12_2100, /* 16s -> 32h */ - &&conv_xx12_0012, /* 16s -> 32s */ - &&conv_xx12_xxxA, /* 16s ^> 8h */ - &&conv_xx12_xxxA, /* 16s ^> 8s */ - &&conv_xx12_xxA1, /* 16s ^> 16h */ - &&conv_xx12_xx1A, /* 16s ^> 16s */ - &&conv_xx12_xA10, /* 16s ^> 24h */ - &&conv_xx12_01Ax, /* 16s ^> 24s */ - &&conv_xx12_A100, /* 16s ^> 32h */ - &&conv_xx12_001A, /* 16s ^> 32s */ - &&conv_x123_xxx1, /* 24h -> 8h */ - &&conv_x123_xxx1, /* 24h -> 8s */ - &&conv_x123_xx12, /* 24h -> 16h */ - &&conv_x123_xx21, /* 24h -> 16s */ - &&conv_x123_x123, /* 24h -> 24h */ - &&conv_x123_321x, /* 24h -> 24s */ - &&conv_x123_1230, /* 24h -> 32h */ - &&conv_x123_0321, /* 24h -> 32s */ - &&conv_x123_xxx9, /* 24h ^> 8h */ - &&conv_x123_xxx9, /* 24h ^> 8s */ - &&conv_x123_xx92, /* 24h ^> 16h */ - &&conv_x123_xx29, /* 24h ^> 16s */ - &&conv_x123_x923, /* 24h ^> 24h */ - &&conv_x123_329x, /* 24h ^> 24s */ - &&conv_x123_9230, /* 24h ^> 32h */ - &&conv_x123_0329, /* 24h ^> 32s */ - &&conv_123x_xxx3, /* 24s -> 8h */ - &&conv_123x_xxx3, /* 24s -> 8s */ - &&conv_123x_xx32, /* 24s -> 16h */ - &&conv_123x_xx23, /* 24s -> 16s */ - &&conv_123x_x321, /* 24s -> 24h */ - &&conv_123x_123x, /* 24s -> 24s */ - &&conv_123x_3210, /* 24s -> 32h */ - &&conv_123x_0123, /* 24s -> 32s */ - &&conv_123x_xxxB, /* 24s ^> 8h */ - &&conv_123x_xxxB, /* 24s ^> 8s */ - &&conv_123x_xxB2, /* 24s ^> 16h */ - &&conv_123x_xx2B, /* 24s ^> 16s */ - &&conv_123x_xB21, /* 24s ^> 24h */ - &&conv_123x_12Bx, /* 24s ^> 24s */ - &&conv_123x_B210, /* 24s ^> 32h */ - &&conv_123x_012B, /* 24s ^> 32s */ - &&conv_1234_xxx1, /* 32h -> 8h */ - &&conv_1234_xxx1, /* 32h -> 8s */ - &&conv_1234_xx12, /* 32h -> 16h */ - &&conv_1234_xx21, /* 32h -> 16s */ - &&conv_1234_x123, /* 32h -> 24h */ - &&conv_1234_321x, /* 32h -> 24s */ - &&conv_1234_1234, /* 32h -> 32h */ - &&conv_1234_4321, /* 32h -> 32s */ - &&conv_1234_xxx9, /* 32h ^> 8h */ - &&conv_1234_xxx9, /* 32h ^> 8s */ - &&conv_1234_xx92, /* 32h ^> 16h */ - &&conv_1234_xx29, /* 32h ^> 16s */ - &&conv_1234_x923, /* 32h ^> 24h */ - &&conv_1234_329x, /* 32h ^> 24s */ - &&conv_1234_9234, /* 32h ^> 32h */ - &&conv_1234_4329, /* 32h ^> 32s */ - &&conv_1234_xxx4, /* 32s -> 8h */ - &&conv_1234_xxx4, /* 32s -> 8s */ - &&conv_1234_xx43, /* 32s -> 16h */ - &&conv_1234_xx34, /* 32s -> 16s */ - &&conv_1234_x432, /* 32s -> 24h */ - &&conv_1234_234x, /* 32s -> 24s */ - &&conv_1234_4321, /* 32s -> 32h */ - &&conv_1234_1234, /* 32s -> 32s */ - &&conv_1234_xxxC, /* 32s ^> 8h */ - &&conv_1234_xxxC, /* 32s ^> 8s */ - &&conv_1234_xxC3, /* 32s ^> 16h */ - &&conv_1234_xx3C, /* 32s ^> 16s */ - &&conv_1234_xC32, /* 32s ^> 24h */ - &&conv_1234_23Cx, /* 32s ^> 24s */ - &&conv_1234_C321, /* 32s ^> 32h */ - &&conv_1234_123C, /* 32s ^> 32s */ -}; -#endif - -#ifdef CONV_END -while(0) { -conv_xxx1_xxx1: as_u8(dst) = as_u8(src); goto CONV_END; -conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto CONV_END; -conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto CONV_END; -conv_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto CONV_END; -conv_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto CONV_END; -conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto CONV_END; -conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto CONV_END; -conv_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto CONV_END; -conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END; -conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto CONV_END; -conv_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto CONV_END; -conv_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END; -conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto CONV_END; -conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto CONV_END; -conv_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto CONV_END; -conv_xx12_xx12: as_u16(dst) = as_u16(src); goto CONV_END; -conv_xx12_xx21: as_u16(dst) = swab16(as_u16(src)); goto CONV_END; -conv_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END; -conv_xx12_021x: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END; -conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto CONV_END; -conv_xx12_0021: as_u32(dst) = (u_int32_t)swab16(as_u16(src)); goto CONV_END; -conv_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto CONV_END; -conv_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto CONV_END; -conv_xx12_xx29: as_u16(dst) = swab16(as_u16(src)) ^ 0x80; goto CONV_END; -conv_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto CONV_END; -conv_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80) << 8; goto CONV_END; -conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto CONV_END; -conv_xx12_0029: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80); goto CONV_END; -conv_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto CONV_END; -conv_xx12_x210: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END; -conv_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END; -conv_xx12_2100: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 16; goto CONV_END; -conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto CONV_END; -conv_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto CONV_END; -conv_xx12_xxA1: as_u16(dst) = swab16(as_u16(src) ^ 0x80); goto CONV_END; -conv_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto CONV_END; -conv_xx12_xA10: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 8; goto CONV_END; -conv_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto CONV_END; -conv_xx12_A100: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto CONV_END; -conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto CONV_END; -conv_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto CONV_END; -conv_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto CONV_END; -conv_x123_xx21: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END; -conv_x123_x123: as_u32(dst) = as_u32(src); goto CONV_END; -conv_x123_321x: as_u32(dst) = swab32(as_u32(src)); goto CONV_END; -conv_x123_1230: as_u32(dst) = as_u32(src) << 8; goto CONV_END; -conv_x123_0321: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END; -conv_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto CONV_END; -conv_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto CONV_END; -conv_x123_xx29: as_u16(dst) = swab16(as_u32(src) >> 8) ^ 0x80; goto CONV_END; -conv_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto CONV_END; -conv_x123_329x: as_u32(dst) = swab32(as_u32(src)) ^ 0x8000; goto CONV_END; -conv_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto CONV_END; -conv_x123_0329: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x80; goto CONV_END; -conv_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto CONV_END; -conv_123x_xx32: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END; -conv_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto CONV_END; -conv_123x_x321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END; -conv_123x_123x: as_u32(dst) = as_u32(src); goto CONV_END; -conv_123x_3210: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END; -conv_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END; -conv_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto CONV_END; -conv_123x_xxB2: as_u16(dst) = swab16((as_u32(src) >> 8) ^ 0x80); goto CONV_END; -conv_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END; -conv_123x_xB21: as_u32(dst) = swab32(as_u32(src)) ^ 0x800000; goto CONV_END; -conv_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto CONV_END; -conv_123x_B210: as_u32(dst) = swab32(as_u32(src) ^ 0x8000) << 8; goto CONV_END; -conv_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto CONV_END; -conv_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto CONV_END; -conv_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto CONV_END; -conv_1234_xx21: as_u16(dst) = swab16(as_u32(src) >> 16); goto CONV_END; -conv_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END; -conv_1234_321x: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END; -conv_1234_1234: as_u32(dst) = as_u32(src); goto CONV_END; -conv_1234_4321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END; -conv_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto CONV_END; -conv_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto CONV_END; -conv_1234_xx29: as_u16(dst) = swab16(as_u32(src) >> 16) ^ 0x80; goto CONV_END; -conv_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto CONV_END; -conv_1234_329x: as_u32(dst) = (swab32(as_u32(src)) ^ 0x80) << 8; goto CONV_END; -conv_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto CONV_END; -conv_1234_4329: as_u32(dst) = swab32(as_u32(src)) ^ 0x80; goto CONV_END; -conv_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto CONV_END; -conv_1234_xx43: as_u16(dst) = swab16(as_u32(src)); goto CONV_END; -conv_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto CONV_END; -conv_1234_x432: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END; -conv_1234_234x: as_u32(dst) = as_u32(src) << 8; goto CONV_END; -conv_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto CONV_END; -conv_1234_xxC3: as_u16(dst) = swab16(as_u32(src) ^ 0x80); goto CONV_END; -conv_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto CONV_END; -conv_1234_xC32: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x800000; goto CONV_END; -conv_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto CONV_END; -conv_1234_C321: as_u32(dst) = swab32(as_u32(src) ^ 0x80); goto CONV_END; -conv_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto CONV_END; -} -#endif - -#ifdef GET_S16_LABELS -/* src_wid src_endswap unsigned */ -static void *get_s16_labels[4 * 2 * 2] = { - &&get_s16_xxx1_xx10, /* 8h -> 16h */ - &&get_s16_xxx1_xx90, /* 8h ^> 16h */ - &&get_s16_xxx1_xx10, /* 8s -> 16h */ - &&get_s16_xxx1_xx90, /* 8s ^> 16h */ - &&get_s16_xx12_xx12, /* 16h -> 16h */ - &&get_s16_xx12_xx92, /* 16h ^> 16h */ - &&get_s16_xx12_xx21, /* 16s -> 16h */ - &&get_s16_xx12_xxA1, /* 16s ^> 16h */ - &&get_s16_x123_xx12, /* 24h -> 16h */ - &&get_s16_x123_xx92, /* 24h ^> 16h */ - &&get_s16_123x_xx32, /* 24s -> 16h */ - &&get_s16_123x_xxB2, /* 24s ^> 16h */ - &&get_s16_1234_xx12, /* 32h -> 16h */ - &&get_s16_1234_xx92, /* 32h ^> 16h */ - &&get_s16_1234_xx43, /* 32s -> 16h */ - &&get_s16_1234_xxC3, /* 32s ^> 16h */ -}; -#endif - -#ifdef GET_S16_END -while(0) { -get_s16_xxx1_xx10: sample = (u_int16_t)as_u8(src) << 8; goto GET_S16_END; -get_s16_xxx1_xx90: sample = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto GET_S16_END; -get_s16_xx12_xx12: sample = as_u16(src); goto GET_S16_END; -get_s16_xx12_xx92: sample = as_u16(src) ^ 0x8000; goto GET_S16_END; -get_s16_xx12_xx21: sample = swab16(as_u16(src)); goto GET_S16_END; -get_s16_xx12_xxA1: sample = swab16(as_u16(src) ^ 0x80); goto GET_S16_END; -get_s16_x123_xx12: sample = as_u32(src) >> 8; goto GET_S16_END; -get_s16_x123_xx92: sample = (as_u32(src) >> 8) ^ 0x8000; goto GET_S16_END; -get_s16_123x_xx32: sample = swab16(as_u32(src) >> 8); goto GET_S16_END; -get_s16_123x_xxB2: sample = swab16((as_u32(src) >> 8) ^ 0x8000); goto GET_S16_END; -get_s16_1234_xx12: sample = as_u32(src) >> 16; goto GET_S16_END; -get_s16_1234_xx92: sample = (as_u32(src) >> 16) ^ 0x8000; goto GET_S16_END; -get_s16_1234_xx43: sample = swab16(as_u32(src)); goto GET_S16_END; -get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END; -} -#endif - -#ifdef PUT_S16_LABELS -/* dst_wid dst_endswap unsigned */ -static void *put_s16_labels[4 * 2 * 2] = { - &&put_s16_xx12_xxx1, /* 16h -> 8h */ - &&put_s16_xx12_xxx9, /* 16h ^> 8h */ - &&put_s16_xx12_xxx1, /* 16h -> 8s */ - &&put_s16_xx12_xxx9, /* 16h ^> 8s */ - &&put_s16_xx12_xx12, /* 16h -> 16h */ - &&put_s16_xx12_xx92, /* 16h ^> 16h */ - &&put_s16_xx12_xx21, /* 16h -> 16s */ - &&put_s16_xx12_xx29, /* 16h ^> 16s */ - &&put_s16_xx12_x120, /* 16h -> 24h */ - &&put_s16_xx12_x920, /* 16h ^> 24h */ - &&put_s16_xx12_021x, /* 16h -> 24s */ - &&put_s16_xx12_029x, /* 16h ^> 24s */ - &&put_s16_xx12_1200, /* 16h -> 32h */ - &&put_s16_xx12_9200, /* 16h ^> 32h */ - &&put_s16_xx12_0021, /* 16h -> 32s */ - &&put_s16_xx12_0029, /* 16h ^> 32s */ -}; -#endif - -#ifdef PUT_S16_END -while (0) { -put_s16_xx12_xxx1: as_u8(dst) = sample >> 8; goto PUT_S16_END; -put_s16_xx12_xxx9: as_u8(dst) = (sample >> 8) ^ 0x80; goto PUT_S16_END; -put_s16_xx12_xx12: as_u16(dst) = sample; goto PUT_S16_END; -put_s16_xx12_xx92: as_u16(dst) = sample ^ 0x8000; goto PUT_S16_END; -put_s16_xx12_xx21: as_u16(dst) = swab16(sample); goto PUT_S16_END; -put_s16_xx12_xx29: as_u16(dst) = swab16(sample) ^ 0x80; goto PUT_S16_END; -put_s16_xx12_x120: as_u32(dst) = (u_int32_t)sample << 8; goto PUT_S16_END; -put_s16_xx12_x920: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 8; goto PUT_S16_END; -put_s16_xx12_021x: as_u32(dst) = (u_int32_t)swab16(sample) << 8; goto PUT_S16_END; -put_s16_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(sample) ^ 0x80) << 8; goto PUT_S16_END; -put_s16_xx12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT_S16_END; -put_s16_xx12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT_S16_END; -put_s16_xx12_0021: as_u32(dst) = (u_int32_t)swab16(sample); goto PUT_S16_END; -put_s16_xx12_0029: as_u32(dst) = (u_int32_t)swab16(sample) ^ 0x80; goto PUT_S16_END; -} -#endif - -#undef as_u8 -#undef as_u16 -#undef as_u32 -#undef as_s8 -#undef as_s16 -#undef as_s32 diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c index 18d8a0f..66f1dbe 100644 --- a/sound/core/oss/rate.c +++ b/sound/core/oss/rate.c @@ -20,9 +20,6 @@ */ #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -340,5 +337,3 @@ int snd_pcm_plugin_build_rate(struct snd *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c index 46917dc..de3ffde 100644 --- a/sound/core/oss/route.c +++ b/sound/core/oss/route.c @@ -20,9 +20,6 @@ */ #include - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include #include #include @@ -108,5 +105,3 @@ int snd_pcm_plugin_build_route(struct sn *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 0019c59..e5f25ae 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -422,38 +422,6 @@ #endif EXPORT_SYMBOL(snd_pcm_format_set_silence); -/* [width][unsigned][bigendian] */ -static int linear_formats[4][2][2] = { - {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, - { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}}, - {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE}, - {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}}, - {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE}, - {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}}, - {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE}, - {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}} -}; - -/** - * snd_pcm_build_linear_format - return the suitable linear format for the given condition - * @width: the bit-width - * @unsignd: 1 if unsigned, 0 if signed. - * @big_endian: 1 if big-endian, 0 if little-endian - * - * Returns the suitable linear format for the given condition. - */ -snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian) -{ - if (width & 7) - return SND_PCM_FORMAT_UNKNOWN; - width = (width / 8) - 1; - if (width < 0 || width >= 4) - return SND_PCM_FORMAT_UNKNOWN; - return linear_formats[width][!!unsignd][!!big_endian]; -} - -EXPORT_SYMBOL(snd_pcm_build_linear_format); - /** * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields * @runtime: the runtime instance @@ -465,21 +433,16 @@ EXPORT_SYMBOL(snd_pcm_build_linear_forma */ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) { - static unsigned rates[] = { - /* ATTENTION: these values depend on the definition in pcm.h! */ - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 - }; int i; - for (i = 0; i < (int)ARRAY_SIZE(rates); i++) { + for (i = 0; i < (int)snd_pcm_known_rates.count; i++) { if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_min = rates[i]; + runtime->hw.rate_min = snd_pcm_known_rates.list[i]; break; } } - for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) { + for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) { if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_max = rates[i]; + runtime->hw.rate_max = snd_pcm_known_rates.list[i]; break; } } @@ -487,3 +450,21 @@ int snd_pcm_limit_hw_rates(struct snd_pc } EXPORT_SYMBOL(snd_pcm_limit_hw_rates); + +/** + * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit + * @rate: the sample rate to convert + * + * Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or + * SNDRV_PCM_RATE_KNOT for an unknown rate. + */ +unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) +{ + unsigned int i; + + for (i = 0; i < snd_pcm_known_rates.count; i++) + if (snd_pcm_known_rates.list[i] == rate) + return 1u << i; + return SNDRV_PCM_RATE_KNOT; +} +EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 59b29cd..b78a411 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1787,12 +1787,18 @@ #endif static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; +const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, +}; + static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_pcm_hardware *hw = rule->private; return snd_interval_list(hw_param_interval(params, rule->var), - ARRAY_SIZE(rates), rates, hw->rates); + snd_pcm_known_rates.count, + snd_pcm_known_rates.list, hw->rates); } static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index e470c3c..8a91cf8 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -30,7 +30,6 @@ #include #include #include #include -#include #include #include #include diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index ca5a2ed..d0d721c 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -176,29 +176,29 @@ snd_seq_oss_open(struct file *file, int int i, rc; struct seq_oss_devinfo *dp; - if ((dp = kzalloc(sizeof(*dp), GFP_KERNEL)) == NULL) { + dp = kzalloc(sizeof(*dp), GFP_KERNEL); + if (!dp) { snd_printk(KERN_ERR "can't malloc device info\n"); return -ENOMEM; } debug_printk(("oss_open: dp = %p\n", dp)); + dp->cseq = system_client; + dp->port = -1; + dp->queue = -1; + for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) { if (client_table[i] == NULL) break; } + + dp->index = i; if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { snd_printk(KERN_ERR "too many applications\n"); - kfree(dp); - return -ENOMEM; + rc = -ENOMEM; + goto _error; } - dp->index = i; - dp->cseq = system_client; - dp->port = -1; - dp->queue = -1; - dp->readq = NULL; - dp->writeq = NULL; - /* look up synth and midi devices */ snd_seq_oss_synth_setup(dp); snd_seq_oss_midi_setup(dp); @@ -211,14 +211,16 @@ snd_seq_oss_open(struct file *file, int /* create port */ debug_printk(("create new port\n")); - if ((rc = create_port(dp)) < 0) { + rc = create_port(dp); + if (rc < 0) { snd_printk(KERN_ERR "can't create port\n"); goto _error; } /* allocate queue */ debug_printk(("allocate queue\n")); - if ((rc = alloc_seq_queue(dp)) < 0) + rc = alloc_seq_queue(dp); + if (rc < 0) goto _error; /* set address */ @@ -235,7 +237,8 @@ snd_seq_oss_open(struct file *file, int /* initialize read queue */ debug_printk(("initialize read queue\n")); if (is_read_mode(dp->file_mode)) { - if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) { + dp->readq = snd_seq_oss_readq_new(dp, maxqlen); + if (!dp->readq) { rc = -ENOMEM; goto _error; } @@ -245,7 +248,7 @@ snd_seq_oss_open(struct file *file, int debug_printk(("initialize write queue\n")); if (is_write_mode(dp->file_mode)) { dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen); - if (dp->writeq == NULL) { + if (!dp->writeq) { rc = -ENOMEM; goto _error; } @@ -253,7 +256,8 @@ snd_seq_oss_open(struct file *file, int /* initialize timer */ debug_printk(("initialize timer\n")); - if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) { + dp->timer = snd_seq_oss_timer_new(dp); + if (!dp->timer) { snd_printk(KERN_ERR "can't alloc timer\n"); rc = -ENOMEM; goto _error; @@ -276,11 +280,13 @@ snd_seq_oss_open(struct file *file, int return 0; _error: + snd_seq_oss_writeq_delete(dp->writeq); + snd_seq_oss_readq_delete(dp->readq); snd_seq_oss_synth_cleanup(dp); snd_seq_oss_midi_cleanup(dp); - i = dp->queue; delete_port(dp); - delete_seq_queue(i); + delete_seq_queue(dp->queue); + kfree(dp); return rc; } diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 5c84956..2174248 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -63,8 +63,10 @@ snd_seq_oss_writeq_new(struct seq_oss_de void snd_seq_oss_writeq_delete(struct seq_oss_writeq *q) { - snd_seq_oss_writeq_clear(q); /* to be sure */ - kfree(q); + if (q) { + snd_seq_oss_writeq_clear(q); /* to be sure */ + kfree(q); + } } diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c index 5efe652..08bed00 100644 --- a/sound/core/seq/seq_instr.c +++ b/sound/core/seq/seq_instr.c @@ -109,7 +109,7 @@ void snd_seq_instr_list_free(struct snd_ spin_lock_irqsave(&list->lock, flags); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); @@ -198,8 +198,10 @@ int snd_seq_instr_list_free_cond(struct while (flist) { instr = flist; flist = instr->next; - while (instr->use) - schedule_timeout(1); + while (instr->use) { + schedule_timeout_uninterruptible(1); + barrier(); + } if (snd_seq_instr_free(instr, atomic)<0) snd_printk(KERN_WARNING "instrument free problem\n"); instr = next; @@ -555,7 +557,7 @@ static int instr_free(struct snd_seq_kin SNDRV_SEQ_INSTR_NOTIFY_REMOVE); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 5ff80b7..4641677 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -32,10 +32,9 @@ MODULE_AUTHOR("Takashi Iwai sequencer event coder"); MODULE_LICENSE("GPL"); -/* queue type */ -/* from 0 to 7 are normal commands (note off, on, etc.) */ -#define ST_NOTEOFF 0 -#define ST_NOTEON 1 +/* event type, index into status_event[] */ +/* from 0 to 6 are normal commands (note off, on, etc.) for 0x9?-0xe? */ +#define ST_INVALID 7 #define ST_SPECIAL 8 #define ST_SYSEX ST_SPECIAL /* from 8 to 15 are events for 0xf0-0xf7 */ @@ -65,32 +64,33 @@ static struct status_event_list { void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev); void (*decode)(struct snd_seq_event *ev, unsigned char *buf); } status_event[] = { - /* 0x80 - 0xf0 */ - {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, - {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, - {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, - {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, - {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, - {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, - {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */ + /* 0x80 - 0xef */ + {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, + {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, + {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, + {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, + {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, + {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, + {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, + /* invalid */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf0 - 0xff */ - {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ - {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ - {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ - {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */ - {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf7 */ - {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf9 */ - {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ - {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ - {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */ - {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ - {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ + {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ + {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ + {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ + {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf4 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf5 */ + {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf7 */ + {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf9 */ + {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ + {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ + {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xfd */ + {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ + {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ }; static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len, @@ -129,6 +129,7 @@ int snd_midi_event_new(int bufsize, stru } dev->bufsize = bufsize; dev->lastcmd = 0xff; + dev->type = ST_INVALID; spin_lock_init(&dev->lock); *rdev = dev; return 0; @@ -149,7 +150,7 @@ static inline void reset_encode(struct s { dev->read = 0; dev->qlen = 0; - dev->type = 0; + dev->type = ST_INVALID; } void snd_midi_event_reset_encode(struct snd_midi_event *dev) @@ -251,29 +252,31 @@ int snd_midi_event_encode_byte(struct sn ev->type = status_event[ST_SPECIAL + c - 0xf0].event; ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; - return 1; + return ev->type != SNDRV_SEQ_EVENT_NONE; } spin_lock_irqsave(&dev->lock, flags); - if (dev->qlen > 0) { - /* rest of command */ - dev->buf[dev->read++] = c; - if (dev->type != ST_SYSEX) - dev->qlen--; - } else { + if ((c & 0x80) && + (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) { /* new command */ + dev->buf[0] = c; + if ((c & 0xf0) == 0xf0) /* system messages */ + dev->type = (c & 0x0f) + ST_SPECIAL; + else + dev->type = (c >> 4) & 0x07; dev->read = 1; - if (c & 0x80) { - dev->buf[0] = c; - if ((c & 0xf0) == 0xf0) /* special events */ - dev->type = (c & 0x0f) + ST_SPECIAL; - else - dev->type = (c >> 4) & 0x07; - dev->qlen = status_event[dev->type].qlen; - } else { - /* process this byte as argument */ + dev->qlen = status_event[dev->type].qlen; + } else { + if (dev->qlen > 0) { + /* rest of command */ dev->buf[dev->read++] = c; + if (dev->type != ST_SYSEX) + dev->qlen--; + } else { + /* running status */ + dev->buf[1] = c; dev->qlen = status_event[dev->type].qlen - 1; + dev->read = 2; } } if (dev->qlen == 0) { @@ -282,6 +285,8 @@ int snd_midi_event_encode_byte(struct sn ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; if (status_event[dev->type].encode) /* set data values */ status_event[dev->type].encode(dev, ev); + if (dev->type >= ST_SPECIAL) + dev->type = ST_INVALID; rc = 1; } else if (dev->type == ST_SYSEX) { if (c == MIDI_CMD_COMMON_SYSEX_END || diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 4360ae9..77bca5f 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -510,15 +510,7 @@ #define DUMMY_CAPSRC(xname, xindex, addr .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \ .private_value = addr } -static int snd_dummy_capsrc_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_dummy_capsrc_info snd_ctl_boolean_stereo_info static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 2025db5..911c159 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -440,15 +440,7 @@ static void mts64_write_midi(struct mts6 *********************************************************************/ /* SMPTE Switch */ -static int snd_mts64_ctl_smpte_switch_info(struct snd_kcontrol *kctl, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_mts64_ctl_smpte_switch_info snd_ctl_boolean_mono_info static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl, struct snd_ctl_elem_value *uctl) diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile index 1205978..87ec577 100644 --- a/sound/drivers/opl3/Makefile +++ b/sound/drivers/opl3/Makefile @@ -4,10 +4,8 @@ # Copyright (c) 2001 by Jaroslav Kysela # snd-opl3-lib-objs := opl3_lib.o opl3_synth.o -snd-opl3-synth-objs := opl3_seq.o opl3_midi.o opl3_drums.o -ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) -snd-opl3-synth-objs += opl3_oss.o -endif +snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o +snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o # # this function returns: diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index f63152a..b8fcd79 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -647,14 +647,7 @@ static int vx_audio_monitor_put(struct s return 0; } -static int vx_audio_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define vx_audio_sw_info snd_ctl_boolean_stereo_info static int vx_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -865,14 +858,7 @@ static int vx_peak_meter_get(struct snd_ return 0; } -static int vx_saturation_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define vx_saturation_info snd_ctl_boolean_stereo_info static int vx_saturation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile index 45902d4..0856cda 100644 --- a/sound/i2c/Makefile +++ b/sound/i2c/Makefile @@ -7,9 +7,7 @@ snd-i2c-objs := i2c.o snd-cs8427-objs := cs8427.o snd-tea6330t-objs := tea6330t.o -ifeq ($(subst m,y,$(CONFIG_L3)),y) - obj-$(CONFIG_L3) += l3/ -endif +obj-$(CONFIG_L3) += l3/ obj-$(CONFIG_SND) += other/ diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 64388cb..e601caa 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -229,6 +229,12 @@ int snd_cs8427_create(struct snd_i2c_bus snd_i2c_lock(bus); err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER); if (err != CS8427_VER8427A) { + /* give second chance */ + snd_printk(KERN_WARNING "invalid CS8427 signature 0x%x: " + "let me try again...\n", err); + err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER); + } + if (err != CS8427_VER8427A) { snd_i2c_unlock(bus); snd_printk(KERN_ERR "unable to find CS8427 signature " "(expected 0x%x, read 0x%x),\n", diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 1efb973..f2b81e3 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -200,15 +200,7 @@ static int snd_ak4114_in_error_get(struc return 0; } -static int snd_ak4114_in_bit_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ak4114_in_bit_info snd_ctl_boolean_mono_info static int snd_ak4114_in_bit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index c022f29..1614973 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -181,15 +181,7 @@ static int snd_ak4117_in_error_get(struc return 0; } -static int snd_ak4117_in_bit_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ak4117_in_bit_info snd_ctl_boolean_mono_info static int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index fd33515..0fa1072 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -463,15 +463,7 @@ static int snd_akm4xxx_deemphasis_put(st return change; } -static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define ak4xxx_switch_info snd_ctl_boolean_mono_info static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c index e91cc3b..00c83d8 100644 --- a/sound/i2c/other/pt2258.c +++ b/sound/i2c/other/pt2258.c @@ -140,15 +140,7 @@ static int pt2258_stereo_volume_put(stru return -EIO; } -static int pt2258_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define pt2258_switch_info snd_ctl_boolean_mono_info static int pt2258_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index ae5b1e3..21ff974 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -142,15 +142,7 @@ #define TEA6330T_MASTER_SWITCH(xname, xi .info = snd_tea6330t_info_master_switch, \ .get = snd_tea6330t_get_master_switch, .put = snd_tea6330t_put_master_switch } -static int snd_tea6330t_info_master_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_tea6330t_info_master_switch snd_ctl_boolean_stereo_info static int snd_tea6330t_get_master_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index ea5084a..2639a6a 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -191,6 +191,19 @@ config SND_ES18XX To compile this driver as a module, choose M here: the module will be called snd-es18xx. +config SND_SC6000 + tristate "Gallant SC-6000, Audio Excel DSP 16" + depends on SND && HAS_IOPORT + select SND_AD1848_LIB + select SND_OPL3_LIB + select SND_MPU401_UART + help + Say Y here to include support for Gallant SC-6000 card and clones: + Audio Excel DSP 16 and Zoltrix AV302. + + To compile this driver as a module, choose M here: the module + will be called snd-sc6000. + config SND_GUS_SYNTH tristate @@ -414,7 +427,7 @@ config SND_SSCAPE config SND_WAVEFRONT tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" depends on SND - select FW_LOADER if !SND_WAVEFRONT_FIRMWARE_IN_KERNEL + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB @@ -430,8 +443,9 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL depends on SND_WAVEFRONT default y help - Say Y here to include the static firmware built in the kernel - for the Wavefront driver. If you choose N here, you need to - install the firmware files from the alsa-firmware package. + Say Y here to include the static firmware for FX DSP built in + the kernel for the Wavefront driver. If you choose N here, + you need to install the firmware files from the + alsa-firmware package. endmenu diff --git a/sound/isa/Makefile b/sound/isa/Makefile index bb317cc..5378d98 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -10,6 +10,7 @@ snd-cmi8330-objs := cmi8330.o snd-dt019x-objs := dt019x.o snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o +snd-sc6000-objs := sc6000.o snd-sgalaxy-objs := sgalaxy.o snd-sscape-objs := sscape.o @@ -21,6 +22,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330 obj-$(CONFIG_SND_DT019X) += snd-dt019x.o obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o +obj-$(CONFIG_SND_SC6000) += snd-sc6000.o obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index ec9209c..cf18fe4 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -453,7 +453,6 @@ static int snd_ad1816a_playback_open(str if ((error = snd_ad1816a_open(chip, AD1816A_MODE_PLAYBACK)) < 0) return error; - snd_pcm_set_sync(substream); runtime->hw = snd_ad1816a_playback; 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); @@ -469,7 +468,6 @@ static int snd_ad1816a_capture_open(stru if ((error = snd_ad1816a_open(chip, AD1816A_MODE_CAPTURE)) < 0) return error; - snd_pcm_set_sync(substream); runtime->hw = snd_ad1816a_capture; 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); diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile index 45d5999..5c7e3fd 100644 --- a/sound/isa/ad1848/Makefile +++ b/sound/isa/ad1848/Makefile @@ -7,9 +7,6 @@ snd-ad1848-lib-objs := ad1848_lib.o snd-ad1848-objs := ad1848.o # Toplevel Module Dependency -obj-$(CONFIG_SND_CMI8330) += snd-ad1848-lib.o -obj-$(CONFIG_SND_SGALAXY) += snd-ad1848-lib.o -obj-$(CONFIG_SND_AD1848) += snd-ad1848.o snd-ad1848-lib.o -obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-ad1848-lib.o +obj-$(CONFIG_SND_AD1848) += snd-ad1848.o +obj-$(CONFIG_SND_AD1848_LIB) += snd-ad1848-lib.o -obj-m := $(sort $(obj-m)) diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 1bc2e3f..21536b7 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -70,7 +70,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; @@ -99,24 +99,32 @@ static unsigned char snd_ad1848_original * Basic I/O functions */ -void snd_ad1848_out(struct snd_ad1848 *chip, - unsigned char reg, - unsigned char value) +static void snd_ad1848_wait(struct snd_ad1848 *chip) { int timeout; - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); 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); + 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(); -#if 0 - printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); -#endif + snd_printdd("codec out - reg 0x%x = 0x%x\n", + chip->mce_bit | reg, value); } EXPORT_SYMBOL(snd_ad1848_out); @@ -124,10 +132,7 @@ EXPORT_SYMBOL(snd_ad1848_out); static void snd_ad1848_dout(struct snd_ad1848 *chip, unsigned char reg, unsigned char value) { - int timeout; - - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); + snd_ad1848_wait(chip); outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); outb(value, AD1848P(chip, REG)); mb(); @@ -135,13 +140,11 @@ static void snd_ad1848_dout(struct snd_a static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg) { - int timeout; - - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); + 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); + snd_printk(KERN_WARNING "auto calibration time out - " + "reg = 0x%x\n", reg); #endif outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); mb(); @@ -183,8 +186,7 @@ static void snd_ad1848_mce_up(struct snd unsigned long flags; int timeout; - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); + 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"); @@ -201,9 +203,8 @@ #endif static void snd_ad1848_mce_down(struct snd_ad1848 *chip) { - unsigned long flags; - int timeout; - signed long time; + unsigned long flags, timeout; + int reg; spin_lock_irqsave(&chip->reg_lock, flags); for (timeout = 5; timeout > 0; timeout--) @@ -211,61 +212,48 @@ static void snd_ad1848_mce_down(struct s /* end of cleanup sequence */ for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) udelay(100); -#if 0 - printk("(1) timeout = %i\n", timeout); -#endif + + snd_printdd("(1) timeout = %d\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; - timeout = inb(AD1848P(chip, REGSEL)); - outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL)); - if (timeout == 0x80) + 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 ((timeout & AD1848_MCE) == 0) { + if ((reg & AD1848_MCE) == 0) { spin_unlock_irqrestore(&chip->reg_lock, flags); return; } - /* calibration process */ - for (timeout = 500; timeout > 0 && (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0; timeout--); - if ((snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0) { - snd_printd("mce_down - auto calibration time out (1)\n"); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return; - } -#if 0 - printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); -#endif - time = HZ / 4; - while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) { + /* + * 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); - if (time <= 0) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n"); - return; - } - time = schedule_timeout(time); + msleep(1); spin_lock_irqsave(&chip->reg_lock, flags); - } -#if 0 - printk("(3) jiffies = %li\n", jiffies); -#endif - time = HZ / 10; - while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (time <= 0) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); - return; - } - time = schedule_timeout(time); - 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 0 - printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL))); -#endif + 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, @@ -319,11 +307,11 @@ static unsigned char snd_ad1848_get_rate { int i; - for (i = 0; i < 14; i++) + for (i = 0; i < ARRAY_SIZE(rates); i++) if (rate == rates[i]) return freq_bits[i]; snd_BUG(); - return freq_bits[13]; + return freq_bits[ARRAY_SIZE(rates) - 1]; } static int snd_ad1848_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile index 2fb4f74..7136496 100644 --- a/sound/isa/cs423x/Makefile +++ b/sound/isa/cs423x/Makefile @@ -10,17 +10,8 @@ snd-cs4232-objs := cs4232.o snd-cs4236-objs := cs4236.o # Toplevel Module Dependency -obj-$(CONFIG_SND_AZT2320) += snd-cs4231-lib.o -obj-$(CONFIG_SND_MIRO) += snd-cs4231-lib.o -obj-$(CONFIG_SND_OPL3SA2) += snd-cs4231-lib.o -obj-$(CONFIG_SND_CS4231) += snd-cs4231.o snd-cs4231-lib.o -obj-$(CONFIG_SND_CS4232) += snd-cs4232.o snd-cs4231-lib.o -obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o snd-cs4231-lib.o -obj-$(CONFIG_SND_GUSMAX) += snd-cs4231-lib.o -obj-$(CONFIG_SND_INTERWAVE) += snd-cs4231-lib.o -obj-$(CONFIG_SND_INTERWAVE_STB) += snd-cs4231-lib.o -obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-cs4231-lib.o -obj-$(CONFIG_SND_WAVEFRONT) += snd-cs4231-lib.o -obj-$(CONFIG_SND_SSCAPE) += snd-cs4231-lib.o +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 -obj-m := $(sort $(obj-m)) diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 914d77b..e73554f 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -74,7 +74,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; @@ -134,29 +134,31 @@ static inline u8 cs4231_inb(struct snd_c return inb(chip->port + offset); } -static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, - unsigned char mask, unsigned char value) +static void snd_cs4231_wait(struct snd_cs4231 *chip) { int timeout; - unsigned char tmp; 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 - if (chip->calibrate_mute) { - chip->image[reg] &= mask; - chip->image[reg] |= value; - } else { + chip->image[reg] = tmp; + if (!chip->calibrate_mute) { cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - mb(); - tmp = (chip->image[reg] & mask) | value; + wmb(); cs4231_outb(chip, CS4231P(REG), tmp); - chip->image[reg] = tmp; mb(); } } @@ -176,12 +178,7 @@ static void snd_cs4231_dout(struct snd_c void snd_cs4231_out(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(100); + 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); @@ -190,19 +187,13 @@ #endif cs4231_outb(chip, CS4231P(REG), value); chip->image[reg] = value; mb(); -#if 0 - printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); -#endif + 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) { - int timeout; - - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + 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); @@ -304,8 +295,7 @@ void snd_cs4231_mce_up(struct snd_cs4231 unsigned long flags; int timeout; - for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) - udelay(100); + 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"); @@ -326,9 +316,7 @@ void snd_cs4231_mce_down(struct snd_cs42 int timeout; snd_cs4231_busy_wait(chip); -#if 0 - printk("(1) timeout = %i\n", timeout); -#endif + #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)); @@ -346,42 +334,42 @@ #endif } snd_cs4231_busy_wait(chip); - /* calibration process */ + /* + * 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); - for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) - udelay(10); - if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { - snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); - return; - } -#if 0 - printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); -#endif - /* in 10 ms increments, check condition, up to 250 ms */ - timeout = 25; - while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { - if (--timeout < 0) { - snd_printk("mce_down - auto calibration time out (2)\n"); + snd_printdd("(1) jiffies = %lu\n", jiffies); + + /* check condition up to 250 ms */ + timeout = msecs_to_jiffies(250); + while (snd_cs4231_in(chip, CS4231_TEST_INIT) & + CS4231_CALIB_IN_PROGRESS) { + + if (timeout <= 0) { + snd_printk(KERN_ERR "mce_down - " + "auto calibration time out (2)\n"); return; } - msleep(10); + timeout = schedule_timeout(timeout); } -#if 0 - printk("(3) jiffies = %li\n", jiffies); -#endif - /* in 10 ms increments, check condition, up to 100 ms */ - timeout = 10; + + snd_printdd("(2) jiffies = %lu\n", jiffies); + + /* check condition up to 100 ms */ + timeout = msecs_to_jiffies(100); while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { - if (--timeout < 0) { + if (timeout <= 0) { snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); return; } - msleep(10); + timeout = schedule_timeout(timeout); } -#if 0 - printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); -#endif + + 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) @@ -459,11 +447,11 @@ static unsigned char snd_cs4231_get_rate { int i; - for (i = 0; i < 14; i++) + for (i = 0; i < ARRAY_SIZE(rates); i++) if (rate == rates[i]) return freq_bits[i]; // snd_BUG(); - return freq_bits[13]; + return freq_bits[ARRAY_SIZE(rates) - 1]; } static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, @@ -555,6 +543,8 @@ static void snd_cs4231_playback_format(s 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); diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index f7732bf..4a7367a 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1071,14 +1071,7 @@ static int snd_es18xx_put_mux(struct snd return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal; } -static int snd_es18xx_info_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es18xx_info_spatializer_enable snd_ctl_boolean_mono_info static int snd_es18xx_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1120,14 +1113,7 @@ static int snd_es18xx_get_hw_volume(stru return 0; } -static int snd_es18xx_info_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es18xx_info_hw_switch snd_ctl_boolean_stereo_info static int snd_es18xx_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2042,6 +2028,7 @@ static int pnpc_registered; static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { { .id = "ESS1869" }, + { .id = "ESS1879" }, { .id = "" } /* end */ }; diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index acc25a2..7f6aefd 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c @@ -36,14 +36,7 @@ #define GF1_SINGLE(xname, xindex, shift, .get = snd_gf1_get_single, .put = snd_gf1_put_single, \ .private_value = shift | (invert << 8) } -static int snd_gf1_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_gf1_info_single snd_ctl_boolean_mono_info static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index e70db32..244a002 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -253,6 +253,7 @@ static int __devinit snd_opl3sa2_detect( /* 0x03 - YM715B */ /* 0x04 - YM719 - OPL-SA4? */ /* 0x05 - OPL3-SA3 - Libretto 100 */ + /* 0x07 - unknown - Neomagic MagicWave 3D */ break; } str[0] = chip->version + '0'; diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index cd29b30..d295936 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -242,14 +242,7 @@ static int aci_setvalue(struct snd_miro * MIXER part */ -static int snd_miro_info_capture(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - - return 0; -} +#define snd_miro_info_capture snd_ctl_boolean_mono_info static int snd_miro_get_capture(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -344,14 +337,7 @@ static int snd_miro_put_preamp(struct sn return change; } -static int snd_miro_info_amp(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - - return 0; -} +#define snd_miro_info_amp snd_ctl_boolean_mono_info static int snd_miro_get_amp(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 049d479..fb1d070 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -1732,11 +1732,11 @@ #endif #ifdef OPTi93X port = pnp_port_start(pdev, 0) - 4; - fm_port = pnp_port_start(pdev, 1); + fm_port = pnp_port_start(pdev, 1) + 8; #else if (pid->driver_data != 0x0924) port = pnp_port_start(pdev, 1); - fm_port = pnp_port_start(pdev, 2); + fm_port = pnp_port_start(pdev, 2) + 8; #endif /* OPTi93X */ irq = pnp_irq(pdev, 0); dma1 = pnp_dma(pdev, 0); diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index b279f23..3682059 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -979,14 +979,7 @@ static int snd_sb_csp_restart(struct snd * QSound mixer control for PCM */ -static int snd_sb_qsound_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_sb_qsound_switch_info snd_ctl_boolean_mono_info static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index efa9d5c..37470c3 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -234,7 +234,9 @@ int snd_sbdsp_create(struct snd_card *ca chip->dma16 = -1; chip->port = port; - if (request_irq(irq, irq_handler, hardware == SB_HW_ALS4000 ? + if (request_irq(irq, irq_handler, + (hardware == SB_HW_ALS4000 || + hardware == SB_HW_CS5530) ? IRQF_SHARED : IRQF_DISABLED, "SoundBlaster", (void *) chip)) { snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq); diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c new file mode 100644 index 0000000..94daf83 --- /dev/null +++ b/sound/isa/sc6000.c @@ -0,0 +1,656 @@ +/* + * Driver for Gallant SC-6000 soundcard. This card is also known as + * Audio Excel DSP 16 or Zoltrix AV302. + * These cards use CompuMedia ASC-9308 chip + AD1848 codec. + * + * Copyright (C) 2007 Krzysztof Helt + * + * I don't have documentation for this card. I used the driver + * for OSS/Free included in the kernel source as reference. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SNDRV_LEGACY_FIND_FREE_IRQ +#define SNDRV_LEGACY_FIND_FREE_DMA +#include + +MODULE_AUTHOR("Krzysztof Helt"); +MODULE_DESCRIPTION("Gallant SC-6000"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Gallant, SC-6000}," + "{AudioExcel, Audio Excel DSP 16}," + "{Zoltrix, AV302}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220, 0x240 */ +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 11 */ +static long mss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530, 0xe80 */ +static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; + /* 0x300, 0x310, 0x320, 0x330 */ +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */ +static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */ + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for sc-6000 based soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable sc-6000 based soundcard."); +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for sc-6000 driver."); +module_param_array(mss_port, long, NULL, 0444); +MODULE_PARM_DESC(mss_port, "MSS Port # for sc-6000 driver."); +module_param_array(mpu_port, long, NULL, 0444); +MODULE_PARM_DESC(mpu_port, "MPU-401 port # for sc-6000 driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for sc-6000 driver."); +module_param_array(mpu_irq, int, NULL, 0444); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); +module_param_array(dma, int, NULL, 0444); +MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); + +/* + * Commands of SC6000's DSP (SBPRO+special). + * Some of them are COMMAND_xx, in the future they may change. + */ +#define WRITE_MDIRQ_CFG 0x50 /* Set M&I&DRQ mask (the real config) */ +#define COMMAND_52 0x52 /* */ +#define READ_HARD_CFG 0x58 /* Read Hardware Config (I/O base etc) */ +#define COMMAND_5C 0x5c /* */ +#define COMMAND_60 0x60 /* */ +#define COMMAND_66 0x66 /* */ +#define COMMAND_6C 0x6c /* */ +#define COMMAND_6E 0x6e /* */ +#define COMMAND_88 0x88 /* Unknown command */ +#define DSP_INIT_MSS 0x8c /* Enable Microsoft Sound System mode */ +#define COMMAND_C5 0xc5 /* */ +#define GET_DSP_VERSION 0xe1 /* Get DSP Version */ +#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright */ + +/* + * Offsets of SC6000 DSP I/O ports. The offset is added to base I/O port + * to have the actual I/O port. + * Register permissions are: + * (wo) == Write Only + * (ro) == Read Only + * (w-) == Write + * (r-) == Read + */ +#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ +#define DSP_READ 0x0a /* offset of DSP READ (ro) */ +#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ +#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ +#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ +#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ + +#define PFX "sc6000: " +#define DRV_NAME "SC-6000" + +/* hardware dependent functions */ + +/* + * sc6000_irq_to_softcfg - Decode irq number into cfg code. + */ +static __devinit unsigned char sc6000_irq_to_softcfg(int irq) +{ + unsigned char val = 0; + + switch (irq) { + case 5: + val = 0x28; + break; + case 7: + val = 0x8; + break; + case 9: + val = 0x10; + break; + case 10: + val = 0x18; + break; + case 11: + val = 0x20; + break; + default: + break; + } + return val; +} + +/* + * sc6000_dma_to_softcfg - Decode dma number into cfg code. + */ +static __devinit unsigned char sc6000_dma_to_softcfg(int dma) +{ + unsigned char val = 0; + + switch (dma) { + case 0: + val = 1; + break; + case 1: + val = 2; + break; + case 3: + val = 3; + break; + default: + break; + } + return val; +} + +/* + * sc6000_mpu_irq_to_softcfg - Decode MPU-401 irq number into cfg code. + */ +static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) +{ + unsigned char val = 0; + + switch (mpu_irq) { + case 5: + val = 4; + break; + case 7: + val = 0x44; + break; + case 9: + val = 0x84; + break; + case 10: + val = 0xc4; + break; + default: + break; + } + return val; +} + +static __devinit int sc6000_wait_data(char __iomem *vport) +{ + int loop = 1000; + unsigned char val = 0; + + do { + val = ioread8(vport + DSP_DATAVAIL); + if (val & 0x80) + return 0; + cpu_relax(); + } while (loop--); + + return -EAGAIN; +} + +static __devinit int sc6000_read(char __iomem *vport) +{ + if (sc6000_wait_data(vport)) + return -EBUSY; + + return ioread8(vport + DSP_READ); + +} + +static __devinit int sc6000_write(char __iomem *vport, int cmd) +{ + unsigned char val; + int loop = 500000; + + do { + val = ioread8(vport + DSP_STATUS); + /* + * DSP ready to receive data if bit 7 of val == 0 + */ + if (!(val & 0x80)) { + iowrite8(cmd, vport + DSP_COMMAND); + return 0; + } + cpu_relax(); + } while (loop--); + + snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); + + return -EIO; +} + +static int __devinit sc6000_dsp_get_answer(char __iomem *vport, int command, + char *data, int data_len) +{ + int len = 0; + + if (sc6000_write(vport, command)) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); + return -EIO; + } + + do { + int val = sc6000_read(vport); + + if (val < 0) + break; + + data[len++] = val; + + } while (len < data_len); + + /* + * If no more data available, return to the caller, no error if len>0. + * We have no other way to know when the string is finished. + */ + return len ? len : -EIO; +} + +static int __devinit sc6000_dsp_reset(char __iomem *vport) +{ + iowrite8(1, vport + DSP_RESET); + udelay(10); + iowrite8(0, vport + DSP_RESET); + udelay(20); + if (sc6000_read(vport) == 0xaa) + return 0; + return -ENODEV; +} + +/* detection and initialization */ +static int __devinit sc6000_cfg_write(char __iomem *vport, + unsigned char softcfg) +{ + + if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); + return -EIO; + } + if (sc6000_write(vport, softcfg)) { + snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); + return -EIO; + } + return 0; +} + +static int __devinit sc6000_setup_board(char __iomem *vport, int config) +{ + int loop = 10; + + do { + if (sc6000_write(vport, COMMAND_88)) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", + COMMAND_88); + return -EIO; + } + } while ((sc6000_wait_data(vport) < 0) && loop--); + + if (sc6000_read(vport) < 0) { + snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", + COMMAND_88); + return -EIO; + } + + if (sc6000_cfg_write(vport, config)) + return -ENODEV; + + return 0; +} + +static int __devinit sc6000_init_mss(char __iomem *vport, int config, + char __iomem *vmss_port, int mss_config) +{ + if (sc6000_write(vport, DSP_INIT_MSS)) { + snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", + DSP_INIT_MSS); + return -EIO; + } + + msleep(10); + + if (sc6000_cfg_write(vport, config)) + return -EIO; + + iowrite8(mss_config, vmss_port); + + return 0; +} + +static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, + char __iomem *vmss_port, int mpu_irq) +{ + char answer[15]; + char version[2]; + int mss_config = sc6000_irq_to_softcfg(irq) | + sc6000_dma_to_softcfg(dma); + int config = mss_config | + sc6000_mpu_irq_to_softcfg(mpu_irq); + int err; + + err = sc6000_dsp_reset(vport); + if (err < 0) { + snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); + err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); + if (err <= 0) { + snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; + } + /* + * My SC-6000 card return "SC-6000" in DSPCopyright, so + * if we have something different, we have to be warned. + * Mine returns "SC-6000A " - KH + */ + if (strncmp("SC-6000", answer, 7)) + snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); + + if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { + snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + + /* + * 0x0A == (IRQ 7, DMA 1, MIRQ 0) + */ + err = sc6000_cfg_write(vport, 0x0a); + if (err < 0) { + snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); + return -EFAULT; + } + + err = sc6000_setup_board(vport, config); + if (err < 0) { + snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + err = sc6000_init_mss(vport, config, vmss_port, mss_config); + if (err < 0) { + snd_printk(KERN_ERR "Can not initialize" + "Microsoft Sound System mode.\n"); + return -ENODEV; + } + + return 0; +} + +static int __devinit snd_sc6000_mixer(struct snd_ad1848 *chip) +{ + struct snd_card *card = chip->card; + struct snd_ctl_elem_id id1, id2; + int err; + + memset(&id1, 0, sizeof(id1)); + memset(&id2, 0, sizeof(id2)); + id1.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + /* reassign AUX0 to FM */ + strcpy(id1.name, "Aux Playback Switch"); + strcpy(id2.name, "FM Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + strcpy(id1.name, "Aux Playback Volume"); + strcpy(id2.name, "FM Playback Volume"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + /* reassign AUX1 to CD */ + strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strcpy(id2.name, "CD Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + strcpy(id1.name, "Aux Playback Volume"); + strcpy(id2.name, "CD Playback Volume"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + return 0; +} + +static int __devinit snd_sc6000_match(struct device *devptr, unsigned int dev) +{ + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { + printk(KERN_ERR PFX "specify IO port\n"); + return 0; + } + if (mss_port[dev] == SNDRV_AUTO_PORT) { + printk(KERN_ERR PFX "specify MSS port\n"); + return 0; + } + if (port[dev] != 0x220 && port[dev] != 0x240) { + printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); + return 0; + } + if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { + printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); + return 0; + } + if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { + printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); + return 0; + } + if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { + printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x30L) != 0x300) { + printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", + mpu_port[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && + !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { + printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); + return 0; + } + return 1; +} + +static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) +{ + static int possible_irqs[] = { 5, 7, 9, 10, 11, -1 }; + static int possible_dmas[] = { 1, 3, 0, -1 }; + int err; + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; + struct snd_ad1848 *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (!card) + return -ENOMEM; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto err_exit; + } + } + + if (xdma == SNDRV_AUTO_DMA) { + xdma = snd_legacy_find_free_dma(possible_dmas); + if (xdma < 0) { + snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); + err = -EBUSY; + goto err_exit; + } + } + + if (!request_region(port[dev], 0x10, DRV_NAME)) { + snd_printk(KERN_ERR PFX + "I/O port region is already in use.\n"); + err = -EBUSY; + goto err_exit; + } + vport = devm_ioport_map(devptr, port[dev], 0x10); + if (!vport) { + snd_printk(KERN_ERR PFX + "I/O port cannot be iomaped.\n"); + err = -EBUSY; + goto err_unmap1; + } + + /* to make it marked as used */ + if (!request_region(mss_port[dev], 4, DRV_NAME)) { + snd_printk(KERN_ERR PFX + "SC-6000 port I/O port region is already in use.\n"); + err = -EBUSY; + goto err_unmap1; + } + vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); + if (!vport) { + snd_printk(KERN_ERR PFX + "MSS port I/O cannot be iomaped.\n"); + err = -EBUSY; + goto err_unmap2; + } + + snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + + err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); + if (err < 0) + goto err_unmap2; + + err = snd_ad1848_create(card, mss_port[dev] + 4, xirq, xdma, + AD1848_HW_DETECT, &chip); + if (err < 0) + goto err_unmap2; + card->private_data = chip; + + err = snd_ad1848_pcm(chip, 0, NULL); + if (err < 0) { + snd_printk(KERN_ERR PFX + "error creating new ad1848 PCM device\n"); + goto err_unmap2; + } + err = snd_ad1848_mixer(chip); + if (err < 0) { + snd_printk(KERN_ERR PFX "error creating new ad1848 mixer\n"); + goto err_unmap2; + } + err = snd_sc6000_mixer(chip); + if (err < 0) { + snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); + goto err_unmap2; + } + if (snd_opl3_create(card, + 0x388, 0x388 + 2, + OPL3_HW_AUTO, 0, &opl3) < 0) { + snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", + 0x388, 0x388 + 2); + } else { + err = snd_opl3_timer_new(opl3, 0, 1); + if (err < 0) + goto err_unmap2; + + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto err_unmap2; + } + + if (mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; + if (snd_mpu401_uart_new(card, 0, + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], IRQF_DISABLED, + NULL) < 0) + snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", + mpu_port[dev]); + } + + strcpy(card->driver, DRV_NAME); + strcpy(card->shortname, "SC-6000"); + sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d", + mss_port[dev], xirq, xdma); + + snd_card_set_dev(card, devptr); + + err = snd_card_register(card); + if (err < 0) + goto err_unmap2; + + dev_set_drvdata(devptr, card); + return 0; + +err_unmap2: + release_region(mss_port[dev], 4); +err_unmap1: + release_region(port[dev], 0x10); +err_exit: + snd_card_free(card); + return err; +} + +static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) +{ + release_region(port[dev], 0x10); + release_region(mss_port[dev], 4); + + snd_card_free(dev_get_drvdata(devptr)); + dev_set_drvdata(devptr, NULL); + return 0; +} + +static struct isa_driver snd_sc6000_driver = { + .match = snd_sc6000_match, + .probe = snd_sc6000_probe, + .remove = __devexit_p(snd_sc6000_remove), + /* FIXME: suspend/resume */ + .driver = { + .name = DRV_NAME, + }, +}; + + +static int __init alsa_card_sc6000_init(void) +{ + return isa_register_driver(&snd_sc6000_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_sc6000_exit(void) +{ + isa_unregister_driver(&snd_sc6000_driver); +} + +module_init(alsa_card_sc6000_init) +module_exit(alsa_card_sc6000_exit) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index cbad2a5..1cb921d 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -45,10 +45,12 @@ MODULE_LICENSE("GPL"); static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX; static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR; -static long port[SNDRV_CARDS] __devinitdata = { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_PORT }; +static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); @@ -59,6 +61,9 @@ MODULE_PARM_DESC(id, "Description for So module_param_array(port, long, NULL, 0444); MODULE_PARM_DESC(port, "Port # for SoundScape driver."); +module_param_array(wss_port, long, NULL, 0444); +MODULE_PARM_DESC(wss_port, "WSS Port # for SoundScape driver."); + module_param_array(irq, int, NULL, 0444); MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver."); @@ -68,12 +73,16 @@ MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # module_param_array(dma, int, NULL, 0444); MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); +module_param_array(dma2, int, NULL, 0444); +MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver."); + #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; static struct pnp_card_device_id sscape_pnpids[] = { - { .id = "ENS3081", .devs = { { "ENS0000" } } }, + { .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */ + { .id = "ENS4081", .devs = { { "ENS1011" } } }, /* VIVO90 */ { .id = "" } /* end */ }; @@ -124,12 +133,21 @@ #define DMA_8BIT 0x80 #define AD1845_FREQ_SEL_MSB 0x16 #define AD1845_FREQ_SEL_LSB 0x17 +enum card_type { + SSCAPE, + SSCAPE_PNP, + SSCAPE_VIVO, +}; + struct soundscape { spinlock_t lock; unsigned io_base; + unsigned wss_base; int codec_type; int ic_type; + enum card_type type; struct resource *io_res; + struct resource *wss_res; struct snd_cs4231 *chip; struct snd_mpu401 *mpu; struct snd_hwdep *hw; @@ -340,8 +358,9 @@ static inline void activate_ad1845_unsaf */ static void soundscape_free(struct snd_card *c) { - register struct soundscape *sscape = get_card_soundscape(c); + struct soundscape *sscape = get_card_soundscape(c); release_and_free_resource(sscape->io_res); + release_and_free_resource(sscape->wss_res); free_dma(sscape->chip->dma1); } @@ -382,7 +401,7 @@ static int obp_startup_ack(struct sounds unsigned long flags; unsigned char x; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&s->lock, flags); x = inb(HOST_DATA_IO(s->io_base)); @@ -409,7 +428,7 @@ static int host_startup_ack(struct sound unsigned long flags; unsigned char x; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&s->lock, flags); x = inb(HOST_DATA_IO(s->io_base)); @@ -522,7 +541,7 @@ static int upload_dma_data(struct sounds ret = -EAGAIN; } - _release_dma: +_release_dma: /* * NOTE!!! We are NOT holding any spinlocks at this point !!! */ @@ -802,6 +821,7 @@ static int __devinit detect_sscape(struc unsigned long flags; unsigned d; int retval = 0; + int codec = s->wss_base; spin_lock_irqsave(&s->lock, flags); @@ -833,9 +853,27 @@ static int __devinit detect_sscape(struc outb(0xfe, ODIE_ADDR_IO(s->io_base)); if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e) goto _done; - if ((inb(ODIE_DATA_IO(s->io_base)) & 0x9f) != 0x0e) + + outb(0xfe, ODIE_ADDR_IO(s->io_base)); + d = inb(ODIE_DATA_IO(s->io_base)); + if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) goto _done; + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + + if (s->type == SSCAPE_VIVO) + codec += 4; + /* wait for WSS codec */ + for (d = 0; d < 500; d++) { + if ((inb(codec) & 0x80) == 0) + break; + spin_unlock_irqrestore(&s->lock, flags); + msleep(1); + spin_lock_irqsave(&s->lock, flags); + } + snd_printd(KERN_INFO "init delay = %d ms\n", d); + /* * SoundScape successfully detected! */ @@ -995,21 +1033,23 @@ static void ad1845_capture_format(struct * try to support at least some of the extra bits by overriding * some of the CS4231 callback. */ -static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1) +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; int err; -#define CS4231_SHARE_HARDWARE (CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2) - /* - * The AD1845 PCM device is only half-duplex, and so - * we only give it one DMA channel ... - */ - if ((err = snd_cs4231_create(card, - port, -1, irq, dma1, dma1, - CS4231_HW_DETECT, - CS4231_HWSHARE_DMA1, &chip)) == 0) { + if (sscape->type == SSCAPE_VIVO) + port += 4; + + if (dma1 == dma2) + dma2 = -1; + + err = snd_cs4231_create(card, + port, -1, irq, dma1, dma2, + CS4231_HW_DETECT, CS4231_HWSHARE_DMA1, &chip); + if (!err) { unsigned long flags; struct snd_pcm *pcm; @@ -1031,49 +1071,72 @@ #define AD1845_IFACE_CONFIG \ snd_cs4231_mce_down(chip); */ - /* - * The input clock frequency on the SoundScape must - * be 14.31818 MHz, because we must set this register - * to get the playback to sound correct ... - */ - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); + if (sscape->type != SSCAPE_VIVO) { + int val; + /* + * The input clock frequency on the SoundScape must + * be 14.31818 MHz, because we must set this register + * to get the playback to sound correct ... + */ + snd_cs4231_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_cs4231_mce_down(chip); - /* - * More custom configuration: - * a) select "mode 2", and provide a current drive of 8 mA - * b) enable frequency selection (for capture/playback) - */ - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_MISC_INFO, (CS4231_MODE2 | 0x10)); - snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL) | AD1845_FREQ_SEL_ENABLE); - spin_unlock_irqrestore(&chip->reg_lock, flags); + /* + * More custom configuration: + * a) select "mode 2" and provide a current drive of 8mA + * 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); + spin_unlock_irqrestore(&chip->reg_lock, flags); + } - if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) { - snd_printk(KERN_ERR "sscape: No PCM device for AD1845 chip\n"); + err = snd_cs4231_pcm(chip, 0, &pcm); + if (err < 0) { + snd_printk(KERN_ERR "sscape: No PCM device " + "for AD1845 chip\n"); goto _error; } - if ((err = snd_cs4231_mixer(chip)) < 0) { - snd_printk(KERN_ERR "sscape: No mixer device for AD1845 chip\n"); + err = snd_cs4231_mixer(chip); + if (err < 0) { + snd_printk(KERN_ERR "sscape: No mixer device " + "for AD1845 chip\n"); goto _error; } - - if ((err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip))) < 0) { - snd_printk(KERN_ERR "sscape: Could not create MIDI mixer control\n"); + err = snd_cs4231_timer(chip, 0, NULL); + if (err < 0) { + snd_printk(KERN_ERR "sscape: No timer device " + "for AD1845 chip\n"); goto _error; } + if (sscape->type != SSCAPE_VIVO) { + err = snd_ctl_add(card, + snd_ctl_new1(&midi_mixer_ctl, chip)); + if (err < 0) { + snd_printk(KERN_ERR "sscape: Could not create " + "MIDI mixer control\n"); + goto _error; + } + chip->set_playback_format = ad1845_playback_format; + chip->set_capture_format = ad1845_capture_format; + } + strcpy(card->driver, "SoundScape"); strcpy(card->shortname, pcm->name); snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, IRQ %d, DMA %d\n", - pcm->name, chip->port, chip->irq, chip->dma1); - chip->set_playback_format = ad1845_playback_format; - chip->set_capture_format = ad1845_capture_format; + "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", + pcm->name, chip->port, chip->irq, + chip->dma1, chip->dma2); + sscape->chip = chip; } @@ -1086,15 +1149,15 @@ #define AD1845_IFACE_CONFIG \ * Create an ALSA soundcard entry for the SoundScape, using * the given list of port, IRQ and DMA resources. */ -static int __devinit create_sscape(int dev, struct snd_card **rcardp) +static int __devinit create_sscape(int dev, struct snd_card *card) { - struct snd_card *card; - register struct soundscape *sscape; - register unsigned dma_cfg; + struct soundscape *sscape = get_card_soundscape(card); + unsigned dma_cfg; unsigned irq_cfg; unsigned mpu_irq_cfg; unsigned xport; struct resource *io_res; + struct resource *wss_res; unsigned long flags; int err; @@ -1118,61 +1181,69 @@ static int __devinit create_sscape(int d * Grab IO ports that we will need to probe so that we * can detect and control this hardware ... */ - if ((io_res = request_region(xport, 8, "SoundScape")) == NULL) { + io_res = request_region(xport, 8, "SoundScape"); + if (!io_res) { snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport); return -EBUSY; } + wss_res = NULL; + if (sscape->type == SSCAPE_VIVO) { + wss_res = request_region(wss_port[dev], 4, "SoundScape"); + if (!wss_res) { + snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n", + wss_port[dev]); + err = -EBUSY; + goto _release_region; + } + } /* - * Grab both DMA channels (OK, only one for now) ... + * Grab one DMA channel ... */ - if ((err = request_dma(dma[dev], "SoundScape")) < 0) { + err = request_dma(dma[dev], "SoundScape"); + if (err < 0) { snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]); goto _release_region; } - /* - * Create a new ALSA sound card entry, in anticipation - * of detecting our hardware ... - */ - if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE, - sizeof(struct soundscape))) == NULL) { - err = -ENOMEM; - goto _release_dma; - } - - sscape = get_card_soundscape(card); spin_lock_init(&sscape->lock); spin_lock_init(&sscape->fwlock); sscape->io_res = io_res; + sscape->wss_res = wss_res; sscape->io_base = xport; + sscape->wss_base = wss_port[dev]; if (!detect_sscape(sscape)) { printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base); err = -ENODEV; - goto _release_card; + goto _release_dma; } printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n", - sscape->io_base, irq[dev], dma[dev]); + sscape->io_base, irq[dev], dma[dev]); - /* - * Now create the hardware-specific device so that we can - * load the microcode into the on-board processor. - * We cannot use the MPU-401 MIDI system until this firmware - * has been loaded into the card. - */ - if ((err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw))) < 0) { - printk(KERN_ERR "sscape: Failed to create firmware device\n"); - goto _release_card; + if (sscape->type != SSCAPE_VIVO) { + /* + * Now create the hardware-specific device so that we can + * load the microcode into the on-board processor. + * We cannot use the MPU-401 MIDI system until this firmware + * has been loaded into the card. + */ + err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw)); + if (err < 0) { + printk(KERN_ERR "sscape: Failed to create " + "firmware device\n"); + goto _release_dma; + } + strlcpy(sscape->hw->name, "SoundScape M68K", + sizeof(sscape->hw->name)); + sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; + sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; + sscape->hw->ops.open = sscape_hw_open; + sscape->hw->ops.release = sscape_hw_release; + sscape->hw->ops.ioctl = sscape_hw_ioctl; + sscape->hw->private_data = sscape; } - strlcpy(sscape->hw->name, "SoundScape M68K", sizeof(sscape->hw->name)); - sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; - sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; - sscape->hw->ops.open = sscape_hw_open; - sscape->hw->ops.release = sscape_hw_release; - sscape->hw->ops.ioctl = sscape_hw_ioctl; - sscape->hw->private_data = sscape; /* * Tell the on-board devices where their resources are (I think - @@ -1197,7 +1268,8 @@ static int __devinit create_sscape(int d sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); sscape_write_unsafe(sscape->io_base, - GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); + GA_CDCFG_REG, 0x09 | DMA_8BIT + | (dma[dev] << 4) | (irq_cfg << 1)); spin_unlock_irqrestore(&sscape->lock, flags); @@ -1205,30 +1277,37 @@ static int __devinit create_sscape(int d * We have now enabled the codec chip, and so we should * detect the AD1845 device ... */ - if ((err = create_ad1845(card, CODEC_IO(xport), irq[dev], dma[dev])) < 0) { - printk(KERN_ERR "sscape: No AD1845 device at 0x%x, IRQ %d\n", - CODEC_IO(xport), irq[dev]); - goto _release_card; + err = create_ad1845(card, wss_port[dev], irq[dev], + dma[dev], dma2[dev]); + if (err < 0) { + printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n", + wss_port[dev], irq[dev]); + goto _release_dma; } #define MIDI_DEVNUM 0 - if ((err = create_mpu401(card, MIDI_DEVNUM, MPU401_IO(xport), mpu_irq[dev])) < 0) { - printk(KERN_ERR "sscape: Failed to create MPU-401 device at 0x%x\n", - MPU401_IO(xport)); - goto _release_card; - } + if (sscape->type != SSCAPE_VIVO) { + err = create_mpu401(card, MIDI_DEVNUM, + MPU401_IO(xport), mpu_irq[dev]); + if (err < 0) { + printk(KERN_ERR "sscape: Failed to create " + "MPU-401 device at 0x%x\n", + MPU401_IO(xport)); + goto _release_dma; + } - /* - * Enable the master IRQ ... - */ - sscape_write(sscape, GA_INTENA_REG, 0x80); + /* + * Enable the master IRQ ... + */ + sscape_write(sscape, GA_INTENA_REG, 0x80); - /* - * Initialize mixer - */ - sscape->midi_vol = 0; - host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); - host_write_ctrl_unsafe(sscape->io_base, 0, 100); - host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + /* + * Initialize mixer + */ + sscape->midi_vol = 0; + host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, 0, 100); + host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + } /* * Now that we have successfully created this sound card, @@ -1237,17 +1316,14 @@ #define MIDI_DEVNUM 0 * function now that our "constructor" has completed. */ card->private_free = soundscape_free; - *rcardp = card; return 0; - _release_card: - snd_card_free(card); - - _release_dma: +_release_dma: free_dma(dma[dev]); - _release_region: +_release_region: + release_and_free_resource(wss_res); release_and_free_resource(io_res); return err; @@ -1276,19 +1352,33 @@ static int __devinit snd_sscape_match(st static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) { struct snd_card *card; + struct soundscape *sscape; int ret; + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(struct soundscape)); + if (!card) + return -ENOMEM; + + sscape = get_card_soundscape(card); + sscape->type = SSCAPE; + dma[dev] &= 0x03; - ret = create_sscape(dev, &card); + ret = create_sscape(dev, card); if (ret < 0) - return ret; + goto _release_card; + snd_card_set_dev(card, pdev); if ((ret = snd_card_register(card)) < 0) { printk(KERN_ERR "sscape: Failed to register sound card\n"); - return ret; + goto _release_card; } dev_set_drvdata(pdev, card); return 0; + +_release_card: + snd_card_free(card); + return ret; } static int __devexit snd_sscape_remove(struct device *devptr, unsigned int dev) @@ -1325,6 +1415,7 @@ static int __devinit sscape_pnp_detect(s static int idx = 0; struct pnp_dev *dev; struct snd_card *card; + struct soundscape *sscape; int ret; /* @@ -1366,26 +1457,55 @@ static int __devinit sscape_pnp_detect(s } /* + * Create a new ALSA sound card entry, in anticipation + * of detecting our hardware ... + */ + card = snd_card_new(index[idx], id[idx], THIS_MODULE, + sizeof(struct soundscape)); + if (!card) + return -ENOMEM; + + sscape = get_card_soundscape(card); + + /* + * Identify card model ... + */ + if (!strncmp("ENS4081", pid->id, 7)) + sscape->type = SSCAPE_VIVO; + else + sscape->type = SSCAPE_PNP; + + /* * Read the correct parameters off the ISA PnP bus ... */ port[idx] = pnp_port_start(dev, 0); irq[idx] = pnp_irq(dev, 0); mpu_irq[idx] = pnp_irq(dev, 1); dma[idx] = pnp_dma(dev, 0) & 0x03; + if (sscape->type == SSCAPE_PNP) { + dma2[idx] = dma[idx]; + wss_port[idx] = CODEC_IO(port[idx]); + } else { + wss_port[idx] = pnp_port_start(dev, 1); + dma2[idx] = pnp_dma(dev, 1); + } - ret = create_sscape(idx, &card); + ret = create_sscape(idx, card); if (ret < 0) - return ret; + goto _release_card; + snd_card_set_dev(card, &pcard->card->dev); if ((ret = snd_card_register(card)) < 0) { printk(KERN_ERR "sscape: Failed to register sound card\n"); - snd_card_free(card); - return ret; + goto _release_card; } pnp_set_card_drvdata(pcard, card); ++idx; + return 0; +_release_card: + snd_card_free(card); return ret; } diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index bacc51c..a1ebb7c 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -27,6 +27,7 @@ #include #include #include #include +#include #include #include #include @@ -53,9 +54,8 @@ static int debug_default = 0; /* you ca /* XXX this needs to be made firmware and hardware version dependent */ -static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed - version of the WaveFront OS - */ +#define DEFAULT_OSPATH "wavefront.os" +static char *ospath = DEFAULT_OSPATH; /* the firmware file name */ static int wait_usecs = 150; /* This magic number seems to give pretty optimal throughput based on my limited experimentation. @@ -97,7 +97,7 @@ MODULE_PARM_DESC(sleep_interval, "how lo module_param(sleep_tries, int, 0444); MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait"); module_param(ospath, charp, 0444); -MODULE_PARM_DESC(ospath, "full pathname to processed ICS2115 OS firmware"); +MODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware"); module_param(reset_time, int, 0444); MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect"); module_param(ramcheck_time, int, 0444); @@ -1768,7 +1768,7 @@ snd_wavefront_interrupt_bits (int irq) static void __devinit wavefront_should_cause_interrupt (snd_wavefront_t *dev, - int val, int port, int timeout) + int val, int port, unsigned long timeout) { wait_queue_t wait; @@ -1779,11 +1779,9 @@ wavefront_should_cause_interrupt (snd_wa dev->irq_ok = 0; outb (val,port); spin_unlock_irq(&dev->irq_lock); - while (1) { - if ((timeout = schedule_timeout(timeout)) == 0) - return; - if (dev->irq_ok) - return; + while (!dev->irq_ok && time_before(jiffies, timeout)) { + schedule_timeout_uninterruptible(1); + barrier(); } } @@ -1938,111 +1936,75 @@ wavefront_reset_to_cleanliness (snd_wave return (1); } -#include -#include -#include -#include -#include -#include - - static int __devinit wavefront_download_firmware (snd_wavefront_t *dev, char *path) { - unsigned char section[WF_SECTION_MAX]; - signed char section_length; /* yes, just a char; max value is WF_SECTION_MAX */ + unsigned char *buf; + int len, err; int section_cnt_downloaded = 0; - int fd; - int c; - int i; - mm_segment_t fs; - - /* This tries to be a bit cleverer than the stuff Alan Cox did for - the generic sound firmware, in that it actually knows - something about the structure of the Motorola firmware. In - particular, it uses a version that has been stripped of the - 20K of useless header information, and had section lengths - added, making it possible to load the entire OS without any - [kv]malloc() activity, since the longest entity we ever read is - 42 bytes (well, WF_SECTION_MAX) long. - */ - - fs = get_fs(); - set_fs (get_ds()); + const struct firmware *firmware; - if ((fd = sys_open ((char __user *) path, 0, 0)) < 0) { - snd_printk ("Unable to load \"%s\".\n", - path); + err = request_firmware(&firmware, path, dev->card->dev); + if (err < 0) { + snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path); return 1; } - while (1) { - int x; - - if ((x = sys_read (fd, (char __user *) §ion_length, sizeof (section_length))) != - sizeof (section_length)) { - snd_printk ("firmware read error.\n"); - goto failure; - } - - if (section_length == 0) { + len = 0; + buf = firmware->data; + for (;;) { + int section_length = *(signed char *)buf; + if (section_length == 0) break; - } - if (section_length < 0 || section_length > WF_SECTION_MAX) { - snd_printk ("invalid firmware section length %d\n", - section_length); + snd_printk(KERN_ERR + "invalid firmware section length %d\n", + section_length); goto failure; } + buf++; + len++; - if (sys_read (fd, (char __user *) section, section_length) != section_length) { - snd_printk ("firmware section " - "read error.\n"); + if (firmware->size < len + section_length) { + snd_printk(KERN_ERR "firmware section read error.\n"); goto failure; } /* Send command */ - - if (wavefront_write (dev, WFC_DOWNLOAD_OS)) { + if (wavefront_write(dev, WFC_DOWNLOAD_OS)) goto failure; - } - for (i = 0; i < section_length; i++) { - if (wavefront_write (dev, section[i])) { + for (; section_length; section_length--) { + if (wavefront_write(dev, *buf)) goto failure; - } + buf++; + len++; } /* get ACK */ - - if (wavefront_wait (dev, STAT_CAN_READ)) { - - if ((c = inb (dev->data_port)) != WF_ACK) { - - snd_printk ("download " - "of section #%d not " - "acknowledged, ack = 0x%x\n", - section_cnt_downloaded + 1, c); - goto failure; - - } - - } else { - snd_printk ("time out for firmware ACK.\n"); + if (!wavefront_wait(dev, STAT_CAN_READ)) { + snd_printk(KERN_ERR "time out for firmware ACK.\n"); + goto failure; + } + err = inb(dev->data_port); + if (err != WF_ACK) { + snd_printk(KERN_ERR + "download of section #%d not " + "acknowledged, ack = 0x%x\n", + section_cnt_downloaded + 1, err); goto failure; } + section_cnt_downloaded++; } - sys_close (fd); - set_fs (fs); + release_firmware(firmware); return 0; failure: - sys_close (fd); - set_fs (fs); - snd_printk ("firmware download failed!!!\n"); + release_firmware(firmware); + snd_printk(KERN_ERR "firmware download failed!!!\n"); return 1; } @@ -2232,3 +2194,5 @@ snd_wavefront_detect (snd_wavefront_card return 0; } + +MODULE_FIRMWARE(DEFAULT_OSPATH); diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index c6b4410..356bf21 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -170,14 +170,14 @@ config SND_CA0106 will be called snd-ca0106. config SND_CMIPCI - tristate "C-Media 8738, 8338" + tristate "C-Media 8338, 8738, 8768, 8770" depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM help - If you want to use soundcards based on C-Media CMI8338 or CMI8738 - chips, say Y here and read + If you want to use soundcards based on C-Media CMI8338, CMI8738, + CMI8768 or CMI8770 chips, say Y here and read . To compile this driver as a module, choose M here: the module @@ -500,6 +500,103 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. +config SND_HDA_HWDEP + bool "Build hwdep interface for HD-audio driver" + depends on SND_HDA_INTEL + select SND_HWDEP + help + Say Y here to build a hwdep interface for HD-audio driver. + This interface can be used for out-of-band communication + with codecs for debugging purposes. + +config SND_HDA_CODEC_REALTEK + bool "Build Realtek HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Realtek HD-audio codec support in + snd-hda-intel driver, such as ALC880. + +config SND_HDA_CODEC_ANALOG + bool "Build Analog Device HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Analog Device HD-audio codec support in + snd-hda-intel driver, such as AD1986A. + +config SND_HDA_CODEC_SIGMATEL + bool "Build IDT/Sigmatel HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include IDT (Sigmatel) HD-audio codec support in + snd-hda-intel driver, such as STAC9200. + +config SND_HDA_CODEC_VIA + bool "Build VIA HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include VIA HD-audio codec support in + snd-hda-intel driver, such as VT1708. + +config SND_HDA_CODEC_ATIHDMI + bool "Build ATI HDMI HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + 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_CONEXANT + bool "Build Conexant HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Conexant HD-audio codec support in + snd-hda-intel driver, such as CX20549. + +config SND_HDA_CODEC_CMEDIA + bool "Build C-Media HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include C-Media HD-audio codec support in + snd-hda-intel driver, such as CMI9880. + +config SND_HDA_CODEC_SI3054 + bool "Build Silicon Labs 3054 HD-modem codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Silicon Labs 3054 HD-modem codec + (and compatibles) support in snd-hda-intel driver. + +config SND_HDA_GENERIC + bool "Enable generic HD-audio codec parser" + depends on SND_HDA_INTEL + default y + help + Say Y here to enable the generic HD-audio codec parser + in snd-hda-intel driver. + +config SND_HDA_POWER_SAVE + bool "Aggressive power-saving on HD-audio" + depends on SND_HDA_INTEL && EXPERIMENTAL + help + Say Y here to enable more aggressive power-saving mode on + HD-audio driver. The power-saving timeout can be configured + via power_save option or over sysfs on-the-fly. + +config SND_HDA_POWER_SAVE_DEFAULT + int "Default time-out for HD-audio power-save mode" + depends on SND_HDA_POWER_SAVE + default 0 + help + The default time-out value in seconds for HD-audio automatic + power-save mode. 0 means to disable the power-save mode. + config SND_HDSP tristate "RME Hammerfall DSP Audio" depends on SND @@ -799,4 +896,12 @@ config SND_AC97_POWER_SAVE snd-ac97-codec driver. You can toggle it dynamically over sysfs, too. +config SND_AC97_POWER_SAVE_DEFAULT + int "Default time-out for AC97 power-save mode" + depends on SND_AC97_POWER_SAVE + default 0 + help + The default time-out value in seconds for AC97 automatic + power-save mode. 0 means to disable the power-save mode. + endmenu diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index bbed644..e13893d 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -49,7 +49,7 @@ module_param(enable_loopback, bool, 0444 MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); #ifdef CONFIG_SND_AC97_POWER_SAVE -static int power_save; +static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; module_param(power_save, bool, 0644); MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); #endif @@ -176,7 +176,7 @@ static const struct ac97_codec_id snd_ac { 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, { 0x574d4C12, 0xffffffff, "WM9711,WM9712", patch_wolfson11, NULL}, { 0x574d4c13, 0xffffffff, "WM9713,WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF}, -{ 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, +{ 0x594d4800, 0xffffffff, "YMF743", patch_yamaha_ymf743, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, { 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, { 0x83847600, 0xffffffff, "STAC9700,83,84", patch_sigmatel_stac9700, NULL }, @@ -779,6 +779,12 @@ static int snd_ac97_spdif_default_put(st change |= snd_ac97_update_bits_nolock(ac97, AC97_CXR_AUDIO_MISC, AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT, v); + } else if (ac97->id == AC97_ID_YMF743) { + change |= snd_ac97_update_bits_nolock(ac97, + AC97_YMF7X3_DIT_CTRL, + 0xff38, + ((val << 4) & 0xff00) | + ((val << 2) & 0x0038)); } else { unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS); snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */ @@ -1375,7 +1381,8 @@ static int snd_ac97_mixer_build(struct s for (idx = 0; idx < 2; idx++) { if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0) return err; - if (ac97->id == AC97_ID_YMF753) { + if (ac97->id == AC97_ID_YMF743 || + ac97->id == AC97_ID_YMF753) { kctl->private_value &= ~(0xff << 16); kctl->private_value |= 7 << 16; } @@ -2036,11 +2043,12 @@ #endif else { udelay(50); if (ac97->scaps & AC97_SCAP_SKIP_AUDIO) - err = ac97_reset_wait(ac97, HZ/2, 1); + err = ac97_reset_wait(ac97, msecs_to_jiffies(500), 1); else { - err = ac97_reset_wait(ac97, HZ/2, 0); + err = ac97_reset_wait(ac97, msecs_to_jiffies(500), 0); if (err < 0) - err = ac97_reset_wait(ac97, HZ/2, 1); + err = ac97_reset_wait(ac97, + msecs_to_jiffies(500), 1); } if (err < 0) { snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); @@ -2104,7 +2112,7 @@ #endif } /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); - end_time = jiffies + (HZ / 10); + end_time = jiffies + msecs_to_jiffies(100); do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; @@ -2136,7 +2144,7 @@ #endif udelay(100); /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); - end_time = jiffies + (HZ / 10); + end_time = jiffies + msecs_to_jiffies(100); do { if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) goto __ready_ok; @@ -2354,7 +2362,8 @@ int snd_ac97_update_power(struct snd_ac9 * (for avoiding loud click noises for many (OSS) apps * that open/close frequently) */ - schedule_delayed_work(&ac97->power_work, HZ*2); + schedule_delayed_work(&ac97->power_work, + msecs_to_jiffies(2000)); else { cancel_delayed_work(&ac97->power_work); update_power_regs(ac97); @@ -2436,7 +2445,7 @@ EXPORT_SYMBOL(snd_ac97_suspend); /* * restore ac97 status */ -void snd_ac97_restore_status(struct snd_ac97 *ac97) +static void snd_ac97_restore_status(struct snd_ac97 *ac97) { int i; @@ -2457,7 +2466,7 @@ void snd_ac97_restore_status(struct snd_ /* * restore IEC958 status */ -void snd_ac97_restore_iec958(struct snd_ac97 *ac97) +static void snd_ac97_restore_iec958(struct snd_ac97 *ac97) { if (ac97->ext_id & AC97_EI_SPDIF) { if (ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_SPDIF) { @@ -2494,7 +2503,10 @@ void snd_ac97_resume(struct snd_ac97 *ac snd_ac97_write(ac97, AC97_POWERDOWN, 0); if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) { - snd_ac97_write(ac97, AC97_RESET, 0); + if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) + snd_ac97_write(ac97, AC97_RESET, 0); + else if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) + snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); udelay(100); snd_ac97_write(ac97, AC97_POWERDOWN, 0); } diff --git a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h index 6d73514..0a7dadc 100644 --- a/sound/pci/ac97/ac97_id.h +++ b/sound/pci/ac97/ac97_id.h @@ -54,6 +54,7 @@ #define AC97_ID_ALC655 0x414c4760 #define AC97_ID_ALC658 0x414c4780 #define AC97_ID_ALC658D 0x414c4781 #define AC97_ID_ALC850 0x414c4790 +#define AC97_ID_YMF743 0x594d4800 #define AC97_ID_YMF753 0x594d4803 #define AC97_ID_VT1616 0x49434551 #define AC97_ID_CM9738 0x434d4941 diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 581ebba..2e683dd 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -204,9 +204,13 @@ static inline int is_shared_micin(struct /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ +/* Modified for YMF743 by Keita Maehara */ -/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ -static int snd_ac97_ymf753_info_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +/* It is possible to indicate to the Yamaha YMF7x3 the type of + speakers being used. */ + +static int snd_ac97_ymf7x3_info_speaker(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { static char *texts[3] = { "Standard", "Small", "Smaller" @@ -221,12 +225,13 @@ static int snd_ac97_ymf753_info_speaker( return 0; } -static int snd_ac97_ymf753_get_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_get_speaker(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; + val = ac97->regs[AC97_YMF7X3_3D_MODE_SEL]; val = (val >> 10) & 3; if (val > 0) /* 0 = invalid */ val--; @@ -234,7 +239,8 @@ static int snd_ac97_ymf753_get_speaker(s return 0; } -static int snd_ac97_ymf753_put_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_put_speaker(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -242,20 +248,22 @@ static int snd_ac97_ymf753_put_speaker(s if (ucontrol->value.enumerated.item[0] > 2) return -EINVAL; val = (ucontrol->value.enumerated.item[0] + 1) << 10; - return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); + return snd_ac97_update(ac97, AC97_YMF7X3_3D_MODE_SEL, val); } -static const struct snd_kcontrol_new snd_ac97_ymf753_controls_speaker = +static const struct snd_kcontrol_new snd_ac97_ymf7x3_controls_speaker = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Speaker", - .info = snd_ac97_ymf753_info_speaker, - .get = snd_ac97_ymf753_get_speaker, - .put = snd_ac97_ymf753_put_speaker, + .info = snd_ac97_ymf7x3_info_speaker, + .get = snd_ac97_ymf7x3_get_speaker, + .put = snd_ac97_ymf7x3_put_speaker, }; -/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ -static int snd_ac97_ymf753_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +/* It is possible to indicate to the Yamaha YMF7x3 the source to + direct to the S/PDIF output. */ +static int snd_ac97_ymf7x3_spdif_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { static char *texts[2] = { "AC-Link", "A/D Converter" }; @@ -268,17 +276,19 @@ static int snd_ac97_ymf753_spdif_source_ return 0; } -static int snd_ac97_ymf753_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_spdif_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = ac97->regs[AC97_YMF753_DIT_CTRL2]; + val = ac97->regs[AC97_YMF7X3_DIT_CTRL]; ucontrol->value.enumerated.item[0] = (val >> 1) & 1; return 0; } -static int snd_ac97_ymf753_spdif_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_spdif_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -286,7 +296,75 @@ static int snd_ac97_ymf753_spdif_source_ if (ucontrol->value.enumerated.item[0] > 1) return -EINVAL; val = ucontrol->value.enumerated.item[0] << 1; - return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); + return snd_ac97_update_bits(ac97, AC97_YMF7X3_DIT_CTRL, 0x0002, val); +} + +static int patch_yamaha_ymf7x3_3d(struct snd_ac97 *ac97) +{ + struct snd_kcontrol *kctl; + int err; + + kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); + err = snd_ctl_add(ac97->bus->card, kctl); + if (err < 0) + return err; + strcpy(kctl->id.name, "3D Control - Wide"); + kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); + snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); + err = snd_ctl_add(ac97->bus->card, + snd_ac97_cnew(&snd_ac97_ymf7x3_controls_speaker, + ac97)); + if (err < 0) + return err; + snd_ac97_write_cache(ac97, AC97_YMF7X3_3D_MODE_SEL, 0x0c00); + return 0; +} + +static const struct snd_kcontrol_new snd_ac97_yamaha_ymf743_controls_spdif[3] = +{ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), + AC97_YMF7X3_DIT_CTRL, 0, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Source", + .info = snd_ac97_ymf7x3_spdif_source_info, + .get = snd_ac97_ymf7x3_spdif_source_get, + .put = snd_ac97_ymf7x3_spdif_source_put, + }, + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", NONE, NONE) "Mute", + AC97_YMF7X3_DIT_CTRL, 2, 1, 1) +}; + +static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97) +{ + int err; + + err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3); + if (err < 0) + return err; + err = patch_build_controls(ac97, + snd_ac97_yamaha_ymf743_controls_spdif, 3); + if (err < 0) + return err; + /* set default PCM S/PDIF params */ + /* PCM audio,no copyright,no preemphasis,PCM coder,original */ + snd_ac97_write_cache(ac97, AC97_YMF7X3_DIT_CTRL, 0xa201); + return 0; +} + +static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { + .build_spdif = patch_yamaha_ymf743_build_spdif, + .build_3d = patch_yamaha_ymf7x3_3d, +}; + +static int patch_yamaha_ymf743(struct snd_ac97 *ac97) +{ + ac97->build_ops = &patch_yamaha_ymf743_ops; + ac97->caps |= AC97_BC_BASS_TREBLE; + ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */ + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ + ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ + return 0; } /* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. @@ -311,7 +389,7 @@ static int snd_ac97_ymf753_spdif_output_ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = ac97->regs[AC97_YMF753_DIT_CTRL2]; + val = ac97->regs[AC97_YMF7X3_DIT_CTRL]; ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; return 0; } @@ -325,7 +403,7 @@ static int snd_ac97_ymf753_spdif_output_ return -EINVAL; val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; - return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); + return snd_ac97_update_bits(ac97, AC97_YMF7X3_DIT_CTRL, 0x0028, val); /* The following can be used to direct S/PDIF output to pin 47 (EAPD). snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ } @@ -334,9 +412,9 @@ static const struct snd_kcontrol_new snd { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_ymf753_spdif_source_info, - .get = snd_ac97_ymf753_spdif_source_get, - .put = snd_ac97_ymf753_spdif_source_put, + .info = snd_ac97_ymf7x3_spdif_source_info, + .get = snd_ac97_ymf7x3_spdif_source_get, + .put = snd_ac97_ymf7x3_spdif_source_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -345,25 +423,10 @@ static const struct snd_kcontrol_new snd .get = snd_ac97_ymf753_spdif_output_pin_get, .put = snd_ac97_ymf753_spdif_output_pin_put, }, - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", NONE, NONE) "Mute", + AC97_YMF7X3_DIT_CTRL, 2, 1, 1) }; -static int patch_yamaha_ymf753_3d(struct snd_ac97 * ac97) -{ - struct snd_kcontrol *kctl; - int err; - - if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) - return err; - strcpy(kctl->id.name, "3D Control - Wide"); - kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); - snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) - return err; - snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); - return 0; -} - static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) { int err; @@ -374,7 +437,7 @@ static int patch_yamaha_ymf753_post_spdi } static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { - .build_3d = patch_yamaha_ymf753_3d, + .build_3d = patch_yamaha_ymf7x3_3d, .build_post_spdif = patch_yamaha_ymf753_post_spdif }; @@ -1880,14 +1943,7 @@ static int patch_ad1981b(struct snd_ac97 return 0; } -static int snd_ac97_ad1888_lohpsel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ac97_ad1888_lohpsel_info snd_ctl_boolean_mono_info static int snd_ac97_ad1888_lohpsel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2186,15 +2242,7 @@ static int patch_ad1985(struct snd_ac97 return 0; } -static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ac97_ad1986_bool_info snd_ctl_boolean_mono_info static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index a3fdd7d..f547986 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -236,10 +236,14 @@ static void snd_ac97_proc_read_main(stru val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE); snd_iprintf(buffer, "PCM MIC ADC : %iHz\n", val); } - if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) { + if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF) || + (ac97->id == AC97_ID_YMF743)) { if (ac97->flags & AC97_CS_SPDIF) val = snd_ac97_read(ac97, AC97_CSR_SPDIF); - else + else if (ac97->id == AC97_ID_YMF743) { + val = snd_ac97_read(ac97, AC97_YMF7X3_DIT_CTRL); + val = 0x2000 | (val & 0xff00) >> 4 | (val & 0x38) >> 2; + } else val = snd_ac97_read(ac97, AC97_SPDIF); snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n", diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 05b4c86..4c2bd7a 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1804,15 +1804,7 @@ #define ALI5451_SPDIF(xname, xindex, val .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ .put = snd_ali5451_spdif_put, .private_value = value} -static int snd_ali5451_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ali5451_spdif_info snd_ctl_boolean_mono_info static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 5ec1b6f..f70286a 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -232,6 +232,7 @@ snd_vortex_create(struct snd_card *card, pci_disable_device(chip->pci_dev); //FIXME: this not the right place to unregister the gameport vortex_gameport_unregister(chip); + kfree(chip); return err; } diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 0c86a31..38602b8 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -728,15 +728,7 @@ static void vortex_Eqlzr_shutdown(vortex /* ALSA interface */ /* Control interface */ -static int -snd_vortex_eqtoggle_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_vortex_eqtoggle_info snd_ctl_boolean_mono_info static int snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index d3e662a..978b856 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -370,8 +370,8 @@ static void vortex_wt_SetFrequency(vorte while ((edx & 0x80000000) == 0) { edx <<= 1; eax--; - if (eax == 0) ; - break; + if (eax == 0) + break; } if (eax) edx <<= 1; diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 188c7cf..2d296eb 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -147,15 +147,56 @@ #define MY_INTERRUPTS (INT_RISCI | ERROR /* SYNC, one WRITE per line, one extra WRITE per page boundary, SYNC, JUMP */ #define MAX_RISC_SIZE ((1 + 255 + (PAGE_ALIGN(255 * 4092) / PAGE_SIZE - 1) + 1 + 1) * 8) +/* Cards with configuration information */ +enum snd_bt87x_boardid { + SND_BT87X_BOARD_UNKNOWN, + SND_BT87X_BOARD_GENERIC, /* both an & dig interfaces, 32kHz */ + SND_BT87X_BOARD_ANALOG, /* board with no external A/D */ + SND_BT87X_BOARD_OSPREY2x0, + SND_BT87X_BOARD_OSPREY440, + SND_BT87X_BOARD_AVPHONE98, +}; + +/* Card configuration */ +struct snd_bt87x_board { + int dig_rate; /* Digital input sampling rate */ + u32 digital_fmt; /* Register settings for digital input */ + unsigned no_analog:1; /* No analog input */ + unsigned no_digital:1; /* No digital input */ +}; + +static const __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = { + [SND_BT87X_BOARD_UNKNOWN] = { + .dig_rate = 32000, /* just a guess */ + }, + [SND_BT87X_BOARD_GENERIC] = { + .dig_rate = 32000, + }, + [SND_BT87X_BOARD_ANALOG] = { + .no_digital = 1, + }, + [SND_BT87X_BOARD_OSPREY2x0] = { + .dig_rate = 44100, + .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT), + }, + [SND_BT87X_BOARD_OSPREY440] = { + .dig_rate = 32000, + .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT), + .no_analog = 1, + }, + [SND_BT87X_BOARD_AVPHONE98] = { + .dig_rate = 48000, + }, +}; + struct snd_bt87x { struct snd_card *card; struct pci_dev *pci; + struct snd_bt87x_board board; void __iomem *mmio; int irq; - int dig_rate; - spinlock_t reg_lock; long opened; struct snd_pcm_substream *substream; @@ -340,30 +381,11 @@ static struct snd_pcm_hardware snd_bt87x static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime) { - static struct { - int rate; - unsigned int bit; - } ratebits[] = { - {8000, SNDRV_PCM_RATE_8000}, - {11025, SNDRV_PCM_RATE_11025}, - {16000, SNDRV_PCM_RATE_16000}, - {22050, SNDRV_PCM_RATE_22050}, - {32000, SNDRV_PCM_RATE_32000}, - {44100, SNDRV_PCM_RATE_44100}, - {48000, SNDRV_PCM_RATE_48000} - }; - int i; - - chip->reg_control |= CTL_DA_IOM_DA; + chip->reg_control |= CTL_DA_IOM_DA | CTL_A_PWRDN; runtime->hw = snd_bt87x_digital_hw; - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - for (i = 0; i < ARRAY_SIZE(ratebits); ++i) - if (chip->dig_rate == ratebits[i].rate) { - runtime->hw.rates = ratebits[i].bit; - break; - } - runtime->hw.rate_min = chip->dig_rate; - runtime->hw.rate_max = chip->dig_rate; + runtime->hw.rates = snd_pcm_rate_to_rate_bit(chip->board.dig_rate); + runtime->hw.rate_min = chip->board.dig_rate; + runtime->hw.rate_max = chip->board.dig_rate; return 0; } @@ -380,7 +402,7 @@ static int snd_bt87x_set_analog_hw(struc .rats = &analog_clock }; - chip->reg_control &= ~CTL_DA_IOM_DA; + chip->reg_control &= ~(CTL_DA_IOM_DA | CTL_A_PWRDN); runtime->hw = snd_bt87x_analog_hw; return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraint_rates); @@ -419,6 +441,11 @@ static int snd_bt87x_close(struct snd_pc { struct snd_bt87x *chip = snd_pcm_substream_chip(substream); + spin_lock_irq(&chip->reg_lock); + chip->reg_control |= CTL_A_PWRDN; + snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); + spin_unlock_irq(&chip->reg_lock); + chip->substream = NULL; clear_bit(0, &chip->opened); smp_mb__after_clear_bit(); @@ -569,15 +596,7 @@ static struct snd_kcontrol_new snd_bt87x .put = snd_bt87x_capture_volume_put, }; -static int snd_bt87x_capture_boost_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - info->count = 1; - info->value.integer.min = 0; - info->value.integer.max = 1; - return 0; -} +#define snd_bt87x_capture_boost_info snd_ctl_boolean_mono_info static int snd_bt87x_capture_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) @@ -736,61 +755,69 @@ static int __devinit snd_bt87x_create(st chip->mmio = ioremap_nocache(pci_resource_start(pci, 0), pci_resource_len(pci, 0)); if (!chip->mmio) { - snd_bt87x_free(chip); snd_printk(KERN_ERR "cannot remap io memory\n"); - return -ENOMEM; + err = -ENOMEM; + goto fail; } - chip->reg_control = CTL_DA_ES2 | CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); + chip->reg_control = CTL_A_PWRDN | CTL_DA_ES2 | + CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); chip->interrupt_mask = MY_INTERRUPTS; snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); snd_bt87x_writel(chip, REG_INT_MASK, 0); snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); - if (request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, - "Bt87x audio", chip)) { - snd_bt87x_free(chip); - snd_printk(KERN_ERR "cannot grab irq\n"); - return -EBUSY; + err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, + "Bt87x audio", chip); + if (err < 0) { + snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq); + goto fail; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) { - snd_bt87x_free(chip); - return err; - } + if (err < 0) + goto fail; + snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; + +fail: + snd_bt87x_free(chip); + return err; } -#define BT_DEVICE(chip, subvend, subdev, rate) \ +#define BT_DEVICE(chip, subvend, subdev, id) \ { .vendor = PCI_VENDOR_ID_BROOKTREE, \ .device = chip, \ .subvendor = subvend, .subdevice = subdev, \ - .driver_data = rate } + .driver_data = SND_BT87X_BOARD_ ## id } +/* driver_data is the card id for that device */ -/* driver_data is the default digital_rate value for that device */ static struct pci_device_id snd_bt87x_ids[] = { /* Hauppauge WinTV series */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), /* Hauppauge WinTV series */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, GENERIC), /* Viewcast Osprey 200 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, OSPREY2x0), /* Viewcast Osprey 440 (rate is configurable via gpio) */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, OSPREY440), /* ATI TV-Wonder */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC), /* Leadtek Winfast tv 2000xp delux */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), /* Voodoo TV 200 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), /* AVerMedia Studio No. 103, 203, ...? */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), + /* Prolink PixelView PV-M4900 */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1554, 0x4011, GENERIC), + /* Pinnacle Studio PCTV rave */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0xbd11, 0x1200, GENERIC), { } }; MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); @@ -815,7 +842,7 @@ static struct { static struct pci_driver driver; -/* return the rate of the card, or a negative value if it's blacklisted */ +/* return the id of the card, or a negative value if it's blacklisted */ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) { int i; @@ -833,12 +860,12 @@ static int __devinit snd_bt87x_detect_ca return -EBUSY; } - snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x, using default rate 32000\n", - pci->device, pci->subsystem_vendor, pci->subsystem_device); + snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n", + pci->device, pci->subsystem_vendor, pci->subsystem_device); snd_printk(KERN_DEBUG "please mail id, board name, and, " "if it works, the correct digital_rate option to " "\n"); - return 32000; /* default rate */ + return SND_BT87X_BOARD_UNKNOWN; } static int __devinit snd_bt87x_probe(struct pci_dev *pci, @@ -847,12 +874,16 @@ static int __devinit snd_bt87x_probe(str static int dev; struct snd_card *card; struct snd_bt87x *chip; - int err, rate; + int err; + enum snd_bt87x_boardid boardid; - rate = pci_id->driver_data; - if (! rate) - if ((rate = snd_bt87x_detect_card(pci)) <= 0) + if (!pci_id->driver_data) { + err = snd_bt87x_detect_card(pci); + if (err < 0) return -ENODEV; + boardid = err; + } else + boardid = pci_id->driver_data; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -869,27 +900,39 @@ static int __devinit snd_bt87x_probe(str if (err < 0) goto _error; - if (digital_rate[dev] > 0) - chip->dig_rate = digital_rate[dev]; - else - chip->dig_rate = rate; + memcpy(&chip->board, &snd_bt87x_boards[boardid], sizeof(chip->board)); - err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital"); - if (err < 0) - goto _error; - err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog"); - if (err < 0) - goto _error; + if (!chip->board.no_digital) { + if (digital_rate[dev] > 0) + chip->board.dig_rate = digital_rate[dev]; - err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_volume, chip)); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_boost, chip)); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_source, chip)); - if (err < 0) - goto _error; + chip->reg_control |= chip->board.digital_fmt; + + err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital"); + if (err < 0) + goto _error; + } + if (!chip->board.no_analog) { + err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog"); + if (err < 0) + goto _error; + err = snd_ctl_add(card, snd_ctl_new1( + &snd_bt87x_capture_volume, chip)); + if (err < 0) + goto _error; + err = snd_ctl_add(card, snd_ctl_new1( + &snd_bt87x_capture_boost, chip)); + if (err < 0) + goto _error; + err = snd_ctl_add(card, snd_ctl_new1( + &snd_bt87x_capture_source, chip)); + if (err < 0) + goto _error; + } + snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital " + "(rate %d Hz)\n", dev, boardid, + chip->board.no_analog ? "no " : "", + chip->board.no_digital ? "no " : "", chip->board.dig_rate); strcpy(card->driver, "Bt87x"); sprintf(card->shortname, "Brooktree Bt%x", pci->device); @@ -920,8 +963,8 @@ static void __devexit snd_bt87x_remove(s /* default entries for all Bt87x cards - it's not exported */ /* driver_data is set to 0 to call detection */ static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = { - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, 0), - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, 0), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), { } }; diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index a0420bc..75da174 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.21 + * Version: 0.0.22 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -47,6 +47,8 @@ * Added GPIO info for SB Live 24bit. * 0.0.21 * Implement support for Line-in capture on SB Live 24bit. + * 0.0.22 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * * * This code was initally based on code from ALSA's emu10k1x.c which is: @@ -552,6 +554,95 @@ #define CONTROL_REAR_CHANNEL 3 #define CONTROL_CENTER_LFE_CHANNEL 1 #define CONTROL_UNKNOWN_CHANNEL 2 + +/* Based on WM8768 Datasheet Rev 4.2 page 32 */ +#define SPI_REG_MASK 0x1ff /* 16-bit SPI writes have a 7-bit address */ +#define SPI_REG_SHIFT 9 /* followed by 9 bits of data */ + +#define SPI_LDA1_REG 0 /* digital attenuation */ +#define SPI_RDA1_REG 1 +#define SPI_LDA2_REG 4 +#define SPI_RDA2_REG 5 +#define SPI_LDA3_REG 6 +#define SPI_RDA3_REG 7 +#define SPI_LDA4_REG 13 +#define SPI_RDA4_REG 14 +#define SPI_MASTDA_REG 8 + +#define SPI_DA_BIT_UPDATE (1<<8) /* update attenuation values */ +#define SPI_DA_BIT_0dB 0xff /* 0 dB */ +#define SPI_DA_BIT_infdB 0x00 /* inf dB attenuation (mute) */ + +#define SPI_PL_REG 2 +#define SPI_PL_BIT_L_M (0<<5) /* left channel = mute */ +#define SPI_PL_BIT_L_L (1<<5) /* left channel = left */ +#define SPI_PL_BIT_L_R (2<<5) /* left channel = right */ +#define SPI_PL_BIT_L_C (3<<5) /* left channel = (L+R)/2 */ +#define SPI_PL_BIT_R_M (0<<7) /* right channel = mute */ +#define SPI_PL_BIT_R_L (1<<7) /* right channel = left */ +#define SPI_PL_BIT_R_R (2<<7) /* right channel = right */ +#define SPI_PL_BIT_R_C (3<<7) /* right channel = (L+R)/2 */ +#define SPI_IZD_REG 2 +#define SPI_IZD_BIT (1<<4) /* infinite zero detect */ + +#define SPI_FMT_REG 3 +#define SPI_FMT_BIT_RJ (0<<0) /* right justified mode */ +#define SPI_FMT_BIT_LJ (1<<0) /* left justified mode */ +#define SPI_FMT_BIT_I2S (2<<0) /* I2S mode */ +#define SPI_FMT_BIT_DSP (3<<0) /* DSP Modes A or B */ +#define SPI_LRP_REG 3 +#define SPI_LRP_BIT (1<<2) /* invert LRCLK polarity */ +#define SPI_BCP_REG 3 +#define SPI_BCP_BIT (1<<3) /* invert BCLK polarity */ +#define SPI_IWL_REG 3 +#define SPI_IWL_BIT_16 (0<<4) /* 16-bit world length */ +#define SPI_IWL_BIT_20 (1<<4) /* 20-bit world length */ +#define SPI_IWL_BIT_24 (2<<4) /* 24-bit world length */ +#define SPI_IWL_BIT_32 (3<<4) /* 32-bit world length */ + +#define SPI_MS_REG 10 +#define SPI_MS_BIT (1<<5) /* master mode */ +#define SPI_RATE_REG 10 /* only applies in master mode */ +#define SPI_RATE_BIT_128 (0<<6) /* MCLK = LRCLK * 128 */ +#define SPI_RATE_BIT_192 (1<<6) +#define SPI_RATE_BIT_256 (2<<6) +#define SPI_RATE_BIT_384 (3<<6) +#define SPI_RATE_BIT_512 (4<<6) +#define SPI_RATE_BIT_768 (5<<6) + +/* They really do label the bit for the 4th channel "4" and not "3" */ +#define SPI_DMUTE0_REG 9 +#define SPI_DMUTE1_REG 9 +#define SPI_DMUTE2_REG 9 +#define SPI_DMUTE4_REG 15 +#define SPI_DMUTE0_BIT (1<<3) +#define SPI_DMUTE1_BIT (1<<4) +#define SPI_DMUTE2_BIT (1<<5) +#define SPI_DMUTE4_BIT (1<<2) + +#define SPI_PHASE0_REG 3 +#define SPI_PHASE1_REG 3 +#define SPI_PHASE2_REG 3 +#define SPI_PHASE4_REG 15 +#define SPI_PHASE0_BIT (1<<6) +#define SPI_PHASE1_BIT (1<<7) +#define SPI_PHASE2_BIT (1<<8) +#define SPI_PHASE4_BIT (1<<3) + +#define SPI_PDWN_REG 2 /* power down all DACs */ +#define SPI_PDWN_BIT (1<<2) +#define SPI_DACD0_REG 10 /* power down individual DACs */ +#define SPI_DACD1_REG 10 +#define SPI_DACD2_REG 10 +#define SPI_DACD4_REG 15 +#define SPI_DACD0_BIT (1<<1) +#define SPI_DACD1_BIT (1<<2) +#define SPI_DACD2_BIT (1<<3) +#define SPI_DACD4_BIT (1<<0) /* datasheet error says it's 1 */ + +#define SPI_PWRDNALL_REG 10 /* power down everything */ +#define SPI_PWRDNALL_BIT (1<<4) + #include "ca_midi.h" struct snd_ca0106; @@ -611,6 +702,8 @@ struct snd_ca0106 { struct snd_ca_midi midi; struct snd_ca_midi midi2; + + u16 spi_dac_reg[16]; }; int snd_ca0106_mixer(struct snd_ca0106 *emu); @@ -627,4 +720,5 @@ void snd_ca0106_ptr_write(struct snd_ca0 int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); - +int snd_ca0106_spi_write(struct snd_ca0106 * emu, + unsigned int data); diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index fcab8fb..31d8db9 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.23 + * Version: 0.0.25 * * FEATURES currently supported: * Front, Rear and Center/LFE. @@ -79,6 +79,10 @@ * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 * 0.0.23 * Implement support for Line-in capture on SB Live 24bit. + * 0.0.24 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) + * 0.0.25 + * Powerdown SPI DAC channels when not in use * * BUGS: * Some stability problems when unloading the snd-ca0106 kernel module. @@ -170,6 +174,15 @@ #include "ca0106.h" static struct snd_ca0106_details ca0106_chip_details[] = { /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ /* It is really just a normal SB Live 24bit. */ + /* Tested: + * See ALSA bug#3251 + */ + { .serial = 0x10131102, + .name = "X-Fi Extreme Audio [SBxxxx]", + .gpio_type = 1, + .i2c_adc = 1 } , + /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ + /* It is really just a normal SB Live 24bit. */ /* * CTRL:CA0111-WTLF * ADC: WM8775SEDS @@ -261,10 +274,11 @@ static struct snd_ca0106_details ca0106_ /* hardware definition */ static struct snd_pcm_hardware snd_ca0106_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), @@ -447,6 +461,19 @@ static void snd_ca0106_pcm_free_substrea kfree(runtime->private_data); } +static const int spi_dacd_reg[] = { + [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, + [PCM_REAR_CHANNEL] = SPI_DACD0_REG, + [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, + [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, +}; +static const int spi_dacd_bit[] = { + [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, + [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, + [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, + [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, +}; + /* open_playback callback */ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) @@ -481,6 +508,17 @@ static int snd_ca0106_pcm_open_playback_ return err; if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) return err; + snd_pcm_set_sync(substream); + + if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { + const int reg = spi_dacd_reg[channel_id]; + + /* Power up dac */ + chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; + err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + if (err < 0) + return err; + } return 0; } @@ -491,6 +529,14 @@ static int snd_ca0106_pcm_close_playback struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ca0106_pcm *epcm = runtime->private_data; chip->playback_channels[epcm->channel_id].use = 0; + + if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { + const int reg = spi_dacd_reg[epcm->channel_id]; + + /* Power down DAC */ + chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; + snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + } /* FIXME: maybe zero others */ return 0; } @@ -809,6 +855,9 @@ static int snd_ca0106_pcm_trigger_playba break; } snd_pcm_group_for_each_entry(s, substream) { + if (snd_pcm_substream_chip(s) != emu || + s->stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; @@ -1214,28 +1263,23 @@ static int __devinit snd_ca0106_pcm(stru return 0; } +#define SPI_REG(reg, value) (((reg) << SPI_REG_SHIFT) | (value)) static unsigned int spi_dac_init[] = { - 0x00ff, - 0x02ff, - 0x0400, - 0x0520, - 0x0620, /* Set 24 bit. Was 0x0600 */ - 0x08ff, - 0x0aff, - 0x0cff, - 0x0eff, - 0x10ff, - 0x1200, - 0x1400, - 0x1480, - 0x1800, - 0x1aff, - 0x1cff, - 0x1e00, - 0x0530, - 0x0602, - 0x0622, - 0x1400, + SPI_REG(SPI_LDA1_REG, SPI_DA_BIT_0dB), /* 0dB dig. attenuation */ + SPI_REG(SPI_RDA1_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_PL_REG, SPI_PL_BIT_L_L | SPI_PL_BIT_R_R | SPI_IZD_BIT), + SPI_REG(SPI_FMT_REG, SPI_FMT_BIT_I2S | SPI_IWL_BIT_24), + SPI_REG(SPI_LDA2_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_RDA2_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_LDA3_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_RDA3_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_MASTDA_REG, SPI_DA_BIT_0dB), + SPI_REG(9, 0x00), + SPI_REG(SPI_MS_REG, SPI_DACD0_BIT | SPI_DACD1_BIT | SPI_DACD2_BIT), + SPI_REG(12, 0x00), + SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), + SPI_REG(SPI_DACD4_REG, 0x00), }; static unsigned int i2c_adc_init[][2] = { @@ -1475,8 +1519,13 @@ #endif int size, n; size = ARRAY_SIZE(spi_dac_init); - for (n=0; n < size; n++) + for (n = 0; n < size; n++) { + int reg = spi_dac_init[n] >> SPI_REG_SHIFT; + snd_ca0106_spi_write(chip, spi_dac_init[n]); + if (reg < ARRAY_SIZE(chip->spi_dac_reg)) + chip->spi_dac_reg[reg] = spi_dac_init[n]; + } } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 9c3a9c8..be519a1 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.17 + * Version: 0.0.18 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -39,6 +39,8 @@ * Modified Copyright message. * 0.0.17 * Implement Mic and Line in Capture. + * 0.0.18 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes @@ -77,15 +79,7 @@ #include "ca0106.h" static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); -static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ca0106_shared_spdif_info snd_ctl_boolean_mono_info static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -470,6 +464,42 @@ static int snd_ca0106_i2c_volume_put(str return change; } +#define spi_mute_info snd_ctl_boolean_mono_info + +static int spi_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; + unsigned int bit = kcontrol->private_value & SPI_REG_MASK; + + ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit); + return 0; +} + +static int spi_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; + unsigned int bit = kcontrol->private_value & SPI_REG_MASK; + int ret; + + ret = emu->spi_dac_reg[reg] & bit; + if (ucontrol->value.integer.value[0]) { + if (!ret) /* bit already cleared, do nothing */ + return 0; + emu->spi_dac_reg[reg] &= ~bit; + } else { + if (ret) /* bit already set, do nothing */ + return 0; + emu->spi_dac_reg[reg] |= bit; + } + + ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]); + return ret ? -1 : 1; +} + #define CA_VOLUME(xname,chid,reg) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -562,6 +592,28 @@ static struct snd_kcontrol_new snd_ca010 I2C_VOLUME("Aux Capture Volume", 3), }; +#define SPI_SWITCH(xname,reg,bit) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = spi_mute_info, \ + .get = spi_mute_get, \ + .put = spi_mute_put, \ + .private_value = (reg<card; char **c; static char *ca0106_remove_ctls[] = { @@ -640,17 +702,9 @@ #if 1 rename_ctl(card, c[0], c[1]); #endif - for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu)); - if (err < 0) - return err; - } + ADD_CTLS(emu, snd_ca0106_volume_ctls); if (emu->details->i2c_adc == 1) { - for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu)); - if (err < 0) - return err; - } + ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls); if (emu->details->gpio_type == 1) err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); else /* gpio_type == 2 */ @@ -658,6 +712,8 @@ #endif if (err < 0) return err; } + if (emu->details->spi_dac == 1) + ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls); return 0; } diff --git a/sound/pci/ca0106/ca_midi.h b/sound/pci/ca0106/ca_midi.h index b72c093..922ed3e 100644 --- a/sound/pci/ca0106/ca_midi.h +++ b/sound/pci/ca0106/ca_midi.h @@ -22,9 +22,9 @@ * */ -#include -#include -#include +#include +#include +#include #define CA_MIDI_MODE_INPUT MPU401_MODE_INPUT #define CA_MIDI_MODE_OUTPUT MPU401_MODE_OUTPUT diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 7d3c5ee..6832649 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -95,30 +95,34 @@ #define CM_CHADC1 0x00000002 /* ch1, 0: #define CM_CHADC0 0x00000001 /* ch0, 0:playback, 1:record */ #define CM_REG_FUNCTRL1 0x04 -#define CM_ASFC_MASK 0x0000E000 /* ADC sampling frequency */ -#define CM_ASFC_SHIFT 13 -#define CM_DSFC_MASK 0x00001C00 /* DAC sampling frequency */ -#define CM_DSFC_SHIFT 10 +#define CM_DSFC_MASK 0x0000E000 /* channel 1 (DAC?) sampling frequency */ +#define CM_DSFC_SHIFT 13 +#define CM_ASFC_MASK 0x00001C00 /* channel 0 (ADC?) sampling frequency */ +#define CM_ASFC_SHIFT 10 #define CM_SPDF_1 0x00000200 /* SPDIF IN/OUT at channel B */ #define CM_SPDF_0 0x00000100 /* SPDIF OUT only channel A */ -#define CM_SPDFLOOP 0x00000080 /* ext. SPDIIF/OUT -> IN loopback */ +#define CM_SPDFLOOP 0x00000080 /* ext. SPDIIF/IN -> OUT loopback */ #define CM_SPDO2DAC 0x00000040 /* SPDIF/OUT can be heard from internal DAC */ #define CM_INTRM 0x00000020 /* master control block (MCB) interrupt enabled */ #define CM_BREQ 0x00000010 /* bus master enabled */ #define CM_VOICE_EN 0x00000008 /* legacy voice (SB16,FM) */ -#define CM_UART_EN 0x00000004 /* UART */ -#define CM_JYSTK_EN 0x00000002 /* joy stick */ +#define CM_UART_EN 0x00000004 /* legacy UART */ +#define CM_JYSTK_EN 0x00000002 /* legacy joystick */ +#define CM_ZVPORT 0x00000001 /* ZVPORT */ #define CM_REG_CHFORMAT 0x08 #define CM_CHB3D5C 0x80000000 /* 5,6 channels */ +#define CM_FMOFFSET2 0x40000000 /* initial FM PCM offset 2 when Fmute=1 */ #define CM_CHB3D 0x20000000 /* 4 channels */ #define CM_CHIP_MASK1 0x1f000000 #define CM_CHIP_037 0x01000000 - -#define CM_SPDIF_SELECT1 0x00080000 /* for model <= 037 ? */ +#define CM_SETLAT48 0x00800000 /* set latency timer 48h */ +#define CM_EDGEIRQ 0x00400000 /* emulated edge trigger legacy IRQ */ +#define CM_SPD24SEL39 0x00200000 /* 24-bit spdif: model 039 */ #define CM_AC3EN1 0x00100000 /* enable AC3: model 037 */ +#define CM_SPDIF_SELECT1 0x00080000 /* for model <= 037 ? */ #define CM_SPD24SEL 0x00020000 /* 24bit spdif: model 037 */ /* #define CM_SPDIF_INVERSE 0x00010000 */ /* ??? */ @@ -128,35 +132,45 @@ #define CM_ADCBITLEN_15 0x00004000 #define CM_ADCBITLEN_14 0x00008000 #define CM_ADCBITLEN_13 0x0000C000 -#define CM_ADCDACLEN_MASK 0x00003000 +#define CM_ADCDACLEN_MASK 0x00003000 /* model 037 */ #define CM_ADCDACLEN_060 0x00000000 #define CM_ADCDACLEN_066 0x00001000 #define CM_ADCDACLEN_130 0x00002000 #define CM_ADCDACLEN_280 0x00003000 +#define CM_ADCDLEN_MASK 0x00003000 /* model 039 */ +#define CM_ADCDLEN_ORIGINAL 0x00000000 +#define CM_ADCDLEN_EXTRA 0x00001000 +#define CM_ADCDLEN_24K 0x00002000 +#define CM_ADCDLEN_WEIGHT 0x00003000 + #define CM_CH1_SRATE_176K 0x00000800 +#define CM_CH1_SRATE_96K 0x00000800 /* model 055? */ #define CM_CH1_SRATE_88K 0x00000400 #define CM_CH0_SRATE_176K 0x00000200 +#define CM_CH0_SRATE_96K 0x00000200 /* model 055? */ #define CM_CH0_SRATE_88K 0x00000100 #define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ +#define CM_DBLSPDS 0x00000040 /* double SPDIF sample rate 88.2/96 */ +#define CM_POLVALID 0x00000020 /* inverse SPDIF/IN valid bit */ +#define CM_SPDLOCKED 0x00000010 -#define CM_CH1FMT_MASK 0x0000000C +#define CM_CH1FMT_MASK 0x0000000C /* bit 3: 16 bits, bit 2: stereo */ #define CM_CH1FMT_SHIFT 2 -#define CM_CH0FMT_MASK 0x00000003 +#define CM_CH0FMT_MASK 0x00000003 /* bit 1: 16 bits, bit 0: stereo */ #define CM_CH0FMT_SHIFT 0 #define CM_REG_INT_HLDCLR 0x0C #define CM_CHIP_MASK2 0xff000000 +#define CM_CHIP_8768 0x20000000 +#define CM_CHIP_055 0x08000000 #define CM_CHIP_039 0x04000000 #define CM_CHIP_039_6CH 0x01000000 -#define CM_CHIP_055 0x08000000 -#define CM_CHIP_8768 0x20000000 +#define CM_UNKNOWN_INT_EN 0x00080000 /* ? */ #define CM_TDMA_INT_EN 0x00040000 #define CM_CH1_INT_EN 0x00020000 #define CM_CH0_INT_EN 0x00010000 -#define CM_INT_HOLD 0x00000002 -#define CM_INT_CLEAR 0x00000001 #define CM_REG_INT_STATUS 0x10 #define CM_INTR 0x80000000 @@ -175,12 +189,13 @@ #define CM_CHINT1 0x00000002 #define CM_CHINT0 0x00000001 #define CM_REG_LEGACY_CTRL 0x14 -#define CM_NXCHG 0x80000000 /* h/w multi channels? */ +#define CM_NXCHG 0x80000000 /* don't map base reg dword->sample */ #define CM_VMPU_MASK 0x60000000 /* MPU401 i/o port address */ #define CM_VMPU_330 0x00000000 #define CM_VMPU_320 0x20000000 #define CM_VMPU_310 0x40000000 #define CM_VMPU_300 0x60000000 +#define CM_ENWR8237 0x10000000 /* enable bus master to write 8237 base reg */ #define CM_VSBSEL_MASK 0x0C000000 /* SB16 base address */ #define CM_VSBSEL_220 0x00000000 #define CM_VSBSEL_240 0x04000000 @@ -191,44 +206,74 @@ #define CM_FMSEL_388 0x00000000 #define CM_FMSEL_3C8 0x01000000 #define CM_FMSEL_3E0 0x02000000 #define CM_FMSEL_3E8 0x03000000 -#define CM_ENSPDOUT 0x00800000 /* enable XPDIF/OUT to I/O interface */ -#define CM_SPDCOPYRHT 0x00400000 /* set copyright spdif in/out */ +#define CM_ENSPDOUT 0x00800000 /* enable XSPDIF/OUT to I/O interface */ +#define CM_SPDCOPYRHT 0x00400000 /* spdif in/out copyright bit */ #define CM_DAC2SPDO 0x00200000 /* enable wave+fm_midi -> SPDIF/OUT */ -#define CM_SETRETRY 0x00010000 /* 0: legacy i/o wait (default), 1: legacy i/o bus retry */ +#define CM_INVIDWEN 0x00100000 /* internal vendor ID write enable, model 039? */ +#define CM_SETRETRY 0x00100000 /* 0: legacy i/o wait (default), 1: legacy i/o bus retry */ +#define CM_C_EEACCESS 0x00080000 /* direct programming eeprom regs */ +#define CM_C_EECS 0x00040000 +#define CM_C_EEDI46 0x00020000 +#define CM_C_EECK46 0x00010000 #define CM_CHB3D6C 0x00008000 /* 5.1 channels support */ -#define CM_LINE_AS_BASS 0x00006000 /* use line-in as bass */ +#define CM_CENTR2LIN 0x00004000 /* line-in as center out */ +#define CM_BASE2LIN 0x00002000 /* line-in as bass out */ +#define CM_EXBASEN 0x00001000 /* external bass input enable */ #define CM_REG_MISC_CTRL 0x18 -#define CM_PWD 0x80000000 +#define CM_PWD 0x80000000 /* power down */ #define CM_RESET 0x40000000 -#define CM_SFIL_MASK 0x30000000 -#define CM_TXVX 0x08000000 -#define CM_N4SPK3D 0x04000000 /* 4ch output */ +#define CM_SFIL_MASK 0x30000000 /* filter control at front end DAC, model 037? */ +#define CM_VMGAIN 0x10000000 /* analog master amp +6dB, model 039? */ +#define CM_TXVX 0x08000000 /* model 037? */ +#define CM_N4SPK3D 0x04000000 /* copy front to rear */ #define CM_SPDO5V 0x02000000 /* 5V spdif output (1 = 0.5v (coax)) */ #define CM_SPDIF48K 0x01000000 /* write */ #define CM_SPATUS48K 0x01000000 /* read */ -#define CM_ENDBDAC 0x00800000 /* enable dual dac */ +#define CM_ENDBDAC 0x00800000 /* enable double dac */ #define CM_XCHGDAC 0x00400000 /* 0: front=ch0, 1: front=ch1 */ #define CM_SPD32SEL 0x00200000 /* 0: 16bit SPDIF, 1: 32bit */ -#define CM_SPDFLOOPI 0x00100000 /* int. SPDIF-IN -> int. OUT */ -#define CM_FM_EN 0x00080000 /* enalbe FM */ +#define CM_SPDFLOOPI 0x00100000 /* int. SPDIF-OUT -> int. IN */ +#define CM_FM_EN 0x00080000 /* enable legacy FM */ #define CM_AC3EN2 0x00040000 /* enable AC3: model 039 */ -#define CM_VIDWPDSB 0x00010000 +#define CM_ENWRASID 0x00010000 /* choose writable internal SUBID (audio) */ +#define CM_VIDWPDSB 0x00010000 /* model 037? */ #define CM_SPDF_AC97 0x00008000 /* 0: SPDIF/OUT 44.1K, 1: 48K */ -#define CM_MASK_EN 0x00004000 -#define CM_VIDWPPRT 0x00002000 -#define CM_SFILENB 0x00001000 -#define CM_MMODE_MASK 0x00000E00 +#define CM_MASK_EN 0x00004000 /* activate channel mask on legacy DMA */ +#define CM_ENWRMSID 0x00002000 /* choose writable internal SUBID (modem) */ +#define CM_VIDWPPRT 0x00002000 /* model 037? */ +#define CM_SFILENB 0x00001000 /* filter stepping at front end DAC, model 037? */ +#define CM_MMODE_MASK 0x00000E00 /* model DAA interface mode */ #define CM_SPDIF_SELECT2 0x00000100 /* for model > 039 ? */ #define CM_ENCENTER 0x00000080 -#define CM_FLINKON 0x00000040 -#define CM_FLINKOFF 0x00000020 -#define CM_MIDSMP 0x00000010 -#define CM_UPDDMA_MASK 0x0000000C -#define CM_TWAIT_MASK 0x00000003 +#define CM_FLINKON 0x00000080 /* force modem link detection on, model 037 */ +#define CM_MUTECH1 0x00000040 /* mute PCI ch1 to DAC */ +#define CM_FLINKOFF 0x00000040 /* force modem link detection off, model 037 */ +#define CM_UNKNOWN_18_5 0x00000020 /* ? */ +#define CM_MIDSMP 0x00000010 /* 1/2 interpolation at front end DAC */ +#define CM_UPDDMA_MASK 0x0000000C /* TDMA position update notification */ +#define CM_UPDDMA_2048 0x00000000 +#define CM_UPDDMA_1024 0x00000004 +#define CM_UPDDMA_512 0x00000008 +#define CM_UPDDMA_256 0x0000000C +#define CM_TWAIT_MASK 0x00000003 /* model 037 */ +#define CM_TWAIT1 0x00000002 /* FM i/o cycle, 0: 48, 1: 64 PCICLKs */ +#define CM_TWAIT0 0x00000001 /* i/o cycle, 0: 4, 1: 6 PCICLKs */ + +#define CM_REG_TDMA_POSITION 0x1C +#define CM_TDMA_CNT_MASK 0xFFFF0000 /* current byte/word count */ +#define CM_TDMA_ADR_MASK 0x0000FFFF /* current address */ /* byte */ #define CM_REG_MIXER0 0x20 +#define CM_REG_SBVR 0x20 /* write: sb16 version */ +#define CM_REG_DEV 0x20 /* read: hardware device version */ + +#define CM_REG_MIXER21 0x21 +#define CM_UNKNOWN_21_MASK 0x78 /* ? */ +#define CM_X_ADPCM 0x04 /* SB16 ADPCM enable */ +#define CM_PROINV 0x02 /* SBPro left/right channel switching */ +#define CM_X_SB16 0x01 /* SB16 compatible */ #define CM_REG_SB16_DATA 0x22 #define CM_REG_SB16_ADDR 0x23 @@ -243,8 +288,8 @@ #define CM_FMMUTE 0x80 /* mute FM */ #define CM_FMMUTE_SHIFT 7 #define CM_WSMUTE 0x40 /* mute PCM */ #define CM_WSMUTE_SHIFT 6 -#define CM_SPK4 0x20 /* lin-in -> rear line out */ -#define CM_SPK4_SHIFT 5 +#define CM_REAR2LIN 0x20 /* lin-in -> rear line out */ +#define CM_REAR2LIN_SHIFT 5 #define CM_REAR2FRONT 0x10 /* exchange rear/front */ #define CM_REAR2FRONT_SHIFT 4 #define CM_WAVEINL 0x08 /* digital wave rec. left chan */ @@ -276,12 +321,13 @@ #define CM_VAUXL_MASK 0xf0 #define CM_VAUXR_MASK 0x0f #define CM_REG_MISC 0x27 +#define CM_UNKNOWN_27_MASK 0xd8 /* ? */ #define CM_XGPO1 0x20 // #define CM_XGPBIO 0x04 #define CM_MIC_CENTER_LFE 0x04 /* mic as center/lfe out? (model 039 or later?) */ #define CM_SPDIF_INVERSE 0x04 /* spdif input phase inverse (model 037) */ #define CM_SPDVALID 0x02 /* spdif input valid check */ -#define CM_DMAUTO 0x01 +#define CM_DMAUTO 0x01 /* SB16 DMA auto detect */ #define CM_REG_AC97 0x28 /* hmmm.. do we have ac97 link? */ /* @@ -322,18 +368,20 @@ #define CM_REG_PLL 0xf8 /* * extended registers */ -#define CM_REG_CH0_FRAME1 0x80 /* base address */ -#define CM_REG_CH0_FRAME2 0x84 +#define CM_REG_CH0_FRAME1 0x80 /* write: base address */ +#define CM_REG_CH0_FRAME2 0x84 /* read: current address */ #define CM_REG_CH1_FRAME1 0x88 /* 0-15: count of samples at bus master; buffer size */ #define CM_REG_CH1_FRAME2 0x8C /* 16-31: count of samples at codec; fragment size */ + #define CM_REG_EXT_MISC 0x90 -#define CM_REG_MISC_CTRL_8768 0x92 /* reg. name the same as 0x18 */ -#define CM_CHB3D8C 0x20 /* 7.1 channels support */ -#define CM_SPD32FMT 0x10 /* SPDIF/IN 32k */ -#define CM_ADC2SPDIF 0x08 /* ADC output to SPDIF/OUT */ -#define CM_SHAREADC 0x04 /* DAC in ADC as Center/LFE */ -#define CM_REALTCMP 0x02 /* monitor the CMPL/CMPR of ADC */ -#define CM_INVLRCK 0x01 /* invert ZVPORT's LRCK */ +#define CM_ADC48K44K 0x10000000 /* ADC parameters group, 0: 44k, 1: 48k */ +#define CM_CHB3D8C 0x00200000 /* 7.1 channels support */ +#define CM_SPD32FMT 0x00100000 /* SPDIF/IN 32k sample rate */ +#define CM_ADC2SPDIF 0x00080000 /* ADC output to SPDIF/OUT */ +#define CM_SHAREADC 0x00040000 /* DAC in ADC as Center/LFE */ +#define CM_REALTCMP 0x00020000 /* monitor the CMPL/CMPR of ADC */ +#define CM_INVLRCK 0x00010000 /* invert ZVPORT's LRCK */ +#define CM_UNKNOWN_90_MASK 0x0000FFFF /* ? */ /* * size of i/o region @@ -383,15 +431,14 @@ #endif struct cmipci_pcm { struct snd_pcm_substream *substream; - int running; /* dac/adc running? */ + u8 running; /* dac/adc running? */ + u8 fmt; /* format bits */ + u8 is_dac; + u8 needs_silencing; unsigned int dma_size; /* in frames */ - unsigned int period_size; /* in frames */ + unsigned int shift; + unsigned int ch; /* channel (0/1) */ unsigned int offset; /* physical address of the buffer */ - unsigned int fmt; /* format bits */ - int ch; /* channel (0/1) */ - unsigned int is_dac; /* is dac? */ - int bytes_per_frame; - int shift; }; /* mixer elements toggled/resumed during ac3 playback */ @@ -424,7 +471,6 @@ struct cmipci { int chip_version; int max_channels; - unsigned int has_dual_dac: 1; unsigned int can_ac3_sw: 1; unsigned int can_ac3_hw: 1; unsigned int can_multi_ch: 1; @@ -557,6 +603,9 @@ static unsigned int rates[] = { 5512, 11 static unsigned int snd_cmipci_rate_freq(unsigned int rate) { unsigned int i; + + if (rate > 48000) + rate /= 2; for (i = 0; i < ARRAY_SIZE(rates); i++) { if (rates[i] == rate) return i; @@ -671,19 +720,19 @@ static int snd_cmipci_hw_free(struct snd /* */ -static unsigned int hw_channels[] = {1, 2, 4, 5, 6, 8}; +static unsigned int hw_channels[] = {1, 2, 4, 6, 8}; static struct snd_pcm_hw_constraint_list hw_constraints_channels_4 = { .count = 3, .list = hw_channels, .mask = 0, }; static struct snd_pcm_hw_constraint_list hw_constraints_channels_6 = { - .count = 5, + .count = 4, .list = hw_channels, .mask = 0, }; static struct snd_pcm_hw_constraint_list hw_constraints_channels_8 = { - .count = 6, + .count = 5, .list = hw_channels, .mask = 0, }; @@ -691,48 +740,37 @@ static struct snd_pcm_hw_constraint_list static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int channels) { if (channels > 2) { - if (! cm->can_multi_ch) + if (!cm->can_multi_ch || !rec->ch) return -EINVAL; if (rec->fmt != 0x03) /* stereo 16bit only */ return -EINVAL; + } + if (cm->can_multi_ch) { spin_lock_irq(&cm->reg_lock); - snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); - if (channels > 4) { - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); - snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); + if (channels > 2) { + snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); } else { - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); - snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); + snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); } - if (channels >= 6) { + if (channels == 8) + snd_cmipci_set_bit(cm, CM_REG_EXT_MISC, CM_CHB3D8C); + else + snd_cmipci_clear_bit(cm, CM_REG_EXT_MISC, CM_CHB3D8C); + if (channels == 6) { + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); } else { - snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); - } - if (cm->chip_version == 68) { - if (channels == 8) { - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C); - } else { - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C); - } - } - spin_unlock_irq(&cm->reg_lock); - - } else { - if (cm->can_multi_ch) { - spin_lock_irq(&cm->reg_lock); - snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); - spin_unlock_irq(&cm->reg_lock); } + if (channels == 4) + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); + else + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); + spin_unlock_irq(&cm->reg_lock); } return 0; } @@ -746,6 +784,7 @@ static int snd_cmipci_pcm_prepare(struct struct snd_pcm_substream *substream) { unsigned int reg, freq, val; + unsigned int period_size; struct snd_pcm_runtime *runtime = substream->runtime; rec->fmt = 0; @@ -765,11 +804,11 @@ static int snd_cmipci_pcm_prepare(struct rec->offset = runtime->dma_addr; /* buffer and period sizes in frame */ rec->dma_size = runtime->buffer_size << rec->shift; - rec->period_size = runtime->period_size << rec->shift; + period_size = runtime->period_size << rec->shift; if (runtime->channels > 2) { /* multi-channels */ rec->dma_size = (rec->dma_size * runtime->channels) / 2; - rec->period_size = (rec->period_size * runtime->channels) / 2; + period_size = (period_size * runtime->channels) / 2; } spin_lock_irq(&cm->reg_lock); @@ -780,7 +819,7 @@ static int snd_cmipci_pcm_prepare(struct /* program sample counts */ reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; snd_cmipci_write_w(cm, reg, rec->dma_size - 1); - snd_cmipci_write_w(cm, reg + 2, rec->period_size - 1); + snd_cmipci_write_w(cm, reg + 2, period_size - 1); /* set adc/dac flag */ val = rec->ch ? CM_CHADC1 : CM_CHADC0; @@ -795,11 +834,11 @@ static int snd_cmipci_pcm_prepare(struct freq = snd_cmipci_rate_freq(runtime->rate); val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); if (rec->ch) { - val &= ~CM_ASFC_MASK; - val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK; - } else { val &= ~CM_DSFC_MASK; val |= (freq << CM_DSFC_SHIFT) & CM_DSFC_MASK; + } else { + val &= ~CM_ASFC_MASK; + val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK; } snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); //snd_printd("cmipci: functrl1 = %08x\n", val); @@ -813,6 +852,16 @@ static int snd_cmipci_pcm_prepare(struct val &= ~CM_CH0FMT_MASK; val |= rec->fmt << CM_CH0FMT_SHIFT; } + if (cm->chip_version == 68) { + if (runtime->rate == 88200) + val |= CM_CH0_SRATE_88K << (rec->ch * 2); + else + val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); + if (runtime->rate == 96000) + val |= CM_CH0_SRATE_96K << (rec->ch * 2); + else + val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); + } snd_cmipci_write(cm, CM_REG_CHFORMAT, val); //snd_printd("cmipci: chformat = %08x\n", val); @@ -826,7 +875,7 @@ static int snd_cmipci_pcm_prepare(struct * PCM trigger/stop */ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, - struct snd_pcm_substream *substream, int cmd) + int cmd) { unsigned int inthld, chen, reset, pause; int result = 0; @@ -855,6 +904,7 @@ static int snd_cmipci_pcm_trigger(struct cm->ctrl &= ~chen; snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset); snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); + rec->needs_silencing = rec->is_dac; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -906,7 +956,7 @@ static int snd_cmipci_playback_trigger(s int cmd) { struct cmipci *cm = snd_pcm_substream_chip(substream); - return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_PLAY], substream, cmd); + return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_PLAY], cmd); } static snd_pcm_uframes_t snd_cmipci_playback_pointer(struct snd_pcm_substream *substream) @@ -925,7 +975,7 @@ static int snd_cmipci_capture_trigger(st int cmd) { struct cmipci *cm = snd_pcm_substream_chip(substream); - return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_CAPT], substream, cmd); + return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_CAPT], cmd); } static snd_pcm_uframes_t snd_cmipci_capture_pointer(struct snd_pcm_substream *substream) @@ -1199,15 +1249,19 @@ static int setup_spdif_playback(struct c snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); setup_ac3(cm, subs, do_ac3, rate); - if (rate == 48000) + if (rate == 48000 || rate == 96000) snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K | CM_SPDF_AC97); else snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K | CM_SPDF_AC97); - + if (rate > 48000) + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); + else + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); } else { /* they are controlled via "IEC958 Output Switch" */ /* snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT); */ /* snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_SPDO2DAC); */ + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); setup_ac3(cm, subs, 0, 0); } @@ -1227,7 +1281,7 @@ static int snd_cmipci_playback_prepare(s int rate = substream->runtime->rate; int err, do_spdif, do_ac3 = 0; - do_spdif = ((rate == 44100 || rate == 48000) && + do_spdif = (rate >= 44100 && substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && substream->runtime->channels == 2); if (do_spdif && cm->can_ac3_hw) @@ -1252,11 +1306,75 @@ static int snd_cmipci_playback_spdif_pre return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); } +/* + * Apparently, the samples last played on channel A stay in some buffer, even + * after the channel is reset, and get added to the data for the rear DACs when + * playing a multichannel stream on channel B. This is likely to generate + * wraparounds and thus distortions. + * To avoid this, we play at least one zero sample after the actual stream has + * stopped. + */ +static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) +{ + struct snd_pcm_runtime *runtime = rec->substream->runtime; + unsigned int reg, val; + + if (rec->needs_silencing && runtime && runtime->dma_area) { + /* set up a small silence buffer */ + memset(runtime->dma_area, 0, PAGE_SIZE); + reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; + val = ((PAGE_SIZE / 4) - 1) | (((PAGE_SIZE / 4) / 2 - 1) << 16); + snd_cmipci_write(cm, reg, val); + + /* configure for 16 bits, 2 channels, 8 kHz */ + if (runtime->channels > 2) + set_dac_channels(cm, rec, 2); + spin_lock_irq(&cm->reg_lock); + val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); + val &= ~(CM_ASFC_MASK << (rec->ch * 3)); + val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3); + snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); + val = snd_cmipci_read(cm, CM_REG_CHFORMAT); + val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); + val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); + if (cm->chip_version == 68) { + val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); + val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); + } + snd_cmipci_write(cm, CM_REG_CHFORMAT, val); + + /* start stream (we don't need interrupts) */ + cm->ctrl |= CM_CHEN0 << rec->ch; + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); + spin_unlock_irq(&cm->reg_lock); + + msleep(1); + + /* stop and reset stream */ + spin_lock_irq(&cm->reg_lock); + cm->ctrl &= ~(CM_CHEN0 << rec->ch); + val = CM_RST_CH0 << rec->ch; + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val); + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val); + spin_unlock_irq(&cm->reg_lock); + + rec->needs_silencing = 0; + } +} + static int snd_cmipci_playback_hw_free(struct snd_pcm_substream *substream) { struct cmipci *cm = snd_pcm_substream_chip(substream); setup_spdif_playback(cm, substream, 0, 0); restore_mixer_state(cm); + snd_cmipci_silence_hack(cm, &cm->channel[0]); + return snd_cmipci_hw_free(substream); +} + +static int snd_cmipci_playback2_hw_free(struct snd_pcm_substream *substream) +{ + struct cmipci *cm = snd_pcm_substream_chip(substream); + snd_cmipci_silence_hack(cm, &cm->channel[1]); return snd_cmipci_hw_free(substream); } @@ -1515,7 +1633,11 @@ static int snd_cmipci_playback_open(stru if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0) return err; runtime->hw = snd_cmipci_playback; - runtime->hw.channels_max = cm->max_channels; + if (cm->chip_version == 68) { + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + runtime->hw.rate_max = 96000; + } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); cm->dig_pcm_status = cm->dig_status; return 0; @@ -1558,9 +1680,14 @@ static int snd_cmipci_playback2_open(str else if (cm->max_channels == 8) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8); } - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); } mutex_unlock(&cm->open_mutex); + if (cm->chip_version == 68) { + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + runtime->hw.rate_max = 96000; + } + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); return 0; } @@ -1574,8 +1701,15 @@ static int snd_cmipci_playback_spdif_ope return err; if (cm->can_ac3_hw) { runtime->hw = snd_cmipci_playback_spdif; - if (cm->chip_version >= 37) + if (cm->chip_version >= 37) { runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + } + if (cm->chip_version == 68) { + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + runtime->hw.rate_max = 96000; + } } else { runtime->hw = snd_cmipci_playback_iec958_subframe; } @@ -1668,7 +1802,7 @@ static struct snd_pcm_ops snd_cmipci_pla .close = snd_cmipci_playback2_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_playback2_hw_params, - .hw_free = snd_cmipci_hw_free, + .hw_free = snd_cmipci_playback2_hw_free, .prepare = snd_cmipci_capture_prepare, /* channel B */ .trigger = snd_cmipci_capture_trigger, /* channel B */ .pointer = snd_cmipci_capture_pointer, /* channel B */ @@ -2139,15 +2273,7 @@ struct cmipci_switch_args { */ }; -static int snd_cmipci_uswitch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_cmipci_uswitch_info snd_ctl_boolean_mono_info static int _snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, @@ -2260,8 +2386,8 @@ #else DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0); #endif DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); -// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); -// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); +// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_REAR2LIN, 1, 0); +// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_CENTR2LIN|CM_BASE2LIN, 0, 0); // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); @@ -2331,11 +2457,11 @@ static inline unsigned int get_line_in_m unsigned int val; if (cm->chip_version >= 39) { val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL); - if (val & CM_LINE_AS_BASS) + if (val & (CM_CENTR2LIN | CM_BASE2LIN)) return 2; } val = snd_cmipci_read_b(cm, CM_REG_MIXER1); - if (val & CM_SPK4) + if (val & CM_REAR2LIN) return 1; return 0; } @@ -2359,13 +2485,13 @@ static int snd_cmipci_line_in_mode_put(s spin_lock_irq(&cm->reg_lock); if (ucontrol->value.enumerated.item[0] == 2) - change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CENTR2LIN | CM_BASE2LIN); else - change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CENTR2LIN | CM_BASE2LIN); if (ucontrol->value.enumerated.item[0] == 1) - change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN); else - change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN); spin_unlock_irq(&cm->reg_lock); return change; } @@ -2583,19 +2709,18 @@ static void snd_cmipci_proc_read(struct struct snd_info_buffer *buffer) { struct cmipci *cm = entry->private_data; - int i; + int i, v; - snd_iprintf(buffer, "%s\n\n", cm->card->longname); - for (i = 0; i < 0x40; i++) { - int v = inb(cm->iobase + i); + snd_iprintf(buffer, "%s\n", cm->card->longname); + for (i = 0; i < 0x94; i++) { + if (i == 0x28) + i = 0x90; + v = inb(cm->iobase + i); if (i % 4 == 0) - snd_iprintf(buffer, "%02x: ", i); - snd_iprintf(buffer, "%02x", v); - if (i % 4 == 3) - snd_iprintf(buffer, "\n"); - else - snd_iprintf(buffer, " "); + snd_iprintf(buffer, "\n%02x:", i); + snd_iprintf(buffer, " %02x", v); } + snd_iprintf(buffer, "\n"); } static void __devinit snd_cmipci_proc_init(struct cmipci *cm) @@ -2633,46 +2758,40 @@ static void __devinit query_chip(struct if (! detect) { /* check reg 08h, bit 24-28 */ detect = snd_cmipci_read(cm, CM_REG_CHFORMAT) & CM_CHIP_MASK1; - if (! detect) { + switch (detect) { + case 0: cm->chip_version = 33; - cm->max_channels = 2; if (cm->do_soft_ac3) cm->can_ac3_sw = 1; else cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - } else { + break; + case CM_CHIP_037: cm->chip_version = 37; - cm->max_channels = 2; cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; + break; + default: + cm->chip_version = 39; + cm->can_ac3_hw = 1; + break; } + cm->max_channels = 2; } else { - /* check reg 0Ch, bit 26 */ - if (detect & CM_CHIP_8768) { - cm->chip_version = 68; - cm->max_channels = 8; - cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - cm->can_multi_ch = 1; - } else if (detect & CM_CHIP_055) { - cm->chip_version = 55; - cm->max_channels = 6; - cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - cm->can_multi_ch = 1; - } else if (detect & CM_CHIP_039) { + if (detect & CM_CHIP_039) { cm->chip_version = 39; if (detect & CM_CHIP_039_6CH) /* 4 or 6 channels */ cm->max_channels = 6; else cm->max_channels = 4; - cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - cm->can_multi_ch = 1; + } else if (detect & CM_CHIP_8768) { + cm->chip_version = 68; + cm->max_channels = 8; } else { - printk(KERN_ERR "chip %x version not supported\n", detect); + cm->chip_version = 55; + cm->max_channels = 6; } + cm->can_ac3_hw = 1; + cm->can_multi_ch = 1; } } @@ -2782,10 +2901,14 @@ static int __devinit snd_cmipci_create_f if (!fm_port) goto disable_fm; - /* first try FM regs in PCI port range */ - iosynth = cm->iobase + CM_REG_FM_PCI; - err = snd_opl3_create(cm->card, iosynth, iosynth + 2, - OPL3_HW_OPL3, 1, &opl3); + if (cm->chip_version >= 39) { + /* first try FM regs in PCI port range */ + iosynth = cm->iobase + CM_REG_FM_PCI; + err = snd_opl3_create(cm->card, iosynth, iosynth + 2, + OPL3_HW_OPL3, 1, &opl3); + } else { + err = -EIO; + } if (err < 0) { /* then try legacy ports */ val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL) & ~CM_FMSEL_MASK; @@ -2829,9 +2952,10 @@ static int __devinit snd_cmipci_create(s static struct snd_device_ops ops = { .dev_free = snd_cmipci_dev_free, }; - unsigned int val = 0; + unsigned int val; long iomidi; - int integrated_midi; + int integrated_midi = 0; + char modelstr[16]; int pcm_index, pcm_spdif_index; static struct pci_device_id intel_82437vx[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, @@ -2904,6 +3028,8 @@ #else #endif /* initialize codec registers */ + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_RESET); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_RESET); snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); /* disable ints */ snd_cmipci_ch_reset(cm, CM_CH_PLAY); snd_cmipci_ch_reset(cm, CM_CH_CAPT); @@ -2917,6 +3043,10 @@ #if CM_CH_PLAY == 1 #else snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); #endif + if (cm->chip_version) { + snd_cmipci_write_b(cm, CM_REG_EXT_MISC, 0x20); /* magic */ + snd_cmipci_write_b(cm, CM_REG_EXT_MISC + 1, 0x09); /* more magic */ + } /* Set Bus Master Request */ snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_BREQ); @@ -2931,15 +3061,55 @@ #endif break; } + if (cm->chip_version < 68) { + val = pci->device < 0x110 ? 8338 : 8738; + } else { + switch (snd_cmipci_read_b(cm, CM_REG_INT_HLDCLR + 3) & 0x03) { + case 0: + val = 8769; + break; + case 2: + val = 8762; + break; + default: + switch ((pci->subsystem_vendor << 16) | + pci->subsystem_device) { + case 0x13f69761: + case 0x584d3741: + case 0x584d3751: + case 0x584d3761: + case 0x584d3771: + case 0x72848384: + val = 8770; + break; + default: + val = 8768; + break; + } + } + } + sprintf(card->shortname, "C-Media CMI%d", val); + if (cm->chip_version < 68) + sprintf(modelstr, " (model %d)", cm->chip_version); + else + modelstr[0] = '\0'; + sprintf(card->longname, "%s%s at %#lx, irq %i", + card->shortname, modelstr, cm->iobase, cm->irq); + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cm, &ops)) < 0) { snd_cmipci_free(cm); return err; } - integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff; - if (integrated_midi && mpu_port[dev] == 1) - iomidi = cm->iobase + CM_REG_MPU_PCI; - else { + if (cm->chip_version >= 39) { + val = snd_cmipci_read_b(cm, CM_REG_MPU_PCI + 1); + if (val != 0x00 && val != 0xff) { + iomidi = cm->iobase + CM_REG_MPU_PCI; + integrated_midi = 1; + } + } + if (!integrated_midi) { + val = 0; iomidi = mpu_port[dev]; switch (iomidi) { case 0x320: val = CM_VMPU_320; break; @@ -2953,11 +3123,21 @@ #endif snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val); /* enable UART */ snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN); + if (inb(iomidi + 1) == 0xff) { + snd_printk(KERN_ERR "cannot enable MPU-401 port" + " at %#lx\n", iomidi); + snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, + CM_UART_EN); + iomidi = 0; + } } } - if ((err = snd_cmipci_create_fm(cm, fm_port[dev])) < 0) - return err; + if (cm->chip_version < 68) { + err = snd_cmipci_create_fm(cm, fm_port[dev]); + if (err < 0) + return err; + } /* reset mixer */ snd_cmipci_mixer_write(cm, 0, 0); @@ -2969,11 +3149,9 @@ #endif if ((err = snd_cmipci_pcm_new(cm, pcm_index)) < 0) return err; pcm_index++; - if (cm->has_dual_dac) { - if ((err = snd_cmipci_pcm2_new(cm, pcm_index)) < 0) - return err; - pcm_index++; - } + if ((err = snd_cmipci_pcm2_new(cm, pcm_index)) < 0) + return err; + pcm_index++; if (cm->can_ac3_hw || cm->can_ac3_sw) { pcm_spdif_index = pcm_index; if ((err = snd_cmipci_pcm_spdif_new(cm, pcm_index)) < 0) @@ -3057,15 +3235,6 @@ static int __devinit snd_cmipci_probe(st } card->private_data = cm; - sprintf(card->shortname, "C-Media PCI %s", card->driver); - sprintf(card->longname, "%s (model %d) at 0x%lx, irq %i", - card->shortname, - cm->chip_version, - cm->iobase, - cm->irq); - - //snd_printd("%s is detected\n", card->longname); - if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 44cf546..1fca49a 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -842,12 +842,11 @@ static snd_pcm_uframes_t snd_cs4281_poin static struct snd_pcm_hardware snd_cs4281_playback = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | @@ -868,12 +867,11 @@ static struct snd_pcm_hardware snd_cs428 static struct snd_pcm_hardware snd_cs4281_capture = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | @@ -904,7 +902,6 @@ static int snd_cs4281_playback_open(stru dma->right_slot = 1; runtime->private_data = dma; runtime->hw = snd_cs4281_playback; - snd_pcm_set_sync(substream); /* should be detected from the AC'97 layer, but it seems that although CS4297A rev B reports 18-bit ADC resolution, samples are 20-bit */ @@ -924,7 +921,6 @@ static int snd_cs4281_capture_open(struc dma->right_slot = 11; runtime->private_data = dma; runtime->hw = snd_cs4281_capture; - snd_pcm_set_sync(substream); /* should be detected from the AC'97 layer, but it seems that although CS4297A rev B reports 18-bit ADC resolution, samples are 20-bit */ diff --git a/sound/pci/cs46xx/Makefile b/sound/pci/cs46xx/Makefile index d8b77b8..7fcc967 100644 --- a/sound/pci/cs46xx/Makefile +++ b/sound/pci/cs46xx/Makefile @@ -3,10 +3,8 @@ # Makefile for ALSA # Copyright (c) 2001 by Jaroslav Kysela # -snd-cs46xx-objs := cs46xx.o cs46xx_lib.o -ifeq ($(CONFIG_SND_CS46XX_NEW_DSP),y) - snd-cs46xx-objs += dsp_spos.o dsp_spos_scb_lib.o -endif +snd-cs46xx-y := cs46xx.o cs46xx_lib.o +snd-cs46xx-$(CONFIG_SND_CS46XX_NEW_DSP) += dsp_spos.o dsp_spos_scb_lib.o # Toplevel Module Dependency obj-$(CONFIG_SND_CS46XX) += snd-cs46xx.o diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 71d7aab..0dc69d0 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1818,15 +1818,7 @@ static int snd_cs46xx_vol_iec958_put(str } #endif -static int snd_mixer_boolean_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_mixer_boolean_info snd_ctl_boolean_mono_info static int snd_cs46xx_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 57e357d..eded4df 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -1480,7 +1480,7 @@ void cs46xx_dsp_destroy_pcm_channel (str 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, + snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot < DSP_MAX_SRC_NR, return ); ins->src_scb_slots[pcm_channel->src_slot] = 0; diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index ad947b4..bb3d57e 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -2,11 +2,8 @@ # # Makefile for cs5535audio # -snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o - -ifeq ($(CONFIG_PM),y) -snd-cs5535audio-objs += cs5535audio_pm.o -endif +snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o +snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index b8e75ef..2b35889 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -206,7 +206,6 @@ static void process_bm1_irq(struct cs553 static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) { u16 acc_irq_stat; - u8 bm_stat; unsigned char count; struct cs5535audio *cs5535au = dev_id; @@ -217,7 +216,7 @@ static irqreturn_t snd_cs5535audio_inter if (!acc_irq_stat) return IRQ_NONE; - for (count = 0; count < 10; count++) { + for (count = 0; count < 4; count++) { if (acc_irq_stat & (1 << count)) { switch (count) { case IRQ_STS: @@ -232,26 +231,9 @@ static irqreturn_t snd_cs5535audio_inter case BM1_IRQ_STS: process_bm1_irq(cs5535au); break; - case BM2_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM2_STATUS); - break; - case BM3_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM3_STATUS); - break; - case BM4_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM4_STATUS); - break; - case BM5_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM5_STATUS); - break; - case BM6_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM6_STATUS); - break; - case BM7_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM7_STATUS); - break; default: - snd_printk(KERN_ERR "Unexpected irq src\n"); + snd_printk(KERN_ERR "Unexpected irq src: " + "0x%x\n", acc_irq_stat); break; } } diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 4fd1f31..66bae76 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -16,57 +16,28 @@ #define ACC_CODEC_CNTL 0x0C #define ACC_IRQ_STATUS 0x12 #define ACC_BM0_CMD 0x20 #define ACC_BM1_CMD 0x28 -#define ACC_BM2_CMD 0x30 -#define ACC_BM3_CMD 0x38 -#define ACC_BM4_CMD 0x40 -#define ACC_BM5_CMD 0x48 -#define ACC_BM6_CMD 0x50 -#define ACC_BM7_CMD 0x58 #define ACC_BM0_PRD 0x24 #define ACC_BM1_PRD 0x2C -#define ACC_BM2_PRD 0x34 -#define ACC_BM3_PRD 0x3C -#define ACC_BM4_PRD 0x44 -#define ACC_BM5_PRD 0x4C -#define ACC_BM6_PRD 0x54 -#define ACC_BM7_PRD 0x5C #define ACC_BM0_STATUS 0x21 #define ACC_BM1_STATUS 0x29 -#define ACC_BM2_STATUS 0x31 -#define ACC_BM3_STATUS 0x39 -#define ACC_BM4_STATUS 0x41 -#define ACC_BM5_STATUS 0x49 -#define ACC_BM6_STATUS 0x51 -#define ACC_BM7_STATUS 0x59 #define ACC_BM0_PNTR 0x60 #define ACC_BM1_PNTR 0x64 -#define ACC_BM2_PNTR 0x68 -#define ACC_BM3_PNTR 0x6C -#define ACC_BM4_PNTR 0x70 -#define ACC_BM5_PNTR 0x74 -#define ACC_BM6_PNTR 0x78 -#define ACC_BM7_PNTR 0x7C + /* acc_codec bar0 reg bits */ /* ACC_IRQ_STATUS */ #define IRQ_STS 0 #define WU_IRQ_STS 1 #define BM0_IRQ_STS 2 #define BM1_IRQ_STS 3 -#define BM2_IRQ_STS 4 -#define BM3_IRQ_STS 5 -#define BM4_IRQ_STS 6 -#define BM5_IRQ_STS 7 -#define BM6_IRQ_STS 8 -#define BM7_IRQ_STS 9 /* ACC_BMX_STATUS */ #define EOP (1<<0) #define BM_EOP_ERR (1<<1) /* ACC_BMX_CTL */ -#define BM_CTL_EN 0x00000001 -#define BM_CTL_PAUSE 0x00000011 -#define BM_CTL_DIS 0x00000000 -#define BM_CTL_BYTE_ORD_LE 0x00000000 -#define BM_CTL_BYTE_ORD_BE 0x00000100 +#define BM_CTL_EN 0x01 +#define BM_CTL_PAUSE 0x03 +#define BM_CTL_DIS 0x00 +#define BM_CTL_BYTE_ORD_LE 0x00 +#define BM_CTL_BYTE_ORD_BE 0x04 /* cs5535 specific ac97 codec register defines */ #define CMD_MASK 0xFF00FFFF #define CMD_NEW 0x00010000 @@ -106,7 +77,6 @@ struct cs5535audio_dma { struct snd_pcm_substream *substream; unsigned int buf_addr, buf_bytes; unsigned int period_bytes, periods; - int suspended; u32 saved_prd; }; diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 5450a9e..21df063 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -43,7 +43,6 @@ static struct snd_pcm_hardware snd_cs553 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_RESUME ), .formats = ( @@ -71,8 +70,7 @@ static struct snd_pcm_hardware snd_cs553 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_START + SNDRV_PCM_INFO_MMAP_VALID ), .formats = ( SNDRV_PCM_FMTBIT_S16_LE @@ -102,7 +100,6 @@ static int snd_cs5535audio_playback_open runtime->hw = snd_cs5535audio_playback; cs5535au->playback_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); - snd_pcm_set_sync(substream); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; @@ -164,6 +161,7 @@ static int cs5535audio_build_dma_packets jmpprd_addr = cpu_to_le32(lastdesc->addr + (sizeof(struct cs5535audio_dma_desc)*periods)); + dma->substream = substream; dma->period_bytes = period_bytes; dma->periods = periods; spin_lock_irq(&cs5535au->reg_lock); @@ -241,6 +239,7 @@ static void cs5535audio_clear_dma_packet { snd_dma_free_pages(&dma->desc_buf); dma->desc_buf.area = NULL; + dma->substream = NULL; } static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream, @@ -298,14 +297,12 @@ static int snd_cs5535audio_trigger(struc break; case SNDRV_PCM_TRIGGER_RESUME: dma->ops->enable_dma(cs5535au); - dma->suspended = 0; break; case SNDRV_PCM_TRIGGER_STOP: dma->ops->disable_dma(cs5535au); break; case SNDRV_PCM_TRIGGER_SUSPEND: dma->ops->disable_dma(cs5535au); - dma->suspended = 1; break; default: snd_printk(KERN_ERR "unhandled trigger\n"); @@ -348,7 +345,6 @@ static int snd_cs5535audio_capture_open( runtime->hw = snd_cs5535audio_capture; cs5535au->capture_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); - snd_pcm_set_sync(substream); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 3e4d198..838708f 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -64,18 +64,21 @@ int snd_cs5535audio_suspend(struct pci_d int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + snd_pcm_suspend_all(cs5535au->pcm); + snd_ac97_suspend(cs5535au->ac97); for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { struct cs5535audio_dma *dma = &cs5535au->dmas[i]; - if (dma && dma->substream && !dma->suspended) + if (dma && dma->substream) dma->saved_prd = dma->ops->read_prd(cs5535au); } - snd_pcm_suspend_all(cs5535au->pcm); - snd_ac97_suspend(cs5535au->ac97); /* save important regs, then disable aclink in hw */ snd_cs5535audio_stop_hardware(cs5535au); + if (pci_save_state(pci)) { + printk(KERN_ERR "cs5535audio: pci_save_state failed!\n"); + return -EIO; + } pci_disable_device(pci); - pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } @@ -89,7 +92,12 @@ int snd_cs5535audio_resume(struct pci_de int i; pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); + if (pci_restore_state(pci) < 0) { + printk(KERN_ERR "cs5535audio: pci_restore_state failed, " + "disabling device\n"); + snd_card_disconnect(card); + return -EIO; + } if (pci_enable_device(pci) < 0) { printk(KERN_ERR "cs5535audio: pci_enable_device failed, " "disabling device\n"); @@ -112,17 +120,17 @@ int snd_cs5535audio_resume(struct pci_de if (!timeout) snd_printk(KERN_ERR "Failure getting AC Link ready\n"); - /* we depend on ac97 to perform the codec power up */ - snd_ac97_resume(cs5535au->ac97); /* set up rate regs, dma. actual initiation is done in trig */ for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { struct cs5535audio_dma *dma = &cs5535au->dmas[i]; - if (dma && dma->substream && dma->suspended) { + if (dma && dma->substream) { dma->substream->ops->prepare(dma->substream); dma->ops->setup_prd(cs5535au, dma->saved_prd); } } - + + /* we depend on ac97 to perform the codec power up */ + snd_ac97_resume(cs5535au->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index f27b6a7..499ee1a 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1595,15 +1595,7 @@ #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */ #ifdef ECHOCARD_HAS_PHANTOM_POWER /******************* Phantom power switch *******************/ -static int snd_echo_phantom_power_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_echo_phantom_power_info snd_ctl_boolean_mono_info static int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1646,15 +1638,7 @@ #endif /* ECHOCARD_HAS_PHANTOM_POWER */ #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE /******************* Digital input automute switch *******************/ -static int snd_echo_automute_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_echo_automute_info snd_ctl_boolean_mono_info static int snd_echo_automute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1695,18 +1679,7 @@ #endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMU /******************* VU-meters switch *******************/ -static int snd_echo_vumeters_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_echo_vumeters_switch_info snd_ctl_boolean_mono_info static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 42afa83..e6c1007 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -43,11 +43,11 @@ static int wait_handshake(struct echoaud { int i; - /* Wait up to 10ms for the handshake from the DSP */ + /* Wait up to 20ms for the handshake from the DSP */ for (i = 0; i < HANDSHAKE_TIMEOUT; i++) { /* Look for the handshake value */ + barrier(); if (chip->comm_page->handshake) { - /*if (i) DE_ACT(("Handshake time: %d\n", i));*/ return 0; } udelay(1); diff --git a/sound/pci/echoaudio/echoaudio_dsp.h b/sound/pci/echoaudio/echoaudio_dsp.h index e55ee00..e352f3a 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.h +++ b/sound/pci/echoaudio/echoaudio_dsp.h @@ -642,18 +642,18 @@ struct comm_page { /* Base Length*/ u32 flags; /* See Appendix A below 0x004 4 */ u32 unused; /* Unused entry 0x008 4 */ u32 sample_rate; /* Card sample rate in Hz 0x00c 4 */ - volatile u32 handshake; /* DSP command handshake 0x010 4 */ + u32 handshake; /* DSP command handshake 0x010 4 */ u32 cmd_start; /* Chs. to start mask 0x014 4 */ u32 cmd_stop; /* Chs. to stop mask 0x018 4 */ u32 cmd_reset; /* Chs. to reset mask 0x01c 4 */ u16 audio_format[DSP_MAXPIPES]; /* Chs. audio format 0x020 32*2 */ struct sg_entry sglist_addr[DSP_MAXPIPES]; /* Chs. Physical sglist addrs 0x060 32*8 */ - volatile u32 position[DSP_MAXPIPES]; + u32 position[DSP_MAXPIPES]; /* Positions for ea. ch. 0x160 32*4 */ - volatile s8 vu_meter[DSP_MAXPIPES]; + s8 vu_meter[DSP_MAXPIPES]; /* VU meters 0x1e0 32*1 */ - volatile s8 peak_meter[DSP_MAXPIPES]; + s8 peak_meter[DSP_MAXPIPES]; /* Peak meters 0x200 32*1 */ s8 line_out_level[DSP_MAXAUDIOOUTPUTS]; /* Output gain 0x220 16*1 */ @@ -665,7 +665,7 @@ struct comm_page { /* Base Length*/ /* Gina/Darla play filters - obsolete 0x3c0 168*4 */ u32 rec_coeff[MAX_REC_TAPS]; /* Gina/Darla record filters - obsolete 0x660 192*4 */ - volatile u16 midi_input[MIDI_IN_BUFFER_SIZE]; + u16 midi_input[MIDI_IN_BUFFER_SIZE]; /* MIDI input data transfer buffer 0x960 256*2 */ u8 gd_clock_state; /* Chg Gina/Darla clock state 0xb60 1 */ u8 gd_spdif_status; /* Chg. Gina/Darla S/PDIF state 0xb61 1 */ @@ -674,11 +674,10 @@ struct comm_page { /* Base Length*/ u32 nominal_level_mask; /* -10 level enable mask 0xb64 4 */ u16 input_clock; /* Chg. Input clock state 0xb68 2 */ u16 output_clock; /* Chg. Output clock state 0xb6a 2 */ - volatile u32 status_clocks; - /* Current Input clock state 0xb6c 4 */ + u32 status_clocks; /* Current Input clock state 0xb6c 4 */ u32 ext_box_status; /* External box status 0xb70 4 */ u32 cmd_add_buffer; /* Pipes to add (obsolete) 0xb74 4 */ - volatile u32 midi_out_free_count; + u32 midi_out_free_count; /* # of bytes free in MIDI output FIFO 0xb78 4 */ u32 unused2; /* Cyclic pipes 0xb7c 4 */ u32 control_register; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 404ae1b..b112b29 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -31,6 +31,8 @@ * */ +#include +#include #include #include #include @@ -702,6 +704,65 @@ #endif return 0; } +int emu1010_firmware_thread(void *data) { + struct snd_emu10k1 * emu = data; + int tmp,tmp2; + int reg; + int err; + + for (;;) { + /* Delay to allow Audio Dock to settle */ + msleep(1000); + if (kthread_should_stop()) + break; + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ + if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { + /* Audio Dock attached */ + /* Return to Audio Dock programming mode */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); + if (emu->card_capabilities->emu1010 == 1) { + if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { + return err; + } + } else if (emu->card_capabilities->emu1010 == 2) { + if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + return err; + } + } else if (emu->card_capabilities->emu1010 == 3) { + if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + return err; + } + } + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + if ((reg & 0x1f) != 0x15) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + return 0; + return -ENODEV; + } + snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); + snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); + /* Sync clocking between 1010 and Dock */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all. Default is muted after a firmware load */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + } + } + return 0; +} + /* * EMU-1010 - details found out from this driver, official MS Win drivers, * testing the card: @@ -817,8 +878,16 @@ static int snd_emu10k1_emu1010_init(stru snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); - /* ADAT input. */ - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); + /* Optical -> ADAT I/O */ + /* 0 : SPDIF + * 1 : ADAT + */ + emu->emu1010.optical_in = 1; /* IN_ADAT */ + emu->emu1010.optical_out = 1; /* IN_ADAT */ + tmp = 0; + tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | + (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp ); snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); /* Set no attenuation on Audio Dock pads. */ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); @@ -1004,49 +1073,12 @@ #endif snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ - /* Delay to allow Audio Dock to settle */ - msleep(100); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ - /* FIXME: The loading of this should be able to happen any time, - * as the user can plug/unplug it at any time - */ - if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) { - /* Audio Dock attached */ - /* Return to Audio Dock programming mode */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); - if (emu->card_capabilities->emu1010 == 1) { - if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { - return err; - } - } else if (emu->card_capabilities->emu1010 == 2) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { - return err; - } - } else if (emu->card_capabilities->emu1010 == 3) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { - return err; - } - } + /* Start Micro/Audio Dock firmware loader thread */ + emu->emu1010.firmware_thread = kthread_create(&emu1010_firmware_thread, + emu, + "emu1010_firmware"); + wake_up_process(emu->emu1010.firmware_thread); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); - /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); - if ((reg & 0x3f) != 0x15) { - /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); - return 0; - return -ENODEV; - } - snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); - snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); - } #if 0 snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ @@ -1132,7 +1164,7 @@ #endif emu->emu1010.output_source[23] = 28; /* TEMP: Select SPDIF in/out */ - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ /* TEMP: Select 48kHz SPDIF out */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ @@ -1173,6 +1205,7 @@ static int snd_emu10k1_free(struct snd_e if (emu->card_capabilities->emu1010) { /* Disable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + kthread_stop(emu->emu1010.firmware_thread); } if (emu->memhdr) snd_util_memhdr_free(emu->memhdr); @@ -1722,8 +1755,9 @@ int __devinit snd_emu10k1_create(struct goto error; } - emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*)); - emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long)); + emu->page_ptr_table = vmalloc(emu->max_cache_pages * sizeof(void *)); + emu->page_addr_table = vmalloc(emu->max_cache_pages * + sizeof(unsigned long)); if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) { err = -ENOMEM; goto error; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index e4af7a9..1ec7eba 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1062,14 +1062,7 @@ static int __devinit snd_emu10k1x_proc_i return 0; } -static int snd_emu10k1x_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_emu10k1x_shared_spdif_info snd_ctl_boolean_mono_info static int snd_emu10k1x_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 7206c0f..3c503bb 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -642,10 +642,8 @@ snd_emu10k1_look_for_ctl(struct snd_emu1 { struct snd_emu10k1_fx8010_ctl *ctl; struct snd_kcontrol *kcontrol; - struct list_head *list; - - list_for_each(list, &emu->fx8010.gpr_ctl) { - ctl = emu10k1_gpr_ctl(list); + + list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) { kcontrol = ctl->kcontrol; if (kcontrol->id.iface == id->iface && !strcmp(kcontrol->id.name, id->name) && @@ -895,14 +893,12 @@ static int snd_emu10k1_list_controls(str struct snd_emu10k1_fx8010_control_gpr *gctl; struct snd_emu10k1_fx8010_ctl *ctl; struct snd_ctl_elem_id *id; - struct list_head *list; gctl = kmalloc(sizeof(*gctl), GFP_KERNEL); if (! gctl) return -ENOMEM; - list_for_each(list, &emu->fx8010.gpr_ctl) { - ctl = emu10k1_gpr_ctl(list); + list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) { total++; if (icode->gpr_list_controls && i < icode->gpr_list_control_count) { @@ -1207,7 +1203,7 @@ #if 1 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); gpr += 2; - + /* PCM Surround Playback (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); @@ -1267,8 +1263,16 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G /* emu1212 DSP 0 and DSP 1 Capture */ if (emu->card_capabilities->emu1010) { - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + if (emu->card_capabilities->ca0108_chip) { + /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ + A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp)); + A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp)); + } else { + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + } snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); gpr += 2; } @@ -1516,7 +1520,11 @@ #undef TREBLE_GPR /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ snd_printk("EMU outputs on\n"); for (z = 0; z < 8; z++) { - A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + if (emu->card_capabilities->ca0108_chip) { + A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } else { + A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } } } @@ -1557,106 +1565,116 @@ #else #endif if (emu->card_capabilities->emu1010) { - snd_printk("EMU inputs on\n"); - /* Capture 16 (originally 8) channels of S32_LE sound */ - - /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ - /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ - /* A_P16VIN(0) is delayed by one sample, - * so all other A_P16VIN channels will need to also be delayed - */ - /* Left ADC in. 1 of 2 */ - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); - /* Right ADC in 1 of 2 */ - gpr_map[gpr++] = 0x00000000; - /* Delaying by one sample: instead of copying the input - * value A_P16VIN to output A_FXBUS2 as in the first channel, - * we use an auxiliary register, delaying the value by one - * sample - */ - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); - /* For 96kHz mode */ - /* Left ADC in. 2 of 2 */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); - /* Right ADC in 2 of 2 */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); - /* Pavel Hofman - we still have voices, A_FXBUS2s, and - * A_P16VINs available - - * let's add 8 more capture channels - total of 16 - */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x10)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x12)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x14)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x16)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x18)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1a)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1c)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1e)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf), - A_C_00000000, A_C_00000000); + if (emu->card_capabilities->ca0108_chip) { + snd_printk("EMU2 inputs on\n"); + for (z = 0; z < 0x10; z++) { + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, + bit_shifter16, + A3_EMU32IN(z), + A_FXBUS2(z*2) ); + } + } else { + snd_printk("EMU inputs on\n"); + /* Capture 16 (originally 8) channels of S32_LE sound */ + + /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ + /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ + /* A_P16VIN(0) is delayed by one sample, + * so all other A_P16VIN channels will need to also be delayed + */ + /* Left ADC in. 1 of 2 */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); + /* Right ADC in 1 of 2 */ + gpr_map[gpr++] = 0x00000000; + /* Delaying by one sample: instead of copying the input + * value A_P16VIN to output A_FXBUS2 as in the first channel, + * we use an auxiliary register, delaying the value by one + * sample + */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); + /* For 96kHz mode */ + /* Left ADC in. 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); + /* Right ADC in 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); + /* Pavel Hofman - we still have voices, A_FXBUS2s, and + * A_P16VINs available - + * let's add 8 more capture channels - total of 16 + */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x10)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x12)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x14)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x16)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x18)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x1a)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x1c)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x1e)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf), + A_C_00000000, A_C_00000000); + } #if 0 for (z = 4; z < 8; z++) { @@ -2418,14 +2436,13 @@ static void copy_string(char *dst, char strcpy(dst, src); } -static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu, +static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_info *info) { char **fxbus, **extin, **extout; unsigned short fxbus_mask, extin_mask, extout_mask; int res; - memset(info, 0, sizeof(info)); info->internal_tram_size = emu->fx8010.itram_size; info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; fxbus = fxbuses; @@ -2442,7 +2459,6 @@ static int snd_emu10k1_fx8010_info(struc for (res = 16; res < 32; res++, extout++) copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res); info->gpr_controls = emu->fx8010.gpr_count; - return 0; } static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg) @@ -2463,10 +2479,7 @@ static int snd_emu10k1_fx8010_ioctl(stru info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) { - kfree(info); - return res; - } + snd_emu10k1_fx8010_info(emu, info); if (copy_to_user(argp, info, sizeof(*info))) { kfree(info); return -EFAULT; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 7b2c1dc..71ad5a0 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -400,15 +400,7 @@ static struct snd_kcontrol_new snd_emu10 - -static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -456,14 +448,7 @@ static struct snd_kcontrol_new snd_emu10 EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), }; -static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -516,17 +501,19 @@ static struct snd_kcontrol_new snd_emu10 static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { - "44100", "48000" + static char *texts[4] = { + "44100", "48000", "SPDIF", "ADAT" }; - + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; + uinfo->value.enumerated.items = 4; + 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; + + } static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, @@ -584,6 +571,44 @@ static int snd_emu1010_internal_clock_pu /* Unmute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); break; + + case 2: /* Take clock from S/PDIF IN */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, sync to S/PDIF input */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + + case 3: + /* Take clock from ADAT IN */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, sync to ADAT input */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + + + break; } } return change; @@ -871,7 +896,7 @@ static struct snd_kcontrol_new snd_emu10 .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), - .count = 4, + .count = 3, .info = snd_emu10k1_spdif_info, .get = snd_emu10k1_spdif_get_mask }; @@ -880,7 +905,7 @@ static struct snd_kcontrol_new snd_emu10 { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), - .count = 4, + .count = 3, .info = snd_emu10k1_spdif_info, .get = snd_emu10k1_spdif_get, .put = snd_emu10k1_spdif_put @@ -1326,14 +1351,7 @@ static struct snd_kcontrol_new snd_emu10 .put = snd_emu10k1_efx_attn_put }; -static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 2c15859..3e2ed1d 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -240,8 +240,42 @@ static void snd_emu10k1_proc_spdif_read( struct snd_info_buffer *buffer) { struct snd_emu10k1 *emu = entry->private_data; - snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); - snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); + u32 value; + u32 value2; + unsigned long flags; + u32 rate; + + if (emu->card_capabilities->emu1010) { + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x38, &value); + spin_unlock_irqrestore(&emu->emu_lock, flags); + if ((value & 0x1) == 0) { + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x2a, &value); + snd_emu1010_fpga_read(emu, 0x2b, &value2); + spin_unlock_irqrestore(&emu->emu_lock, flags); + rate = 0x1770000 / (((value << 5) | value2)+1); + snd_iprintf(buffer, "ADAT Locked : %u\n", rate); + } else { + snd_iprintf(buffer, "ADAT Unlocked\n"); + } + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x20, &value); + spin_unlock_irqrestore(&emu->emu_lock, flags); + if ((value & 0x4) == 0) { + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x28, &value); + snd_emu1010_fpga_read(emu, 0x29, &value2); + spin_unlock_irqrestore(&emu->emu_lock, flags); + rate = 0x1770000 / (((value << 5) | value2)+1); + snd_iprintf(buffer, "SPDIF Locked : %d\n", rate); + } else { + snd_iprintf(buffer, "SPDIF Unlocked\n"); + } + } else { + snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); + snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); + } #if 0 val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); snd_iprintf(buffer, "\nZoomed Video\n"); @@ -379,20 +413,16 @@ static void snd_emu_proc_emu1010_reg_rea struct snd_info_buffer *buffer) { struct snd_emu10k1 *emu = entry->private_data; - unsigned long value; + int value; unsigned long flags; - unsigned long regs; int i; snd_iprintf(buffer, "EMU1010 Registers:\n\n"); - for(i = 0; i < 0x30; i+=1) { + for(i = 0; i < 0x40; i+=1) { spin_lock_irqsave(&emu->emu_lock, flags); - regs=i+0x40; /* 0x40 upwards are registers. */ - outl(regs, emu->port + A_IOCFG); - outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - value = inl(emu->port + A_IOCFG); + snd_emu1010_fpga_read(emu, i, &value); spin_unlock_irqrestore(&emu->emu_lock, flags); - snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f); + snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f); } } @@ -555,9 +585,9 @@ int __devinit snd_emu10k1_proc_init(stru { struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG - if ((emu->card_capabilities->emu1010) && - snd_card_proc_new(emu->card, "emu1010_regs", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); + if (emu->card_capabilities->emu1010) { + if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) + snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); } if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 116e1c8..971458b 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -226,9 +226,9 @@ int snd_emu10k1_i2c_write(struct snd_emu return 0; } -int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) +int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) { - if (reg < 0 || reg > 0x3f) + if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ @@ -244,9 +244,9 @@ int snd_emu1010_fpga_write(struct snd_em return 0; } -int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) +int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) { - if (reg < 0 || reg > 0x3f) + if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ outl(reg, emu->port + A_IOCFG); @@ -261,7 +261,7 @@ int snd_emu1010_fpga_read(struct snd_emu /* Each Destination has one and only one Source, * but one Source can feed any number of Destinations simultaneously. */ -int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src) +int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src) { snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 7ee19c6..d619a38 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -124,11 +124,12 @@ #define CONTROL_SIDE_CHANNEL 2 /* hardware definition */ static struct snd_pcm_hardware snd_p16v_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_MMAP_VALID), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START, .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, .rate_min = 44100, @@ -207,6 +208,11 @@ static int snd_p16v_pcm_open_playback_ch if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; + runtime->sync.id32[0] = substream->pcm->card->number; + runtime->sync.id32[1] = 'P'; + runtime->sync.id32[2] = 16; + runtime->sync.id32[3] = 'V'; + return 0; } /* open_capture callback */ @@ -448,6 +454,9 @@ static int snd_p16v_pcm_trigger_playback break; } snd_pcm_group_for_each_entry(s, substream) { + if (snd_pcm_substream_chip(s) != emu || + s->stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; runtime = s->runtime; epcm = runtime->private_data; channel = substream->pcm->device-emu->p16v_device_offset; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 21cb426..9017bdb 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1419,15 +1419,7 @@ #define ES1371_SPDIF(xname) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_es1371_spdif_info, \ .get = snd_es1371_spdif_get, .put = snd_es1371_spdif_put } -static int snd_es1371_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1371_spdif_info snd_ctl_boolean_mono_info static int snd_es1371_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1489,15 +1481,7 @@ static struct snd_kcontrol_new snd_es137 }; -static int snd_es1373_rear_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1373_rear_info snd_ctl_boolean_mono_info static int snd_es1373_rear_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1542,15 +1526,7 @@ static struct snd_kcontrol_new snd_ens13 .put = snd_es1373_rear_put, }; -static int snd_es1373_line_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1373_line_info snd_ctl_boolean_mono_info static int snd_es1373_line_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1707,15 +1683,7 @@ #define ENSONIQ_CONTROL(xname, mask) \ .get = snd_ensoniq_control_get, .put = snd_ensoniq_control_put, \ .private_value = mask } -static int snd_ensoniq_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ensoniq_control_info snd_ctl_boolean_mono_info static int snd_ensoniq_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fec29a1..fc686db 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1066,15 +1066,7 @@ static int snd_es1938_put_mux(struct snd return snd_es1938_mixer_bits(chip, 0x1c, 0x07, val) != val; } -static int snd_es1938_info_spatializer_enable(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1938_info_spatializer_enable snd_ctl_boolean_mono_info static int snd_es1938_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1120,15 +1112,7 @@ static int snd_es1938_get_hw_volume(stru return 0; } -static int snd_es1938_info_hw_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1938_info_hw_switch snd_ctl_boolean_stereo_info static int snd_es1938_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 2faf009..d69b11d 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -843,10 +843,9 @@ static void snd_es1968_bob_dec(struct es snd_es1968_bob_stop(chip); else if (chip->bob_freq > ESM_BOB_FREQ) { /* check reduction of timer frequency */ - struct list_head *p; int max_freq = ESM_BOB_FREQ; - list_for_each(p, &chip->substream_list) { - struct esschan *es = list_entry(p, struct esschan, list); + struct esschan *es; + list_for_each_entry(es, &chip->substream_list, list) { if (max_freq < es->bob_freq) max_freq = es->bob_freq; } @@ -1316,12 +1315,11 @@ static struct snd_pcm_hardware snd_es196 static int calc_available_memory_size(struct es1968 *chip) { - struct list_head *p; int max_size = 0; - + struct esm_memory *buf; + mutex_lock(&chip->memory_mutex); - list_for_each(p, &chip->buf_list) { - struct esm_memory *buf = list_entry(p, struct esm_memory, list); + list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes > max_size) max_size = buf->buf.bytes; } @@ -1335,12 +1333,10 @@ static int calc_available_memory_size(st static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size) { struct esm_memory *buf; - struct list_head *p; - + size = ALIGN(size, ESM_MEM_ALIGN); mutex_lock(&chip->memory_mutex); - list_for_each(p, &chip->buf_list) { - buf = list_entry(p, struct esm_memory, list); + list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes >= size) goto __found; } @@ -1938,10 +1934,9 @@ static irqreturn_t snd_es1968_interrupt( } if (event & ESM_SOUND_IRQ) { - struct list_head *p; + struct esschan *es; spin_lock(&chip->substream_lock); - list_for_each(p, &chip->substream_list) { - struct esschan *es = list_entry(p, struct esschan, list); + list_for_each_entry(es, &chip->substream_list, list) { if (es->running) snd_es1968_update_pcm(chip, es); } @@ -2345,7 +2340,7 @@ static int es1968_resume(struct pci_dev { struct snd_card *card = pci_get_drvdata(pci); struct es1968 *chip = card->private_data; - struct list_head *p; + struct esschan *es; if (! chip->do_pm) return 0; @@ -2374,8 +2369,7 @@ static int es1968_resume(struct pci_dev /* restore ac97 state */ snd_ac97_resume(chip->ac97); - list_for_each(p, &chip->substream_list) { - struct esschan *es = list_entry(p, struct esschan, list); + list_for_each_entry(es, &chip->substream_list, list) { switch (es->mode) { case ESM_MODE_PLAY: snd_es1968_playback_setup(chip, es, es->substream->runtime); diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index b2484bb..ab0c726 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,19 +1,18 @@ -snd-hda-intel-objs := hda_intel.o +snd-hda-intel-y := hda_intel.o # since snd-hda-intel is the only driver using hda-codec, # merge it into a single module although it was originally # designed to be individual modules -snd-hda-intel-objs += hda_codec.o \ - hda_generic.o \ - patch_realtek.o \ - patch_cmedia.o \ - patch_analog.o \ - patch_sigmatel.o \ - patch_si3054.o \ - patch_atihdmi.o \ - patch_conexant.o \ - patch_via.o -ifdef CONFIG_PROC_FS -snd-hda-intel-objs += hda_proc.o -endif +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_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 +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o +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 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f87f8f0..18ef0aa 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -31,7 +31,15 @@ #include #include #include #include "hda_local.h" - +#include + +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* define this option here to hide as static */ +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, int, 0644); +MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); +#endif /* * vendor / preset table @@ -59,6 +67,13 @@ static struct hda_vendor_id hda_vendor_i #include "hda_patch.h" +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_power_work(struct work_struct *work); +static void hda_keep_power_on(struct hda_codec *codec); +#else +static inline void hda_keep_power_on(struct hda_codec *codec) {} +#endif + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -76,12 +91,14 @@ unsigned int snd_hda_codec_read(struct h unsigned int verb, unsigned int parm) { unsigned int res; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) res = codec->bus->ops.get_response(codec); else res = (unsigned int)-1; mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return res; } @@ -101,9 +118,11 @@ int snd_hda_codec_write(struct hda_codec unsigned int verb, unsigned int parm) { int err; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); err = codec->bus->ops.command(codec, nid, direct, verb, parm); mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return err; } @@ -136,6 +155,8 @@ int snd_hda_get_sub_nodes(struct hda_cod unsigned int parm; parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); + if (parm == -1) + return 0; *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } @@ -387,6 +408,13 @@ int __devinit snd_hda_bus_new(struct snd return 0; } +#ifdef CONFIG_SND_HDA_GENERIC +#define is_generic_config(codec) \ + (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) +#else +#define is_generic_config(codec) 0 +#endif + /* * find a matching codec preset */ @@ -395,7 +423,7 @@ find_codec_preset(struct hda_codec *code { const struct hda_codec_preset **tbl, *preset; - if (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) + if (is_generic_config(codec)) return NULL; /* use the generic parser */ for (tbl = hda_preset_tables; *tbl; tbl++) { @@ -486,6 +514,10 @@ static int read_widget_caps(struct hda_c } +static void init_hda_cache(struct hda_cache_rec *cache, + unsigned int record_size); +static void free_hda_cache(struct hda_cache_rec *cache); + /* * codec destructor */ @@ -493,17 +525,20 @@ static void snd_hda_codec_free(struct hd { if (!codec) return; +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); + flush_scheduled_work(); +#endif list_del(&codec->list); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); - kfree(codec->amp_info); + free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); kfree(codec->wcaps); kfree(codec); } -static void init_amp_hash(struct hda_codec *codec); - /** * snd_hda_codec_new - create a HDA codec * @bus: the bus to assign @@ -537,7 +572,17 @@ int __devinit snd_hda_codec_new(struct h codec->bus = bus; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); - init_amp_hash(codec); + init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); + +#ifdef CONFIG_SND_HDA_POWER_SAVE + INIT_DELAYED_WORK(&codec->power_work, hda_power_work); + /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. + * the caller has to power down appropriatley after initialization + * phase. + */ + hda_keep_power_on(codec); +#endif list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -581,10 +626,26 @@ int __devinit snd_hda_codec_new(struct h snd_hda_get_codec_name(codec, bus->card->mixername, sizeof(bus->card->mixername)); - if (codec->preset && codec->preset->patch) - err = codec->preset->patch(codec); - else +#ifdef CONFIG_SND_HDA_GENERIC + if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); + goto patched; + } +#endif + if (codec->preset && codec->preset->patch) { + err = codec->preset->patch(codec); + goto patched; + } + + /* call the default parser */ +#ifdef CONFIG_SND_HDA_GENERIC + err = snd_hda_parse_generic_codec(codec); +#else + printk(KERN_ERR "hda-codec: No codec parser is available\n"); + err = -ENODEV; +#endif + + patched: if (err < 0) { snd_hda_codec_free(codec); return err; @@ -594,6 +655,9 @@ int __devinit snd_hda_codec_new(struct h init_unsol_queue(bus); snd_hda_codec_proc_new(codec); +#ifdef CONFIG_SND_HDA_HWDEP + snd_hda_create_hwdep(codec); +#endif sprintf(component, "HDA:%08x", codec->vendor_id); snd_component_add(codec->bus->card, component); @@ -637,59 +701,72 @@ #define INFO_AMP_CAPS (1<<0) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void __devinit init_amp_hash(struct hda_codec *codec) +static void __devinit init_hda_cache(struct hda_cache_rec *cache, + unsigned int record_size) { - memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); - codec->num_amp_entries = 0; - codec->amp_info_size = 0; - codec->amp_info = NULL; + memset(cache, 0, sizeof(*cache)); + memset(cache->hash, 0xff, sizeof(cache->hash)); + cache->record_size = record_size; +} + +static void free_hda_cache(struct hda_cache_rec *cache) +{ + kfree(cache->buffer); } /* query the hash. allocate an entry if not found. */ -static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) +static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, + u32 key) { - u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); - u16 cur = codec->amp_hash[idx]; - struct hda_amp_info *info; + u16 idx = key % (u16)ARRAY_SIZE(cache->hash); + u16 cur = cache->hash[idx]; + struct hda_cache_head *info; while (cur != 0xffff) { - info = &codec->amp_info[cur]; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ - if (codec->num_amp_entries >= codec->amp_info_size) { + if (cache->num_entries >= cache->size) { /* reallocate the array */ - int new_size = codec->amp_info_size + 64; - struct hda_amp_info *new_info; - new_info = kcalloc(new_size, sizeof(struct hda_amp_info), - GFP_KERNEL); - if (!new_info) { + unsigned int new_size = cache->size + 64; + void *new_buffer; + new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); + if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } - if (codec->amp_info) { - memcpy(new_info, codec->amp_info, - codec->amp_info_size * - sizeof(struct hda_amp_info)); - kfree(codec->amp_info); + if (cache->buffer) { + memcpy(new_buffer, cache->buffer, + cache->size * cache->record_size); + kfree(cache->buffer); } - codec->amp_info_size = new_size; - codec->amp_info = new_info; + cache->size = new_size; + cache->buffer = new_buffer; } - cur = codec->num_amp_entries++; - info = &codec->amp_info[cur]; + cur = cache->num_entries++; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); info->key = key; - info->status = 0; /* not initialized yet */ - info->next = codec->amp_hash[idx]; - codec->amp_hash[idx] = cur; + info->val = 0; + info->next = cache->hash[idx]; + cache->hash[idx] = cur; return info; } +/* query and allocate an amp hash entry */ +static inline struct hda_amp_info * +get_alloc_amp_hash(struct hda_codec *codec, u32 key) +{ + return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); +} + /* * query AMP capabilities for the given widget and direction */ @@ -700,7 +777,7 @@ static u32 query_amp_caps(struct hda_cod info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); if (!info) return 0; - if (!(info->status & INFO_AMP_CAPS)) { + if (!(info->head.val & INFO_AMP_CAPS)) { if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) nid = codec->afg; info->amp_caps = snd_hda_param_read(codec, nid, @@ -708,7 +785,7 @@ static u32 query_amp_caps(struct hda_cod AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); if (info->amp_caps) - info->status |= INFO_AMP_CAPS; + info->head.val |= INFO_AMP_CAPS; } return info->amp_caps; } @@ -722,7 +799,7 @@ int snd_hda_override_amp_caps(struct hda if (!info) return -EINVAL; info->amp_caps = caps; - info->status |= INFO_AMP_CAPS; + info->head.val |= INFO_AMP_CAPS; return 0; } @@ -736,7 +813,7 @@ static unsigned int get_vol_mute(struct { u32 val, parm; - if (info->status & INFO_AMP_VOL(ch)) + if (info->head.val & INFO_AMP_VOL(ch)) return info->vol[ch]; parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; @@ -745,7 +822,7 @@ static unsigned int get_vol_mute(struct val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); info->vol[ch] = val & 0xff; - info->status |= INFO_AMP_VOL(ch); + info->head.val |= INFO_AMP_VOL(ch); return info->vol[ch]; } @@ -792,12 +869,50 @@ int snd_hda_codec_amp_update(struct hda_ return 0; val &= mask; val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; - if (info->vol[ch] == val && !codec->in_resume) + if (info->vol[ch] == val) return 0; put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } +/* + * update the AMP stereo with the same mask and value + */ +int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, + int direction, int idx, int mask, int val) +{ + int ch, ret = 0; + for (ch = 0; ch < 2; ch++) + ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, + idx, mask, val); + return ret; +} + +#ifdef SND_HDA_NEEDS_RESUME +/* resume the all amp commands from the cache */ +void snd_hda_codec_resume_amp(struct hda_codec *codec) +{ + struct hda_amp_info *buffer = codec->amp_cache.buffer; + int i; + + for (i = 0; i < codec->amp_cache.size; i++, buffer++) { + u32 key = buffer->head.key; + hda_nid_t nid; + unsigned int idx, dir, ch; + if (!key) + continue; + nid = key & 0xff; + idx = (key >> 16) & 0xff; + dir = (key >> 24) & 0xff; + for (ch = 0; ch < 2; ch++) { + if (!(buffer->head.val & INFO_AMP_VOL(ch))) + continue; + put_vol_mute(codec, buffer, nid, ch, dir, idx, + buffer->vol[ch]); + } + } +} +#endif /* SND_HDA_NEEDS_RESUME */ /* * AMP control callbacks @@ -844,9 +959,11 @@ int snd_hda_mixer_amp_volume_get(struct long *valp = ucontrol->value.integer.value; if (chs & 1) - *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; + *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) + & HDA_AMP_VOLMASK; if (chs & 2) - *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; + *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) + & HDA_AMP_VOLMASK; return 0; } @@ -861,6 +978,7 @@ int snd_hda_mixer_amp_volume_put(struct long *valp = ucontrol->value.integer.value; int change = 0; + snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 0x7f, *valp); @@ -869,6 +987,7 @@ int snd_hda_mixer_amp_volume_put(struct if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 0x7f, *valp); + snd_hda_power_down(codec); return change; } @@ -923,10 +1042,10 @@ int snd_hda_mixer_amp_switch_get(struct if (chs & 1) *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & - 0x80) ? 0 : 1; + HDA_AMP_MUTE) ? 0 : 1; if (chs & 2) *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & - 0x80) ? 0 : 1; + HDA_AMP_MUTE) ? 0 : 1; return 0; } @@ -941,15 +1060,22 @@ int snd_hda_mixer_amp_switch_put(struct long *valp = ucontrol->value.integer.value; int change = 0; + snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - 0x80, *valp ? 0 : 0x80); + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE); valp++; } if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - 0x80, *valp ? 0 : 0x80); - + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, nid); +#endif + snd_hda_power_down(codec); return change; } @@ -1002,6 +1128,93 @@ int snd_hda_mixer_bind_switch_put(struct } /* + * generic bound volume/swtich controls + */ +int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->info(kcontrol, uinfo); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->get(kcontrol, ucontrol); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + unsigned long *vals; + int err = 0, change = 0; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + for (vals = c->values; *vals; vals++) { + kcontrol->private_value = *vals; + err = c->ops->put(kcontrol, ucontrol); + if (err < 0) + break; + change |= err; + } + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err < 0 ? err : change; +} + +int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +struct hda_ctl_ops snd_hda_bind_vol = { + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = snd_hda_mixer_amp_volume_put, + .tlv = snd_hda_mixer_amp_tlv +}; + +struct hda_ctl_ops snd_hda_bind_sw = { + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = snd_hda_mixer_amp_switch_put, + .tlv = snd_hda_mixer_amp_tlv +}; + +/* * SPDIF out controls */ @@ -1118,26 +1331,20 @@ static int snd_hda_spdif_default_put(str change = codec->spdif_ctls != val; codec->spdif_ctls = val; - if (change || codec->in_resume) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, - val >> 8); + 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); } mutex_unlock(&codec->spdif_mutex); return change; } -static int snd_hda_spdif_out_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1161,17 +1368,16 @@ static int snd_hda_spdif_out_switch_put( if (ucontrol->value.integer.value[0]) val |= AC_DIG1_ENABLE; change = codec->spdif_ctls != val; - if (change || codec->in_resume) { + if (change) { codec->spdif_ctls = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + val & 0xff); /* unmute amp switch (if any) */ if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && (val & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | - AC_AMP_SET_OUTPUT); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); } mutex_unlock(&codec->spdif_mutex); return change; @@ -1219,8 +1425,7 @@ static struct snd_kcontrol_new dig_mixes * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t nid) +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; @@ -1264,10 +1469,10 @@ static int snd_hda_spdif_in_switch_put(s mutex_lock(&codec->spdif_mutex); change = codec->spdif_in_enable != val; - if (change || codec->in_resume) { + if (change) { codec->spdif_in_enable = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, val); } mutex_unlock(&codec->spdif_mutex); return change; @@ -1318,8 +1523,7 @@ static struct snd_kcontrol_new dig_in_ct * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, - hda_nid_t nid) +int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; @@ -1338,6 +1542,79 @@ int __devinit snd_hda_create_spdif_in_ct return 0; } +#ifdef SND_HDA_NEEDS_RESUME +/* + * command cache + */ + +/* build a 32bit cache key with the widget id and the command parameter */ +#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) +#define get_cmd_cache_nid(key) ((key) & 0xff) +#define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) + +/** + * snd_hda_codec_write_cache - send a single command with caching + * @codec: the HDA codec + * @nid: NID to send the command + * @direct: direct flag + * @verb: the verb to send + * @parm: the parameter for the verb + * + * Send a single command without waiting for response. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) +{ + int err; + snd_hda_power_up(codec); + mutex_lock(&codec->bus->cmd_mutex); + err = codec->bus->ops.command(codec, nid, direct, verb, parm); + if (!err) { + struct hda_cache_head *c; + u32 key = build_cmd_cache_key(nid, verb); + c = get_alloc_hash(&codec->cmd_cache, key); + if (c) + c->val = parm; + } + mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); + return err; +} + +/* resume the all commands from the cache */ +void snd_hda_codec_resume_cache(struct hda_codec *codec) +{ + struct hda_cache_head *buffer = codec->cmd_cache.buffer; + int i; + + for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { + u32 key = buffer->key; + if (!key) + continue; + snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, + get_cmd_cache_cmd(key), buffer->val); + } +} + +/** + * snd_hda_sequence_write_cache - sequence writes with caching + * @codec: the HDA codec + * @seq: VERB array to send + * + * Send the commands sequentially from the given array. + * Thte commands are recorded on cache for power-save and resume. + * The array must be terminated with NID=0. + */ +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq) +{ + for (; seq->nid; seq++) + snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, + seq->param); +} +#endif /* SND_HDA_NEEDS_RESUME */ /* * set power state of the codec @@ -1345,24 +1622,73 @@ int __devinit snd_hda_create_spdif_in_ct static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state) { - hda_nid_t nid, nid_start; - int nodes; + hda_nid_t nid; + int i; snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); - nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { if (get_wcaps(codec, nid) & AC_WCAP_POWER) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, power_state); } - if (power_state == AC_PWRST_D0) + if (power_state == AC_PWRST_D0) { + unsigned long end_time; + int state; msleep(10); + /* wait until the codec reachs to D0 */ + end_time = jiffies + msecs_to_jiffies(500); + do { + state = snd_hda_codec_read(codec, fg, 0, + AC_VERB_GET_POWER_STATE, 0); + if (state == power_state) + break; + msleep(1); + } while (time_after_eq(end_time, jiffies)); + } } +#ifdef SND_HDA_NEEDS_RESUME +/* + * call suspend and power-down; used both from PM and power-save + */ +static void hda_call_codec_suspend(struct hda_codec *codec) +{ + if (codec->patch_ops.suspend) + codec->patch_ops.suspend(codec, PMSG_SUSPEND); + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D3); +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); + codec->power_on = 0; + codec->power_transition = 0; +#endif +} + +/* + * kick up codec; used both from PM and power-save + */ +static void hda_call_codec_resume(struct hda_codec *codec) +{ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D0); + if (codec->patch_ops.resume) + codec->patch_ops.resume(codec); + else { + if (codec->patch_ops.init) + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + } +} +#endif /* SND_HDA_NEEDS_RESUME */ + /** * snd_hda_build_controls - build mixer controls @@ -1376,28 +1702,24 @@ int __devinit snd_hda_build_controls(str { struct hda_codec *codec; - /* build controls */ list_for_each_entry(codec, &bus->codec_list, list) { - int err; - if (!codec->patch_ops.build_controls) - continue; - err = codec->patch_ops.build_controls(codec); - if (err < 0) - return err; - } - - /* initialize */ - list_for_each_entry(codec, &bus->codec_list, list) { - int err; + int err = 0; + /* fake as if already powered-on */ + hda_keep_power_on(codec); + /* then fire up */ hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); - if (!codec->patch_ops.init) - continue; - err = codec->patch_ops.init(codec); + /* continue to initialize... */ + if (codec->patch_ops.init) + err = codec->patch_ops.init(codec); + if (!err && codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + snd_hda_power_down(codec); if (err < 0) return err; } + return 0; } @@ -1789,9 +2111,9 @@ int __devinit snd_hda_build_pcms(struct * * If no entries are matching, the function returns a negative value. */ -int __devinit snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char **models, - const struct snd_pci_quirk *tbl) +int snd_hda_check_board_config(struct hda_codec *codec, + int num_configs, const char **models, + const struct snd_pci_quirk *tbl) { if (codec->bus->modelname && models) { int i; @@ -1841,10 +2163,9 @@ #endif * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_add_new_ctls(struct hda_codec *codec, - struct snd_kcontrol_new *knew) +int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) { - int err; + int err; for (; knew->name; knew++) { struct snd_kcontrol *kctl; @@ -1867,6 +2188,93 @@ int __devinit snd_hda_add_new_ctls(struc return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state); + +static void hda_power_work(struct work_struct *work) +{ + struct hda_codec *codec = + container_of(work, struct hda_codec, power_work.work); + + if (!codec->power_on || codec->power_count) { + codec->power_transition = 0; + return; + } + + hda_call_codec_suspend(codec); + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); +} + +static void hda_keep_power_on(struct hda_codec *codec) +{ + codec->power_count++; + codec->power_on = 1; +} + +void snd_hda_power_up(struct hda_codec *codec) +{ + codec->power_count++; + if (codec->power_on || codec->power_transition) + return; + + codec->power_on = 1; + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); + hda_call_codec_resume(codec); + cancel_delayed_work(&codec->power_work); + codec->power_transition = 0; +} + +void snd_hda_power_down(struct hda_codec *codec) +{ + --codec->power_count; + if (!codec->power_on || codec->power_count || codec->power_transition) + return; + if (power_save) { + codec->power_transition = 1; /* avoid reentrance */ + schedule_delayed_work(&codec->power_work, + msecs_to_jiffies(power_save * 1000)); + } +} + +int snd_hda_check_amp_list_power(struct hda_codec *codec, + struct hda_loopback_check *check, + hda_nid_t nid) +{ + struct hda_amp_list *p; + int ch, v; + + if (!check->amplist) + return 0; + for (p = check->amplist; p->nid; p++) { + if (p->nid == nid) + break; + } + if (!p->nid) + return 0; /* nothing changed */ + + for (p = check->amplist; p->nid; p++) { + for (ch = 0; ch < 2; ch++) { + v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, + p->idx); + if (!(v & HDA_AMP_MUTE) && v > 0) { + if (!check->power_on) { + check->power_on = 1; + snd_hda_power_up(codec); + } + return 1; + } + } + } + if (check->power_on) { + check->power_on = 0; + snd_hda_power_down(codec); + } + return 0; +} +#endif /* * Channel mode helper @@ -1913,12 +2321,12 @@ int snd_hda_ch_mode_put(struct hda_codec mode = ucontrol->value.enumerated.item[0]; snd_assert(mode < num_chmodes, return -EINVAL); - if (*max_channelsp == chmode[mode].channels && !codec->in_resume) + if (*max_channelsp == chmode[mode].channels) return 0; /* change the current channel setting */ *max_channelsp = chmode[mode].channels; if (chmode[mode].sequence) - snd_hda_sequence_write(codec, chmode[mode].sequence); + snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } @@ -1951,10 +2359,10 @@ int snd_hda_input_mux_put(struct hda_cod idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, + imux->items[idx].index); *cur_val = idx; return 1; } @@ -2118,7 +2526,7 @@ int snd_hda_multi_out_analog_cleanup(str * Helper for automatic ping configuration */ -static int __devinit is_in_nid_list(hda_nid_t nid, hda_nid_t *list) +static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) { for (; *list; list++) if (*list == nid) @@ -2169,9 +2577,9 @@ static void sort_pins_by_sequence(hda_ni * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ -int __devinit snd_hda_parse_pin_def_config(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids) +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + hda_nid_t *ignore_nids) { hda_nid_t nid, nid_start; int nodes; @@ -2371,13 +2779,12 @@ int snd_hda_suspend(struct hda_bus *bus, { struct hda_codec *codec; - /* FIXME: should handle power widget capabilities */ list_for_each_entry(codec, &bus->codec_list, list) { - if (codec->patch_ops.suspend) - codec->patch_ops.suspend(codec, state); - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D3); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif + hda_call_codec_suspend(codec); } return 0; } @@ -2388,76 +2795,30 @@ int snd_hda_suspend(struct hda_bus *bus, * @state: resume state * * Returns 0 if successful. + * + * This fucntion is defined only when POWER_SAVE isn't set. + * In the power-save mode, the codec is resumed dynamically. */ int snd_hda_resume(struct hda_bus *bus) { struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - if (codec->patch_ops.resume) - codec->patch_ops.resume(codec); + if (snd_hda_codec_needs_resume(codec)) + hda_call_codec_resume(codec); } return 0; } - -/** - * snd_hda_resume_ctls - resume controls in the new control list - * @codec: the HDA codec - * @knew: the array of struct snd_kcontrol_new - * - * This function resumes the mixer controls in the struct snd_kcontrol_new array, - * originally for snd_hda_add_new_ctls(). - * The array must be terminated with an empty entry as terminator. - */ -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) +#ifdef CONFIG_SND_HDA_POWER_SAVE +int snd_hda_codecs_inuse(struct hda_bus *bus) { - struct snd_ctl_elem_value *val; + struct hda_codec *codec; - val = kmalloc(sizeof(*val), GFP_KERNEL); - if (!val) - return -ENOMEM; - codec->in_resume = 1; - for (; knew->name; knew++) { - int i, count; - count = knew->count ? knew->count : 1; - for (i = 0; i < count; i++) { - memset(val, 0, sizeof(*val)); - val->id.iface = knew->iface; - val->id.device = knew->device; - val->id.subdevice = knew->subdevice; - strcpy(val->id.name, knew->name); - val->id.index = knew->index ? knew->index : i; - /* Assume that get callback reads only from cache, - * not accessing to the real hardware - */ - if (snd_ctl_elem_read(codec->bus->card, val) < 0) - continue; - snd_ctl_elem_write(codec->bus->card, NULL, val); - } + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; } - codec->in_resume = 0; - kfree(val); return 0; } - -/** - * snd_hda_resume_spdif_out - resume the digital out - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_out(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_mixes); -} - -/** - * snd_hda_resume_spdif_in - resume the digital in - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_in(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_in_ctls); -} +#endif #endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 56c26e7..2bce925 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -24,6 +24,11 @@ #define __SOUND_HDA_CODEC_H #include #include #include +#include + +#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) +#define SND_HDA_NEEDS_RESUME /* resume control code is required */ +#endif /* * nodes @@ -199,7 +204,9 @@ #define AC_AMPCAP_OFFSET (0x7f<<0) /* #define AC_AMPCAP_OFFSET_SHIFT 0 #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ #define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB in 0.25dB */ +#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB + * in 0.25dB + */ #define AC_AMPCAP_STEP_SIZE_SHIFT 16 #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ #define AC_AMPCAP_MUTE_SHIFT 31 @@ -409,6 +416,10 @@ struct hda_bus_ops { unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + /* notify power-up/down from codec to contoller */ + void (*pm_notify)(struct hda_codec *codec); +#endif }; /* template to pass to the bus constructor */ @@ -436,7 +447,8 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; - struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ + /* link caddr -> codec */ + struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; struct mutex cmd_mutex; @@ -469,19 +481,34 @@ struct hda_codec_ops { int (*init)(struct hda_codec *codec); void (*free)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME int (*suspend)(struct hda_codec *codec, pm_message_t state); int (*resume)(struct hda_codec *codec); #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE + int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); +#endif }; /* record for amp information cache */ -struct hda_amp_info { +struct hda_cache_head { u32 key; /* hash key */ + u16 val; /* assigned value */ + u16 next; /* next link; -1 = terminal */ +}; + +struct hda_amp_info { + struct hda_cache_head head; u32 amp_caps; /* amp capabilities */ u16 vol[2]; /* current volume & mute */ - u16 status; /* update flag */ - u16 next; /* next link */ +}; + +struct hda_cache_rec { + u16 hash[64]; /* hash table for index */ + unsigned int num_entries; /* number of assigned entries */ + unsigned int size; /* allocated size */ + unsigned int record_size; /* record size (including header) */ + void *buffer; /* hash table entries */ }; /* PCM callbacks */ @@ -499,7 +526,7 @@ struct hda_pcm_ops { /* PCM information for each substream */ struct hda_pcm_stream { - unsigned int substreams; /* number of substreams, 0 = not exist */ + unsigned int substreams; /* number of substreams, 0 = not exist*/ unsigned int channels_min; /* min. number of channels */ unsigned int channels_max; /* max. number of channels */ hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ @@ -536,11 +563,6 @@ struct hda_codec { /* set by patch */ struct hda_codec_ops patch_ops; - /* resume phase - all controls should update even if - * the values are not changed - */ - unsigned int in_resume; - /* PCM to create, set by patch_ops.build_pcms callback */ unsigned int num_pcms; struct hda_pcm *pcm_info; @@ -553,16 +575,22 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; - /* hash for amp access */ - u16 amp_hash[32]; - int num_amp_entries; - int amp_info_size; - struct hda_amp_info *amp_info; + struct hda_cache_rec amp_cache; /* cache for amp access */ + struct hda_cache_rec cmd_cache; /* cache for other commands */ struct mutex spdif_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ + + struct snd_hwdep *hwdep; /* assigned hwdep device */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE + unsigned int power_on :1; /* current (global) power-state */ + unsigned int power_transition :1; /* power-state in transition */ + int power_count; /* current (global) power refcount */ + struct delayed_work power_work; /* delayed task for powerdown */ +#endif }; /* direction */ @@ -582,13 +610,17 @@ int snd_hda_codec_new(struct hda_bus *bu /* * low level functions */ -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, +unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); -#define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) -int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); +#define snd_hda_param_read(codec, nid, param) \ + snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) +int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *start_id); +int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); struct hda_verb { hda_nid_t nid; @@ -596,11 +628,24 @@ struct hda_verb { u32 param; }; -void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq); +void snd_hda_sequence_write(struct hda_codec *codec, + const struct hda_verb *seq); /* unsolicited event */ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); +/* cached write */ +#ifdef SND_HDA_NEEDS_RESUME +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq); +void snd_hda_codec_resume_cache(struct hda_codec *codec); +#else +#define snd_hda_codec_write_cache snd_hda_codec_write +#define snd_hda_sequence_write_cache snd_hda_sequence_write +#endif + /* * Mixer */ @@ -610,10 +655,13 @@ int snd_hda_build_controls(struct hda_bu * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); -void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, +void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int channel_id, int format); -unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, - unsigned int format, unsigned int maxbps); +unsigned int snd_hda_calc_stream_format(unsigned int rate, + unsigned int channels, + unsigned int format, + unsigned int maxbps); int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, @@ -632,4 +680,19 @@ int snd_hda_suspend(struct hda_bus *bus, int snd_hda_resume(struct hda_bus *bus); #endif +/* + * power saving + */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +void snd_hda_power_up(struct hda_codec *codec); +void snd_hda_power_down(struct hda_codec *codec); +#define snd_hda_codec_needs_resume(codec) codec->power_count +int snd_hda_codecs_inuse(struct hda_bus *bus); +#else +static inline void snd_hda_power_up(struct hda_codec *codec) {} +static inline void snd_hda_power_down(struct hda_codec *codec) {} +#define snd_hda_codec_needs_resume(codec) 1 +#define snd_hda_codecs_inuse(bus) 1 +#endif + #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 000287f..c957eb5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -70,6 +70,13 @@ struct hda_gspec { struct hda_pcm pcm_rec; /* PCM information */ struct list_head nid_list; /* list of widgets */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define MAX_LOOPBACK_AMPS 7 + struct hda_loopback_check loopback; + int num_loopbacks; + struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; +#endif }; /* @@ -88,13 +95,12 @@ #define defcfg_port_conn(node) (((node)- static void snd_hda_generic_free(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p, *n; + struct hda_gnode *node, *n; if (! spec) return; /* free all widgets */ - list_for_each_safe(p, n, &spec->nid_list) { - struct hda_gnode *node = list_entry(p, struct hda_gnode, list); + list_for_each_entry_safe(node, n, &spec->nid_list, list) { if (node->conn_list != node->slist) kfree(node->conn_list); kfree(node); @@ -196,11 +202,9 @@ static int build_afg_tree(struct hda_cod /* FIXME: should avoid the braindead linear search */ static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) { - struct list_head *p; struct hda_gnode *node; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->nid == nid) return node; } @@ -218,9 +222,8 @@ static int unmute_output(struct hda_code ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_OUTPUT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); + return 0; } /* @@ -234,11 +237,8 @@ static int unmute_input(struct hda_codec ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_INPUT; - // awk added - fixed to allow unmuting of indexed amps - val |= index << AC_AMP_SET_INDEX_SHIFT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); + return 0; } /* @@ -248,7 +248,8 @@ static int select_input_connection(struc unsigned int index) { snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); + return snd_hda_codec_write_cache(codec, node->nid, 0, + AC_VERB_SET_CONNECT_SEL, index); } /* @@ -256,11 +257,9 @@ static int select_input_connection(struc */ static void clear_check_flags(struct hda_gspec *spec) { - struct list_head *p; struct hda_gnode *node; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { node->checked = 0; } } @@ -343,12 +342,10 @@ static struct hda_gnode *parse_output_ja struct hda_gspec *spec, int jack_type) { - struct list_head *p; struct hda_gnode *node; int err; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->type != AC_WID_PIN) continue; /* output capable? */ @@ -379,7 +376,7 @@ static struct hda_gnode *parse_output_ja /* unmute the PIN output */ unmute_output(codec, node); /* set PIN-Out enable */ - snd_hda_codec_write(codec, node->nid, 0, + snd_hda_codec_write_cache(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN | ((node->pin_caps & AC_PINCAP_HP_DRV) ? @@ -570,7 +567,8 @@ static int parse_adc_sub_nodes(struct hd /* unmute the PIN external input */ unmute_input(codec, node, 0); /* index = 0? */ /* set PIN-In enable */ - snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + snd_hda_codec_write_cache(codec, node->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); return 1; /* found */ } @@ -659,7 +657,6 @@ static int parse_input_path(struct hda_c static int parse_input(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p; struct hda_gnode *node; int err; @@ -668,8 +665,7 @@ static int parse_input(struct hda_codec * If it reaches to certain input PINs, we take it as the * input path. */ - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->wid_caps & AC_WCAP_DIGITAL) continue; /* skip SPDIF */ if (node->type == AC_WID_AUD_IN) { @@ -684,11 +680,33 @@ static int parse_input(struct hda_codec return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx) +{ + struct hda_gspec *spec = codec->spec; + struct hda_amp_list *p; + + if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { + snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); + return; + } + p = &spec->loopback_list[spec->num_loopbacks++]; + p->nid = nid; + p->dir = dir; + p->idx = idx; + spec->loopback.amplist = spec->loopback_list; +} +#else +#define add_input_loopback(codec,nid,dir,idx) +#endif + /* * create mixer controls if possible */ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index, const char *type, const char *dir_sfx) + unsigned int index, const char *type, + const char *dir_sfx, int is_loopback) { char name[32]; int err; @@ -702,6 +720,8 @@ static int create_mixer(struct hda_codec if ((node->wid_caps & AC_WCAP_IN_AMP) && (node->amp_in_caps & AC_AMPCAP_MUTE)) { knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); + if (is_loopback) + add_input_loopback(codec, node->nid, HDA_INPUT, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; @@ -709,6 +729,8 @@ static int create_mixer(struct hda_codec } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && (node->amp_out_caps & AC_AMPCAP_MUTE)) { knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); + if (is_loopback) + add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; @@ -767,7 +789,7 @@ static int create_output_mixers(struct h for (i = 0; i < spec->pcm_vol_nodes; i++) { err = create_mixer(codec, spec->pcm_vol[i].node, spec->pcm_vol[i].index, - names[i], "Playback"); + names[i], "Playback", 0); if (err < 0) return err; } @@ -784,7 +806,7 @@ static int build_output_controls(struct case 1: return create_mixer(codec, spec->pcm_vol[0].node, spec->pcm_vol[0].index, - "Master", "Playback"); + "Master", "Playback", 0); case 2: if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) return create_output_mixers(codec, types_speaker); @@ -820,7 +842,7 @@ static int build_input_controls(struct h if (spec->input_mux.num_items == 1) { err = create_mixer(codec, adc_node, spec->input_mux.items[0].index, - NULL, "Capture"); + NULL, "Capture", 0); if (err < 0) return err; return 0; @@ -886,7 +908,8 @@ static int parse_loopback_path(struct hd return err; else if (err >= 1) { if (err == 1) { - err = create_mixer(codec, node, i, type, "Playback"); + err = create_mixer(codec, node, i, type, + "Playback", 1); if (err < 0) return err; if (err > 0) @@ -911,7 +934,6 @@ static int parse_loopback_path(struct hd static int build_loopback_controls(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p; struct hda_gnode *node; int err; const char *type; @@ -919,8 +941,7 @@ static int build_loopback_controls(struc if (! spec->out_pin_node[0]) return 0; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->type != AC_WID_PIN) continue; /* input capable? */ @@ -1022,6 +1043,14 @@ static int build_generic_pcms(struct hda return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_gspec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* */ @@ -1029,6 +1058,9 @@ static struct hda_codec_ops generic_patc .build_controls = build_generic_controls, .build_pcms = build_generic_pcms, .free = snd_hda_generic_free, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = generic_check_power_status, +#endif }; /* diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c new file mode 100644 index 0000000..bafb7b0 --- /dev/null +++ b/sound/pci/hda/hda_hwdep.c @@ -0,0 +1,122 @@ +/* + * HWDEP Interface for HD-audio codec + * + * Copyright (c) 2007 Takashi Iwai + * + * 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 +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" +#include + +/* + * write/read an out-of-bound verb + */ +static int verb_write_ioctl(struct hda_codec *codec, + struct hda_verb_ioctl __user *arg) +{ + u32 verb, res; + + if (get_user(verb, &arg->verb)) + return -EFAULT; + res = snd_hda_codec_read(codec, verb >> 24, 0, + (verb >> 8) & 0xffff, verb & 0xff); + if (put_user(res, &arg->res)) + return -EFAULT; + return 0; +} + +static int get_wcap_ioctl(struct hda_codec *codec, + struct hda_verb_ioctl __user *arg) +{ + u32 verb, res; + + if (get_user(verb, &arg->verb)) + return -EFAULT; + res = get_wcaps(codec, verb >> 24); + if (put_user(res, &arg->res)) + return -EFAULT; + return 0; +} + + +/* + */ +static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct hda_codec *codec = hw->private_data; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case HDA_IOCTL_PVERSION: + return put_user(HDA_HWDEP_VERSION, (int __user *)argp); + case HDA_IOCTL_VERB_WRITE: + return verb_write_ioctl(codec, argp); + case HDA_IOCTL_GET_WCAP: + return get_wcap_ioctl(codec, argp); + } + return -ENOIOCTLCMD; +} + +#ifdef CONFIG_COMPAT +static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) +{ +#ifndef CONFIG_SND_DEBUG_DETECT + if (!capable(CAP_SYS_RAWIO)) + return -EACCES; +#endif + return 0; +} + +int __devinit snd_hda_create_hwdep(struct hda_codec *codec) +{ + char hwname[16]; + struct snd_hwdep *hwdep; + int err; + + sprintf(hwname, "HDA Codec %d", codec->addr); + err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep); + if (err < 0) + return err; + codec->hwdep = hwdep; + sprintf(hwdep->name, "HDA Codec %d", codec->addr); + hwdep->iface = SNDRV_HWDEP_IFACE_HDA; + hwdep->private_data = codec; + hwdep->exclusive = 1; + + hwdep->ops.open = hda_hwdep_open; + hwdep->ops.ioctl = hda_hwdep_ioctl; +#ifdef CONFIG_COMPAT + hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; +#endif + + return 0; +} diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 92bc8b3..3fa0f97 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1,6 +1,7 @@ /* * - * hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio. + * hda_intel.c - Implementation of primary alsa driver code base + * for Intel HD Audio. * * Copyright(c) 2004 Intel Corporation. All rights reserved. * @@ -64,14 +65,27 @@ MODULE_PARM_DESC(id, "ID string for Inte module_param(model, charp, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param(position_fix, int, 0444); -MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); +MODULE_PARM_DESC(position_fix, "Fix DMA pointer " + "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); module_param(probe_mask, int, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param(single_cmd, bool, 0444); -MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); +MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " + "(for debugging only)."); module_param(enable_msi, int, 0); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* power_save option is defined in hda_codec.c */ + +/* reset the HD-audio controller in power save mode. + * this may give more power-saving, but will take longer time to + * wake up. + */ +static int power_save_controller = 1; +module_param(power_save_controller, bool, 0644); +MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); +#endif /* just for backward compatibility */ static int enable; @@ -98,6 +112,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " + /* * registers */ @@ -213,15 +228,16 @@ #define SD_CTL_STREAM_TAG_SHIFT 20 #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ #define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE) +#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ + SD_INT_COMPLETE) /* SD_STS */ #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ /* GCTL unsolicited response enable bit */ #define ICH6_GCTL_UREN (1<<8) @@ -257,22 +273,26 @@ #define NVIDIA_HDA_ENABLE_COHBITS 0x */ struct azx_dev { - u32 *bdl; /* virtual address of the BDL */ - dma_addr_t bdl_addr; /* physical address of the BDL */ - u32 *posbuf; /* position buffer pointer */ + u32 *bdl; /* virtual address of the BDL */ + dma_addr_t bdl_addr; /* physical address of the BDL */ + u32 *posbuf; /* position buffer pointer */ - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int fragsize; /* size of each period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ + unsigned int bufsize; /* size of the play buffer in bytes */ + unsigned int fragsize; /* size of each period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ - void __iomem *sd_addr; /* stream descriptor pointer */ + void __iomem *sd_addr; /* stream descriptor pointer */ - u32 sd_int_sta_mask; /* stream int status mask */ + u32 sd_int_sta_mask; /* stream int status mask */ /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, set in PCM open */ - unsigned int format_val; /* format value to be set in the controller and the codec */ + struct snd_pcm_substream *substream; /* assigned substream, + * set in PCM open + */ + unsigned int format_val; /* format value to be set in the + * controller and the codec + */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ /* for sanity check of position buffer */ @@ -337,6 +357,7 @@ struct azx { /* flags */ int position_fix; + unsigned int running :1; unsigned int initialized :1; unsigned int single_cmd :1; unsigned int polling_mode :1; @@ -418,7 +439,8 @@ static int azx_alloc_cmd_io(struct azx * int err; /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->rb); if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); @@ -531,9 +553,9 @@ static unsigned int azx_rirb_get_respons azx_update_rirb(chip); spin_unlock_irq(&chip->reg_lock); } - if (! chip->rirb.cmds) + if (!chip->rirb.cmds) return chip->rirb.res; /* the last value */ - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(timeout, jiffies)); if (chip->msi) { @@ -585,16 +607,19 @@ static int azx_single_send_cmd(struct hd while (timeout--) { /* check ICB busy bit */ - if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) { + if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { /* Clear IRV valid bit */ - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_VALID); azx_writel(chip, IC, val); - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_BUSY); return 0; } udelay(1); } - snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val); + snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", + azx_readw(chip, IRS), val); return -EIO; } @@ -610,7 +635,8 @@ static unsigned int azx_single_get_respo return azx_readl(chip, IR); udelay(1); } - snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); + snd_printd(SFX "get_response timeout: IRS=0x%x\n", + azx_readw(chip, IRS)); return (unsigned int)-1; } @@ -652,12 +678,18 @@ static unsigned int azx_get_response(str return azx_rirb_get_response(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void azx_power_notify(struct hda_codec *codec); +#endif /* reset codec link */ static int azx_reset(struct azx *chip) { int count; + /* clear STATESTS */ + azx_writeb(chip, STATESTS, STATESTS_INT_MASK); + /* reset controller */ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); @@ -777,18 +809,12 @@ static void azx_stream_stop(struct azx * /* - * initialize the chip + * reset and start the controller registers */ static void azx_init_chip(struct azx *chip) { - unsigned char reg; - - /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio codecs - */ - pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); - pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); + if (chip->initialized) + return; /* reset controller */ azx_reset(chip); @@ -805,19 +831,45 @@ static void azx_init_chip(struct azx *ch azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); + chip->initialized = 1; +} + +/* + * initialize the PCI registers + */ +/* update bits in a PCI register byte */ +static void update_pci_byte(struct pci_dev *pci, unsigned int reg, + unsigned char mask, unsigned char val) +{ + unsigned char data; + + pci_read_config_byte(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_byte(pci, reg, data); +} + +static void azx_init_pci(struct azx *chip) +{ + /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio + * codecs + */ + update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + switch (chip->driver_type) { case AZX_DRIVER_ATI: /* For ATI SB450 azalia HD audio, we need to enable snoop */ - pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - ®); - pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); + update_pci_byte(chip->pci, + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); break; case AZX_DRIVER_NVIDIA: /* For NVIDIA HDA, enable snoop */ - pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, ®); - pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, - (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS); + update_pci_byte(chip->pci, + NVIDIA_HDA_TRANSREG_ADDR, + 0x0f, NVIDIA_HDA_ENABLE_COHBITS); break; } } @@ -857,7 +909,7 @@ static irqreturn_t azx_interrupt(int irq /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (! chip->single_cmd && (status & RIRB_INT_RESPONSE)) + if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) azx_update_rirb(chip); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -911,9 +963,11 @@ static int azx_setup_controller(struct a int timeout; /* make sure the run bit is zero for SD */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START); + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & + ~SD_CTL_DMA_START); /* reset stream */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET); + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | + SD_CTL_STREAM_RESET); udelay(3); timeout = 300; while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && @@ -931,7 +985,7 @@ static int azx_setup_controller(struct a /* program the stream_tag */ azx_sd_writel(azx_dev, SD_CTL, - (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) | + (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); /* program the length of samples in cyclic buffer */ @@ -951,11 +1005,13 @@ static int azx_setup_controller(struct a azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, + (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE); /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); + azx_sd_writel(azx_dev, SD_CTL, + azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); return 0; } @@ -986,8 +1042,12 @@ static int __devinit azx_codec_create(st bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; +#ifdef CONFIG_SND_HDA_POWER_SAVE + bus_temp.ops.pm_notify = azx_power_notify; +#endif - if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0) + err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); + if (err < 0) return err; codecs = audio_codecs = 0; @@ -1038,7 +1098,7 @@ static inline struct azx_dev *azx_assign nums = chip->capture_streams; } for (i = 0; i < nums; i++, dev++) - if (! chip->azx_dev[dev].opened) { + if (!chip->azx_dev[dev].opened) { chip->azx_dev[dev].opened = 1; return &chip->azx_dev[dev]; } @@ -1052,7 +1112,8 @@ static inline void azx_release_device(st } static struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | /* No full-resume yet implemented */ @@ -1105,8 +1166,11 @@ static int azx_pcm_open(struct snd_pcm_s 128); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); - if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { + snd_hda_power_up(apcm->codec); + err = hinfo->ops.open(hinfo, apcm->codec, substream); + if (err < 0) { azx_release_device(azx_dev); + snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return err; } @@ -1135,13 +1199,16 @@ static int azx_pcm_close(struct snd_pcm_ spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); hinfo->ops.close(hinfo, apcm->codec, substream); + snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return 0; } -static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) +static int azx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); } static int azx_pcm_hw_free(struct snd_pcm_substream *substream) @@ -1175,13 +1242,15 @@ static int azx_pcm_prepare(struct snd_pc runtime->channels, runtime->format, hinfo->maxbps); - if (! azx_dev->format_val) { - snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", + if (!azx_dev->format_val) { + snd_printk(KERN_ERR SFX + "invalid format_val, rate=%d, ch=%d, format=%d\n", runtime->rate, runtime->channels, runtime->format); return -EINVAL; } - snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n", + snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, " + "format=0x%x\n", azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); azx_setup_periods(azx_dev); azx_setup_controller(chip, azx_dev); @@ -1223,7 +1292,8 @@ static int azx_pcm_trigger(struct snd_pc cmd == SNDRV_PCM_TRIGGER_SUSPEND || cmd == SNDRV_PCM_TRIGGER_STOP) { int timeout = 5000; - while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) + while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) && + --timeout) ; } return err; @@ -1241,7 +1311,7 @@ static snd_pcm_uframes_t azx_pcm_pointer /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); if (chip->position_fix == POS_FIX_AUTO && - azx_dev->period_intr == 1 && ! pos) { + azx_dev->period_intr == 1 && !pos) { printk(KERN_WARNING "hda-intel: Invalid position buffer, " "using LPIB read method instead.\n"); @@ -1292,7 +1362,8 @@ static int __devinit create_codec_pcm(st snd_assert(cpcm->name, return -EINVAL); err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, - cpcm->stream[0].substreams, cpcm->stream[1].substreams, + cpcm->stream[0].substreams, + cpcm->stream[1].substreams, &pcm); if (err < 0) return err; @@ -1322,26 +1393,27 @@ static int __devinit create_codec_pcm(st static int __devinit azx_pcm_create(struct azx *chip) { - struct list_head *p; struct hda_codec *codec; int c, err; int pcm_dev; - if ((err = snd_hda_build_pcms(chip->bus)) < 0) + err = snd_hda_build_pcms(chip->bus); + if (err < 0) return err; /* create audio PCMs */ pcm_dev = 0; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { if (codec->pcm_info[c].is_modem) continue; /* create later */ if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { - snd_printk(KERN_ERR SFX "Too many audio PCMs\n"); + snd_printk(KERN_ERR SFX + "Too many audio PCMs\n"); return -EINVAL; } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + err = create_codec_pcm(chip, codec, + &codec->pcm_info[c], pcm_dev); if (err < 0) return err; pcm_dev++; @@ -1350,16 +1422,17 @@ static int __devinit azx_pcm_create(stru /* create modem PCMs */ pcm_dev = AZX_MAX_AUDIO_PCMS; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { - if (! codec->pcm_info[c].is_modem) + if (!codec->pcm_info[c].is_modem) continue; /* already created */ if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); + snd_printk(KERN_ERR SFX + "Too many modem PCMs\n"); return -EINVAL; } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + err = create_codec_pcm(chip, codec, + &codec->pcm_info[c], pcm_dev); if (err < 0) return err; chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; @@ -1386,7 +1459,8 @@ static int __devinit azx_init_stream(str int i; /* initialize each stream (aka device) - * assign the starting bdl address to each stream (device) and initialize + * assign the starting bdl address to each stream (device) + * and initialize */ for (i = 0; i < chip->num_streams; i++) { unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); @@ -1423,6 +1497,46 @@ static int azx_acquire_irq(struct azx *c } +static void azx_stop_chip(struct azx *chip) +{ + if (!chip->initialized) + return; + + /* disable interrupts */ + azx_int_disable(chip); + azx_int_clear(chip); + + /* disable CORB/RIRB */ + azx_free_cmd_io(chip); + + /* disable position buffer */ + azx_writel(chip, DPLBASE, 0); + azx_writel(chip, DPUBASE, 0); + + chip->initialized = 0; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* power-up/down the controller */ +static void azx_power_notify(struct hda_codec *codec) +{ + struct azx *chip = codec->bus->private_data; + struct hda_codec *c; + int power_on = 0; + + list_for_each_entry(c, &codec->bus->codec_list, list) { + if (c->power_on) { + power_on = 1; + break; + } + } + if (power_on) + azx_init_chip(chip); + else if (chip->running && power_save_controller) + azx_stop_chip(chip); +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #ifdef CONFIG_PM /* * power management @@ -1436,8 +1550,9 @@ static int azx_suspend(struct pci_dev *p snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); - snd_hda_suspend(chip->bus, state); - azx_free_cmd_io(chip); + if (chip->initialized) + snd_hda_suspend(chip->bus, state); + azx_stop_chip(chip); if (chip->irq >= 0) { synchronize_irq(chip->irq); free_irq(chip->irq, chip); @@ -1470,7 +1585,11 @@ static int azx_resume(struct pci_dev *pc chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; - azx_init_chip(chip); + azx_init_pci(chip); + + if (snd_hda_codecs_inuse(chip->bus)) + azx_init_chip(chip); + snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; @@ -1485,20 +1604,9 @@ static int azx_free(struct azx *chip) { if (chip->initialized) { int i; - for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); + azx_stop_chip(chip); } if (chip->irq >= 0) { @@ -1534,6 +1642,7 @@ static int azx_dev_free(struct snd_devic */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), + SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), {} }; @@ -1544,7 +1653,7 @@ static int __devinit check_position_fix( if (fix == POS_FIX_AUTO) { q = snd_pci_quirk_lookup(chip->pci, position_fix_list); if (q) { - snd_printdd(KERN_INFO + printk(KERN_INFO "hda_intel: position_fix set to %d " "for device %04x:%04x\n", q->value, q->subvendor, q->subdevice); @@ -1555,6 +1664,36 @@ static int __devinit check_position_fix( } /* + * black-lists for probe_mask + */ +static struct snd_pci_quirk probe_mask_list[] __devinitdata = { + /* Thinkpad often breaks the controller communication when accessing + * to the non-working (or non-existing) modem codec slot. + */ + SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + {} +}; + +static void __devinit check_probe_mask(struct azx *chip) +{ + const struct snd_pci_quirk *q; + + if (probe_mask == -1) { + q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); + if (q) { + printk(KERN_INFO + "hda_intel: probe_mask set to 0x%x " + "for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); + probe_mask = q->value; + } + } +} + + +/* * constructor */ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, @@ -1589,6 +1728,7 @@ static int __devinit azx_create(struct s chip->msi = enable_msi; chip->position_fix = check_position_fix(chip, position_fix); + check_probe_mask(chip); chip->single_cmd = single_cmd; @@ -1650,37 +1790,43 @@ #endif break; } chip->num_streams = chip->playback_streams + chip->capture_streams; - chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); + chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), + GFP_KERNEL); if (!chip->azx_dev) { snd_printk(KERN_ERR "cannot malloc azx_dev\n"); goto errout; } /* allocate memory for the BDL for each stream */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - BDL_SIZE, &chip->bdl)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + BDL_SIZE, &chip->bdl); + if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - chip->num_streams * 8, &chip->posbuf)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + chip->num_streams * 8, &chip->posbuf); + if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); goto errout; } /* allocate CORB/RIRB */ - if (! chip->single_cmd) - if ((err = azx_alloc_cmd_io(chip)) < 0) + if (!chip->single_cmd) { + err = azx_alloc_cmd_io(chip); + if (err < 0) goto errout; + } /* initialize streams */ azx_init_stream(chip); /* initialize chip */ + azx_init_pci(chip); azx_init_chip(chip); - chip->initialized = 1; - /* codec detection */ if (!chip->codec_mask) { snd_printk(KERN_ERR SFX "no codecs found!\n"); @@ -1688,14 +1834,16 @@ #endif goto errout; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err <0) { snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); goto errout; } strcpy(card->driver, "HDA-Intel"); strcpy(card->shortname, driver_short_names[chip->driver_type]); - sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; @@ -1705,7 +1853,21 @@ #endif return err; } -static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +static void power_down_all_codecs(struct azx *chip) +{ +#ifdef CONFIG_SND_HDA_POWER_SAVE + /* The codecs were powered up in snd_hda_codec_new(). + * Now all initialization done, so turn them down if possible + */ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) { + snd_hda_power_down(codec); + } +#endif +} + +static int __devinit azx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct azx *chip; @@ -1725,31 +1887,37 @@ static int __devinit azx_probe(struct pc card->private_data = chip; /* create codec instances */ - if ((err = azx_codec_create(chip, model)) < 0) { + err = azx_codec_create(chip, model); + if (err < 0) { snd_card_free(card); return err; } /* create PCM streams */ - if ((err = azx_pcm_create(chip)) < 0) { + err = azx_pcm_create(chip); + if (err < 0) { snd_card_free(card); return err; } /* create mixer controls */ - if ((err = azx_mixer_create(chip)) < 0) { + err = azx_mixer_create(chip); + if (err < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pci->dev); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, card); + chip->running = 1; + power_down_all_codecs(chip); return err; } @@ -1791,6 +1959,10 @@ static struct pci_device_id azx_ids[] = { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ + { 0x10de, 0x0ac0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index f91ea5e..a79d0ed 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -26,7 +26,8 @@ #define __SOUND_HDA_LOCAL_H /* * for mixer controls */ -#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) +#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ + ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ @@ -64,18 +65,35 @@ #define HDA_CODEC_MUTE_MONO(xname, nid, #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) -int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); -int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv); +int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); /* lowlevel accessor with caching; use carefully */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); +int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val); +#ifdef SND_HDA_NEEDS_RESUME +void snd_hda_codec_resume_amp(struct hda_codec *codec); +#endif + +/* amp value bits */ +#define HDA_AMP_MUTE 0x80 +#define HDA_AMP_UNMUTE 0x00 +#define HDA_AMP_VOLMASK 0x7f /* mono switch binding multiple inputs */ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ @@ -86,11 +104,61 @@ #define HDA_BIND_MUTE_MONO(xname, nid, c .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } /* stereo switch binding multiple inputs */ -#define HDA_BIND_MUTE(xname,nid,indices,dir) HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) +#define HDA_BIND_MUTE(xname,nid,indices,dir) \ + HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) + +int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +/* more generic bound controls */ +struct hda_ctl_ops { + snd_kcontrol_info_t *info; + snd_kcontrol_get_t *get; + snd_kcontrol_put_t *put; + snd_kcontrol_tlv_rw_t *tlv; +}; -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +extern struct hda_ctl_ops snd_hda_bind_vol; /* for bind-volume with TLV */ +extern struct hda_ctl_ops snd_hda_bind_sw; /* for bind-switch */ +struct hda_bind_ctls { + struct hda_ctl_ops *ops; + long values[]; +}; + +int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv); + +#define HDA_BIND_VOL(xname, bindrec) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ + SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,\ + .info = snd_hda_mixer_bind_ctls_info,\ + .get = snd_hda_mixer_bind_ctls_get,\ + .put = snd_hda_mixer_bind_ctls_put,\ + .tlv = { .c = snd_hda_mixer_bind_tlv },\ + .private_value = (long) (bindrec) } +#define HDA_BIND_SW(xname, bindrec) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ + .name = xname, \ + .info = snd_hda_mixer_bind_ctls_info,\ + .get = snd_hda_mixer_bind_ctls_get,\ + .put = snd_hda_mixer_bind_ctls_put,\ + .private_value = (long) (bindrec) } + +/* + * SPDIF I/O + */ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); @@ -107,8 +175,10 @@ struct hda_input_mux { struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; }; -int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo); -int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, +int snd_hda_input_mux_info(const struct hda_input_mux *imux, + struct snd_ctl_elem_info *uinfo); +int snd_hda_input_mux_put(struct hda_codec *codec, + const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); @@ -120,13 +190,19 @@ struct hda_channel_mode { const struct hda_verb *sequence; }; -int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, int num_chmodes); -int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, +int snd_hda_ch_mode_info(struct hda_codec *codec, + struct snd_ctl_elem_info *uinfo, + const struct hda_channel_mode *chmode, + int num_chmodes); +int snd_hda_ch_mode_get(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol, + const struct hda_channel_mode *chmode, + int num_chmodes, int max_channels); -int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, +int snd_hda_ch_mode_put(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol, + const struct hda_channel_mode *chmode, + int num_chmodes, int *max_channelsp); /* @@ -146,20 +222,25 @@ struct hda_multi_out { int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ }; -int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); -int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); +int snd_hda_multi_out_dig_open(struct hda_codec *codec, + struct hda_multi_out *mout); +int snd_hda_multi_out_dig_close(struct hda_codec *codec, + struct hda_multi_out *mout); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, +int snd_hda_multi_out_analog_open(struct hda_codec *codec, + struct hda_multi_out *mout, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, +int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, + struct hda_multi_out *mout, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); +int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, + struct hda_multi_out *mout); /* * generic codec parser @@ -181,16 +262,8 @@ #endif int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **modelnames, const struct snd_pci_quirk *pci_list); -int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); - -/* - * power management - */ -#ifdef CONFIG_PM -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); -int snd_hda_resume_spdif_out(struct hda_codec *codec); -int snd_hda_resume_spdif_in(struct hda_codec *codec); -#endif +int snd_hda_add_new_ctls(struct hda_codec *codec, + struct snd_kcontrol_new *knew); /* * unsolicited event handler @@ -232,7 +305,9 @@ extern const char *auto_pin_cfg_labels[A struct auto_pin_cfg { int line_outs; - hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t line_out_pins[5]; /* sorted in the order of + * Front/Surr/CLFE/Side + */ int speaker_outs; hda_nid_t speaker_pins[5]; int hp_outs; @@ -243,13 +318,19 @@ struct auto_pin_cfg { hda_nid_t dig_in_pin; }; -#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) -#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) -#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) -#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) - -int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, +#define get_defcfg_connect(cfg) \ + ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) \ + ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_location(cfg) \ + ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define get_defcfg_sequence(cfg) \ + (cfg & AC_DEFCFG_SEQUENCE) +#define get_defcfg_device(cfg) \ + ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) + +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, hda_nid_t *ignore_nids); /* amp values */ @@ -280,4 +361,32 @@ static inline u32 get_wcaps(struct hda_c int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); +/* + * hwdep interface + */ +int snd_hda_create_hwdep(struct hda_codec *codec); + +/* + * power-management + */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +void snd_hda_schedule_power_save(struct hda_codec *codec); + +struct hda_amp_list { + hda_nid_t nid; + unsigned char dir; + unsigned char idx; +}; + +struct hda_loopback_check { + struct hda_amp_list *amplist; + int power_on; +}; + +int snd_hda_check_amp_list_power(struct hda_codec *codec, + struct hda_loopback_check *check, + hda_nid_t nid); +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 9f9e9ae..f5c23bb 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -20,13 +20,29 @@ extern struct hda_codec_preset snd_hda_p extern struct hda_codec_preset snd_hda_preset_via[]; static const struct hda_codec_preset *hda_preset_tables[] = { +#ifdef CONFIG_SND_HDA_CODEC_REALTEK snd_hda_preset_realtek, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CMEDIA snd_hda_preset_cmedia, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ANALOG snd_hda_preset_analog, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL snd_hda_preset_sigmatel, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SI3054 snd_hda_preset_si3054, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI snd_hda_preset_atihdmi, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CONEXANT snd_hda_preset_conexant, +#endif +#ifdef CONFIG_SND_HDA_CODEC_VIA snd_hda_preset_via, +#endif NULL }; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ac15066..e94944f 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -58,7 +58,8 @@ static void print_amp_caps(struct snd_in snd_iprintf(buffer, "N/A\n"); return; } - snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n", + snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, " + "mute=%x\n", caps & AC_AMPCAP_OFFSET, (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, @@ -76,11 +77,13 @@ static void print_amp_vals(struct snd_in for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); if (stereo) { - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_LEFT | dir | i); snd_iprintf(buffer, "0x%02x ", val); } - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_RIGHT | dir | i); snd_iprintf(buffer, "0x%02x]", val); } @@ -237,7 +240,8 @@ static void print_pin_caps(struct snd_in } -static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void print_codec_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct hda_codec *codec = entry->private_data; char buf[32]; @@ -258,6 +262,7 @@ static void print_codec_info(struct snd_ if (! codec->afg) return; + snd_hda_power_up(codec); snd_iprintf(buffer, "Default PCM:\n"); print_pcm_caps(buffer, codec, codec->afg); snd_iprintf(buffer, "Default Amp-In caps: "); @@ -268,12 +273,15 @@ static void print_codec_info(struct snd_ nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (! nid || nodes < 0) { snd_iprintf(buffer, "Invalid AFG subtree\n"); + snd_hda_power_down(codec); return; } for (i = 0; i < nodes; i++, nid++) { - unsigned int wid_caps = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int wid_caps = + snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = + (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; int conn_len = 0; hda_nid_t conn[HDA_MAX_CONNECTIONS]; @@ -313,7 +321,9 @@ static void print_codec_info(struct snd_ if (wid_type == AC_WID_PIN) { unsigned int pinctls; print_pin_caps(buffer, codec, nid); - pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + pinctls = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0); snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); if (pinctls & AC_PINCTL_IN_EN) snd_iprintf(buffer, " IN"); @@ -333,7 +343,8 @@ static void print_codec_info(struct snd_ if (wid_caps & AC_WCAP_POWER) snd_iprintf(buffer, " Power: 0x%x\n", snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0)); + AC_VERB_GET_POWER_STATE, + 0)); if (wid_caps & AC_WCAP_CONN_LIST) { int c, curr = -1; @@ -350,6 +361,7 @@ static void print_codec_info(struct snd_ snd_iprintf(buffer, "\n"); } } + snd_hda_power_down(codec); } /* diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4d7f8d1..54cfd45 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -73,6 +73,12 @@ struct ad198x_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + + unsigned int jack_present :1; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; /* @@ -144,6 +150,14 @@ static int ad198x_build_controls(struct return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* * Analog playback callbacks */ @@ -318,30 +332,13 @@ static void ad198x_free(struct hda_codec kfree(codec->spec); } -#ifdef CONFIG_PM -static int ad198x_resume(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - static struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, .init = ad198x_init, .free = ad198x_free, -#ifdef CONFIG_PM - .resume = ad198x_resume, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = ad198x_check_power_status, #endif }; @@ -350,15 +347,7 @@ #endif * EAPD control * the private value = nid | (invert << 8) */ -static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define ad198x_eapd_info snd_ctl_boolean_mono_info static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -384,12 +373,12 @@ static int ad198x_eapd_put(struct snd_kc eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; - if (eapd == spec->cur_eapd && ! codec->in_resume) + if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); + snd_hda_codec_write_cache(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); return 1; } @@ -430,94 +419,36 @@ static struct hda_input_mux ad1986a_capt }, }; -/* - * PCM control - * - * bind volumes/mutes of 3 DACs as a single PCM control for simplicity - */ - -#define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info - -static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; - - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} - -#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info -static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; +static struct hda_bind_ctls ad1986a_bind_pcm_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), + 0 + }, +}; - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} +static struct hda_bind_ctls ad1986a_bind_pcm_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* * mixers */ static struct snd_kcontrol_new ad1986a_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, - .info = ad1986a_pcm_amp_vol_info, - .get = ad1986a_pcm_amp_vol_get, - .put = ad1986a_pcm_amp_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = ad1986a_pcm_amp_sw_info, - .get = ad1986a_pcm_amp_sw_get, - .put = ad1986a_pcm_amp_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, + /* + * bind volumes/mutes of 3 DACs as a single PCM control for simplicity + */ + HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), + HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), @@ -569,13 +500,30 @@ static struct snd_kcontrol_new ad1986a_3 /* laptop model - 2ch only */ static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; +/* master controls both pins 0x1a and 0x1b */ +static struct hda_bind_ctls ad1986a_laptop_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; + +static struct hda_bind_ctls ad1986a_laptop_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; + static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), @@ -603,68 +551,114 @@ static struct snd_kcontrol_new ad1986a_l /* laptop-eapd model - 2ch only */ -/* master controls both pins 0x1a and 0x1b */ -static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x4 }, + { "Mix", 0x5 }, + }, +}; + +static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + +/* laptop-automute - 2ch only */ + +static void ad1986a_update_hp(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; + struct ad198x_spec *spec = codec->spec; + unsigned int mute; - change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } -static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void ad1986a_hp_automute(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + ad1986a_update_hp(codec); +} + +#define AD1986A_HP_EVENT 0x37 + +static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) != AD1986A_HP_EVENT) + return; + ad1986a_hp_automute(codec); +} + +static int ad1986a_hp_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1986a_hp_automute(codec); + return 0; +} + +/* bind hp and internal speaker mute (with plug check) */ +static int ad1986a_hp_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, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + ad1986a_update_hp(codec); return change; } -static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x4 }, - { "Mix", 0x5 }, - }, -}; - -static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1986a_laptop_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, +static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_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 = ad1986a_laptop_master_sw_put, + .put = ad1986a_hp_master_sw_put, .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -674,6 +668,8 @@ static struct snd_kcontrol_new ad1986a_l HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), { @@ -807,12 +803,20 @@ static struct hda_verb ad1986a_ultra_ini { } /* end */ }; +/* pin sensing on HP jack */ +static struct hda_verb ad1986a_hp_init_verbs[] = { + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, + {} +}; + + /* models */ enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, + AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, AD1986A_MODELS }; @@ -822,6 +826,7 @@ static const char *ad1986a_models[AD1986 [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", + [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", }; @@ -850,11 +855,22 @@ static struct snd_pci_quirk ad1986a_cfg_ SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), {} }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1986a_loopbacks[] = { + { 0x13, HDA_OUTPUT, 0 }, /* Mic */ + { 0x14, HDA_OUTPUT, 0 }, /* Phone */ + { 0x15, HDA_OUTPUT, 0 }, /* CD */ + { 0x16, HDA_OUTPUT, 0 }, /* Aux */ + { 0x17, HDA_OUTPUT, 0 }, /* Line */ + { } /* end */ +}; +#endif + static int patch_ad1986a(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -864,7 +880,6 @@ static int patch_ad1986a(struct hda_code if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 6; @@ -879,6 +894,9 @@ static int patch_ad1986a(struct hda_code spec->mixers[0] = ad1986a_mixers; spec->num_init_verbs = 1; spec->init_verbs[0] = ad1986a_init_verbs; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1986a_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -914,6 +932,19 @@ static int patch_ad1986a(struct hda_code spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1986a_laptop_eapd_capture_source; break; + case AD1986A_LAPTOP_AUTOMUTE: + spec->mixers[0] = ad1986a_laptop_automute_mixers; + spec->num_init_verbs = 3; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->init_verbs[2] = ad1986a_hp_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; + codec->patch_ops.init = ad1986a_hp_init; + break; case AD1986A_ULTRA: spec->mixers[0] = ad1986a_laptop_eapd_mixers; spec->num_init_verbs = 2; @@ -982,8 +1013,9 @@ static int ad1983_spdif_route_put(struct if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { spec->spdif_route = ucontrol->value.enumerated.item[0]; - snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, - AC_VERB_SET_CONNECT_SEL, spec->spdif_route); + snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, + AC_VERB_SET_CONNECT_SEL, + spec->spdif_route); return 1; } return 0; @@ -1063,6 +1095,13 @@ static struct hda_verb ad1983_init_verbs { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1983_loopbacks[] = { + { 0x12, HDA_OUTPUT, 0 }, /* Mic */ + { 0x13, HDA_OUTPUT, 0 }, /* Line */ + { } /* end */ +}; +#endif static int patch_ad1983(struct hda_codec *codec) { @@ -1072,7 +1111,6 @@ static int patch_ad1983(struct hda_codec if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -1088,6 +1126,9 @@ static int patch_ad1983(struct hda_codec spec->num_init_verbs = 1; spec->init_verbs[0] = ad1983_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1983_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -1211,6 +1252,17 @@ static struct hda_verb ad1981_init_verbs { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1981_loopbacks[] = { + { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ + { 0x13, HDA_OUTPUT, 0 }, /* Line */ + { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ + { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ + { 0x1d, HDA_OUTPUT, 0 }, /* CD */ + { } /* end */ +}; +#endif + /* * Patch for HP nx6320 * @@ -1240,31 +1292,21 @@ static int ad1981_hp_master_sw_put(struc return 0; /* toggle HP mute appropriately */ - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); + snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + spec->cur_eapd ? 0 : HDA_AMP_MUTE); return 1; } /* bind volumes of both NID 0x05 and 0x06 */ -static int ad1981_hp_master_vol_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, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls ad1981_hp_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* mute internal speaker if HP is plugged */ static void ad1981_hp_automute(struct hda_codec *codec) @@ -1273,10 +1315,8 @@ static void ad1981_hp_automute(struct hd present = snd_hda_codec_read(codec, 0x06, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* toggle input of built-in and mic jack appropriately */ @@ -1327,14 +1367,7 @@ static struct hda_input_mux ad1981_hp_ca }; static struct snd_kcontrol_new ad1981_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1981_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -1474,7 +1507,6 @@ static int patch_ad1981(struct hda_codec if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -1490,6 +1522,9 @@ static int patch_ad1981(struct hda_codec spec->num_init_verbs = 1; spec->init_verbs[0] = ad1981_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1981_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -1897,16 +1932,19 @@ static int ad1988_spdif_playback_source_ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int sel; - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); - if (sel > 0) { + sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + if (!(sel & 0x80)) + ucontrol->value.enumerated.item[0] = 0; + else { sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0); if (sel < 3) sel++; else sel = 0; + ucontrol->value.enumerated.item[0] = sel; } - ucontrol->value.enumerated.item[0] = sel; return 0; } @@ -1918,23 +1956,39 @@ static int ad1988_spdif_playback_source_ int change; val = ucontrol->value.enumerated.item[0]; - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); if (!val) { - change = sel != 0; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x02, 0, - AC_VERB_SET_CONNECT_SEL, 0); + sel = snd_hda_codec_read(codec, 0x1d, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + change = sel & 0x80; + if (change) { + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(1)); + } } else { - change = sel == 0; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x02, 0, - AC_VERB_SET_CONNECT_SEL, 1); + sel = snd_hda_codec_read(codec, 0x1d, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT | 0x01); + change = sel & 0x80; + if (change) { + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + } sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1; change |= sel != val; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x0b, 0, - AC_VERB_SET_CONNECT_SEL, val - 1); + if (change) + snd_hda_codec_write_cache(codec, 0x0b, 0, + AC_VERB_SET_CONNECT_SEL, + val - 1); } return change; } @@ -2047,10 +2101,9 @@ static struct hda_verb ad1988_spdif_init {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* SPDIF out pin */ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ { } }; @@ -2225,6 +2278,15 @@ static void ad1988_laptop_unsol_event(st snd_hda_sequence_write(codec, ad1988_laptop_hp_off); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1988_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Line */ + { 0x20, HDA_INPUT, 4 }, /* Mic */ + { 0x20, HDA_INPUT, 6 }, /* CD */ + { } /* end */ +}; +#endif /* * Automatic parse of I/O pins from the BIOS configuration @@ -2663,7 +2725,6 @@ static int patch_ad1988(struct hda_codec if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; if (is_rev2(codec)) @@ -2770,6 +2831,9 @@ static int patch_ad1988(struct hda_codec codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; break; } +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1988_loopbacks; +#endif return 0; } @@ -2926,6 +2990,16 @@ static struct hda_verb ad1884_init_verbs { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1884_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Mic */ + { 0x20, HDA_INPUT, 2 }, /* CD */ + { 0x20, HDA_INPUT, 4 }, /* Docking */ + { } /* end */ +}; +#endif + static int patch_ad1884(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -2950,6 +3024,9 @@ static int patch_ad1884(struct hda_codec spec->num_init_verbs = 1; spec->init_verbs[0] = ad1884_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1884_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -3331,6 +3408,16 @@ static struct hda_verb ad1882_init_verbs { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1882_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Mic */ + { 0x20, HDA_INPUT, 4 }, /* Line */ + { 0x20, HDA_INPUT, 6 }, /* CD */ + { } /* end */ +}; +#endif + /* models */ enum { AD1882_3STACK, @@ -3369,6 +3456,9 @@ static int patch_ad1882(struct hda_codec spec->num_init_verbs = 1; spec->init_verbs[0] = ad1882_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1882_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 72d3ab9..fbb8969 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int atihdmi_resume(struct hda_codec *codec) -{ - atihdmi_init(codec); - snd_hda_resume_spdif_out(codec); - - return 0; -} -#endif - /* * Digital out */ @@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patc .build_pcms = atihdmi_build_pcms, .init = atihdmi_init, .free = atihdmi_free, -#ifdef CONFIG_PM - .resume = atihdmi_resume, -#endif }; static int patch_atihdmi(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 3c722e6..2468f31 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int cmi9880_resume(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - cmi9880_init(codec); - snd_hda_resume_ctls(codec, cmi9880_basic_mixer); - if (spec->channel_modes) - snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - /* * Analog playback callbacks */ @@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patc .build_pcms = cmi9880_build_pcms, .init = cmi9880_init, .free = cmi9880_free, -#ifdef CONFIG_PM - .resume = cmi9880_resume, -#endif }; static int patch_cmi9880(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4d8e8af..080e300 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -311,23 +311,6 @@ static void conexant_free(struct hda_cod kfree(codec->spec); } -#ifdef CONFIG_PM -static int conexant_resume(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - static int conexant_build_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_pat .build_pcms = conexant_build_pcms, .init = conexant_init, .free = conexant_free, -#ifdef CONFIG_PM - .resume = conexant_resume, -#endif }; /* @@ -368,15 +348,7 @@ #endif * the private value = nid | (invert << 8) */ -static int cxt_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define cxt_eapd_info snd_ctl_boolean_mono_info static int cxt_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -404,13 +376,13 @@ static int cxt_eapd_put(struct snd_kcont eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; - if (eapd == spec->cur_eapd && !codec->in_resume) + if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); + snd_hda_codec_write_cache(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); return 1; } @@ -500,34 +472,25 @@ static int cxt5045_hp_master_sw_put(stru /* toggle internal speakers mute depending of presence of * the headphone jack */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); return 1; } /* bind volumes of both NID 0x10 and 0x11 */ -static int cxt5045_hp_master_vol_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, 0x10, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* toggle input of built-in and mic jack appropriately */ static void cxt5045_hp_automic(struct hda_codec *codec) @@ -562,9 +525,9 @@ static void cxt5045_hp_automute(struct h spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* unsolicited event for HP jack sensing */ @@ -595,14 +558,7 @@ static struct snd_kcontrol_new cxt5045_m HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5045_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -915,33 +871,24 @@ static int cxt5047_hp_master_sw_put(stru /* toggle internal speakers mute depending of presence of * the headphone jack */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); return 1; } /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ -static int cxt5047_hp_master_vol_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, 0x1d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls cxt5047_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* mute internal speaker if HP is plugged */ static void cxt5047_hp_automute(struct hda_codec *codec) @@ -952,12 +899,12 @@ static void cxt5047_hp_automute(struct h spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* mute internal speaker if HP is plugged */ @@ -969,12 +916,12 @@ static void cxt5047_hp2_automute(struct spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = spec->hp_present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->hp_present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* toggle input of built-in and mic jack appropriately */ @@ -1063,14 +1010,7 @@ static struct snd_kcontrol_new cxt5047_t HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5047_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a47eec..ec14dd5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -102,6 +102,8 @@ enum { /* ALC268 models */ enum { ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, ALC268_AUTO, ALC268_MODEL_LAST /* last tag */ }; @@ -129,6 +131,7 @@ enum { ALC861VD_6ST_DIG, ALC861VD_LENOVO, ALC861VD_DALLAS, + ALC861VD_HP, ALC861VD_AUTO, ALC861VD_MODEL_LAST, }; @@ -152,7 +155,9 @@ enum { ALC882_W2JC, ALC882_TARGA, ALC882_ASUS_A7J, + ALC882_ASUS_A7M, ALC885_MACPRO, + ALC885_MBP3, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -167,12 +172,14 @@ enum { ALC883_TARGA_DIG, ALC883_TARGA_2ch_DIG, ALC883_ACER, + ALC883_ACER_ASPIRE, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, ALC883_LENOVO_101E_2ch, ALC883_LENOVO_NB0763, - ALC888_LENOVO_MS7195_DIG, + ALC888_LENOVO_MS7195_DIG, + ALC883_HAIER_W66, ALC888_6ST_HP, ALC888_3ST_HP, ALC883_AUTO, @@ -239,6 +246,10 @@ struct alc_spec { /* for pin sensing */ unsigned int sense_updated: 1; unsigned int jack_present: 1; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; /* @@ -263,6 +274,9 @@ struct alc_config_preset { const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); void (*init_hook)(struct hda_codec *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_amp_list *loopbacks; +#endif }; @@ -441,8 +455,9 @@ static int alc_pin_mode_put(struct snd_k change = pinctl != alc_pin_mode_values[val]; if (change) { /* Set pin mode to that requested */ - snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); /* Also enable the retasking pin's input/output as required * for the requested pin mode. Enum values of 2 or less are @@ -455,19 +470,15 @@ static int alc_pin_mode_put(struct snd_k * this turns out to be necessary in the future. */ if (val <= 2) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); } else { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); } } return change; @@ -486,15 +497,7 @@ #define ALC_PIN_MODE(xname, nid, dir) \ * needed for any "production" models. */ #ifdef CONFIG_SND_DEBUG -static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define alc_gpio_data_info snd_ctl_boolean_mono_info static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -527,7 +530,8 @@ static int alc_gpio_data_put(struct snd_ gpio_data &= ~mask; else gpio_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); return change; } @@ -547,15 +551,7 @@ #endif /* CONFIG_SND_DEBUG */ * necessary. */ #ifdef CONFIG_SND_DEBUG -static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -588,8 +584,8 @@ static int alc_spdif_ctrl_put(struct snd ctrl_data &= ~mask; else ctrl_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); return change; } @@ -638,6 +634,9 @@ static void setup_preset(struct alc_spec spec->unsol_event = preset->unsol_event; spec->init_hook = preset->init_hook; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = preset->loopbacks; +#endif } /* Enable GPIO mask and set output */ @@ -1304,11 +1303,13 @@ static struct hda_verb alc880_volume_ini * 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_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(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)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* * Set up output mixers (0x0c - 0x0f) @@ -1568,15 +1569,11 @@ static void alc880_uniwill_hp_automute(s present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* auto-toggle front mic */ @@ -1587,11 +1584,8 @@ static void alc880_uniwill_mic_automute( present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } static void alc880_uniwill_automute(struct hda_codec *codec) @@ -1623,11 +1617,8 @@ static void alc880_uniwill_p53_hp_automu present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -1635,19 +1626,14 @@ static void alc880_uniwill_p53_dcvol_aut unsigned int present; present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; - - snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, present); - - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, present); - + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); + snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); } + static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -1868,8 +1854,8 @@ static struct hda_verb alc880_lg_init_ve {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* mute all amp mixer inputs */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* line-in to input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -1900,11 +1886,9 @@ static void alc880_lg_automute(struct hd present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1973,7 +1957,7 @@ static struct hda_verb alc880_lg_lw_init {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* speaker-out */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -1999,11 +1983,9 @@ static void alc880_lg_lw_automute(struct present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) @@ -2015,6 +1997,24 @@ static void alc880_lg_lw_unsol_event(str alc880_lg_lw_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc880_loopbacks[] = { + { 0x0b, HDA_INPUT, 0 }, + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 2 }, + { 0x0b, HDA_INPUT, 3 }, + { 0x0b, HDA_INPUT, 4 }, + { } /* end */ +}; + +static struct hda_amp_list alc880_lg_loopbacks[] = { + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 6 }, + { 0x0b, HDA_INPUT, 7 }, + { } /* end */ +}; +#endif + /* * Common callbacks */ @@ -2041,24 +2041,11 @@ static void alc_unsol_event(struct hda_c spec->unsol_event(codec, res); } -#ifdef CONFIG_PM -/* - * resume - */ -static int alc_resume(struct hda_codec *codec) +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct alc_spec *spec = codec->spec; - int i; - - alc_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } #endif @@ -2293,8 +2280,8 @@ static struct hda_codec_ops alc_patch_op .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, -#ifdef CONFIG_PM - .resume = alc_resume, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = alc_check_power_status, #endif }; @@ -2392,11 +2379,14 @@ static int alc_test_pin_ctl_put(struct s AC_VERB_GET_PIN_WIDGET_CONTROL, 0); new_ctl = ctls[ucontrol->value.enumerated.item[0]]; if (old_ctl != new_ctl) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - (ucontrol->value.enumerated.item[0] >= 3 ? - 0xb080 : 0xb000)); + int val; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_ctl); + val = ucontrol->value.enumerated.item[0] >= 3 ? + HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); return 1; } return 0; @@ -2439,7 +2429,8 @@ static int alc_test_pin_src_put(struct s sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; if (ucontrol->value.enumerated.item[0] != sel) { sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, sel); return 1; } return 0; @@ -2885,6 +2876,7 @@ static struct alc_config_preset alc880_p alc880_beep_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, @@ -2916,6 +2908,9 @@ static struct alc_config_preset alc880_p .input_mux = &alc880_lg_capture_source, .unsol_event = alc880_lg_unsol_event, .init_hook = alc880_lg_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .loopbacks = alc880_lg_loopbacks, +#endif }, [ALC880_LG_LW] = { .mixers = { alc880_lg_lw_mixer }, @@ -3399,6 +3394,10 @@ static int patch_alc880(struct hda_codec codec->patch_ops = alc_patch_ops; if (board_config == ALC880_AUTO) spec->init_hook = alc880_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc880_loopbacks; +#endif return 0; } @@ -3747,12 +3746,12 @@ static struct hda_verb alc260_init_verbs /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* mute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* mute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* mute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* mute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -3797,12 +3796,12 @@ static struct hda_verb alc260_hp_init_ve /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, @@ -3847,12 +3846,12 @@ static struct hda_verb alc260_hp_3013_in /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, @@ -4069,13 +4068,17 @@ static void alc260_replacer_672v_automut present = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; if (present) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 1); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_HP); } else { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); } } @@ -4470,11 +4473,12 @@ static struct hda_verb alc260_volume_ini * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x08 - 0x0a) @@ -4551,6 +4555,17 @@ static void alc260_auto_init(struct hda_ alc260_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc260_loopbacks[] = { + { 0x07, HDA_INPUT, 0 }, + { 0x07, HDA_INPUT, 1 }, + { 0x07, HDA_INPUT, 2 }, + { 0x07, HDA_INPUT, 3 }, + { 0x07, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + /* * ALC260 configurations */ @@ -4750,6 +4765,10 @@ static int patch_alc260(struct hda_codec codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) spec->init_hook = alc260_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc260_loopbacks; +#endif return 0; } @@ -4812,12 +4831,13 @@ static int alc882_mux_enum_put(struct sn idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -4879,6 +4899,38 @@ static struct hda_channel_mode alc882_si { 8, alc882_sixstack_ch8_init }, }; +/* + * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic + */ + +/* + * 2ch mode + */ +static struct hda_verb alc885_mbp_ch2_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc885_mbp_ch6_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } /* end */ +}; + +static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { + { 2, alc885_mbp_ch2_init }, + { 6, alc885_mbp_ch6_init }, +}; + + /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -4909,6 +4961,19 @@ static struct snd_kcontrol_new alc882_ba { } /* end */ }; +static struct snd_kcontrol_new alc885_mbp3_mixer[] = { + HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -4934,8 +4999,10 @@ static struct snd_kcontrol_new alc882_ta 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("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -4955,6 +5022,23 @@ static struct snd_kcontrol_new alc882_as HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, 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("Mic Boost", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc882_asus_a7m_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", 0x15, 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("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -5119,6 +5203,66 @@ static struct hda_verb alc882_macpro_ini { } }; +/* Macbook Pro rev3 */ +static struct hda_verb alc885_mbp3_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, 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 */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + /* iMac 24 mixer. */ static struct snd_kcontrol_new alc885_imac24_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), @@ -5154,14 +5298,10 @@ static void alc885_imac24_automute(struc present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* Processes unsolicited events. */ @@ -5173,6 +5313,27 @@ static void alc885_imac24_unsol_event(st alc885_imac24_automute(codec); } +static void alc885_mbp3_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); + +} +static void alc885_mbp3_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_mbp3_automute(codec); +} + + static struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -5198,11 +5359,10 @@ static void alc882_targa_automute(struct present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -5233,6 +5393,24 @@ static struct hda_verb alc882_asus_a7j_v { } /* end */ }; +static struct hda_verb alc882_asus_a7m_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {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 */ + + {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 */ + { } /* end */ +}; + static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) { unsigned int gpiostate, gpiomask, gpiodir; @@ -5265,6 +5443,20 @@ static void alc882_gpio_mute(struct hda_ AC_VERB_SET_GPIO_DATA, gpiostate); } +/* set up GPIO at initialization */ +static void alc885_macpro_init_hook(struct hda_codec *codec) +{ + alc882_gpio_mute(codec, 0, 0); + alc882_gpio_mute(codec, 1, 0); +} + +/* set up GPIO and update auto-muting at initialization */ +static void alc885_imac24_init_hook(struct hda_codec *codec) +{ + alc885_macpro_init_hook(codec); + alc885_imac24_automute(codec); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -5279,17 +5471,17 @@ static struct hda_verb alc882_auto_init_ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -5378,6 +5570,10 @@ static struct snd_kcontrol_new alc882_ca { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc882_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc882_pcm_analog_playback alc880_pcm_analog_playback #define alc882_pcm_analog_capture alc880_pcm_analog_capture @@ -5392,7 +5588,11 @@ static const char *alc882_models[ALC882_ [ALC882_6ST_DIG] = "6stack-dig", [ALC882_ARIMA] = "arima", [ALC882_W2JC] = "w2jc", + [ALC882_TARGA] = "targa", + [ALC882_ASUS_A7J] = "asus-a7j", + [ALC882_ASUS_A7M] = "asus-a7m", [ALC885_MACPRO] = "macpro", + [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", }; @@ -5404,6 +5604,8 @@ static struct snd_pci_quirk alc882_cfg_t SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), @@ -5455,6 +5657,20 @@ static struct alc_config_preset alc882_p .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mbp_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_mbp3_unsol_event, + .init_hook = alc885_mbp3_automute, + }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, .init_verbs = { alc882_macpro_init_verbs }, @@ -5465,6 +5681,7 @@ static struct alc_config_preset alc882_p .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, + .init_hook = alc885_macpro_init_hook, }, [ALC885_IMAC24] = { .mixers = { alc885_imac24_mixer }, @@ -5477,7 +5694,7 @@ static struct alc_config_preset alc882_p .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, .unsol_event = alc885_imac24_unsol_event, - .init_hook = alc885_imac24_automute, + .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer, @@ -5509,6 +5726,19 @@ static struct alc_config_preset alc882_p .need_dac_fix = 1, .input_mux = &alc882_capture_source, }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, + alc880_gpio1_init_verbs, + alc882_asus_a7m_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, }; @@ -5608,6 +5838,32 @@ static void alc882_auto_init_analog_inpu } } +/* add mic boosts if needed */ +static int alc_auto_add_mic_boost(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + hda_nid_t nid; + + nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; + if (nid) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; + if (nid) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Front Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + return 0; +} + /* almost identical with ALC880 parser... */ static int alc882_parse_auto_config(struct hda_codec *codec) { @@ -5616,10 +5872,17 @@ static int alc882_parse_auto_config(stru if (err < 0) return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc882_auto_init_verbs; - return err; + else if (!err) + return 0; /* no config found */ + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + /* hack - override the init verbs */ + spec->init_verbs[0] = alc882_auto_init_verbs; + + return 1; /* config found */ } /* additional initialization for auto-configuration model */ @@ -5654,6 +5917,9 @@ static int patch_alc882(struct hda_codec case 0x106b1000: /* iMac 24 */ board_config = ALC885_IMAC24; break; + case 0x106b2c00: /* Macbook Pro rev3 */ + board_config = ALC885_MBP3; + break; default: printk(KERN_INFO "hda_codec: Unknown model for ALC882, " "trying auto-probe from BIOS...\n"); @@ -5680,11 +5946,6 @@ static int patch_alc882(struct hda_codec if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); - if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) { - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); - } - spec->stream_name_analog = "ALC882 Analog"; spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; @@ -5715,6 +5976,10 @@ static int patch_alc882(struct hda_codec codec->patch_ops = alc_patch_ops; if (board_config == ALC882_AUTO) spec->init_hook = alc882_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc882_loopbacks; +#endif return 0; } @@ -5792,12 +6057,13 @@ static int alc883_mux_enum_put(struct sn idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -5822,6 +6088,18 @@ static struct hda_verb alc883_3ST_ch2_in }; /* + * 4ch mode + */ +static struct hda_verb alc883_3ST_ch4_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* * 6ch mode */ static struct hda_verb alc883_3ST_ch6_init[] = { @@ -5834,8 +6112,9 @@ static struct hda_verb alc883_3ST_ch6_in { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_modes[2] = { +static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { { 2, alc883_3ST_ch2_init }, + { 4, alc883_3ST_ch4_init }, { 6, alc883_3ST_ch6_init }, }; @@ -6235,6 +6514,31 @@ static struct snd_kcontrol_new alc888_3s { } /* end */ }; +static struct snd_kcontrol_new alc883_acer_aspire_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_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 snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -6270,11 +6574,12 @@ static struct hda_verb alc883_init_verbs {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* mute analog input loopbacks */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -6366,6 +6671,19 @@ static struct hda_verb alc888_lenovo_ms7 { } /* end */ }; +static struct hda_verb alc883_haier_w66_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + static struct hda_verb alc888_6st_hp_verbs[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */ @@ -6409,15 +6727,10 @@ static void alc888_lenovo_ms7195_front_a present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* toggle RCA according to the front-jack state */ @@ -6427,12 +6740,10 @@ static void alc888_lenovo_ms7195_rca_aut present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } + static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -6459,10 +6770,8 @@ static void alc883_medion_md2_automute(s present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } static void alc883_medion_md2_unsol_event(struct hda_codec *codec, @@ -6480,13 +6789,11 @@ static void alc883_tagra_automute(struct present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - present ? 1 : 3); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) @@ -6495,6 +6802,25 @@ static void alc883_tagra_unsol_event(str alc883_tagra_automute(codec); } +static void alc883_haier_w66_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) & 0x80000000; + bits = present ? 0x80 : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + 0x80, bits); +} + +static void alc883_haier_w66_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_haier_w66_automute(codec); +} + static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) { unsigned int present; @@ -6502,11 +6828,9 @@ static void alc883_lenovo_101e_ispeaker_ present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) @@ -6516,15 +6840,11 @@ static void alc883_lenovo_101e_all_autom present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, @@ -6536,6 +6856,44 @@ static void alc883_lenovo_101e_unsol_eve alc883_lenovo_101e_ispeaker_automute(codec); } +/* toggle speaker-output according to the hp-jack state */ +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, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + +static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_acer_aspire_automute(codec); +} + +static struct hda_verb alc883_acer_eapd_verbs[] = { + /* HP Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + /* * generic initialization of ADC, input mixers and output mixers */ @@ -6548,17 +6906,17 @@ static struct hda_verb alc883_auto_init_ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -6621,6 +6979,10 @@ static struct snd_kcontrol_new alc883_ca { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc883_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc883_pcm_analog_playback alc880_pcm_analog_playback #define alc883_pcm_analog_capture alc880_pcm_analog_capture @@ -6638,12 +7000,14 @@ static const char *alc883_models[ALC883_ [ALC883_TARGA_DIG] = "targa-dig", [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_ACER] = "acer", + [ALC883_ACER_ASPIRE] = "acer-aspire", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", [ALC883_LENOVO_101E_2ch] = "lenovo-101e", [ALC883_LENOVO_NB0763] = "lenovo-nb0763", [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", + [ALC883_HAIER_W66] = "haier-w66", [ALC888_6ST_HP] = "6stack-hp", [ALC888_3ST_HP] = "3stack-hp", [ALC883_AUTO] = "auto", @@ -6669,10 +7033,14 @@ static struct snd_pci_quirk alc883_cfg_t SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + 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, 0, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), @@ -6685,6 +7053,10 @@ static struct snd_pci_quirk alc883_cfg_t SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), + SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), + SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), {} }; @@ -6771,8 +7143,7 @@ static struct alc_config_preset alc883_p .init_hook = alc883_tagra_automute, }, [ALC883_ACER] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, + .mixers = { alc883_base_mixer }, /* On TravelMate laptops, GPIO 0 enables the internal speaker * and the headphone jack. Turn this on and rely on the * standard mute methods whenever the user wants to turn @@ -6787,6 +7158,20 @@ static struct alc_config_preset alc883_p .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, }, + [ALC883_ACER_ASPIRE] = { + .mixers = { alc883_acer_aspire_mixer }, + .init_verbs = { alc883_init_verbs, alc883_acer_eapd_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_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_acer_aspire_unsol_event, + .init_hook = alc883_acer_aspire_automute, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, @@ -6815,8 +7200,7 @@ static struct alc_config_preset alc883_p .init_hook = alc883_medion_md2_automute, }, [ALC883_LAPTOP_EAPD] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, + .mixers = { alc883_base_mixer }, .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -6867,6 +7251,20 @@ static struct alc_config_preset alc883_p .input_mux = &alc883_capture_source, .unsol_event = alc883_lenovo_ms7195_unsol_event, .init_hook = alc888_lenovo_ms7195_front_automute, + }, + [ALC883_HAIER_W66] = { + .mixers = { alc883_tagra_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_haier_w66_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_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_haier_w66_unsol_event, + .init_hook = alc883_haier_w66_automute, }, [ALC888_6ST_HP] = { .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer }, @@ -6977,12 +7375,19 @@ static int alc883_parse_auto_config(stru if (err < 0) return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc883_auto_init_verbs; + else if (!err) + return 0; /* no config found */ + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + /* hack - override the init verbs */ + spec->init_verbs[0] = alc883_auto_init_verbs; spec->mixers[spec->num_mixers] = alc883_capture_mixer; spec->num_mixers++; - return err; + + return 1; /* config found */ } /* additional initialization for auto-configuration model */ @@ -7046,6 +7451,10 @@ static int patch_alc883(struct hda_codec codec->patch_ops = alc_patch_ops; if (board_config == ALC883_AUTO) spec->init_hook = alc883_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc883_loopbacks; +#endif return 0; } @@ -7156,9 +7565,46 @@ static struct snd_kcontrol_new alc262_HP { } /* end */ }; +/* bind hp and internal speaker mute (with plug check) */ +static int alc262_sony_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 hp mute */ + change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) { + /* change speaker according to HP jack state */ + struct alc_spec *spec = codec->spec; + unsigned int mute; + if (spec->jack_present) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, + HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } + return change; +} + static struct snd_kcontrol_new alc262_sony_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 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 = 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("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -7194,17 +7640,17 @@ static struct hda_verb alc262_init_verbs {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(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) @@ -7285,34 +7731,26 @@ static struct hda_verb alc262_sony_unsol }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec, int force) +static void alc262_hippo_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int mute; + unsigned int present; - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; if (spec->jack_present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7322,37 +7760,27 @@ static void alc262_hippo_unsol_event(str { if ((res >> 26) != ALC880_HP_EVENT) return; - alc262_hippo_automute(codec, 1); + alc262_hippo_automute(codec); } -static void alc262_hippo1_automute(struct hda_codec *codec, int force) +static void alc262_hippo1_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; unsigned int mute; + unsigned int present; - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - 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); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } - if (spec->jack_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_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, 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_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7362,7 +7790,7 @@ static void alc262_hippo1_unsol_event(st { if ((res >> 26) != ALC880_HP_EVENT) return; - alc262_hippo1_automute(codec, 1); + alc262_hippo1_automute(codec); } /* @@ -7390,13 +7818,23 @@ static struct hda_input_mux alc262_HP_ca .num_items = 5, .items = { { "Mic", 0x0 }, - { "Front Mic", 0x3 }, + { "Front Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, { "AUX IN", 0x6 }, }, }; +static struct hda_input_mux alc262_HP_D7000_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + }, +}; + /* mute/unmute internal speaker according to the hp jack and mute state */ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) { @@ -7414,18 +7852,13 @@ static void alc262_fujitsu_automute(stru } if (spec->jack_present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + 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_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7439,23 +7872,14 @@ static void alc262_fujitsu_unsol_event(s } /* bind volumes of both NID 0x0c and 0x0d */ -static int alc262_fujitsu_master_vol_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, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* bind hp and internal speaker mute (with plug check) */ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, @@ -7466,24 +7890,18 @@ static int alc262_fujitsu_master_sw_put( int change; change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - if (change || codec->in_resume) - alc262_fujitsu_automute(codec, codec->in_resume); + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc262_fujitsu_automute(codec, 0); return change; } static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = alc262_fujitsu_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -7611,17 +8029,17 @@ static struct hda_verb alc262_volume_ini {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -7672,19 +8090,19 @@ static struct hda_verb alc262_HP_BPC_ini {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, + {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)}, + {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) @@ -7759,20 +8177,20 @@ static struct hda_verb alc262_HP_BPC_Wil {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for front * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {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)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* * Set up output mixers (0x0c - 0x0e) */ @@ -7842,6 +8260,10 @@ static struct hda_verb alc262_HP_BPC_Wil { } }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc262_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc262_pcm_analog_playback alc880_pcm_analog_playback #define alc262_pcm_analog_capture alc880_pcm_analog_capture @@ -7884,6 +8306,10 @@ static int alc262_parse_auto_config(stru spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -7939,6 +8365,7 @@ static struct snd_pci_quirk alc262_cfg_t SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), @@ -7967,6 +8394,7 @@ static struct alc_config_preset alc262_p .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -7979,6 +8407,7 @@ static struct alc_config_preset alc262_p .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo1_unsol_event, + .init_hook = alc262_hippo1_automute, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -8010,7 +8439,7 @@ static struct alc_config_preset alc262_p .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, + .input_mux = &alc262_HP_D7000_capture_source, }, [ALC262_HP_BPC_D7000_WL] = { .mixers = { alc262_HP_BPC_WildWest_mixer, @@ -8021,7 +8450,7 @@ static struct alc_config_preset alc262_p .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, + .input_mux = &alc262_HP_D7000_capture_source, }, [ALC262_BENQ_ED8] = { .mixers = { alc262_base_mixer }, @@ -8043,6 +8472,7 @@ static struct alc_config_preset alc262_p .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -8054,6 +8484,7 @@ static struct alc_config_preset alc262_p .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, }; @@ -8139,6 +8570,10 @@ #endif codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) spec->init_hook = alc262_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; +#endif return 0; } @@ -8170,9 +8605,125 @@ static struct snd_kcontrol_new alc268_ba HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + { } +}; + +static struct hda_verb alc268_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* Toshiba specific */ +#define alc268_toshiba_automute alc262_hippo_automute + +static struct hda_verb alc268_toshiba_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* Acer specific */ +/* bind volumes of both NID 0x02 and 0x03 */ +static struct hda_bind_ctls alc268_acer_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 + }, +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc268_acer_automute(struct hda_codec *codec, int force) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + if (force || !spec->sense_updated) { + unsigned int present; + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + spec->sense_updated = 1; + } + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} + + +/* bind hp and internal speaker mute (with plug check) */ +static int alc268_acer_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, 0x14, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc268_acer_automute(codec, 0); + return change; +} + +static struct snd_kcontrol_new alc268_acer_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", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + { } +}; + +static struct hda_verb alc268_acer_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } }; +/* unsolicited event for HP jack sensing */ +static void alc268_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_toshiba_automute(codec); +} + +static void alc268_acer_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_acer_automute(codec, 1); +} + +static void alc268_acer_init_hook(struct hda_codec *codec) +{ + alc268_acer_automute(codec, 1); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -8282,14 +8833,16 @@ static int alc268_mux_enum_put(struct sn idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - idx ); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx ); } *cur_val = idx; return 1; @@ -8530,6 +9083,10 @@ static int alc268_parse_auto_config(stru spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -8551,11 +9108,19 @@ static void alc268_auto_init(struct hda_ */ static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", [ALC268_AUTO] = "auto", }; static struct snd_pci_quirk alc268_cfg_tbl[] = { 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(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), {} }; @@ -8573,6 +9138,37 @@ static struct alc_config_preset alc268_p .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, }, + [ALC268_TOSHIBA] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_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, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .input_mux = &alc268_capture_source, + .unsol_event = alc268_toshiba_unsol_event, + .init_hook = alc268_toshiba_automute, + }, + [ALC268_ACER] = { + .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_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, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, + }, }; static int patch_alc268(struct hda_codec *codec) @@ -9279,14 +9875,10 @@ static void alc861_toshiba_automute(stru present = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); } static void alc861_toshiba_unsol_event(struct hda_codec *codec, @@ -9599,6 +10191,16 @@ static void alc861_auto_init(struct hda_ alc861_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc861_loopbacks[] = { + { 0x15, HDA_INPUT, 0 }, + { 0x15, HDA_INPUT, 1 }, + { 0x15, HDA_INPUT, 2 }, + { 0x15, HDA_INPUT, 3 }, + { } /* end */ +}; +#endif + /* * configuration and preset @@ -9796,6 +10398,10 @@ static int patch_alc861(struct hda_codec codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) spec->init_hook = alc861_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861_loopbacks; +#endif return 0; } @@ -9852,6 +10458,14 @@ static struct hda_input_mux alc861vd_dal }, }; +static struct hda_input_mux alc861vd_hp_capture_source = { + .num_items = 2, + .items = { + { "Front Mic", 0x0 }, + { "ATAPI Mic", 0x1 }, + }, +}; + #define alc861vd_mux_enum_info alc_mux_enum_info #define alc861vd_mux_enum_get alc_mux_enum_get @@ -9870,12 +10484,13 @@ static int alc861vd_mux_enum_put(struct idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -10049,17 +10664,22 @@ static struct snd_kcontrol_new alc861vd_ HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, 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, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, Line-out = 0x15, + * Front Mic=0x18, ATAPI Mic = 0x19, + */ +static struct snd_kcontrol_new alc861vd_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + 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 */ }; @@ -10077,11 +10697,11 @@ static struct hda_verb alc861vd_volume_i * the analog-loopback mixer widget */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(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)}, /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -10210,11 +10830,9 @@ static void alc861vd_lenovo_hp_automute( present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) @@ -10224,11 +10842,9 @@ static void alc861vd_lenovo_mic_automute present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, + HDA_AMP_MUTE, bits); } static void alc861vd_lenovo_automute(struct hda_codec *codec) @@ -10302,10 +10918,8 @@ static void alc861vd_dallas_automute(str present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) @@ -10314,6 +10928,10 @@ static void alc861vd_dallas_unsol_event( alc861vd_dallas_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc861vd_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture @@ -10325,12 +10943,13 @@ #define alc861vd_pcm_digital_capture alc */ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", - [ALC660VD_3ST_DIG]= "3stack-660-digout", + [ALC660VD_3ST_DIG] = "3stack-660-digout", [ALC861VD_3ST] = "3stack", [ALC861VD_3ST_DIG] = "3stack-digout", [ALC861VD_6ST_DIG] = "6stack-digout", [ALC861VD_LENOVO] = "lenovo", [ALC861VD_DALLAS] = "dallas", + [ALC861VD_HP] = "hp", [ALC861VD_AUTO] = "auto", }; @@ -10341,11 +10960,15 @@ static struct snd_pci_quirk alc861vd_cfg SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS), + /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), + SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), {} }; @@ -10435,7 +11058,21 @@ static struct alc_config_preset alc861vd .input_mux = &alc861vd_dallas_capture_source, .unsol_event = alc861vd_dallas_unsol_event, .init_hook = alc861vd_dallas_automute, - }, + }, + [ALC861VD_HP] = { + .mixers = { alc861vd_hp_mixer }, + .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), + .dig_out_nid = ALC861VD_DIGOUT_NID, + .adc_nids = alc861vd_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, + }, }; /* @@ -10668,6 +11305,10 @@ static int alc861vd_parse_auto_config(st spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -10735,6 +11376,10 @@ static int patch_alc861vd(struct hda_cod if (board_config == ALC861VD_AUTO) spec->init_hook = alc861vd_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861vd_loopbacks; +#endif return 0; } @@ -10792,7 +11437,7 @@ static int alc662_mux_enum_put(struct sn struct alc_spec *spec = codec->spec; const struct hda_input_mux *imux = spec->input_mux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; + static hda_nid_t capture_mixers[2] = { 0x23, 0x22 }; hda_nid_t nid = capture_mixers[adc_idx]; unsigned int *cur_val = &spec->cur_mux[adc_idx]; unsigned int i, idx; @@ -10800,12 +11445,13 @@ static int alc662_mux_enum_put(struct sn idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -11014,18 +11660,18 @@ static struct hda_verb alc662_init_verbs {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(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)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(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)}, /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -11087,11 +11733,11 @@ static struct hda_verb alc662_auto_init_ * 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_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -11103,23 +11749,19 @@ static struct hda_verb alc662_auto_init_ /* set up input amps for analog loopback */ /* Amp Indices: DAC = 0, mixer = 1 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(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)}, /* FIXME: use matrix-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /*{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},*/ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { } }; @@ -11150,11 +11792,9 @@ static void alc662_lenovo_101e_ispeaker_ present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) @@ -11164,15 +11804,11 @@ static void alc662_lenovo_101e_all_autom present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, @@ -11184,6 +11820,10 @@ static void alc662_lenovo_101e_unsol_eve alc662_lenovo_101e_ispeaker_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc662_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc662_pcm_analog_playback alc880_pcm_analog_playback @@ -11296,7 +11936,7 @@ static int alc662_auto_create_multi_out_ for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; - nid = alc880_idx_to_mixer(i); + nid = alc880_idx_to_dac(i); if (i == 2) { /* Center/LFE */ err = add_control(spec, ALC_CTL_WIDGET_VOL, @@ -11586,6 +12226,10 @@ static int patch_alc662(struct hda_codec codec->patch_ops = alc_patch_ops; if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc662_loopbacks; +#endif return 0; } diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 6d2ecc3..2a4b960 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -78,6 +78,8 @@ #define SI3054_CHIPID_CODEC_ID (1<< /* si3054 codec registers (nodes) access macros */ #define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) #define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) +#define SET_REG_CACHE(codec,reg,val) \ + snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val) struct si3054_spec { @@ -94,15 +96,7 @@ #define PRIVATE_VALUE(reg,mask) ((reg<<1 #define PRIVATE_REG(val) ((val>>16)&0xffff) #define PRIVATE_MASK(val) (val&0xffff) -static int si3054_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define si3054_switch_info snd_ctl_boolean_mono_info static int si3054_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue) @@ -121,9 +115,9 @@ static int si3054_switch_put(struct snd_ u16 reg = PRIVATE_REG(kcontrol->private_value); u16 mask = PRIVATE_MASK(kcontrol->private_value); if (uvalue->value.integer.value[0]) - SET_REG(codec, reg, (GET_REG(codec, reg)) | mask); + SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask); else - SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask); + SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask); return 0; } @@ -275,10 +269,6 @@ static struct hda_codec_ops si3054_patch .build_pcms = si3054_build_pcms, .init = si3054_init, .free = si3054_free, -#ifdef CONFIG_PM - //.suspend = si3054_suspend, - .resume = si3054_init, -#endif }; static int patch_si3054(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3f25de7..27360d2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -39,12 +39,24 @@ #define STAC_HP_EVENT 0x37 enum { STAC_REF, + STAC_9200_DELL_D21, + STAC_9200_DELL_D22, + STAC_9200_DELL_D23, + STAC_9200_DELL_M21, + STAC_9200_DELL_M22, + STAC_9200_DELL_M23, + STAC_9200_DELL_M24, + STAC_9200_DELL_M25, + STAC_9200_DELL_M26, + STAC_9200_DELL_M27, STAC_9200_MODELS }; enum { STAC_9205_REF, - STAC_M43xx, + STAC_9205_DELL_M42, + STAC_9205_DELL_M43, + STAC_9205_DELL_M44, STAC_9205_MODELS }; @@ -60,19 +72,22 @@ enum { STAC_D945_REF, STAC_D945GTP3, STAC_D945GTP5, - STAC_922X_DELL, STAC_INTEL_MAC_V1, STAC_INTEL_MAC_V2, STAC_INTEL_MAC_V3, STAC_INTEL_MAC_V4, STAC_INTEL_MAC_V5, - /* for backward compitability */ + /* for backward compatibility */ STAC_MACMINI, STAC_MACBOOK, STAC_MACBOOK_PRO_V1, STAC_MACBOOK_PRO_V2, STAC_IMAC_INTEL, STAC_IMAC_INTEL_20, + STAC_922X_DELL_D81, + STAC_922X_DELL_D82, + STAC_922X_DELL_M81, + STAC_922X_DELL_M82, STAC_922X_MODELS }; @@ -80,6 +95,7 @@ enum { STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, + STAC_DELL_3ST, STAC_927X_MODELS }; @@ -95,6 +111,8 @@ struct sigmatel_spec { unsigned int hp_detect: 1; unsigned int gpio_mute: 1; + unsigned int gpio_mask, gpio_data; + /* playback */ struct hda_multi_out multiout; hda_nid_t dac_nids[5]; @@ -127,6 +145,8 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; + unsigned int clfe_swap; + unsigned int aloopback; struct hda_pcm pcm_rec[2]; /* PCM information */ @@ -276,6 +296,82 @@ static int stac92xx_mux_enum_put(struct spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); } +#define stac92xx_aloopback_info snd_ctl_boolean_mono_info + +static int stac92xx_aloopback_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.integer.value[0] = spec->aloopback; + return 0; +} + +static int stac92xx_aloopback_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; + unsigned int dac_mode; + + if (spec->aloopback == ucontrol->value.integer.value[0]) + return 0; + + spec->aloopback = ucontrol->value.integer.value[0]; + + + dac_mode = snd_hda_codec_read(codec, codec->afg, 0, + kcontrol->private_value & 0xFFFF, 0x0); + + if (spec->aloopback) { + snd_hda_power_up(codec); + dac_mode |= 0x40; + } else { + snd_hda_power_down(codec); + dac_mode &= ~0x40; + } + + snd_hda_codec_write_cache(codec, codec->afg, 0, + kcontrol->private_value >> 16, dac_mode); + + return 1; +} + +static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 127; + return 0; +} + +static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = kcontrol->private_value; + return 0; +} + +static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + if (kcontrol->private_value == ucontrol->value.integer.value[0]) + return 0; + + kcontrol->private_value = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, 0x24, 0, + AC_VERB_SET_VOLUME_KNOB_CONTROL, + kcontrol->private_value | 0x80); + return 1; +} + + static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -316,17 +412,43 @@ static struct hda_verb stac9205_core_ini {} }; +#define STAC_INPUT_SOURCE(cnt) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Input Source", \ + .count = cnt, \ + .info = stac92xx_mux_enum_info, \ + .get = stac92xx_mux_enum_get, \ + .put = stac92xx_mux_enum_put, \ + } + +#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Analog Loopback", \ + .count = 1, \ + .info = stac92xx_aloopback_info, \ + .get = stac92xx_aloopback_get, \ + .put = stac92xx_aloopback_put, \ + .private_value = verb_read | (verb_write << 16), \ + } + +#define STAC_VOLKNOB \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Volume", \ + .count = 1, \ + .info = stac92xx_volknob_info, \ + .get = stac92xx_volknob_get, \ + .put = stac92xx_volknob_put, \ + .private_value = 127, \ + } + + static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + 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), @@ -334,86 +456,68 @@ static struct snd_kcontrol_new stac9200_ }; static struct snd_kcontrol_new stac925x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), { } /* end */ }; -/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac922x_mixer[] = { +static struct snd_kcontrol_new stac9205_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", + .name = "Digital Input Source", .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, + .info = stac92xx_dmux_enum_info, + .get = stac92xx_dmux_enum_get, + .put = stac92xx_dmux_enum_put, }, - HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), + STAC_INPUT_SOURCE(2), + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), + STAC_VOLKNOB, + + 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 */ }; /* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac9227_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), +static struct snd_kcontrol_new stac922x_mixer[] = { + STAC_INPUT_SOURCE(2), + STAC_VOLKNOB, + 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 */ }; + static struct snd_kcontrol_new stac927x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; + STAC_INPUT_SOURCE(3), + STAC_VOLKNOB, + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), -static struct snd_kcontrol_new stac9205_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - .count = 1, - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), + 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 */ }; @@ -451,12 +555,144 @@ static unsigned int ref9200_pin_configs[ 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; +/* + STAC 9200 pin configs for + 102801A8 + 102801DE + 102801E8 +*/ +static unsigned int dell9200_d21_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, + 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, +}; + +/* + STAC 9200 pin configs for + 102801C0 + 102801C1 +*/ +static unsigned int dell9200_d22_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, + 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, +}; + +/* + STAC 9200 pin configs for + 102801C4 (Dell Dimension E310) + 102801C5 + 102801C7 + 102801D9 + 102801DA + 102801E3 +*/ +static unsigned int dell9200_d23_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, + 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, +}; + + +/* + STAC 9200-32 pin configs for + 102801B5 (Dell Inspiron 630m) + 102801D8 (Dell Inspiron 640m) +*/ +static unsigned int dell9200_m21_pin_configs[8] = { + 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, + 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, +}; + +/* + STAC 9200-32 pin configs for + 102801C2 (Dell Latitude D620) + 102801C8 + 102801CC (Dell Latitude D820) + 102801D4 + 102801D6 +*/ +static unsigned int dell9200_m22_pin_configs[8] = { + 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, + 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, +}; + +/* + STAC 9200-32 pin configs for + 102801CE (Dell XPS M1710) + 102801CF (Dell Precision M90) +*/ +static unsigned int dell9200_m23_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, + 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, +}; + +/* + STAC 9200-32 pin configs for + 102801C9 + 102801CA + 102801CB (Dell Latitude 120L) + 102801D3 +*/ +static unsigned int dell9200_m24_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, + 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, +}; + +/* + STAC 9200-32 pin configs for + 102801BD (Dell Inspiron E1505n) + 102801EE + 102801EF +*/ +static unsigned int dell9200_m25_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, + 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, +}; + +/* + STAC 9200-32 pin configs for + 102801F5 (Dell Inspiron 1501) + 102801F6 +*/ +static unsigned int dell9200_m26_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, + 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, +}; + +/* + STAC 9200-32 + 102801CD (Dell Inspiron E1705/9400) +*/ +static unsigned int dell9200_m27_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, + 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, +}; + + static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_REF] = ref9200_pin_configs, + [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, + [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, + [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, + [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, + [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, + [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, + [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, + [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, + [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, + [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, }; static const char *stac9200_models[STAC_9200_MODELS] = { [STAC_REF] = "ref", + [STAC_9200_DELL_D21] = "dell-d21", + [STAC_9200_DELL_D22] = "dell-d22", + [STAC_9200_DELL_D23] = "dell-d23", + [STAC_9200_DELL_M21] = "dell-m21", + [STAC_9200_DELL_M22] = "dell-m22", + [STAC_9200_DELL_M23] = "dell-m23", + [STAC_9200_DELL_M24] = "dell-m24", + [STAC_9200_DELL_M25] = "dell-m25", + [STAC_9200_DELL_M26] = "dell-m26", + [STAC_9200_DELL_M27] = "dell-m27", }; static struct snd_pci_quirk stac9200_cfg_tbl[] = { @@ -464,27 +700,64 @@ static struct snd_pci_quirk stac9200_cfg SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), /* Dell laptops have BIOS problem */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8, + "unknown Dell", STAC_9200_DELL_D21), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, - "Dell Inspiron 630m", STAC_REF), + "Dell Inspiron 630m", STAC_9200_DELL_M21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd, + "Dell Inspiron E1505n", STAC_9200_DELL_M25), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0, + "unknown Dell", STAC_9200_DELL_D22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1, + "unknown Dell", STAC_9200_DELL_D22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, - "Dell Latitude D620", STAC_REF), + "Dell Latitude D620", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8, + "unknown Dell", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9, + "unknown Dell", STAC_9200_DELL_M24), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca, + "unknown Dell", STAC_9200_DELL_M24), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, - "Dell Latitude 120L", STAC_REF), + "Dell Latitude 120L", STAC_9200_DELL_M24), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, - "Dell Latitude D820", STAC_REF), + "Dell Latitude D820", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, - "Dell Inspiron E1705/9400", STAC_REF), + "Dell Inspiron E1705/9400", STAC_9200_DELL_M27), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, - "Dell XPS M1710", STAC_REF), + "Dell XPS M1710", STAC_9200_DELL_M23), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf, - "Dell Precision M90", STAC_REF), + "Dell Precision M90", STAC_9200_DELL_M23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3, + "unknown Dell", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4, + "unknown Dell", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6, - "unknown Dell", STAC_REF), + "unknown Dell", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8, - "Dell Inspiron 640m", STAC_REF), + "Dell Inspiron 640m", STAC_9200_DELL_M21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de, + "unknown Dell", STAC_9200_DELL_D21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8, + "unknown Dell", STAC_9200_DELL_D21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee, + "unknown Dell", STAC_9200_DELL_M25), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef, + "unknown Dell", STAC_9200_DELL_M25), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5, - "Dell Inspiron 1501", STAC_REF), - + "Dell Inspiron 1501", STAC_9200_DELL_M26), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6, + "unknown Dell", STAC_9200_DELL_M26), /* Panasonic */ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), @@ -543,6 +816,51 @@ static unsigned int ref922x_pin_configs[ 0x40000100, 0x40000100, }; +/* + STAC 922X pin configs for + 102801A7 + 102801AB + 102801A9 + 102801D1 + 102801D2 +*/ +static unsigned int dell_922x_d81_pin_configs[10] = { + 0x02214030, 0x01a19021, 0x01111012, 0x01114010, + 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, + 0x01813122, 0x400001f2, +}; + +/* + STAC 922X pin configs for + 102801AC + 102801D0 +*/ +static unsigned int dell_922x_d82_pin_configs[10] = { + 0x02214030, 0x01a19021, 0x01111012, 0x01114010, + 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, + 0x01813122, 0x400001f1, +}; + +/* + STAC 922X pin configs for + 102801BF +*/ +static unsigned int dell_922x_m81_pin_configs[10] = { + 0x0321101f, 0x01112024, 0x01111222, 0x91174220, + 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, + 0x40C003f1, 0x405003f0, +}; + +/* + STAC 9221 A1 pin configs for + 102801D7 (Dell XPS M1210) +*/ +static unsigned int dell_922x_m82_pin_configs[10] = { + 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, + 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, + 0x508003f3, 0x405003f4, +}; + static unsigned int d945gtp3_pin_configs[10] = { 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, 0x40000100, 0x40000100, 0x40000100, 0x40000100, @@ -585,48 +903,49 @@ static unsigned int intel_mac_v5_pin_con 0x400000fc, 0x400000fb, }; -static unsigned int stac922x_dell_pin_configs[10] = { - 0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310, - 0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2, - 0x50a003f3, 0x405003f4 -}; static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_D945_REF] = ref922x_pin_configs, [STAC_D945GTP3] = d945gtp3_pin_configs, [STAC_D945GTP5] = d945gtp5_pin_configs, - [STAC_922X_DELL] = stac922x_dell_pin_configs, [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, - /* for backward compitability */ + /* for backward compatibility */ [STAC_MACMINI] = intel_mac_v3_pin_configs, [STAC_MACBOOK] = intel_mac_v5_pin_configs, [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, [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_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, + [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, }; static const char *stac922x_models[STAC_922X_MODELS] = { [STAC_D945_REF] = "ref", [STAC_D945GTP5] = "5stack", [STAC_D945GTP3] = "3stack", - [STAC_922X_DELL] = "dell", [STAC_INTEL_MAC_V1] = "intel-mac-v1", [STAC_INTEL_MAC_V2] = "intel-mac-v2", [STAC_INTEL_MAC_V3] = "intel-mac-v3", [STAC_INTEL_MAC_V4] = "intel-mac-v4", [STAC_INTEL_MAC_V5] = "intel-mac-v5", - /* for backward compitability */ + /* for backward compatibility */ [STAC_MACMINI] = "macmini", [STAC_MACBOOK] = "macbook", [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", [STAC_MACBOOK_PRO_V2] = "macbook-pro", [STAC_IMAC_INTEL] = "imac-intel", [STAC_IMAC_INTEL_20] = "imac-intel-20", + [STAC_922X_DELL_D81] = "dell-d81", + [STAC_922X_DELL_D82] = "dell-d82", + [STAC_922X_DELL_M81] = "dell-m81", + [STAC_922X_DELL_M82] = "dell-m82", }; static struct snd_pci_quirk stac922x_cfg_tbl[] = { @@ -690,9 +1009,25 @@ static struct snd_pci_quirk stac922x_cfg /* Apple Mac Mini (early 2006) */ SND_PCI_QUIRK(0x8384, 0x7680, "Mac Mini", STAC_INTEL_MAC_V3), - /* Dell */ - SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL), - + /* Dell systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac, + "unknown Dell", STAC_922X_DELL_D82), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf, + "unknown Dell", STAC_922X_DELL_M81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0, + "unknown Dell", STAC_922X_DELL_D82), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, + "Dell XPS M1210", STAC_922X_DELL_M82), {} /* terminator */ }; @@ -717,16 +1052,25 @@ static unsigned int d965_5st_pin_configs 0x40000100, 0x40000100 }; +static unsigned int dell_3st_pin_configs[14] = { + 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, + 0x01111212, 0x01116211, 0x01813050, 0x01112214, + 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, + 0x40c003fc, 0x40000100 +}; + static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, [STAC_D965_5ST] = d965_5st_pin_configs, + [STAC_DELL_3ST] = dell_3st_pin_configs, }; static const char *stac927x_models[STAC_927X_MODELS] = { [STAC_D965_REF] = "ref", [STAC_D965_3ST] = "3stack", [STAC_D965_5ST] = "5stack", + [STAC_DELL_3ST] = "dell-3stack", }; static struct snd_pci_quirk stac927x_cfg_tbl[] = { @@ -753,6 +1097,10 @@ static struct snd_pci_quirk stac927x_cfg SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), + /* Dell 3 stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), /* 965 based 5 stack systems */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), @@ -772,23 +1120,97 @@ static unsigned int ref9205_pin_configs[ 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 }; +/* + STAC 9205 pin configs for + 102801F1 + 102801F2 + 102801FC + 102801FD + 10280204 + 1028021F +*/ +static unsigned int dell_9205_m42_pin_configs[12] = { + 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, + 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, + 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, +}; + +/* + STAC 9205 pin configs for + 102801F9 + 102801FA + 102801FE + 102801FF (Dell Precision M4300) + 10280206 + 10280200 + 10280201 +*/ +static unsigned int dell_9205_m43_pin_configs[12] = { + 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, + 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, + 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, +}; + +static unsigned int dell_9205_m44_pin_configs[12] = { + 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, + 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, + 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, +}; + static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { - [STAC_REF] = ref9205_pin_configs, - [STAC_M43xx] = NULL, + [STAC_9205_REF] = ref9205_pin_configs, + [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, + [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, + [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, }; static const char *stac9205_models[STAC_9205_MODELS] = { [STAC_9205_REF] = "ref", + [STAC_9205_DELL_M42] = "dell-m42", + [STAC_9205_DELL_M43] = "dell-m43", + [STAC_9205_DELL_M44] = "dell-m44", }; static struct snd_pci_quirk stac9205_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8, - "Dell Precision", STAC_M43xx), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff, - "Dell Precision", STAC_M43xx), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, + "Dell Precision M4300", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, + "Dell Inspiron", STAC_9205_DELL_M44), {} /* terminator */ }; @@ -854,20 +1276,20 @@ static void stac92xx_set_config_regs(str spec->pin_configs[i]); } -static void stac92xx_enable_gpio_mask(struct hda_codec *codec, - int gpio_mask, int gpio_data) +static void stac92xx_enable_gpio_mask(struct hda_codec *codec) { + struct sigmatel_spec *spec = codec->spec; /* Configure GPIOx as output */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpio_mask); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); /* Configure GPIOx as CMOS */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); + snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); /* Assert GPIOx */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpio_data); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, spec->gpio_data); /* Enable GPIOx */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpio_mask); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, spec->gpio_mask); } /* @@ -1000,10 +1422,9 @@ static struct hda_pcm_stream stac92xx_pc }; static struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .substreams = 2, .channels_min = 2, .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ + /* NID + .substreams is set in stac92xx_build_pcms */ .ops = { .prepare = stac92xx_capture_pcm_prepare, .cleanup = stac92xx_capture_pcm_cleanup @@ -1022,6 +1443,7 @@ static int stac92xx_build_pcms(struct hd info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; if (spec->alt_switch) { codec->num_pcms++; @@ -1066,17 +1488,11 @@ static unsigned int stac92xx_get_vref(st static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); } -static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define stac92xx_io_switch_info snd_ctl_boolean_mono_info static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1109,6 +1525,36 @@ static int stac92xx_io_switch_put(struct return 1; } +#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info + +static int stac92xx_clfe_switch_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.integer.value[0] = spec->clfe_swap; + return 0; +} + +static int stac92xx_clfe_switch_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 = kcontrol->private_value & 0xff; + + if (spec->clfe_swap == ucontrol->value.integer.value[0]) + return 0; + + spec->clfe_swap = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + spec->clfe_swap ? 0x4 : 0x0); + + return 1; +} + #define STAC_CODEC_IO_SWITCH(xname, xpval) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -1119,17 +1565,28 @@ #define STAC_CODEC_IO_SWITCH(xname, xpva .private_value = xpval, \ } +#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = 0, \ + .info = stac92xx_clfe_switch_info, \ + .get = stac92xx_clfe_switch_get, \ + .put = stac92xx_clfe_switch_put, \ + .private_value = xpval, \ + } enum { STAC_CTL_WIDGET_VOL, STAC_CTL_WIDGET_MUTE, STAC_CTL_WIDGET_IO_SWITCH, + STAC_CTL_WIDGET_CLFE_SWITCH }; static struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), STAC_CODEC_IO_SWITCH(NULL, 0), + STAC_CODEC_CLFE_SWITCH(NULL, 0), }; /* add dynamic controls */ @@ -1182,7 +1639,8 @@ static int stac92xx_add_dyn_out_pins(str case 3: /* add line-in as side */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { - cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } @@ -1190,12 +1648,14 @@ static int stac92xx_add_dyn_out_pins(str case 2: /* add line-in as clfe and mic as side */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { - cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { - cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } @@ -1203,12 +1663,14 @@ static int stac92xx_add_dyn_out_pins(str case 1: /* add line-in as surr and mic as clfe */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { - cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { - cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } @@ -1282,8 +1744,8 @@ static int stac92xx_auto_fill_dac_nids(s spec->multiout.num_dacs++; if (conn_len > 1) { /* select this DAC in the pin's input mux */ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, j); } } @@ -1318,7 +1780,7 @@ static int create_controls(struct sigmat } /* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, +static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static const char *chname[4] = { @@ -1327,6 +1789,10 @@ static int stac92xx_auto_create_multi_ou hda_nid_t nid; int i, err; + struct sigmatel_spec *spec = codec->spec; + unsigned int wid_caps; + + for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; @@ -1341,6 +1807,18 @@ static int stac92xx_auto_create_multi_ou err = create_controls(spec, "LFE", nid, 2); if (err < 0) return err; + + wid_caps = get_wcaps(codec, nid); + + if (wid_caps & AC_WCAP_LR_SWAP) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_CLFE_SWITCH, + "Swap Center/LFE Playback Switch", nid); + + if (err < 0) + return err; + } + } else { err = create_controls(spec, chname[i], nid, 3); if (err < 0) @@ -1536,9 +2014,9 @@ static int stac92xx_auto_create_analog_i * NID lists. Hopefully this won't get confused. */ for (i = 0; i < spec->num_muxes; i++) { - snd_hda_codec_write(codec, spec->mux_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); + snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); } } @@ -1593,9 +2071,19 @@ static int stac92xx_parse_auto_config(st if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) return err; - if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) + err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); + + if (err < 0) return err; if (spec->num_dmics > 0) @@ -1764,9 +2252,9 @@ static void enable_pin_detect(struct hda unsigned int event) { if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event)); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | event)); } static int stac92xx_init(struct hda_codec *codec) @@ -1870,7 +2358,7 @@ static void stac92xx_set_pinctl(struct h if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl | flag); } @@ -1880,7 +2368,7 @@ static void stac92xx_reset_pinctl(struct { unsigned int pin_ctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl & ~flag); } @@ -1936,22 +2424,22 @@ static void stac92xx_unsol_event(struct } } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i; - stac92xx_init(codec); stac92xx_set_config_regs(codec); - snd_hda_resume_ctls(codec, spec->mixer); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - + snd_hda_sequence_write(codec, spec->init); + if (spec->gpio_mute) { + stac922x_gpio_mute(codec, 0, 0); + stac922x_gpio_mute(codec, 1, 0); + } + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + /* invoke unsolicited event to reset the HP state */ + if (spec->hp_detect) + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 0; } #endif @@ -1962,7 +2450,7 @@ static struct hda_codec_ops stac92xx_pat .init = stac92xx_init, .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .resume = stac92xx_resume, #endif }; @@ -2002,6 +2490,7 @@ static int patch_stac9200(struct hda_cod spec->mux_nids = stac9200_mux_nids; spec->num_muxes = 1; spec->num_dmics = 0; + spec->num_adcs = 1; spec->init = stac9200_core_init; spec->mixer = stac9200_mixer; @@ -2053,6 +2542,7 @@ static int patch_stac925x(struct hda_cod spec->adc_nids = stac925x_adc_nids; spec->mux_nids = stac925x_mux_nids; spec->num_muxes = 1; + spec->num_adcs = 1; switch (codec->vendor_id) { case 0x83847632: /* STAC9202 */ case 0x83847633: /* STAC9202D */ @@ -2156,6 +2646,7 @@ static int patch_stac922x(struct hda_cod spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); spec->num_dmics = 0; spec->init = stac922x_core_init; @@ -2224,22 +2715,25 @@ static int patch_stac927x(struct hda_cod spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; case STAC_D965_5ST: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; default: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = stac927x_core_init; spec->mixer = stac927x_mixer; @@ -2247,7 +2741,8 @@ static int patch_stac927x(struct hda_cod spec->multiout.dac_nids = spec->dac_nids; /* GPIO0 High = Enable EAPD */ - stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001); + spec->gpio_mask = spec->gpio_data = 0x00000001; + stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { @@ -2272,7 +2767,7 @@ static int patch_stac927x(struct hda_cod static int patch_stac9205(struct hda_codec *codec) { struct sigmatel_spec *spec; - int err, gpio_mask, gpio_data; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -2299,6 +2794,7 @@ static int patch_stac9205(struct hda_cod } 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->dmic_nids = stac9205_dmic_nids; @@ -2310,20 +2806,25 @@ static int patch_stac9205(struct hda_cod spec->multiout.dac_nids = spec->dac_nids; - if (spec->board_config == STAC_M43xx) { + switch (spec->board_config){ + case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ stac92xx_set_config_reg(codec, 0x1f, 0x01441030); stac92xx_set_config_reg(codec, 0x20, 0x1c410030); - gpio_mask = 0x00000007; /* GPIO0-2 */ + spec->gpio_mask = 0x00000007; /* GPIO0-2 */ /* GPIO0 High = EAPD, GPIO1 Low = DRM, * GPIO2 High = Headphone Mute */ - gpio_data = 0x00000005; - } else - gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */ + spec->gpio_data = 0x00000005; + break; + default: + /* GPIO0 High = EAPD */ + spec->gpio_mask = spec->gpio_data = 0x00000001; + break; + } - stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data); + stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); if (!err) { if (spec->board_config < 0) { @@ -2366,6 +2867,7 @@ static struct hda_input_mux vaio_mux = { static struct hda_verb vaio_init[] = { {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ + {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ @@ -2397,61 +2899,28 @@ static struct hda_verb vaio_ar_init[] = }; /* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_master_vol_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, 0x02, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls vaio_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_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, 0x02, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); - return change; -} +static struct hda_bind_ctls vaio_bind_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0, + }, +}; static struct snd_kcontrol_new vaio_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, 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 = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -2467,22 +2936,8 @@ static struct snd_kcontrol_new vaio_mixe }; static struct snd_kcontrol_new vaio_ar_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, 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 = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -2504,6 +2959,49 @@ static struct hda_codec_ops stac9872_pat .build_pcms = stac92xx_build_pcms, .init = stac92xx_init, .free = stac92xx_free, +#ifdef SND_HDA_NEEDS_RESUME + .resume = stac92xx_resume, +#endif +}; + +static int stac9872_vaio_init(struct hda_codec *codec) +{ + int err; + + err = stac92xx_init(codec); + if (err < 0) + return err; + if (codec->patch_ops.unsol_event) + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + return 0; +} + +static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) +{ + if (get_pin_presence(codec, 0x0a)) { + stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + } else { + stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + } +} + +static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res) +{ + switch (res >> 26) { + case STAC_HP_EVENT: + stac9872_vaio_hp_detect(codec, res); + break; + } +} + +static struct hda_codec_ops stac9872_vaio_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac9872_vaio_init, + .free = stac92xx_free, + .unsol_event = stac9872_vaio_unsol_event, #ifdef CONFIG_PM .resume = stac92xx_resume, #endif @@ -2564,6 +3062,7 @@ static int patch_stac9872(struct hda_cod spec->adc_nids = vaio_adcs; spec->input_mux = &vaio_mux; spec->mux_nids = vaio_mux_nids; + codec->patch_ops = stac9872_vaio_patch_ops; break; case CXD9872AKD_VAIO: @@ -2577,10 +3076,10 @@ static int patch_stac9872(struct hda_cod spec->adc_nids = vaio_adcs; spec->input_mux = &vaio_mux; spec->mux_nids = vaio_mux_nids; + codec->patch_ops = stac9872_patch_ops; break; } - codec->patch_ops = stac9872_patch_ops; return 0; } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ba32d1e..33b5e1f 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -115,6 +115,10 @@ struct via_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; static hda_nid_t vt1708_adc_nids[2] = { @@ -305,15 +309,15 @@ static struct hda_verb vt1708_volume_ini {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute 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 */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x19 - 0x1b) @@ -543,24 +547,11 @@ static int via_init(struct hda_codec *co return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int via_resume(struct hda_codec *codec) +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct via_spec *spec = codec->spec; - int i; - - via_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } #endif @@ -571,8 +562,8 @@ static struct hda_codec_ops via_patch_op .build_pcms = via_build_pcms, .init = via_init, .free = via_free, -#ifdef CONFIG_PM - .resume = via_resume, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = via_check_power_status, #endif }; @@ -762,6 +753,16 @@ static int vt1708_auto_create_analog_inp return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1708_loopbacks[] = { + { 0x17, HDA_INPUT, 1 }, + { 0x17, HDA_INPUT, 2 }, + { 0x17, HDA_INPUT, 3 }, + { 0x17, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -855,6 +856,9 @@ static int patch_vt1708(struct hda_codec codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708_loopbacks; +#endif return 0; } @@ -895,15 +899,15 @@ static struct hda_verb vt1709_10ch_volum {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output selector (0x1a, 0x1b, 0x29) @@ -1251,6 +1255,16 @@ static int vt1709_parse_auto_config(stru return 1; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1709_loopbacks[] = { + { 0x18, HDA_INPUT, 1 }, + { 0x18, HDA_INPUT, 2 }, + { 0x18, HDA_INPUT, 3 }, + { 0x18, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + static int patch_vt1709_10ch(struct hda_codec *codec) { struct via_spec *spec; @@ -1293,6 +1307,9 @@ static int patch_vt1709_10ch(struct hda_ codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } @@ -1383,6 +1400,9 @@ static int patch_vt1709_6ch(struct hda_c codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 66bacde..ec0699c 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -394,7 +394,7 @@ static int aureon_ac97_vol_put(struct sn /* * AC'97 mute controls */ -#define aureon_ac97_mute_info aureon_mono_bool_info +#define aureon_ac97_mute_info snd_ctl_boolean_mono_info static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -430,7 +430,7 @@ static int aureon_ac97_mute_put(struct s /* * AC'97 mute controls */ -#define aureon_ac97_micboost_info aureon_mono_bool_info +#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -621,19 +621,12 @@ static void wm_put(struct snd_ice1712 *i /* */ -static int aureon_mono_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define aureon_mono_bool_info snd_ctl_boolean_mono_info /* * AC'97 master playback mute controls (Mute on WM8770 chip) */ -#define aureon_ac97_mmute_info aureon_mono_bool_info +#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -708,7 +701,7 @@ static void wm_set_vol(struct snd_ice171 /* * DAC mute control */ -#define wm_pcm_mute_info aureon_mono_bool_info +#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) { @@ -879,13 +872,7 @@ static int wm_mute_put(struct snd_kcontr /* * WM8770 master mute control */ -static int wm_master_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#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) { @@ -969,14 +956,7 @@ static int wm_pcm_vol_put(struct snd_kco /* * ADC mute control */ -static int wm_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define wm_adc_mute_info snd_ctl_boolean_stereo_info static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1210,12 +1190,7 @@ static int aureon_cs8415_rate_get (struc /* * CS8415A Mute */ -static int aureon_cs8415_mute_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - return 0; -} +#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) { @@ -1316,7 +1291,7 @@ static int aureon_get_headphone_amp(stru return ( tmp & AUREON_HP_SEL )!= 0; } -#define aureon_hpamp_info aureon_mono_bool_info +#define aureon_hpamp_info snd_ctl_boolean_mono_info static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1338,7 +1313,7 @@ static int aureon_hpamp_put(struct snd_k * Deemphasis */ -#define aureon_deemp_info aureon_mono_bool_info +#define aureon_deemp_info snd_ctl_boolean_mono_info static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index af65980..66886df 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -393,15 +393,8 @@ static void delta_setup_spdif(struct snd snd_ice1712_delta_cs8403_spdif_write(ice, tmp); } -static int snd_ice1712_delta1010lt_wordclock_status_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_delta1010lt_wordclock_status_info \ + snd_ctl_boolean_mono_info static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index b135389..b2b4eff 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -700,14 +700,7 @@ static struct snd_kcontrol_new snd_ice17 * EWS88D specific controls */ -static int snd_ice1712_ews88d_control_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_ews88d_control_info snd_ctl_boolean_mono_info static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -812,14 +805,7 @@ static int snd_ice1712_6fire_write_pca(s return 0; } -static int snd_ice1712_6fire_control_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_6fire_control_info snd_ctl_boolean_mono_info static int snd_ice1712_6fire_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 6630a0a..caa0886 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -256,14 +256,7 @@ static unsigned short snd_ice1712_pro_ac /* * consumer ac97 digital mix */ -static int snd_ice1712_digmix_route_ac97_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_digmix_route_ac97_info snd_ctl_boolean_mono_info static int snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1300,14 +1293,7 @@ static void snd_ice1712_update_volume(st outw(val, ICEMT(ice, MONITOR_VOLUME)); } -static int snd_ice1712_pro_mixer_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_pro_mixer_switch_info snd_ctl_boolean_stereo_info static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1759,16 +1745,6 @@ static struct snd_kcontrol_new snd_ice17 .put = snd_ice1712_spdif_stream_put }; -int snd_ice1712_gpio_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - int snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1968,15 +1944,7 @@ static struct snd_kcontrol_new snd_ice17 .put = snd_ice1712_pro_internal_clock_default_put }; -static int snd_ice1712_pro_rate_locking_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_pro_rate_locking_info snd_ctl_boolean_mono_info static int snd_ice1712_pro_rate_locking_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2007,15 +1975,7 @@ static struct snd_kcontrol_new snd_ice17 .put = snd_ice1712_pro_rate_locking_put }; -static int snd_ice1712_pro_rate_reset_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ice1712_pro_rate_reset_info snd_ctl_boolean_mono_info static int snd_ice1712_pro_rate_reset_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 6ac486d..d072f7b 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -451,11 +451,10 @@ static inline void snd_ice1712_restore_g /* for bit controls */ #define ICE1712_GPIO(xiface, xname, xindex, mask, invert, xaccess) \ -{ .iface = xiface, .name = xname, .access = xaccess, .info = snd_ice1712_gpio_info, \ +{ .iface = xiface, .name = xname, .access = xaccess, .info = snd_ctl_boolean_mono_info, \ .get = snd_ice1712_gpio_get, .put = snd_ice1712_gpio_put, \ .private_value = mask | (invert << 24) } -int snd_ice1712_gpio_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ee620de..23c9383 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -341,10 +341,12 @@ static int snd_vt1724_pcm_trigger(struct what = 0; snd_pcm_group_for_each_entry(s, substream) { - const struct vt1724_pcm_reg *reg; - reg = s->runtime->private_data; - what |= reg->start; - snd_pcm_trigger_done(s, substream); + if (snd_pcm_substream_chip(s) == ice) { + const struct vt1724_pcm_reg *reg; + reg = s->runtime->private_data; + what |= reg->start; + snd_pcm_trigger_done(s, substream); + } } switch (cmd) { @@ -1479,15 +1481,7 @@ static struct snd_kcontrol_new snd_vt172 .get = snd_vt1724_spdif_maskp_get, }; -static int snd_vt1724_spdif_sw_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_vt1724_spdif_sw_info snd_ctl_boolean_mono_info static int snd_vt1724_spdif_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1532,15 +1526,7 @@ #if 0 /* NOT USED YET */ * GPIO access from extern */ -int snd_vt1724_gpio_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_vt1724_gpio_info snd_ctl_boolean_mono_info int snd_vt1724_gpio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1706,15 +1692,7 @@ static struct snd_kcontrol_new snd_vt172 .put = snd_vt1724_pro_internal_clock_put }; -static int snd_vt1724_pro_rate_locking_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_vt1724_pro_rate_locking_info snd_ctl_boolean_mono_info static int snd_vt1724_pro_rate_locking_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1745,15 +1723,7 @@ static struct snd_kcontrol_new snd_vt172 .put = snd_vt1724_pro_rate_locking_put }; -static int snd_vt1724_pro_rate_reset_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_vt1724_pro_rate_reset_info snd_ctl_boolean_mono_info static int snd_vt1724_pro_rate_reset_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 40a9098..3ac2505 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -270,7 +270,7 @@ static void wm_set_vol(struct snd_ice171 /* * DAC mute control */ -#define wm_pcm_mute_info phase28_mono_bool_info +#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) { @@ -527,13 +527,7 @@ static int wm_mute_put(struct snd_kcontr /* * WM8770 master mute control */ -static int wm_master_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#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) { @@ -615,20 +609,9 @@ static int wm_pcm_vol_put(struct snd_kco } /* - */ -static int phase28_mono_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -/* * Deemphasis */ -#define phase28_deemp_info phase28_mono_bool_info +#define phase28_deemp_info snd_ctl_boolean_mono_info static int phase28_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 01c6945..faefd52 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -216,14 +216,7 @@ static int wm_adc_vol_put(struct snd_kco /* * ADC input mux mixer control */ -static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define wm_adc_mux_info snd_ctl_boolean_mono_info static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -260,14 +253,7 @@ static int wm_adc_mux_put(struct snd_kco /* * Analog bypass (In -> Out) */ -static int wm_bypass_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define wm_bypass_info snd_ctl_boolean_mono_info static int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -302,14 +288,7 @@ static int wm_bypass_put(struct snd_kcon /* * Left/Right swap */ -static int wm_chswap_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define wm_chswap_info snd_ctl_boolean_mono_info static int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 4bae730..4180f97 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -81,14 +81,7 @@ static inline unsigned char stac9460_get /* * DAC mute control */ -static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#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) { @@ -177,14 +170,7 @@ static int stac9460_dac_vol_put(struct s /* * ADC mute control */ -static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#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) { @@ -292,14 +278,7 @@ static int aureon_get_headphone_amp(stru return ( tmp & AUREON_HP_SEL )!= 0; } -static int aureon_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define aureon_bool_info snd_ctl_boolean_mono_info static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 04e535c..7fcce0a 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -71,14 +71,7 @@ static inline unsigned char stac9460_2_g /* * DAC mute control */ -static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - return 0; -} +#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) @@ -218,15 +211,7 @@ static int stac9460_dac_vol_put(struct s /* * ADC mute control */ -static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#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) @@ -357,15 +342,7 @@ static int stac9460_adc_vol_put(struct s * MIC / LINE switch fonction */ -static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#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) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 5338243..c4af57f 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1391,8 +1391,6 @@ static int snd_korg1212_playback_open(st K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_open [%s]\n", stateName[korg1212->cardState]); - snd_pcm_set_sync(substream); // ??? - snd_korg1212_OpenCard(korg1212); runtime->hw = snd_korg1212_playback_info; @@ -1422,8 +1420,6 @@ static int snd_korg1212_capture_open(str K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]); - snd_pcm_set_sync(substream); - snd_korg1212_OpenCard(korg1212); runtime->hw = snd_korg1212_capture_info; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 8a5ff1c..3224577 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1821,7 +1821,6 @@ snd_m3_playback_open(struct snd_pcm_subs return err; runtime->hw = snd_m3_playback; - snd_pcm_set_sync(subs); return 0; } @@ -1846,7 +1845,6 @@ snd_m3_capture_open(struct snd_pcm_subst return err; runtime->hw = snd_m3_capture; - snd_pcm_set_sync(subs); return 0; } diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index ac007ce..880b824 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -652,7 +652,7 @@ static int snd_mixart_hw_free(struct snd static struct snd_pcm_hardware snd_mixart_analog_caps = { .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | @@ -673,7 +673,7 @@ static struct snd_pcm_hardware snd_mixar static struct snd_pcm_hardware snd_mixart_digital_caps = { .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | @@ -1317,6 +1317,12 @@ static int __devinit snd_mixart_probe(st mgr->mem[i].phys = pci_resource_start(pci, i); mgr->mem[i].virt = ioremap_nocache(mgr->mem[i].phys, pci_resource_len(pci, i)); + if (!mgr->mem[i].virt) { + printk(KERN_ERR "unable to remap resource 0x%lx\n", + mgr->mem[i].phys); + snd_mixart_free(mgr); + return -EBUSY; + } } if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index d7d15c0..0e16512 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -403,14 +403,7 @@ static struct snd_kcontrol_new mixart_co }; /* shared */ -static int mixart_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define mixart_sw_info snd_ctl_boolean_stereo_info static int mixart_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index c7621bd..276c576 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -842,7 +842,6 @@ static void snd_nm256_setup_stream(struc runtime->private_data = s; s->substream = substream; - snd_pcm_set_sync(substream); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index f7f6a68..2d618bd 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -646,6 +646,8 @@ static int pcxhr_trigger(struct snd_pcm_ if (snd_pcm_stream_linked(subs)) { struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); snd_pcm_group_for_each_entry(s, subs) { + if (snd_pcm_substream_chip(s) != chip) + continue; stream = s->runtime->private_data; stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN; @@ -662,6 +664,7 @@ static int pcxhr_trigger(struct snd_pcm_ if (pcxhr_update_r_buffer(stream)) return -EINVAL; + stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN; if (pcxhr_set_stream_state(stream)) return -EINVAL; stream->status = PCXHR_STREAM_STATUS_RUNNING; @@ -902,6 +905,8 @@ static int pcxhr_open(struct snd_pcm_sub snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + snd_pcm_set_sync(subs); + mgr->ref_count_rate++; mutex_unlock(&mgr->setup_mutex); diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index d9cc8d2..b913453 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -144,14 +144,7 @@ static struct snd_kcontrol_new pcxhr_con }; /* shared */ -static int pcxhr_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define pcxhr_sw_info snd_ctl_boolean_stereo_info static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 618653e..1475912 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -258,19 +258,6 @@ static inline unsigned int snd_rme32_pcm & RME32_RCR_AUDIO_ADDR_MASK); } -static int snd_rme32_ratecode(int rate) -{ - switch (rate) { - case 32000: return SNDRV_PCM_RATE_32000; - case 44100: return SNDRV_PCM_RATE_44100; - case 48000: return SNDRV_PCM_RATE_48000; - case 64000: return SNDRV_PCM_RATE_64000; - case 88200: return SNDRV_PCM_RATE_88200; - case 96000: return SNDRV_PCM_RATE_96000; - } - return 0; -} - /* silence callback for halfduplex mode */ static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, @@ -887,7 +874,7 @@ static int snd_rme32_playback_spdif_open if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -929,7 +916,7 @@ static int snd_rme32_capture_spdif_open( if (isadat) { return -EIO; } - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -965,7 +952,7 @@ snd_rme32_playback_adat_open(struct snd_ if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -989,7 +976,7 @@ snd_rme32_capture_adat_open(struct snd_p if (!isadat) { return -EIO; } - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1582,16 +1569,8 @@ static void __devinit snd_rme32_proc_ini * control interface */ -static int -snd_rme32_info_loopback_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_rme32_info_loopback_control snd_ctl_boolean_mono_info + static int snd_rme32_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index e3304b7..0b3c532 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -301,20 +301,6 @@ snd_rme96_capture_ptr(struct rme96 *rme9 } static int -snd_rme96_ratecode(int rate) -{ - switch (rate) { - case 32000: return SNDRV_PCM_RATE_32000; - case 44100: return SNDRV_PCM_RATE_44100; - case 48000: return SNDRV_PCM_RATE_48000; - case 64000: return SNDRV_PCM_RATE_64000; - case 88200: return SNDRV_PCM_RATE_88200; - case 96000: return SNDRV_PCM_RATE_96000; - } - return 0; -} - -static int snd_rme96_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, @@ -1176,8 +1162,6 @@ snd_rme96_playback_spdif_open(struct snd struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); @@ -1194,7 +1178,7 @@ snd_rme96_playback_spdif_open(struct snd (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1214,8 +1198,6 @@ snd_rme96_capture_spdif_open(struct snd_ struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - runtime->hw = snd_rme96_capture_spdif_info; if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) @@ -1223,7 +1205,7 @@ snd_rme96_capture_spdif_open(struct snd_ if (isadat) { return -EIO; } - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1247,8 +1229,6 @@ snd_rme96_playback_adat_open(struct snd_ struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); @@ -1265,7 +1245,7 @@ snd_rme96_playback_adat_open(struct snd_ (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1280,8 +1260,6 @@ snd_rme96_capture_adat_open(struct snd_p struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - runtime->hw = snd_rme96_capture_adat_info; if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { /* makes no sense to use analog input. Note that analog @@ -1292,7 +1270,7 @@ snd_rme96_capture_adat_open(struct snd_p if (!isadat) { return -EIO; } - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1826,15 +1804,8 @@ snd_rme96_proc_init(struct rme96 *rme96) * control interface */ -static int -snd_rme96_info_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_rme96_info_loopback_control snd_ctl_boolean_mono_info + static int snd_rme96_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 3b3ef65..2411f0b 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -606,28 +606,28 @@ static void snd_hdsp_9652_enable_mixer ( static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) { - switch (hdsp->firmware_rev) { - case 0xa: + switch (hdsp->io_type) { + case Multiface: + case Digiface: + default: return (64 * out) + (32 + (in)); - case 0x96: - case 0x97: - case 0x98: + case H9632: return (32 * out) + (16 + (in)); - default: + case H9652: return (52 * out) + (26 + (in)); } } static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) { - switch (hdsp->firmware_rev) { - case 0xa: + switch (hdsp->io_type) { + case Multiface: + case Digiface: + default: return (64 * out) + in; - case 0x96: - case 0x97: - case 0x98: + case H9632: return (32 * out) + in; - default: + case H9652: return (52 * out) + in; } } @@ -1623,14 +1623,7 @@ static int hdsp_set_spdif_output(struct return 0; } -static int snd_hdsp_info_spdif_bits(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_spdif_bits snd_ctl_boolean_mono_info static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2111,14 +2104,7 @@ static int snd_hdsp_put_clock_source(str return change; } -static int snd_hdsp_info_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_clock_source_lock snd_ctl_boolean_mono_info static int snd_hdsp_get_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2420,14 +2406,7 @@ static int hdsp_set_xlr_breakout_cable(s return 0; } -static int snd_hdsp_info_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2483,14 +2462,7 @@ static int hdsp_set_aeb(struct hdsp *hds return 0; } -static int snd_hdsp_info_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_aeb snd_ctl_boolean_mono_info static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2729,14 +2701,7 @@ static int hdsp_set_line_output(struct h return 0; } -static int snd_hdsp_info_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_line_out snd_ctl_boolean_mono_info static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2782,14 +2747,7 @@ static int hdsp_set_precise_pointer(stru return 0; } -static int snd_hdsp_info_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_precise_pointer snd_ctl_boolean_mono_info static int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2835,14 +2793,7 @@ static int hdsp_set_use_midi_tasklet(str return 0; } -static int snd_hdsp_info_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdsp_info_use_midi_tasklet snd_ctl_boolean_mono_info static int snd_hdsp_get_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 143185e..f1bdda6 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1,5 +1,4 @@ -/* -*- linux-c -*- - * +/* * ALSA driver for RME Hammerfall DSP MADI audio interface(s) * * Copyright (c) 2003 Winfried Ritsch (IEM) @@ -78,7 +77,8 @@ MODULE_PARM_DESC(enable_monitor, "Enable Analog Out on Channel 63/64 by default."); MODULE_AUTHOR - ("Winfried Ritsch , Paul Davis , " + ("Winfried Ritsch , " + "Paul Davis , " "Marcus Andersson, Thomas Charbonnel , " "Remy Bruno "); MODULE_DESCRIPTION("RME HDSPM"); @@ -161,7 +161,9 @@ #define HDSPM_AutoInp (1<<11) /* Aut 0=off, 1=on */ /* MADI ONLY */ #define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ -#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/ +#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax + * -- MADI ONLY + */ #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ #define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ @@ -189,11 +191,13 @@ #define HDSPM_wclk_sel (1<<30) /* --- bit helper defines */ #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) -#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed) +#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ + HDSPM_DoubleSpeed|HDSPM_QuadSpeed) #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) #define HDSPM_InputOptical 0 #define HDSPM_InputCoaxial (HDSPM_InputSelect0) -#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3) +#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\ + HDSPM_SyncRef2|HDSPM_SyncRef3) #define HDSPM_SyncRef_Word 0 #define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) @@ -205,10 +209,12 @@ #define HDSPM_Frequency44_1KHz HDSPM_Fr #define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) -#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\ + HDSPM_Frequency0) #define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) #define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) -#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\ + HDSPM_Frequency0) /* --- for internal discrimination */ #define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ @@ -256,10 +262,14 @@ #define HDSPM_BIGENDIAN_MODE (1<<9) #define HDSPM_RD_MULTIPLE (1<<10) /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and - that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */ + that do not conflict with specific bits for AES32 seem to be valid also + for the AES32 + */ #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ -#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ -#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ +#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */ +#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 + * (like inp0) + */ #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ @@ -274,12 +284,15 @@ #define HDSPM_madiFreq1 (1<<23) #define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ #define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ -#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with Interrupt */ +#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with + * Interrupt + */ #define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */ #define HDSPM_midi1IRQPending (1<<31) /* and aktiv */ /* --- status bit helpers */ -#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2|HDSPM_madiFreq3) +#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\ + HDSPM_madiFreq2|HDSPM_madiFreq3) #define HDSPM_madiFreq32 (HDSPM_madiFreq0) #define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) #define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) @@ -319,10 +332,12 @@ #define HDSPM_wcFreq88_2 (HDSPM_wc_freq #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) -#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ + HDSPM_SelSyncRef2) #define HDSPM_SelSyncRef_WORD 0 #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) -#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ + HDSPM_SelSyncRef2) /* For AES32, bits for status, status2 and timecode are different @@ -344,7 +359,7 @@ #define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 -#define HDSPM_AES32_AUTOSYNC_FROM_NONE -1 +#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 /* status2 */ /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ @@ -398,6 +413,13 @@ #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_ /* revisions >= 230 indicate AES32 card */ #define HDSPM_AESREVISION 230 +/* speed factor modes */ +#define HDSPM_SPEED_SINGLE 0 +#define HDSPM_SPEED_DOUBLE 1 +#define HDSPM_SPEED_QUAD 2 +/* names for speed modes */ +static char *hdspm_speed_names[] = { "single", "double", "quad" }; + struct hdspm_midi { struct hdspm *hdspm; int id; @@ -412,8 +434,9 @@ struct hdspm_midi { struct hdspm { spinlock_t lock; - struct snd_pcm_substream *capture_substream; /* only one playback */ - struct snd_pcm_substream *playback_substream; /* and/or capture stream */ + /* only one playback and/or capture stream */ + struct snd_pcm_substream *capture_substream; + struct snd_pcm_substream *playback_substream; char *card_name; /* for procinfo */ unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ @@ -460,9 +483,12 @@ struct hdspm { struct pci_dev *pci; /* and an pci info */ /* Mixer vars */ - struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* fast alsa mixer */ - struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ - struct hdspm_mixer *mixer; /* full mixer accessable over mixer ioctl or hwdep-device */ + /* fast alsa mixer */ + struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; + /* but input to much, so not used */ + struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; + /* full mixer accessable over mixer ioctl or hwdep-device */ + struct hdspm_mixer *mixer; }; @@ -616,13 +642,15 @@ static inline int hdspm_external_sample_ if (hdspm->is_aes32) { unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + unsigned int timecode = + hdspm_read(hdspm, HDSPM_timecodeRegister); int syncref = hdspm_autosync_ref(hdspm); if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && status & HDSPM_AES32_wcLock) - return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); + return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) + & 0xF); if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && status2 & (HDSPM_LockAES >> @@ -668,7 +696,9 @@ static inline int hdspm_external_sample_ } } - /* if rate detected and Syncref is Word than have it, word has priority to MADI */ + /* if rate detected and Syncref is Word than have it, + * word has priority to MADI + */ if (rate != 0 && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) return rate; @@ -727,12 +757,12 @@ static snd_pcm_uframes_t hdspm_hw_pointe position = hdspm_read(hdspm, HDSPM_statusRegister); - if (!hdspm->precise_ptr) { - return (position & HDSPM_BufferID) ? (hdspm->period_bytes / - 4) : 0; - } + if (!hdspm->precise_ptr) + return (position & HDSPM_BufferID) ? + (hdspm->period_bytes / 4) : 0; - /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst) + /* hwpointer comes in bytes and is 64Bytes accurate (by docu since + PCI Burst) i have experimented that it is at most 64 Byte to much for playing so substraction of 64 byte should be ok for ALSA, but use it only for application where you know what you do since if you come to @@ -811,7 +841,7 @@ static void hdspm_set_dds_value(struct h // return 104857600000000 / rate; // 100 MHz return 110100480000000 / rate; // 105 MHz */ - //n = 104857600000000ULL; /* = 2^20 * 10^8 */ + /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ 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 */ @@ -822,11 +852,10 @@ static void hdspm_set_dds_value(struct h /* dummy set rate lets see what happens */ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) { - int reject_if_open = 0; int current_rate; int rate_bits; int not_set = 0; - int is_single, is_double, is_quad; + int current_speed, target_speed; /* ASSUMPTION: hdspm->lock is either set, or there is no need for it (e.g. during module initialization). @@ -841,8 +870,9 @@ static int hdspm_set_rate(struct hdspm * just make a warning an remember setting for future master mode switching */ - snd_printk - (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n"); + snd_printk(KERN_WARNING "HDSPM: " + "Warning: device is not running " + "as a clock master.\n"); not_set = 1; } else { @@ -850,16 +880,18 @@ static int hdspm_set_rate(struct hdspm * int external_freq = hdspm_external_sample_rate(hdspm); - if ((hdspm_autosync_ref(hdspm) == - HDSPM_AUTOSYNC_FROM_NONE)) { + if (hdspm_autosync_ref(hdspm) == + HDSPM_AUTOSYNC_FROM_NONE) { - snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n"); + snd_printk(KERN_WARNING "HDSPM: " + "Detected no Externel Sync \n"); not_set = 1; } else if (rate != external_freq) { - snd_printk - (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n"); + snd_printk(KERN_WARNING "HDSPM: " + "Warning: No AutoSync source for " + "requested rate\n"); not_set = 1; } } @@ -877,64 +909,60 @@ static int hdspm_set_rate(struct hdspm * changes in the read/write routines. */ - is_single = (current_rate <= 48000); - is_double = (current_rate > 48000 && current_rate <= 96000); - is_quad = (current_rate > 96000); + if (current_rate <= 48000) + current_speed = HDSPM_SPEED_SINGLE; + else if (current_rate <= 96000) + current_speed = HDSPM_SPEED_DOUBLE; + else + current_speed = HDSPM_SPEED_QUAD; + + if (rate <= 48000) + target_speed = HDSPM_SPEED_SINGLE; + else if (rate <= 96000) + target_speed = HDSPM_SPEED_DOUBLE; + else + target_speed = HDSPM_SPEED_QUAD; switch (rate) { case 32000: - if (!is_single) - reject_if_open = 1; rate_bits = HDSPM_Frequency32KHz; break; case 44100: - if (!is_single) - reject_if_open = 1; rate_bits = HDSPM_Frequency44_1KHz; break; case 48000: - if (!is_single) - reject_if_open = 1; rate_bits = HDSPM_Frequency48KHz; break; case 64000: - if (!is_double) - reject_if_open = 1; rate_bits = HDSPM_Frequency64KHz; break; case 88200: - if (!is_double) - reject_if_open = 1; rate_bits = HDSPM_Frequency88_2KHz; break; case 96000: - if (!is_double) - reject_if_open = 1; rate_bits = HDSPM_Frequency96KHz; break; case 128000: - if (!is_quad) - reject_if_open = 1; rate_bits = HDSPM_Frequency128KHz; break; case 176400: - if (!is_quad) - reject_if_open = 1; rate_bits = HDSPM_Frequency176_4KHz; break; case 192000: - if (!is_quad) - reject_if_open = 1; rate_bits = HDSPM_Frequency192KHz; break; default: return -EINVAL; } - if (reject_if_open + if (current_speed != target_speed && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { snd_printk - (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", + (KERN_ERR "HDSPM: " + "cannot change from %s speed to %s speed mode " + "(capture PID = %d, playback PID = %d)\n", + hdspm_speed_names[current_speed], + hdspm_speed_names[target_speed], hdspm->capture_pid, hdspm->playback_pid); return -EBUSY; } @@ -966,8 +994,14 @@ static int hdspm_set_rate(struct hdspm * static void all_in_all_mixer(struct hdspm * hdspm, int sgain) { int i, j; - unsigned int gain = - (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : sgain; + unsigned int gain; + + if (sgain > UNITY_GAIN) + gain = UNITY_GAIN; + else if (sgain < 0) + gain = 0; + else + gain = sgain; for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { @@ -980,7 +1014,8 @@ static void all_in_all_mixer(struct hdsp MIDI ----------------------------------------------------------------------------*/ -static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, int id) +static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, + int id) { /* the hardware already does the relevant bit-mask with 0xff */ if (id) @@ -989,7 +1024,8 @@ static inline unsigned char snd_hdspm_mi return hdspm_read(hdspm, HDSPM_midiDataIn0); } -static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, int val) +static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, + int val) { /* the hardware already does the relevant bit-mask with 0xff */ if (id) @@ -1011,9 +1047,10 @@ static inline int snd_hdspm_midi_output_ int fifo_bytes_used; if (id) - fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xff; + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1); else - fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xff; + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0); + fifo_bytes_used &= 0xff; if (fifo_bytes_used < 128) return 128 - fifo_bytes_used; @@ -1038,16 +1075,21 @@ static int snd_hdspm_midi_output_write ( /* Output is not interrupt driven */ spin_lock_irqsave (&hmidi->lock, flags); - if (hmidi->output) { - if (!snd_rawmidi_transmit_empty (hmidi->output)) { - if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id)) > 0) { - if (n_pending > (int)sizeof (buf)) - n_pending = sizeof (buf); - - if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { - for (i = 0; i < to_write; ++i) - snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]); - } + if (hmidi->output && + !snd_rawmidi_transmit_empty (hmidi->output)) { + n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, + hmidi->id); + if (n_pending > 0) { + if (n_pending > (int)sizeof (buf)) + n_pending = sizeof (buf); + + to_write = snd_rawmidi_transmit (hmidi->output, buf, + n_pending); + if (to_write > 0) { + for (i = 0; i < to_write; ++i) + snd_hdspm_midi_write_byte (hmidi->hdspm, + hmidi->id, + buf[i]); } } } @@ -1057,51 +1099,55 @@ static int snd_hdspm_midi_output_write ( static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) { - unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */ + unsigned char buf[128]; /* this buffer is designed to match the MIDI + * input FIFO size + */ unsigned long flags; int n_pending; int i; spin_lock_irqsave (&hmidi->lock, flags); - if ((n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id)) > 0) { + n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); + if (n_pending > 0) { if (hmidi->input) { - if (n_pending > (int)sizeof (buf)) { + if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); - } - for (i = 0; i < n_pending; ++i) { - buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); - } - if (n_pending) { - snd_rawmidi_receive (hmidi->input, buf, n_pending); - } + for (i = 0; i < n_pending; ++i) + buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, + hmidi->id); + if (n_pending) + snd_rawmidi_receive (hmidi->input, buf, + n_pending); } else { /* flush the MIDI input FIFO */ - while (n_pending--) { - snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); - } + while (n_pending--) + snd_hdspm_midi_read_byte (hmidi->hdspm, + hmidi->id); } } hmidi->pending = 0; - if (hmidi->id) { + if (hmidi->id) hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable; - } else { + else hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable; - } - hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register); + hdspm_write(hmidi->hdspm, HDSPM_controlRegister, + hmidi->hdspm->control_register); spin_unlock_irqrestore (&hmidi->lock, flags); return snd_hdspm_midi_output_write (hmidi); } -static void snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) +static void +snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdspm *hdspm; struct hdspm_midi *hmidi; unsigned long flags; u32 ie; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; hdspm = hmidi->hdspm; - ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; + ie = hmidi->id ? + HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; spin_lock_irqsave (&hdspm->lock, flags); if (up) { if (!(hdspm->control_register & ie)) { @@ -1138,12 +1184,13 @@ static void snd_hdspm_midi_output_timer( spin_unlock_irqrestore (&hmidi->lock, flags); } -static void snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void +snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdspm_midi *hmidi; unsigned long flags; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { @@ -1155,9 +1202,8 @@ static void snd_hdspm_midi_output_trigge hmidi->istimer++; } } else { - if (hmidi->istimer && --hmidi->istimer <= 0) { + if (hmidi->istimer && --hmidi->istimer <= 0) del_timer (&hmidi->timer); - } } spin_unlock_irqrestore (&hmidi->lock, flags); if (up) @@ -1168,7 +1214,7 @@ static int snd_hdspm_midi_input_open(str { struct hdspm_midi *hmidi; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); hmidi->input = substream; @@ -1181,7 +1227,7 @@ static int snd_hdspm_midi_output_open(st { struct hdspm_midi *hmidi; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = substream; spin_unlock_irq (&hmidi->lock); @@ -1195,7 +1241,7 @@ static int snd_hdspm_midi_input_close(st snd_hdspm_midi_input_trigger (substream, 0); - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->input = NULL; spin_unlock_irq (&hmidi->lock); @@ -1209,7 +1255,7 @@ static int snd_hdspm_midi_output_close(s snd_hdspm_midi_output_trigger (substream, 0); - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = NULL; spin_unlock_irq (&hmidi->lock); @@ -1231,29 +1277,28 @@ static struct snd_rawmidi_ops snd_hdspm_ .trigger = snd_hdspm_midi_input_trigger, }; -static int __devinit snd_hdspm_create_midi (struct snd_card *card, struct hdspm *hdspm, int id) +static int __devinit snd_hdspm_create_midi (struct snd_card *card, + struct hdspm *hdspm, int id) { int err; char buf[32]; hdspm->midi[id].id = id; - hdspm->midi[id].rmidi = NULL; - hdspm->midi[id].input = NULL; - hdspm->midi[id].output = NULL; hdspm->midi[id].hdspm = hdspm; - hdspm->midi[id].istimer = 0; - hdspm->midi[id].pending = 0; spin_lock_init (&hdspm->midi[id].lock); sprintf (buf, "%s MIDI %d", card->shortname, id+1); - if ((err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi)) < 0) + err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi); + if (err < 0) return err; sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; - snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output); - snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input); + snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_hdspm_midi_output); + snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_hdspm_midi_input); hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | @@ -1558,8 +1603,8 @@ static int snd_hdspm_put_clock_source(st val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; - if (val > 6) - val = 6; + if (val > 9) + val = 9; spin_lock_irq(&hdspm->lock); if (val != hdspm_clock_source(hdspm)) change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; @@ -1637,7 +1682,8 @@ static int hdspm_set_pref_sync_ref(struc hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1; break; case 7: - hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; + hdspm->control_register |= + HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; break; case 8: hdspm->control_register |= HDSPM_SyncRef3; @@ -1675,7 +1721,8 @@ static int snd_hdspm_info_pref_sync_ref( uinfo->value.enumerated.items = 9; - 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, @@ -1688,7 +1735,8 @@ static int snd_hdspm_info_pref_sync_ref( uinfo->value.enumerated.items = 2; - 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, @@ -1740,7 +1788,8 @@ static int hdspm_autosync_ref(struct hds { if (hdspm->is_aes32) { unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; + unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & + 0xF; if (syncref == 0) return HDSPM_AES32_AUTOSYNC_FROM_WORD; if (syncref <= 8) @@ -1777,20 +1826,20 @@ static int snd_hdspm_info_autosync_ref(s uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 10; - 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]); - } - else - { + } else { static char *texts[] = { "WordClock", "MADI", "None" }; 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, @@ -1804,7 +1853,7 @@ static int snd_hdspm_get_autosync_ref(st { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); + ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm); return 0; } @@ -1834,15 +1883,7 @@ static int hdspm_set_line_output(struct return 0; } -static int snd_hdspm_info_line_out(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_line_out snd_ctl_boolean_mono_info static int snd_hdspm_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1897,15 +1938,7 @@ static int hdspm_set_tx_64(struct hdspm return 0; } -static int snd_hdspm_info_tx_64(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_tx_64 snd_ctl_boolean_mono_info static int snd_hdspm_get_tx_64(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1960,15 +1993,7 @@ static int hdspm_set_c_tms(struct hdspm return 0; } -static int snd_hdspm_info_c_tms(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_c_tms snd_ctl_boolean_mono_info static int snd_hdspm_get_c_tms(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2023,15 +2048,7 @@ static int hdspm_set_safe_mode(struct hd return 0; } -static int snd_hdspm_info_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_safe_mode snd_ctl_boolean_mono_info static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2086,15 +2103,7 @@ static int hdspm_set_emphasis(struct hds return 0; } -static int snd_hdspm_info_emphasis(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_emphasis snd_ctl_boolean_mono_info static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2149,15 +2158,7 @@ static int hdspm_set_dolby(struct hdspm return 0; } -static int snd_hdspm_info_dolby(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_dolby snd_ctl_boolean_mono_info static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2212,15 +2213,7 @@ static int hdspm_set_professional(struct return 0; } -static int snd_hdspm_info_professional(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hdspm_info_professional snd_ctl_boolean_mono_info static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2472,7 +2465,7 @@ static int snd_hdspm_put_qs_wire(struct if (val > 2) val = 2; spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_qs_wire(hdspm); + change = val != hdspm_qs_wire(hdspm); hdspm_set_qs_wire(hdspm, val); spin_unlock_irq(&hdspm->lock); return change; @@ -2573,8 +2566,8 @@ static int snd_hdspm_put_mixer(struct sn source - HDSPM_MAX_CHANNELS); else - change = - gain != hdspm_read_in_gain(hdspm, destination, source); + change = gain != hdspm_read_in_gain(hdspm, destination, + source); if (change) { if (source >= HDSPM_MAX_CHANNELS) @@ -2627,7 +2620,8 @@ static int snd_hdspm_get_playback_mixer( snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return -EINVAL); - if ((mapped_channel = hdspm->channel_map[channel]) < 0) + mapped_channel = hdspm->channel_map[channel]; + if (mapped_channel < 0) return -EINVAL; spin_lock_irq(&hdspm->lock); @@ -2635,10 +2629,12 @@ static int snd_hdspm_get_playback_mixer( hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); spin_unlock_irq(&hdspm->lock); - /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n", - ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]); - */ - + /* + snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, " + "value %d\n", + ucontrol->id.index, channel, mapped_channel, + ucontrol->value.integer.value[0]); + */ return 0; } @@ -2659,7 +2655,8 @@ static int snd_hdspm_put_playback_mixer( snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return -EINVAL); - if ((mapped_channel = hdspm->channel_map[channel]) < 0) + mapped_channel = hdspm->channel_map[channel]; + if (mapped_channel < 0) return -EINVAL; gain = ucontrol->value.integer.value[0]; @@ -2909,28 +2906,26 @@ static int snd_hdspm_create_controls(str } /* Channel playback mixer as default control -Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer -they are accesible via special IOCTL on hwdep -and the mixer 2dimensional mixer control */ + Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, + thats too * big for any alsamixer they are accesible via special + IOCTL on hwdep and the mixer 2dimensional mixer control + */ snd_hdspm_playback_mixer.name = "Chn"; limit = HDSPM_MAX_CHANNELS; - /* The index values are one greater than the channel ID so that alsamixer - will display them correctly. We want to use the index for fast lookup - of the relevant channel, but if we use it at all, most ALSA software - does the wrong thing with it ... + /* The index values are one greater than the channel ID so that + * alsamixer will display them correctly. We want to use the index + * for fast lookup of the relevant channel, but if we use it at all, + * most ALSA software does the wrong thing with it ... */ for (idx = 0; idx < limit; ++idx) { snd_hdspm_playback_mixer.index = idx + 1; - if ((err = snd_ctl_add(card, - kctl = - snd_ctl_new1 - (&snd_hdspm_playback_mixer, - hdspm)))) { + kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; - } hdspm->playback_mixer_ctls[idx] = kctl; } @@ -2945,7 +2940,7 @@ static void snd_hdspm_proc_read_madi(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - struct hdspm *hdspm = (struct hdspm *) entry->private_data; + struct hdspm *hdspm = entry->private_data; unsigned int status; unsigned int status2; char *pref_sync_ref; @@ -2978,14 +2973,14 @@ snd_hdspm_proc_read_madi(struct snd_info (status & HDSPM_midi1IRQPending) ? 1 : 0, hdspm->irq_count); snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", ((status & HDSPM_BufferID) ? 1 : 0), (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % (2 * - (int)hdspm-> - period_bytes), - ((status & HDSPM_BufferPositionMask) - - 64) % (2 * (int)hdspm->period_bytes), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), (long) hdspm_hw_pointer(hdspm) * 4); snd_iprintf(buffer, @@ -2995,24 +2990,22 @@ snd_hdspm_proc_read_madi(struct snd_info hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); snd_iprintf(buffer, - "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x\n", + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " + "status2=0x%x\n", hdspm->control_register, hdspm->control2_register, status, status2); snd_iprintf(buffer, "--- Settings ---\n"); - x = 1 << (6 + - hdspm_decode_latency(hdspm-> - control_register & - HDSPM_LatencyMask)); + x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & + HDSPM_LatencyMask)); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdspm->period_bytes); snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", - (hdspm-> - control_register & HDSPM_LineOut) ? "on " : "off", + (hdspm->control_register & HDSPM_LineOut) ? "on " : "off", (hdspm->precise_ptr) ? "on" : "off"); switch (hdspm->control_register & HDSPM_InputMask) { @@ -3040,7 +3033,8 @@ snd_hdspm_proc_read_madi(struct snd_info syncref); snd_iprintf(buffer, - "ClearTrackMarker = %s, Transmit in %s Channel Mode, Auto Input %s\n", + "ClearTrackMarker = %s, Transmit in %s Channel Mode, " + "Auto Input %s\n", (hdspm-> control_register & HDSPM_clr_tms) ? "on" : "off", (hdspm-> @@ -3141,7 +3135,7 @@ static void snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - struct hdspm *hdspm = (struct hdspm *) entry->private_data; + struct hdspm *hdspm = entry->private_data; unsigned int status; unsigned int status2; unsigned int timecode; @@ -3171,14 +3165,14 @@ snd_hdspm_proc_read_aes32(struct snd_inf (status & HDSPM_midi1IRQPending) ? 1 : 0, hdspm->irq_count); snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", ((status & HDSPM_BufferID) ? 1 : 0), (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % (2 * - (int)hdspm-> - period_bytes), - ((status & HDSPM_BufferPositionMask) - - 64) % (2 * (int)hdspm->period_bytes), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), (long) hdspm_hw_pointer(hdspm) * 4); snd_iprintf(buffer, @@ -3188,16 +3182,15 @@ snd_hdspm_proc_read_aes32(struct snd_inf hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); snd_iprintf(buffer, - "Register: ctrl1=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n", + "Register: ctrl1=0x%x, status1=0x%x, status2=0x%x, " + "timecode=0x%x\n", hdspm->control_register, status, status2, timecode); snd_iprintf(buffer, "--- Settings ---\n"); - x = 1 << (6 + - hdspm_decode_latency(hdspm-> - control_register & - HDSPM_LatencyMask)); + x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & + HDSPM_LatencyMask)); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", @@ -3280,14 +3273,15 @@ snd_hdspm_proc_read_aes32(struct snd_inf snd_iprintf(buffer, "--- Status:\n"); snd_iprintf(buffer, "Word: %s Frequency: %d\n", - (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock", - HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); + (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock", + HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); for (x = 0; x < 8; x++) { snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", - x+1, - (status2 & (HDSPM_LockAES >> x))? "Sync ": "No Lock", - HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); + x+1, + (status2 & (HDSPM_LockAES >> x)) ? + "Sync ": "No Lock", + HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); } switch (hdspm_autosync_ref(hdspm)) { @@ -3313,12 +3307,11 @@ static void snd_hdspm_proc_read_debug(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - struct hdspm *hdspm = (struct hdspm *)entry->private_data; + struct hdspm *hdspm = entry->private_data; int j,i; - for (i = 0; i < 256 /* 1024*64 */; i += j) - { + for (i = 0; i < 256 /* 1024*64 */; i += j) { snd_iprintf(buffer, "0x%08X: ", i); for (j = 0; j < 16; j += 4) snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); @@ -3361,14 +3354,20 @@ static int snd_hdspm_set_defaults(struct /* set defaults: */ if (hdspm->is_aes32) - hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ - hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + hdspm->control_register = + HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = + * 8192 samples + */ HDSPM_SyncRef0 | /* AES1 is syncclock */ HDSPM_LineOut | /* Analog output in */ HDSPM_Professional; /* Professional mode */ else - hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ - hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + hdspm->control_register = + HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = + * 8192 samples + */ HDSPM_InputCoaxial | /* Input Coax not Optical */ HDSPM_SyncRef_MADI | /* Madi is syncclock */ HDSPM_LineOut | /* Analog output in */ @@ -3399,7 +3398,8 @@ #endif if (line_outs_monitor[hdspm->dev]) { - snd_printk(KERN_INFO "HDSPM: sending all playback streams to line outs.\n"); + snd_printk(KERN_INFO "HDSPM: " + "sending all playback streams to line outs.\n"); for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) { if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN)) @@ -3448,20 +3448,16 @@ static irqreturn_t snd_hdspm_interrupt(i if (audio) { if (hdspm->capture_substream) - snd_pcm_period_elapsed(hdspm->pcm-> - streams - [SNDRV_PCM_STREAM_CAPTURE]. - substream); + snd_pcm_period_elapsed(hdspm->capture_substream); if (hdspm->playback_substream) - snd_pcm_period_elapsed(hdspm->pcm-> - streams - [SNDRV_PCM_STREAM_PLAYBACK]. - substream); + snd_pcm_period_elapsed(hdspm->playback_substream); } if (midi0 && midi0status) { - /* we disable interrupts for this input until processing is done */ + /* we disable interrupts for this input until processing + * is done + */ hdspm->control_register &= ~HDSPM_Midi0InterruptEnable; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); @@ -3469,7 +3465,9 @@ static irqreturn_t snd_hdspm_interrupt(i schedule = 1; } if (midi1 && midi1status) { - /* we disable interrupts for this input until processing is done */ + /* we disable interrupts for this input until processing + * is done + */ hdspm->control_register &= ~HDSPM_Midi1InterruptEnable; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); @@ -3501,16 +3499,16 @@ static char *hdspm_channel_buffer_locati snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return NULL); - if ((mapped_channel = hdspm->channel_map[channel]) < 0) + mapped_channel = hdspm->channel_map[channel]; + if (mapped_channel < 0) return NULL; - if (stream == SNDRV_PCM_STREAM_CAPTURE) { + if (stream == SNDRV_PCM_STREAM_CAPTURE) return hdspm->capture_buffer + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; - } else { + else return hdspm->playback_buffer + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; - } } @@ -3525,9 +3523,9 @@ static int snd_hdspm_playback_copy(struc snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); - channel_buf = hdspm_channel_buffer_location(hdspm, - substream->pstr-> - stream, channel); + channel_buf = + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); snd_assert(channel_buf != NULL, return -EIO); @@ -3544,9 +3542,9 @@ static int snd_hdspm_capture_copy(struct snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); - channel_buf = hdspm_channel_buffer_location(hdspm, - substream->pstr-> - stream, channel); + channel_buf = + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); snd_assert(channel_buf != NULL, return -EIO); return copy_to_user(dst, channel_buf + pos * 4, count * 4); } @@ -3559,8 +3557,8 @@ static int snd_hdspm_hw_silence(struct s char *channel_buf; channel_buf = - hdspm_channel_buffer_location(hdspm, substream->pstr->stream, - channel); + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); snd_assert(channel_buf != NULL, return -EIO); memset(channel_buf + pos * 4, 0, count * 4); return 0; @@ -3616,7 +3614,7 @@ static int snd_hdspm_hw_params(struct sn other_pid = hdspm->playback_pid; } - if ((other_pid > 0) && (this_pid != other_pid)) { + if (other_pid > 0 && this_pid != other_pid) { /* The other stream is open, and not by the same task as this one. Make sure that the parameters @@ -3633,7 +3631,7 @@ static int snd_hdspm_hw_params(struct sn if (params_period_size(params) != hdspm->period_bytes / 4) { spin_unlock_irq(&hdspm->lock); _snd_pcm_hw_param_setempty(params, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return -EBUSY; } @@ -3644,7 +3642,8 @@ static int snd_hdspm_hw_params(struct sn /* how to make sure that the rate matches an externally-set one ? */ spin_lock_irq(&hdspm->lock); - if ((err = hdspm_set_rate(hdspm, params_rate(params), 0)) < 0) { + err = hdspm_set_rate(hdspm, params_rate(params), 0); + if (err < 0) { spin_unlock_irq(&hdspm->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); @@ -3652,16 +3651,17 @@ static int snd_hdspm_hw_params(struct sn } spin_unlock_irq(&hdspm->lock); - if ((err = - hdspm_set_interrupt_interval(hdspm, - params_period_size(params))) < - 0) { + err = hdspm_set_interrupt_interval(hdspm, + params_period_size(params)); + if (err < 0) { _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return err; } - /* Memory allocation, takashi's method, dont know if we should spinlock */ + /* Memory allocation, takashi's method, dont know if we should + * spinlock + */ /* malloc all buffer even if not enabled to get sure */ /* Update for MADI rev 204: we need to allocate for all channels, * otherwise it doesn't work at 96kHz */ @@ -3746,7 +3746,8 @@ static int snd_hdspm_channel_info(struct snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL); - if ((mapped_channel = hdspm->channel_map[info->channel]) < 0) + mapped_channel = hdspm->channel_map[info->channel]; + if (mapped_channel < 0) return -EINVAL; info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; @@ -3760,15 +3761,13 @@ static int snd_hdspm_ioctl(struct snd_pc { switch (cmd) { case SNDRV_PCM_IOCTL1_RESET: - { - return snd_hdspm_reset(substream); - } + return snd_hdspm_reset(substream); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: - { - struct snd_pcm_channel_info *info = arg; - return snd_hdspm_channel_info(substream, info); - } + { + struct snd_pcm_channel_info *info = arg; + return snd_hdspm_channel_info(substream, info); + } default: break; } @@ -3979,9 +3978,12 @@ static int snd_hdspm_hw_rule_channels(st } -static unsigned int hdspm_aes32_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; +static unsigned int hdspm_aes32_sample_rates[] = { + 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 +}; -static struct snd_pcm_hw_constraint_list hdspm_hw_constraints_aes32_sample_rates = { +static struct snd_pcm_hw_constraint_list +hdspm_hw_constraints_aes32_sample_rates = { .count = ARRAY_SIZE(hdspm_aes32_sample_rates), .list = hdspm_aes32_sample_rates, .mask = 0 @@ -4107,7 +4109,7 @@ static int snd_hdspm_hwdep_dummy_op(stru static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg) { - struct hdspm *hdspm = (struct hdspm *) hw->private_data; + struct hdspm *hdspm = hw->private_data; struct hdspm_mixer_ioctl mixer; struct hdspm_config_info info; struct hdspm_version hdspm_version; @@ -4115,11 +4117,12 @@ static int snd_hdspm_hwdep_ioctl(struct switch (cmd) { - case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: if (copy_from_user(&rms, (void __user *)arg, sizeof(rms))) return -EFAULT; - /* maybe there is a chance to memorymap in future so dont touch just copy */ + /* maybe there is a chance to memorymap in future + * so dont touch just copy + */ if(copy_to_user_fromio((void __user *)rms.peak, hdspm->iobase+HDSPM_MADI_peakrmsbase, sizeof(struct hdspm_peak_rms)) != 0 ) @@ -4131,21 +4134,16 @@ static int snd_hdspm_hwdep_ioctl(struct case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO: spin_lock_irq(&hdspm->lock); - info.pref_sync_ref = - (unsigned char) hdspm_pref_sync_ref(hdspm); - info.wordclock_sync_check = - (unsigned char) hdspm_wc_sync_check(hdspm); + info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); + info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); info.system_sample_rate = hdspm->system_sample_rate; info.autosync_sample_rate = hdspm_external_sample_rate(hdspm); - info.system_clock_mode = - (unsigned char) hdspm_system_clock_mode(hdspm); - info.clock_source = - (unsigned char) hdspm_clock_source(hdspm); - info.autosync_ref = - (unsigned char) hdspm_autosync_ref(hdspm); - info.line_out = (unsigned char) hdspm_line_out(hdspm); + info.system_clock_mode = hdspm_system_clock_mode(hdspm); + info.clock_source = hdspm_clock_source(hdspm); + info.autosync_ref = hdspm_autosync_ref(hdspm); + info.line_out = hdspm_line_out(hdspm); info.passthru = 0; spin_unlock_irq(&hdspm->lock); if (copy_to_user((void __user *) arg, &info, sizeof(info))) @@ -4162,8 +4160,8 @@ static int snd_hdspm_hwdep_ioctl(struct case SNDRV_HDSPM_IOCTL_GET_MIXER: if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) return -EFAULT; - if (copy_to_user - ((void __user *)mixer.mixer, hdspm->mixer, sizeof(struct hdspm_mixer))) + if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, + sizeof(struct hdspm_mixer))) return -EFAULT; break; @@ -4206,7 +4204,8 @@ static int __devinit snd_hdspm_create_hw struct snd_hwdep *hw; int err; - if ((err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw)) < 0) + err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw); + if (err < 0) return err; hdspm->hwdep = hw; @@ -4232,15 +4231,15 @@ static int __devinit snd_hdspm_prealloca pcm = hdspm->pcm; -/* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */ wanted = HDSPM_DMA_AREA_BYTES; - if ((err = + err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(hdspm->pci), wanted, - wanted)) < 0) { + wanted); + if (err < 0) { snd_printdd("Could not preallocate %zd Bytes\n", wanted); return err; @@ -4256,8 +4255,7 @@ static void hdspm_set_sgbuf(struct hdspm 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(sgbuf, (size_t) 4096 * i)); } /* ------------- ALSA Devices ---------------------------- */ @@ -4267,7 +4265,8 @@ static int __devinit snd_hdspm_create_pc struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm); + if (err < 0) return err; hdspm->pcm = pcm; @@ -4281,7 +4280,8 @@ static int __devinit snd_hdspm_create_pc pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; - if ((err = snd_hdspm_preallocate_memory(hdspm)) < 0) + err = snd_hdspm_preallocate_memory(hdspm); + if (err < 0) return err; return 0; @@ -4299,19 +4299,24 @@ static int __devinit snd_hdspm_create_al int err; snd_printdd("Create card...\n"); - if ((err = snd_hdspm_create_pcm(card, hdspm)) < 0) + err = snd_hdspm_create_pcm(card, hdspm); + if (err < 0) return err; - if ((err = snd_hdspm_create_midi(card, hdspm, 0)) < 0) + err = snd_hdspm_create_midi(card, hdspm, 0); + if (err < 0) return err; - if ((err = snd_hdspm_create_midi(card, hdspm, 1)) < 0) + err = snd_hdspm_create_midi(card, hdspm, 1); + if (err < 0) return err; - if ((err = snd_hdspm_create_controls(card, hdspm)) < 0) + err = snd_hdspm_create_controls(card, hdspm); + if (err < 0) return err; - if ((err = snd_hdspm_create_hwdep(card, hdspm)) < 0) + err = snd_hdspm_create_hwdep(card, hdspm); + if (err < 0) return err; snd_printdd("proc init...\n"); @@ -4326,7 +4331,8 @@ static int __devinit snd_hdspm_create_al hdspm->playback_substream = NULL; snd_printdd("Set defaults...\n"); - if ((err = snd_hdspm_set_defaults(hdspm)) < 0) + err = snd_hdspm_set_defaults(hdspm); + if (err < 0) return err; snd_printdd("Update mixer controls...\n"); @@ -4334,7 +4340,8 @@ static int __devinit snd_hdspm_create_al snd_printdd("Initializeing complete ???\n"); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_printk(KERN_ERR "HDSPM: error registering card\n"); return err; } @@ -4344,36 +4351,18 @@ static int __devinit snd_hdspm_create_al return 0; } -static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdspm, +static int __devinit snd_hdspm_create(struct snd_card *card, + struct hdspm *hdspm, int precise_ptr, int enable_monitor) { struct pci_dev *pci = hdspm->pci; int err; - int i; - unsigned long io_extent; hdspm->irq = -1; - hdspm->irq_count = 0; - - hdspm->midi[0].rmidi = NULL; - hdspm->midi[1].rmidi = NULL; - hdspm->midi[0].input = NULL; - hdspm->midi[1].input = NULL; - hdspm->midi[0].output = NULL; - hdspm->midi[1].output = NULL; + spin_lock_init(&hdspm->midi[0].lock); spin_lock_init(&hdspm->midi[1].lock); - hdspm->iobase = NULL; - hdspm->control_register = 0; - hdspm->control2_register = 0; - - hdspm->playback_buffer = NULL; - hdspm->capture_buffer = NULL; - - for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) - hdspm->playback_mixer_ctls[i] = NULL; - hdspm->mixer = NULL; hdspm->card = card; @@ -4396,12 +4385,14 @@ static int __devinit snd_hdspm_create(st hdspm->card_name = "RME HDSPM MADI"; } - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(hdspm->pci); - if ((err = pci_request_regions(pci, "hdspm")) < 0) + err = pci_request_regions(pci, "hdspm"); + if (err < 0) return err; hdspm->port = pci_resource_start(pci, 0); @@ -4411,8 +4402,10 @@ static int __devinit snd_hdspm_create(st hdspm->port, hdspm->port + io_extent - 1); - if ((hdspm->iobase = ioremap_nocache(hdspm->port, io_extent)) == NULL) { - snd_printk(KERN_ERR "HDSPM: unable to remap region 0x%lx-0x%lx\n", + hdspm->iobase = ioremap_nocache(hdspm->port, io_extent); + if (!hdspm->iobase) { + snd_printk(KERN_ERR "HDSPM: " + "unable to remap region 0x%lx-0x%lx\n", hdspm->port, hdspm->port + io_extent - 1); return -EBUSY; } @@ -4435,9 +4428,10 @@ static int __devinit snd_hdspm_create(st snd_printdd("kmalloc Mixer memory of %zd Bytes\n", sizeof(struct hdspm_mixer)); - if ((hdspm->mixer = kmalloc(sizeof(struct hdspm_mixer), GFP_KERNEL)) - == NULL) { - snd_printk(KERN_ERR "HDSPM: unable to kmalloc Mixer memory of %d Bytes\n", + hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL); + if (!hdspm->mixer) { + snd_printk(KERN_ERR "HDSPM: " + "unable to kmalloc Mixer memory of %d Bytes\n", (int)sizeof(struct hdspm_mixer)); return err; } @@ -4447,7 +4441,8 @@ static int __devinit snd_hdspm_create(st hdspm->qs_channels = MADI_QS_CHANNELS; snd_printdd("create alsa devices.\n"); - if ((err = snd_hdspm_create_alsa_devices(card, hdspm)) < 0) + err = snd_hdspm_create_alsa_devices(card, hdspm); + if (err < 0) return err; snd_hdspm_initialize_midi_flush(hdspm); @@ -4462,9 +4457,8 @@ static int snd_hdspm_free(struct hdspm * /* stop th audio, and cancel all interrupts */ hdspm->control_register &= - ~(HDSPM_Start | HDSPM_AudioInterruptEnable - | HDSPM_Midi0InterruptEnable | - HDSPM_Midi1InterruptEnable); + ~(HDSPM_Start | HDSPM_AudioInterruptEnable | + HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable); hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); } @@ -4472,7 +4466,6 @@ static int snd_hdspm_free(struct hdspm * if (hdspm->irq >= 0) free_irq(hdspm->irq, (void *) hdspm); - kfree(hdspm->mixer); if (hdspm->iobase) @@ -4487,7 +4480,7 @@ static int snd_hdspm_free(struct hdspm * static void snd_hdspm_card_free(struct snd_card *card) { - struct hdspm *hdspm = (struct hdspm *) card->private_data; + struct hdspm *hdspm = card->private_data; if (hdspm) snd_hdspm_free(hdspm); @@ -4508,20 +4501,21 @@ static int __devinit snd_hdspm_probe(str return -ENOENT; } - if (!(card = snd_card_new(index[dev], id[dev], - THIS_MODULE, sizeof(struct hdspm)))) + card = snd_card_new(index[dev], id[dev], + THIS_MODULE, sizeof(struct hdspm)); + if (!card) return -ENOMEM; - hdspm = (struct hdspm *) card->private_data; + hdspm = card->private_data; card->private_free = snd_hdspm_card_free; hdspm->dev = dev; hdspm->pci = pci; snd_card_set_dev(card, &pci->dev); - if ((err = - snd_hdspm_create(card, hdspm, precise_ptr[dev], - enable_monitor[dev])) < 0) { + err = snd_hdspm_create(card, hdspm, precise_ptr[dev], + enable_monitor[dev]); + if (err < 0) { snd_card_free(card); return err; } @@ -4530,7 +4524,8 @@ static int __devinit snd_hdspm_probe(str sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name, hdspm->port, hdspm->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/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 2de2740..34f96f1 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1067,14 +1067,7 @@ static int rme9652_set_spdif_output(stru return 0; } -static int snd_rme9652_info_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_rme9652_info_spdif_out snd_ctl_boolean_mono_info static int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1338,14 +1331,7 @@ #define RME9652_PASSTHRU(xname, xindex) .put = snd_rme9652_put_passthru, \ .get = snd_rme9652_get_passthru } -static int snd_rme9652_info_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_rme9652_info_passthru snd_ctl_boolean_mono_info static int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1445,14 +1431,7 @@ #define RME9652_TC_VALID(xname, xindex) .info = snd_rme9652_info_tc_valid, \ .get = snd_rme9652_get_tc_valid } -static int snd_rme9652_info_tc_valid(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_rme9652_info_tc_valid snd_ctl_boolean_mono_info static int snd_rme9652_get_tc_valid(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 7ca6062..00e4004 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2317,15 +2317,7 @@ int __devinit snd_trident_spdif_pcm(stru Description: enable/disable S/PDIF out from ac97 mixer ---------------------------------------------------------------------------*/ -static int snd_trident_spdif_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_trident_spdif_control_info snd_ctl_boolean_mono_info static int snd_trident_spdif_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2545,15 +2537,7 @@ static struct snd_kcontrol_new snd_tride Description: enable/disable rear path for ac97 ---------------------------------------------------------------------------*/ -static int snd_trident_ac97_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_trident_ac97_control_info snd_ctl_boolean_mono_info static int snd_trident_ac97_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 6ea09df..45d89de 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1572,15 +1572,7 @@ static struct snd_kcontrol_new snd_via82 .put = snd_via8233_capture_source_put, }; -static int snd_via8233_dxs3_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_via8233_dxs3_spdif_info snd_ctl_boolean_mono_info static int snd_via8233_dxs3_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2098,7 +2090,7 @@ #endif pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) @@ -2117,7 +2109,7 @@ #if 0 /* FIXME: we don't support the sec chip->ac97_secondary = 1; goto __ac97_ok2; } - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 72425e7..3aa9d31 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -983,7 +983,7 @@ #endif pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) @@ -1001,7 +1001,7 @@ #endif chip->ac97_secondary = 1; goto __ac97_ok2; } - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index ab7a81c..e76ed5d 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -84,7 +84,6 @@ static int snd_ymfpci_codec_ready(struct do { if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0) return 0; - set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg)); @@ -171,17 +170,6 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate return val[0]; } -static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm) -{ - unsigned int value; - struct snd_ymfpci_pcm_mixer *mixer; - - mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number]; - value = min_t(unsigned int, mixer->left, 0x7fff) >> 1; - value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16; - snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value); -} - /* * Hardware start management */ @@ -389,6 +377,7 @@ static int snd_ymfpci_playback_trigger(s { struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; + struct snd_kcontrol *kctl = NULL; int result = 0; spin_lock(&chip->reg_lock); @@ -406,6 +395,11 @@ static int snd_ymfpci_playback_trigger(s ypcm->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: + if (substream->pcm == chip->pcm && !ypcm->use_441_slot) { + kctl = chip->pcm_mixer[substream->number].ctl; + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + } + /* fall through */ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0; @@ -419,6 +413,8 @@ static int snd_ymfpci_playback_trigger(s } __unlock: spin_unlock(&chip->reg_lock); + if (kctl) + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return result; } static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream, @@ -526,7 +522,6 @@ static void snd_ymfpci_pcm_init_voice(st ypcm->chip->src441_used = voice->number; ypcm->use_441_slot = 1; format |= 0x10000000; - snd_ymfpci_pcm_441_volume_set(ypcm); } if (ypcm->chip->src441_used == voice->number && (format & 0x10000000) == 0) { @@ -667,6 +662,7 @@ static int snd_ymfpci_playback_prepare(s struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ymfpci_pcm *ypcm = runtime->private_data; + struct snd_kcontrol *kctl; unsigned int nvoice; ypcm->period_size = runtime->period_size; @@ -676,6 +672,12 @@ static int snd_ymfpci_playback_prepare(s for (nvoice = 0; nvoice < runtime->channels; nvoice++) snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime, substream->pcm == chip->pcm); + + if (substream->pcm == chip->pcm && !ypcm->use_441_slot) { + kctl = chip->pcm_mixer[substream->number].ctl; + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); + } return 0; } @@ -926,7 +928,6 @@ static int snd_ymfpci_playback_open(stru struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ymfpci_pcm *ypcm; - struct snd_kcontrol *kctl; int err; if ((err = snd_ymfpci_playback_open_1(substream)) < 0) @@ -941,10 +942,6 @@ static int snd_ymfpci_playback_open(stru chip->rear_opened++; } spin_unlock_irq(&chip->reg_lock); - - kctl = chip->pcm_mixer[substream->number].ctl; - kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return 0; } @@ -1039,7 +1036,6 @@ static int snd_ymfpci_playback_close(str { struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; - struct snd_kcontrol *kctl; spin_lock_irq(&chip->reg_lock); if (ypcm->output_rear && chip->rear_opened > 0) { @@ -1047,9 +1043,6 @@ static int snd_ymfpci_playback_close(str ymfpci_close_extension(chip); } spin_unlock_irq(&chip->reg_lock); - kctl = chip->pcm_mixer[substream->number].ctl; - kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return snd_ymfpci_playback_close_1(substream); } @@ -1443,22 +1436,7 @@ #define YMFPCI_SINGLE(xname, xindex, reg .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \ .private_value = ((reg) | ((shift) << 16)) } -static int snd_ymfpci_info_single(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int reg = kcontrol->private_value & 0xffff; - - switch (reg) { - case YDSXGR_SPDIFOUTCTRL: break; - case YDSXGR_SPDIFINCTRL: break; - default: return -EINVAL; - } - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ymfpci_info_single snd_ctl_boolean_mono_info static int snd_ymfpci_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1567,17 +1545,30 @@ static int snd_ymfpci_put_double(struct return change; } +static int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); + unsigned int reg = YDSXGR_NATIVEDACOUTVOL; + unsigned int reg2 = YDSXGR_BUF441OUTVOL; + int change; + unsigned int value, oval; + + value = ucontrol->value.integer.value[0] & 0x3fff; + value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16; + spin_lock_irq(&chip->reg_lock); + oval = snd_ymfpci_readl(chip, reg); + change = value != oval; + snd_ymfpci_writel(chip, reg, value); + snd_ymfpci_writel(chip, reg2, value); + spin_unlock_irq(&chip->reg_lock); + return change; +} + /* * 4ch duplication */ -static int snd_ymfpci_info_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ymfpci_info_dup4ch snd_ctl_boolean_mono_info static int snd_ymfpci_get_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1598,7 +1589,17 @@ static int snd_ymfpci_put_dup4ch(struct static struct snd_kcontrol_new snd_ymfpci_controls[] __devinitdata = { -YMFPCI_DOUBLE("Wave Playback Volume", 0, YDSXGR_NATIVEDACOUTVOL), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Wave Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = snd_ymfpci_info_double, + .get = snd_ymfpci_get_double, + .put = snd_ymfpci_put_nativedacvol, + .private_value = YDSXGR_NATIVEDACOUTVOL, + .tlv = { .p = db_scale_native }, +}, YMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL), YMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL), YMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL), @@ -1665,14 +1666,7 @@ static int snd_ymfpci_set_gpio_out(struc return 0; } -static int snd_ymfpci_gpio_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ymfpci_gpio_sw_info snd_ctl_boolean_mono_info static int snd_ymfpci_gpio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1748,8 +1742,6 @@ static int snd_ymfpci_pcm_vol_put(struct struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; if (!ypcm->use_441_slot) ypcm->update_pcm_vol = 2; - else - snd_ymfpci_pcm_441_volume_set(ypcm); } spin_unlock_irqrestore(&chip->voice_lock, flags); return 1; diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index 2b1f996..1eff158 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -80,14 +80,7 @@ static struct snd_kcontrol_new vx_contro /* * mic boost level control (for VXP440) */ -static int vx_mic_boost_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define vx_mic_boost_info snd_ctl_boolean_mono_info static int vx_mic_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index 57202b0..c5a1f0b 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -91,15 +91,7 @@ static int daca_set_volume(struct pmac_d /* deemphasis switch */ -static int daca_info_deemphasis(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define daca_info_deemphasis snd_ctl_boolean_mono_info static int daca_get_deemphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 7a22f0f..4f9b19c 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -490,35 +490,14 @@ static int snd_pmac_pcm_open(struct snd_ struct snd_pcm_substream *subs) { struct snd_pcm_runtime *runtime = subs->runtime; - int i, j, fflags; - static int typical_freqs[] = { - 44100, - 22050, - 11025, - 0, - }; - static int typical_freq_flags[] = { - SNDRV_PCM_RATE_44100, - SNDRV_PCM_RATE_22050, - SNDRV_PCM_RATE_11025, - 0, - }; + int i; /* look up frequency table and fill bit mask */ runtime->hw.rates = 0; - fflags = chip->freqs_ok; - for (i = 0; typical_freqs[i]; i++) { - for (j = 0; j < chip->num_freqs; j++) { - if ((chip->freqs_ok & (1 << j)) && - chip->freq_table[j] == typical_freqs[i]) { - runtime->hw.rates |= typical_freq_flags[i]; - fflags &= ~(1 << j); - break; - } - } - } - if (fflags) /* rest */ - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; + for (i = 0; i < chip->num_freqs; i++) + if (chip->freqs_ok & (1 << i)) + runtime->hw.rates |= + snd_pcm_rate_to_rate_bit(chip->freq_table[i]); /* check for minimum and maximum rates */ for (i = 0; i < chip->num_freqs; i++) { @@ -551,9 +530,6 @@ #endif runtime->hw.periods_max = rec->cmd.size - 1; - if (chip->can_duplex) - snd_pcm_set_sync(subs); - /* constraints to fix choppy sound */ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); return 0; @@ -1035,29 +1011,6 @@ static int __init snd_pmac_detect(struct return 0; } -/* - * exported - boolean info callbacks for ease of programming - */ -int snd_pmac_boolean_stereo_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -int snd_pmac_boolean_mono_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - #ifdef PMAC_SUPPORT_AUTOMUTE /* * auto-mute diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h index 8394e66..25c512c 100644 --- a/sound/ppc/pmac.h +++ b/sound/ppc/pmac.h @@ -202,8 +202,8 @@ int snd_pmac_keywest_init(struct pmac_ke void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c); /* misc */ -int snd_pmac_boolean_stereo_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_pmac_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); +#define snd_pmac_boolean_stereo_info snd_ctl_boolean_stereo_info +#define snd_pmac_boolean_mono_info snd_ctl_boolean_mono_info int snd_pmac_add_automute(struct snd_pmac *chip); diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 1aa0b46..27b6189 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -33,7 +33,6 @@ #include #include #include #include -#include #include #include #include diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 7397865..131ec48 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -451,15 +451,7 @@ static int __init snd_aicapcmchip(struct } /* Mixer controls */ -static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define aica_pcmswitch_info snd_ctl_boolean_mono_info static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e5fb437..7824880 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -17,3 +17,23 @@ config SND_SOC_WM8753 config SND_SOC_WM9712 tristate depends on SND_SOC + +# Cirrus Logic CS4270 Codec +config SND_SOC_CS4270 + tristate + depends on SND_SOC + +# 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 + diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e39a747..7ad78e3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,9 +3,11 @@ snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o snd-soc-wm9712-objs := wm9712.o +snd-soc-cs4270-objs := cs4270.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.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_WM9712) += snd-soc-wm9712.o +obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c new file mode 100644 index 0000000..5d601ad --- /dev/null +++ b/sound/soc/codecs/cs4270.c @@ -0,0 +1,805 @@ +/* + * CS4270 ALSA SoC (ASoC) codec driver + * + * Author: Timur Tabi + * + * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * This is an ASoC device driver for the Cirrus Logic CS4270 codec. + * + * Current features/limitations: + * + * 1) Software mode is supported. Stand-alone mode is automatically + * selected if I2C is disabled or if a CS4270 is not found on the I2C + * bus. However, stand-alone mode is only partially implemented because + * there is no mechanism yet for this driver and the machine driver to + * communicate the values of the M0, M1, MCLK1, and MCLK2 pins. + * 2) Only I2C is supported, not SPI + * 3) Only Master mode is supported, not Slave. + * 4) The machine driver's 'startup' function must call + * cs4270_set_dai_sysclk() with the value of MCLK. + * 5) Only I2S and left-justified modes are supported + * 6) Power management is not supported + * 7) The only supported control is volume and hardware mute (if enabled) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cs4270.h" + +/* If I2C is defined, then we support software mode. However, if we're + not compiled as module but I2C is, then we can't use I2C calls. */ +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +#define USE_I2C +#endif + +/* Private data for the CS4270 */ +struct cs4270_private { + unsigned int mclk; /* Input frequency of the MCLK pin */ + unsigned int mode; /* The mode (I2S or left-justified) */ +}; + +/* The number of MCLK/LRCK ratios supported by the CS4270 */ +#define NUM_MCLK_RATIOS 9 + +/* The actual MCLK/LRCK ratios, in increasing numerical order */ +static unsigned int mclk_ratios[NUM_MCLK_RATIOS] = + {64, 96, 128, 192, 256, 384, 512, 768, 1024}; + +/* + * Determine the CS4270 samples rates. + * + * 'freq' is the input frequency to MCLK. The other parameters are ignored. + * + * The value of MCLK is used to determine which sample rates are supported + * by the CS4270. The ratio of MCLK / Fs must be equal to one of nine + * support values: 64, 96, 128, 192, 256, 384, 512, 768, and 1024. + * + * This function calculates the nine ratios and determines which ones match + * a standard sample rate. If there's a match, then it is added to the list + * of support sample rates. + * + * This function must be called by the machine driver's 'startup' function, + * otherwise the list of supported sample rates will not be available in + * time for ALSA. + * + * Note that in stand-alone mode, the sample rate is determined by input + * pins M0, M1, MDIV1, and MDIV2. Also in stand-alone mode, divide-by-3 + * is not a programmable option. However, divide-by-3 is not an available + * option in stand-alone mode. This cases two problems: a ratio of 768 is + * not available (it requires divide-by-3) and B) ratios 192 and 384 can + * only be selected with divide-by-1.5, but there is an errate that make + * this selection difficult. + * + * In addition, there is no mechanism for communicating with the machine + * driver what the input settings can be. This would need to be implemented + * for stand-alone mode to work. + */ +static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4270_private *cs4270 = codec->private_data; + unsigned int rates = 0; + unsigned int rate_min = -1; + unsigned int rate_max = 0; + unsigned int i; + + cs4270->mclk = freq; + + for (i = 0; i < NUM_MCLK_RATIOS; i++) { + unsigned int rate = freq / mclk_ratios[i]; + rates |= snd_pcm_rate_to_rate_bit(rate); + if (rate < rate_min) + rate_min = rate; + if (rate > rate_max) + rate_max = rate; + } + /* FIXME: soc should support a rate list */ + rates &= ~SNDRV_PCM_RATE_KNOT; + + if (!rates) { + printk(KERN_ERR "cs4270: could not find a valid sample rate\n"); + return -EINVAL; + } + + codec_dai->playback.rates = rates; + codec_dai->playback.rate_min = rate_min; + codec_dai->playback.rate_max = rate_max; + + codec_dai->capture.rates = rates; + codec_dai->capture.rate_min = rate_min; + codec_dai->capture.rate_max = rate_max; + + return 0; +} + +/* + * Configure the codec for the selected audio format + * + * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the + * codec accordingly. + * + * Currently, this function only supports SND_SOC_DAIFMT_I2S and + * SND_SOC_DAIFMT_LEFT_J. The CS4270 codec also supports right-justified + * data for playback only, but ASoC currently does not support different + * formats for playback vs. record. + */ +static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4270_private *cs4270 = codec->private_data; + int ret = 0; + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + printk(KERN_ERR "cs4270: invalid DAI format\n"); + ret = -EINVAL; + } + + return ret; +} + +/* + * The codec isn't really big-endian or little-endian, since the I2S + * interface requires data to be sent serially with the MSbit first. + * However, to support BE and LE I2S devices, we specify both here. That + * way, ALSA will always match the bit patterns. + */ +#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) + +#ifdef USE_I2C + +/* CS4270 registers addresses */ +#define CS4270_CHIPID 0x01 /* Chip ID */ +#define CS4270_PWRCTL 0x02 /* Power Control */ +#define CS4270_MODE 0x03 /* Mode Control */ +#define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */ +#define CS4270_TRANS 0x05 /* Transition Control */ +#define CS4270_MUTE 0x06 /* Mute Control */ +#define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */ +#define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */ + +#define CS4270_FIRSTREG 0x01 +#define CS4270_LASTREG 0x08 +#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) + +/* Bit masks for the CS4270 registers */ +#define CS4270_CHIPID_ID 0xF0 +#define CS4270_CHIPID_REV 0x0F +#define CS4270_PWRCTL_FREEZE 0x80 +#define CS4270_PWRCTL_PDN_ADC 0x20 +#define CS4270_PWRCTL_PDN_DAC 0x02 +#define CS4270_PWRCTL_PDN 0x01 +#define CS4270_MODE_SPEED_MASK 0x30 +#define CS4270_MODE_1X 0x00 +#define CS4270_MODE_2X 0x10 +#define CS4270_MODE_4X 0x20 +#define CS4270_MODE_SLAVE 0x30 +#define CS4270_MODE_DIV_MASK 0x0E +#define CS4270_MODE_DIV1 0x00 +#define CS4270_MODE_DIV15 0x02 +#define CS4270_MODE_DIV2 0x04 +#define CS4270_MODE_DIV3 0x06 +#define CS4270_MODE_DIV4 0x08 +#define CS4270_MODE_POPGUARD 0x01 +#define CS4270_FORMAT_FREEZE_A 0x80 +#define CS4270_FORMAT_FREEZE_B 0x40 +#define CS4270_FORMAT_LOOPBACK 0x20 +#define CS4270_FORMAT_DAC_MASK 0x18 +#define CS4270_FORMAT_DAC_LJ 0x00 +#define CS4270_FORMAT_DAC_I2S 0x08 +#define CS4270_FORMAT_DAC_RJ16 0x18 +#define CS4270_FORMAT_DAC_RJ24 0x10 +#define CS4270_FORMAT_ADC_MASK 0x01 +#define CS4270_FORMAT_ADC_LJ 0x00 +#define CS4270_FORMAT_ADC_I2S 0x01 +#define CS4270_TRANS_ONE_VOL 0x80 +#define CS4270_TRANS_SOFT 0x40 +#define CS4270_TRANS_ZERO 0x20 +#define CS4270_TRANS_INV_ADC_A 0x08 +#define CS4270_TRANS_INV_ADC_B 0x10 +#define CS4270_TRANS_INV_DAC_A 0x02 +#define CS4270_TRANS_INV_DAC_B 0x04 +#define CS4270_TRANS_DEEMPH 0x01 +#define CS4270_MUTE_AUTO 0x20 +#define CS4270_MUTE_ADC_A 0x08 +#define CS4270_MUTE_ADC_B 0x10 +#define CS4270_MUTE_POLARITY 0x04 +#define CS4270_MUTE_DAC_A 0x01 +#define CS4270_MUTE_DAC_B 0x02 + +/* + * A list of addresses on which this CS4270 could use. I2C addresses are + * 7 bits. For the CS4270, the upper four bits are always 1001, and the + * lower three bits are determined via the AD2, AD1, and AD0 pins + * (respectively). + */ +static unsigned short normal_i2c[] = { + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; + +/* + * Pre-fill the CS4270 register cache. + * + * We use the auto-increment feature of the CS4270 to read all registers in + * one shot. + */ +static int cs4270_fill_cache(struct snd_soc_codec *codec) +{ + u8 *cache = codec->reg_cache; + struct i2c_client *i2c_client = codec->control_data; + s32 length; + + length = i2c_smbus_read_i2c_block_data(i2c_client, + CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); + + if (length != CS4270_NUMREGS) { + printk(KERN_ERR "cs4270: I2C read failure, addr=0x%x\n", + i2c_client->addr); + return -EIO; + } + + return 0; +} + +/* + * Read from the CS4270 register cache. + * + * This CS4270 registers are cached to avoid excessive I2C I/O operations. + * After the initial read to pre-fill the cache, the CS4270 never updates + * the register values, so we won't have a cache coherncy problem. + */ +static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + + if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) + return -EIO; + + return cache[reg - CS4270_FIRSTREG]; +} + +/* + * Write to a CS4270 register via the I2C bus. + * + * This function writes the given value to the given CS4270 register, and + * also updates the register cache. + * + * Note that we don't use the hw_write function pointer of snd_soc_codec. + * That's because it's too clunky: the hw_write_t prototype does not match + * i2c_smbus_write_byte_data(), and it's just another layer of overhead. + */ +static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 *cache = codec->reg_cache; + + if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) + return -EIO; + + /* Only perform an I2C operation if the new value is different */ + if (cache[reg - CS4270_FIRSTREG] != value) { + struct i2c_client *client = codec->control_data; + if (i2c_smbus_write_byte_data(client, reg, value)) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return -EIO; + } + + /* We've written to the hardware, so update the cache */ + cache[reg - CS4270_FIRSTREG] = value; + } + + return 0; +} + +/* + * Clock Ratio Selection for Master Mode with I2C enabled + * + * The data for this chart is taken from Table 5 of the CS4270 reference + * manual. + * + * This table is used to determine how to program the Mode Control register. + * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling + * rates the CS4270 currently supports. + * + * Each element in this array corresponds to the ratios in mclk_ratios[]. + * These two arrays need to be in sync. + * + * 'speed_mode' is the corresponding bit pattern to be written to the + * MODE bits of the Mode Control Register + * + * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of + * the Mode Control Register. + * + * In situations where a single ratio is represented by multiple speed + * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick + * double-speed instead of quad-speed. However, the CS4270 errata states + * that Divide-By-1.5 can cause failures, so we avoid that mode where + * possible. + * + * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not + * work if VD = 3.3V. If this effects you, select the + * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will + * never select any sample rates that require divide-by-1.5. + */ +static struct { + u8 speed_mode; + u8 mclk; +} cs4270_mode_ratios[NUM_MCLK_RATIOS] = { + {CS4270_MODE_4X, CS4270_MODE_DIV1}, /* 64 */ +#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA + {CS4270_MODE_4X, CS4270_MODE_DIV15}, /* 96 */ +#endif + {CS4270_MODE_2X, CS4270_MODE_DIV1}, /* 128 */ + {CS4270_MODE_4X, CS4270_MODE_DIV3}, /* 192 */ + {CS4270_MODE_1X, CS4270_MODE_DIV1}, /* 256 */ + {CS4270_MODE_2X, CS4270_MODE_DIV3}, /* 384 */ + {CS4270_MODE_1X, CS4270_MODE_DIV2}, /* 512 */ + {CS4270_MODE_1X, CS4270_MODE_DIV3}, /* 768 */ + {CS4270_MODE_1X, CS4270_MODE_DIV4} /* 1024 */ +}; + +/* + * Program the CS4270 with the given hardware parameters. + * + * The .dai_ops functions are used to provide board-specific data, like + * input frequencies, to this driver. This function takes that information, + * combines it with the hardware parameters provided, and programs the + * hardware accordingly. + */ +static int cs4270_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 cs4270_private *cs4270 = codec->private_data; + unsigned int ret = 0; + unsigned int i; + unsigned int rate; + unsigned int ratio; + int reg; + + /* Figure out which MCLK/LRCK ratio to use */ + + rate = params_rate(params); /* Sampling rate, in Hz */ + ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */ + + for (i = 0; i < NUM_MCLK_RATIOS; i++) { + if (mclk_ratios[i] == ratio) + break; + } + + if (i == NUM_MCLK_RATIOS) { + /* We did not find a matching ratio */ + printk(KERN_ERR "cs4270: could not find matching ratio\n"); + return -EINVAL; + } + + /* Freeze and power-down the codec */ + + ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE | + CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | + CS4270_PWRCTL_PDN); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Program the mode control register */ + + reg = snd_soc_read(codec, CS4270_MODE); + reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); + reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk; + + ret = snd_soc_write(codec, CS4270_MODE, reg); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Program the format register */ + + reg = snd_soc_read(codec, CS4270_FORMAT); + reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); + + switch (cs4270->mode) { + case SND_SOC_DAIFMT_I2S: + reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ; + break; + default: + printk(KERN_ERR "cs4270: unknown format\n"); + return -EINVAL; + } + + ret = snd_soc_write(codec, CS4270_FORMAT, reg); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Disable auto-mute. This feature appears to be buggy, because in + some situations, auto-mute will not deactivate when it should. */ + + reg = snd_soc_read(codec, CS4270_MUTE); + reg &= ~CS4270_MUTE_AUTO; + ret = snd_soc_write(codec, CS4270_MUTE, reg); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Thaw and power-up the codec */ + + ret = snd_soc_write(codec, CS4270_PWRCTL, 0); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + return ret; +} + +#ifdef CONFIG_SND_SOC_CS4270_HWMUTE + +/* + * Set the CS4270 external mute + * + * This function toggles the mute bits in the MUTE register. The CS4270's + * mute capability is intended for external muting circuitry, so if the + * board does not have the MUTEA or MUTEB pins connected to such circuitry, + * then this function will do nothing. + */ +static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + int reg6; + + reg6 = snd_soc_read(codec, CS4270_MUTE); + + if (mute) + reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | + CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; + else + reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | + CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); + + return snd_soc_write(codec, CS4270_MUTE, reg6); +} + +#endif + +static int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind); + +/* + * Notify the driver that a new I2C bus has been found. + * + * This function is called for each I2C bus in the system. The function + * then asks the I2C subsystem to probe that bus at the addresses on which + * our device (the CS4270) could exist. If a device is found at one of + * those addresses, then our probe function (cs4270_i2c_probe) is called. + */ +static int cs4270_i2c_attach(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, cs4270_i2c_probe); +} + +static int cs4270_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + + i2c_detach_client(client); + codec->control_data = NULL; + + kfree(codec->reg_cache); + codec->reg_cache = NULL; + + kfree(client); + return 0; +} + +/* A list of non-DAPM controls that the CS4270 supports */ +static const struct snd_kcontrol_new cs4270_snd_controls[] = { + SOC_DOUBLE_R("Master Playback Volume", + CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) +}; + +static struct i2c_driver cs4270_i2c_driver = { + .driver = { + .name = "CS4270 I2C", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_CS4270, + .attach_adapter = cs4270_i2c_attach, + .detach_client = cs4270_i2c_detach, +}; + +/* + * Global variable to store socdev for i2c probe function. + * + * If struct i2c_driver had a private_data field, we wouldn't need to use + * cs4270_socdec. This is the only way to pass the socdev structure to + * cs4270_i2c_probe(). + * + * The real solution to cs4270_socdev is to create a mechanism + * that maps I2C addresses to snd_soc_device structures. Perhaps the + * creation of the snd_soc_device object should be moved out of + * cs4270_probe() and into cs4270_i2c_probe(), but that would make this + * driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby + * the chip is *not* connected to the I2C bus, but is instead configured via + * input pins. + */ +static struct snd_soc_device *cs4270_socdev; + +/* + * Initialize the I2C interface of the CS4270 + * + * This function is called for whenever the I2C subsystem finds a device + * at a particular address. + * + * Note: snd_soc_new_pcms() must be called before this function can be called, + * because of snd_ctl_add(). + */ +static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) +{ + struct snd_soc_device *socdev = cs4270_socdev; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c_client = NULL; + int i; + int ret = 0; + + /* Probing all possible addresses has one drawback: if there are + multiple CS4270s on the bus, then you cannot specify which + socdev is matched with which CS4270. For now, we just reject + this I2C device if the socdev already has one attached. */ + if (codec->control_data) + return -ENODEV; + + /* Note: codec_dai->codec is NULL here */ + + i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!i2c_client) { + printk(KERN_ERR "cs4270: could not allocate I2C client\n"); + return -ENOMEM; + } + + codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); + if (!codec->reg_cache) { + printk(KERN_ERR "cs4270: could not allocate register cache\n"); + ret = -ENOMEM; + goto error; + } + + i2c_set_clientdata(i2c_client, codec); + strcpy(i2c_client->name, "CS4270"); + + i2c_client->driver = &cs4270_i2c_driver; + i2c_client->adapter = adapter; + i2c_client->addr = addr; + + /* Verify that we have a CS4270 */ + + ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to read I2C\n"); + goto error; + } + /* The top four bits of the chip ID should be 1100. */ + if ((ret & 0xF0) != 0xC0) { + /* The device at this address is not a CS4270 codec */ + ret = -ENODEV; + goto error; + } + + printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr); + printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); + + /* Tell the I2C layer a new client has arrived */ + + ret = i2c_attach_client(i2c_client); + if (ret) { + printk(KERN_ERR "cs4270: could not attach codec, " + "I2C address %x, error code %i\n", addr, ret); + goto error; + } + + codec->control_data = i2c_client; + codec->read = cs4270_read_reg_cache; + codec->write = cs4270_i2c_write; + codec->reg_cache_size = CS4270_NUMREGS; + + /* The I2C interface is set up, so pre-fill our register cache */ + + ret = cs4270_fill_cache(codec); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to fill register cache\n"); + goto error; + } + + /* Add the non-DAPM controls */ + + for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { + struct snd_kcontrol *kctrl = + snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); + + ret = snd_ctl_add(codec->card, kctrl); + if (ret < 0) + goto error; + } + + return 0; + +error: + if (codec->control_data) { + i2c_detach_client(i2c_client); + codec->control_data = NULL; + } + + kfree(codec->reg_cache); + codec->reg_cache = NULL; + codec->reg_cache_size = 0; + + kfree(i2c_client); + + return ret; +} + +#endif + +struct snd_soc_codec_dai cs4270_dai = { + .name = "CS4270", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = 0, + .formats = CS4270_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = 0, + .formats = CS4270_FORMATS, + }, + .dai_ops = { + .set_sysclk = cs4270_set_dai_sysclk, + .set_fmt = cs4270_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(cs4270_dai); + +/* + * ASoC probe function + * + * This function is called when the machine driver calls + * platform_device_add(). + */ +static int cs4270_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + printk(KERN_INFO "CS4270 ALSA SoC Codec\n"); + + /* Allocate enough space for the snd_soc_codec structure + and our private data together. */ + codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) + + sizeof(struct cs4270_private), GFP_KERNEL); + if (!codec) { + printk(KERN_ERR "cs4270: Could not allocate codec structure\n"); + return -ENOMEM; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->name = "CS4270"; + codec->owner = THIS_MODULE; + codec->dai = &cs4270_dai; + codec->num_dai = 1; + codec->private_data = codec + ALIGN(sizeof(struct snd_soc_codec), 4); + + socdev->codec = codec; + + /* Register PCMs */ + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to create PCMs\n"); + return ret; + } + +#ifdef USE_I2C + cs4270_socdev = socdev; + + ret = i2c_add_driver(&cs4270_i2c_driver); + if (ret) { + printk(KERN_ERR "cs4270: failed to attach driver"); + snd_soc_free_pcms(socdev); + return ret; + } + + /* Did we find a CS4270 on the I2C bus? */ + if (codec->control_data) { + /* Initialize codec ops */ + cs4270_dai.ops.hw_params = cs4270_hw_params; +#ifdef CONFIG_SND_SOC_CS4270_HWMUTE + cs4270_dai.dai_ops.digital_mute = cs4270_mute; +#endif + } else + printk(KERN_INFO "cs4270: no I2C device found, " + "using stand-alone mode\n"); +#else + printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); +#endif + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to register card\n"); + snd_soc_free_pcms(socdev); + return ret; + } + + return ret; +} + +static int cs4270_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + +#ifdef USE_I2C + if (socdev->codec->control_data) + i2c_del_driver(&cs4270_i2c_driver); +#endif + + kfree(socdev->codec); + socdev->codec = NULL; + + return 0; +} + +/* + * ASoC codec device structure + * + * Assign this variable to the codec_dev field of the machine driver's + * snd_soc_device structure. + */ +struct snd_soc_codec_device soc_codec_device_cs4270 = { + .probe = cs4270_probe, + .remove = cs4270_remove +}; +EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); + +MODULE_AUTHOR("Timur Tabi "); +MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h new file mode 100644 index 0000000..0ced49b --- /dev/null +++ b/sound/soc/codecs/cs4270.h @@ -0,0 +1,28 @@ +/* + * Cirrus Logic CS4270 ALSA SoC Codec Driver + * + * Author: Timur Tabi + * + * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef _CS4270_H +#define _CS4270_H + +/* + * The ASoC codec DAI structure for the CS4270. Assign this structure to + * the .codec_dai field of your machine driver's snd_soc_dai_link structure. + */ +extern struct snd_soc_codec_dai cs4270_dai; + +/* + * The ASoC codec device structure for the CS4270. Assign this structure + * to the .codec_dev field of your machine driver's snd_soc_device + * structure. + */ +extern struct snd_soc_codec_device soc_codec_device_cs4270; + +#endif diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 80e8210..4dd8f35 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -34,7 +34,6 @@ #include #include #include #include -#include #include "../codecs/wm8750.h" #include "pxa2xx-pcm.h" #include "pxa2xx-i2s.h" diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index e97c683..5632a2e 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -18,7 +18,7 @@ config SND_S3C2443_SOC_AC97 config SND_S3C24XX_SOC_NEO1973_WM8753 tristate "SoC I2S Audio support for NEO1973 - WM8753" - depends on SND_S3C24XX_SOC && MACH_GTA01 + depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 select SND_S3C24XX_SOC_I2S select SND_SOC_WM8753 help diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 39f0246..cd89c41 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -385,6 +385,7 @@ static int s3c24xx_i2s_probe(struct plat s3c24xx_i2s.iis_clk=clk_get(&pdev->dev, "iis"); if (s3c24xx_i2s.iis_clk == NULL) { DBG("failed to get iis_clock\n"); + iounmap(s3c24xx_i2s.regs); return -ENODEV; } clk_enable(s3c24xx_i2s.iis_clk); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index bfbdc3c..4107a87 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -158,18 +158,22 @@ static int s3c24xx_pcm_hw_params(struct if (!dma) return 0; - /* prepare DMA */ - prtd->params = dma; + /* this may get called several times by oss emulation + * with different params -HW */ + if (prtd->params == NULL) { + /* prepare DMA */ + prtd->params = dma; - DBG("params %p, client %p, channel %d\n", prtd->params, - prtd->params->client, prtd->params->channel); + DBG("params %p, client %p, channel %d\n", prtd->params, + prtd->params->client, prtd->params->channel); - ret = s3c2410_dma_request(prtd->params->channel, - prtd->params->client, NULL); + ret = s3c2410_dma_request(prtd->params->channel, + prtd->params->client, NULL); - if (ret) { - DBG(KERN_ERR "failed to get dma channel\n"); - return ret; + if (ret) { + DBG(KERN_ERR "failed to get dma channel\n"); + return ret; + } } /* channel needs configuring for mem=>device, increment memory addr, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 92d5d91..91651bd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1362,26 +1362,6 @@ int snd_soc_info_volsw_ext(struct snd_kc EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); /** - * snd_soc_info_bool_ext - external single boolean mixer info callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information about a single boolean external mixer control. - * - * Returns 0 for success. - */ -int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext); - -/** * snd_soc_info_volsw - single mixer info callback * @kcontrol: mixer control * @uinfo: control element information diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 96bce55..b3193e6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -63,7 +63,7 @@ #endif #define POP_DEBUG 0 #if POP_DEBUG #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ -#define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time)) +#define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time)) #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) #else #define pop_dbg(format, arg...) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f2950ca..20daf26 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -30,17 +30,11 @@ #include #ifdef CONFIG_SBUS #define SBUS_SUPPORT -#endif - -#ifdef SBUS_SUPPORT #include #endif #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64) #define EBUS_SUPPORT -#endif - -#ifdef EBUS_SUPPORT #include #include #endif @@ -339,7 +333,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, }; @@ -389,116 +383,85 @@ static unsigned char snd_cs4231_original static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr) { #ifdef EBUS_SUPPORT - if (cp->flags & CS4231_FLAG_EBUS) { + if (cp->flags & CS4231_FLAG_EBUS) return readb(reg_addr); - } else { + else #endif #ifdef SBUS_SUPPORT return sbus_readb(reg_addr); #endif -#ifdef EBUS_SUPPORT - } -#endif } static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val, void __iomem *reg_addr) { #ifdef EBUS_SUPPORT - if (cp->flags & CS4231_FLAG_EBUS) { + if (cp->flags & CS4231_FLAG_EBUS) return writeb(val, reg_addr); - } else { + else #endif #ifdef SBUS_SUPPORT return sbus_writeb(val, reg_addr); #endif -#ifdef EBUS_SUPPORT - } -#endif } /* * Basic I/O functions */ -static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, - unsigned char mask, unsigned char value) +static void snd_cs4231_ready(struct snd_cs4231 *chip) { int timeout; - unsigned char tmp; for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) udelay(100); -#ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); -#endif - if (chip->calibrate_mute) { - chip->image[reg] &= mask; - chip->image[reg] |= value; - } else { - __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); - mb(); - tmp = (chip->image[reg] & mask) | value; - __cs4231_writeb(chip, tmp, CS4231P(chip, REG)); - chip->image[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_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); + snd_printdd("out: auto calibration time out - reg = 0x%x, " + "value = 0x%x\n", + reg, value); #endif __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); + wmb(); __cs4231_writeb(chip, value, CS4231P(chip, REG)); mb(); } -static void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) +static inline void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, + unsigned char mask, unsigned char value) { - int timeout; + unsigned char tmp = (chip->image[reg] & mask) | value; - for (timeout = 250; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); -#ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); -#endif - __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); - __cs4231_writeb(chip, value, CS4231P(chip, REG)); + chip->image[reg] = tmp; + if (!chip->calibrate_mute) + snd_cs4231_dout(chip, reg, tmp); +} + +static void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, + unsigned char value) +{ + snd_cs4231_dout(chip, reg, value); chip->image[reg] = value; mb(); } static unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg) { - int timeout; - unsigned char ret; - - for (timeout = 250; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("in: auto calibration time out - reg = 0x%x\n", reg); + snd_printdd("in: auto calibration time out - reg = 0x%x\n", + reg); #endif __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); mb(); - ret = __cs4231_readb(chip, CS4231P(chip, REG)); - return ret; + return __cs4231_readb(chip, CS4231P(chip, REG)); } /* @@ -517,7 +480,7 @@ static void snd_cs4231_busy_wait(struct for (timeout = 500; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) - udelay(1000); + msleep(1); } static void snd_cs4231_mce_up(struct snd_cs4231 *chip) @@ -526,8 +489,7 @@ static void snd_cs4231_mce_up(struct snd int timeout; spin_lock_irqsave(&chip->lock, flags); - for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) - udelay(100); + snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) snd_printdd("mce_up - auto calibration time out (0)\n"); @@ -565,8 +527,8 @@ #endif /* calibration process */ - for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) - udelay(100); + snd_cs4231_ready(chip); + snd_cs4231_ready(chip); if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); spin_unlock_irqrestore(&chip->lock, flags); @@ -1058,11 +1020,6 @@ static int snd_cs4231_playback_hw_params 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); @@ -1100,11 +1057,6 @@ static int snd_cs4231_capture_hw_params( 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); @@ -1182,10 +1134,6 @@ static snd_pcm_uframes_t snd_cs4231_capt return bytes_to_frames(substream->runtime, ptr); } -/* - - */ - static int __init snd_cs4231_probe(struct snd_cs4231 *chip) { unsigned long flags; @@ -1356,7 +1304,7 @@ static struct snd_pcm_ops snd_cs4231_pla .close = snd_cs4231_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4231_playback_hw_params, - .hw_free = snd_cs4231_playback_hw_free, + .hw_free = snd_pcm_lib_free_pages, .prepare = snd_cs4231_playback_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_playback_pointer, @@ -1367,18 +1315,20 @@ static struct snd_pcm_ops snd_cs4231_cap .close = snd_cs4231_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4231_capture_hw_params, - .hw_free = snd_cs4231_capture_hw_free, + .hw_free = snd_pcm_lib_free_pages, .prepare = snd_cs4231_capture_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_capture_pointer, }; -static int __init snd_cs4231_pcm(struct snd_cs4231 *chip) +static int __init snd_cs4231_pcm(struct snd_card *card) { + struct snd_cs4231 *chip = card->private_data; struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "CS4231", 0, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, "CS4231", 0, 1, 1, &pcm); + if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops); @@ -1396,8 +1346,9 @@ static int __init snd_cs4231_pcm(struct return 0; } -static int __init snd_cs4231_timer(struct snd_cs4231 *chip) +static int __init snd_cs4231_timer(struct snd_card *card) { + struct snd_cs4231 *chip = card->private_data; struct snd_timer *timer; struct snd_timer_id tid; int err; @@ -1405,10 +1356,11 @@ static int __init snd_cs4231_timer(struc /* Timer initialization */ tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; - tid.card = chip->card->number; + tid.card = card->number; tid.device = 0; tid.subdevice = 0; - if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0) + err = snd_timer_new(card, "CS4231", &tid, &timer); + if (err < 0) return err; strcpy(timer->name, "CS4231"); timer->private_data = chip; @@ -1428,9 +1380,7 @@ static int snd_cs4231_info_mux(struct sn static char *texts[4] = { "Line", "CD", "Mic", "Mix" }; - 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; @@ -1670,21 +1620,19 @@ CS4231_SINGLE("Line Out Switch", 0, CS42 CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1) }; -static int __init snd_cs4231_mixer(struct snd_cs4231 *chip) +static int __init snd_cs4231_mixer(struct snd_card *card) { - struct snd_card *card; + struct snd_cs4231 *chip = card->private_data; int err, idx; snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL); - card = chip->card; - strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { - if ((err = snd_ctl_add(card, - snd_ctl_new1(&snd_cs4231_controls[idx], - chip))) < 0) + err = snd_ctl_add(card, + snd_ctl_new1(&snd_cs4231_controls[idx], chip)); + if (err < 0) return err; } return 0; @@ -1695,6 +1643,7 @@ static int dev; static int __init cs4231_attach_begin(struct snd_card **rcard) { struct snd_card *card; + struct snd_cs4231 *chip; *rcard = NULL; @@ -1706,31 +1655,40 @@ static int __init cs4231_attach_begin(st return -ENOENT; } - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(struct snd_cs4231)); if (card == NULL) return -ENOMEM; strcpy(card->driver, "CS4231"); strcpy(card->shortname, "Sun CS4231"); + chip = card->private_data; + chip->card = card; + *rcard = card; return 0; } -static int __init cs4231_attach_finish(struct snd_card *card, struct snd_cs4231 *chip) +static int __init cs4231_attach_finish(struct snd_card *card) { + struct snd_cs4231 *chip = card->private_data; int err; - if ((err = snd_cs4231_pcm(chip)) < 0) + err = snd_cs4231_pcm(card); + if (err < 0) goto out_err; - if ((err = snd_cs4231_mixer(chip)) < 0) + err = snd_cs4231_mixer(card); + if (err < 0) goto out_err; - if ((err = snd_cs4231_timer(chip)) < 0) + err = snd_cs4231_timer(card); + if (err < 0) goto out_err; - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto out_err; chip->next = cs4231_list; @@ -1907,8 +1865,6 @@ static int snd_cs4231_sbus_free(struct s if (chip->port) sbus_iounmap(chip->port, chip->regs_size); - kfree(chip); - return 0; } @@ -1925,23 +1881,16 @@ static struct snd_device_ops snd_cs4231_ static int __init snd_cs4231_sbus_create(struct snd_card *card, struct sbus_dev *sdev, - int dev, - struct snd_cs4231 **rchip) + int dev) { - struct snd_cs4231 *chip; + struct snd_cs4231 *chip = card->private_data; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - spin_lock_init(&chip->lock); spin_lock_init(&chip->c_dma.sbus_info.lock); spin_lock_init(&chip->p_dma.sbus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); - chip->card = card; chip->dev_u.sdev = sdev; chip->regs_size = sdev->reg_addrs[0].reg_size; memcpy(&chip->image, &snd_cs4231_original_image, @@ -1992,14 +1941,12 @@ static int __init snd_cs4231_sbus_create return err; } - *rchip = chip; return 0; } static int __init cs4231_sbus_attach(struct sbus_dev *sdev) { struct resource *rp = &sdev->resource[0]; - struct snd_cs4231 *cp; struct snd_card *card; int err; @@ -2013,12 +1960,13 @@ static int __init cs4231_sbus_attach(str (unsigned long long)rp->start, sdev->irqs[0]); - if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) { + err = snd_cs4231_sbus_create(card, sdev, dev); + if (err < 0) { snd_card_free(card); return err; } - return cs4231_attach_finish(card, cp); + return cs4231_attach_finish(card); } #endif @@ -2087,8 +2035,6 @@ static int snd_cs4231_ebus_free(struct s if (chip->port) iounmap(chip->port); - kfree(chip); - return 0; } @@ -2105,24 +2051,17 @@ static struct snd_device_ops snd_cs4231_ static int __init snd_cs4231_ebus_create(struct snd_card *card, struct linux_ebus_device *edev, - int dev, - struct snd_cs4231 **rchip) + int dev) { - struct snd_cs4231 *chip; + struct snd_cs4231 *chip = card->private_data; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - spin_lock_init(&chip->lock); spin_lock_init(&chip->c_dma.ebus_info.lock); spin_lock_init(&chip->p_dma.ebus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); chip->flags |= CS4231_FLAG_EBUS; - chip->card = card; chip->dev_u.pdev = edev->bus->self; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); @@ -2192,14 +2131,12 @@ static int __init snd_cs4231_ebus_create return err; } - *rchip = chip; return 0; } static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) { struct snd_card *card; - struct snd_cs4231 *chip; int err; err = cs4231_attach_begin(&card); @@ -2211,12 +2148,13 @@ static int __init cs4231_ebus_attach(str edev->resource[0].start, edev->irqs[0]); - if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) { + err = snd_cs4231_ebus_create(card, edev, dev); + if (err < 0) { snd_card_free(card); return err; } - return cs4231_attach_finish(card, chip); + return cs4231_attach_finish(card); } #endif diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index e07085a..376b986 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -8,18 +8,18 @@ * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) * - * This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO - * on Sun SPARCstation 10, 20, LX and Voyager models. + * This is the low level driver for the DBRI & MMCODEC duo used for ISDN & AUDIO + * on Sun SPARCStation 10, 20, LX and Voyager models. * * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel * data time multiplexer with ISDN support (aka T7259) * Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel. * CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?). * Documentation: - * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Tranceiver" from + * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Transceiver" from * Sparc Technology Business (courtesy of Sun Support) * - Data sheet of the T7903, a newer but very similar ISA bus equivalent - * available from the Lucent (formarly AT&T microelectronics) home + * available from the Lucent (formerly AT&T microelectronics) home * page. * - http://www.freesoft.org/Linux/DBRI/ * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec @@ -27,21 +27,21 @@ * Documentation: from the Crystal Semiconductor home page. * * The DBRI is a 32 pipe machine, each pipe can transfer some bits between - * memory and a serial device (long pipes, nr 0-15) or between two serial - * devices (short pipes, nr 16-31), or simply send a fixed data to a serial + * memory and a serial device (long pipes, no. 0-15) or between two serial + * devices (short pipes, no. 16-31), or simply send a fixed data to a serial * device (short pipes). - * A timeslot defines the bit-offset and nr of bits read from a serial device. + * A timeslot defines the bit-offset and no. of bits read from a serial device. * The timeslots are linked to 6 circular lists, one for each direction for * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes * (the second one is a monitor/tee pipe, valid only for serial input). * * The mmcodec is connected via the CHI bus and needs the data & some - * parameters (volume, output selection) timemultiplexed in 8 byte + * parameters (volume, output selection) time multiplexed in 8 byte * chunks. It also has a control mode, which serves for audio format setting. * * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on - * the same CHI bus, so I thought perhaps it is possible to use the onboard - * & the speakerbox codec simultanously, giving 2 (not very independent :-) + * the same CHI bus, so I thought perhaps it is possible to use the on-board + * & the speakerbox codec simultaneously, giving 2 (not very independent :-) * audio devices. But the SUN HW group decided against it, at least on my * LX the speakerbox connector has at least 1 pin missing and 1 wrongly * connected. @@ -56,6 +56,8 @@ #include #include #include +#include +#include #include #include @@ -64,8 +66,7 @@ #include #include #include -#include -#include +#include #include #include @@ -76,7 +77,8 @@ MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable 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 Sun DBRI soundcard."); @@ -104,7 +106,7 @@ static char *cmds[] = { "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV" }; -#define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x) +#define dprintk(a, x...) if (dbri_debug & a) printk(KERN_DEBUG x) #else #define dprintk(a, x...) do { } while (0) @@ -131,7 +133,7 @@ struct cs4215 { }; /* - * Control mode first + * Control mode first */ /* Time Slot 1, Status register */ @@ -219,7 +221,7 @@ #define CS4215_ADI (1<<7) /* A/D Data In /* Time Slot 7, Input Setting */ #define CS4215_LG(v) v /* Left Gain Setting 0xf: 22.5 dB */ #define CS4215_IS (1<<4) /* Input Select: 1=Microphone, 0=Line */ -#define CS4215_OVR (1<<5) /* 1: Overrange condition occurred */ +#define CS4215_OVR (1<<5) /* 1: Over range condition occurred */ #define CS4215_PIO0 (1<<6) /* Parallel I/O 0 */ #define CS4215_PIO1 (1<<7) @@ -232,12 +234,12 @@ #define CS4215_MA(v) (v<<4) /* Monitor P ****************************************************************************/ /* DBRI main registers */ -#define REG0 0x00UL /* Status and Control */ -#define REG1 0x04UL /* Mode and Interrupt */ -#define REG2 0x08UL /* Parallel IO */ -#define REG3 0x0cUL /* Test */ -#define REG8 0x20UL /* Command Queue Pointer */ -#define REG9 0x24UL /* Interrupt Queue Pointer */ +#define REG0 0x00 /* Status and Control */ +#define REG1 0x04 /* Mode and Interrupt */ +#define REG2 0x08 /* Parallel IO */ +#define REG3 0x0c /* Test */ +#define REG8 0x20 /* Command Queue Pointer */ +#define REG9 0x24 /* Interrupt Queue Pointer */ #define DBRI_NO_CMDS 64 #define DBRI_INT_BLK 64 @@ -285,7 +287,7 @@ struct dbri_pipe { /* Per stream (playback or record) information */ struct dbri_streaminfo { struct snd_pcm_substream *substream; - u32 dvma_buffer; /* Device view of Alsa DMA buffer */ + u32 dvma_buffer; /* Device view of ALSA DMA buffer */ int size; /* Size of DMA buffer */ size_t offset; /* offset in user buffer */ int pipe; /* Data pipe used */ @@ -295,8 +297,6 @@ struct dbri_streaminfo { /* This structure holds the information for both chips (DBRI & CS4215) */ struct snd_dbri { - struct snd_card *card; /* ALSA card */ - int regs_size, irq; /* Needed for unload */ struct sbus_dev *sdev; /* SBUS device info */ spinlock_t lock; @@ -317,8 +317,6 @@ struct snd_dbri { struct cs4215 mm; /* mmcodec special info */ /* per stream (playback/record) info */ struct dbri_streaminfo stream_info[DBRI_NO_STREAMS]; - - struct snd_dbri *next; }; #define DBRI_MAX_VOLUME 63 /* Output volume */ @@ -341,11 +339,11 @@ #define D_R (1<<0) /* Soft Reset */ /* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */ #define D_LITTLE_END (1<<8) /* Byte Order */ #define D_BIG_END (0<<8) /* Byte Order */ -#define D_MRR (1<<4) /* Multiple Error Ack on SBus (readonly) */ -#define D_MLE (1<<3) /* Multiple Late Error on SBus (readonly) */ -#define D_LBG (1<<2) /* Lost Bus Grant on SBus (readonly) */ -#define D_MBE (1<<1) /* Burst Error on SBus (readonly) */ -#define D_IR (1<<0) /* Interrupt Indicator (readonly) */ +#define D_MRR (1<<4) /* Multiple Error Ack on SBus (read only) */ +#define D_MLE (1<<3) /* Multiple Late Error on SBus (read only) */ +#define D_LBG (1<<2) /* Lost Bus Grant on SBus (read only) */ +#define D_MBE (1<<1) /* Burst Error on SBus (read only) */ +#define D_IR (1<<0) /* Interrupt Indicator (read only) */ /* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */ #define D_ENPIO3 (1<<7) /* Enable Pin 3 */ @@ -376,11 +374,11 @@ #define D_TEST 0xd /* No comment */ #define D_CDM 0xe /* CHI Data mode command */ /* Special bits for some commands */ -#define D_PIPE(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ +#define D_PIPE(v) ((v)<<0) /* Pipe No.: 0-15 long, 16-21 short */ /* Setup Data Pipe */ /* IRM */ -#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value rcvd */ +#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value received */ #define D_SDP_CHANGE (2<<18) /* Report any changes */ #define D_SDP_EVERY (3<<18) /* Report any changes */ #define D_SDP_EOL (1<<17) /* EOL interrupt enable */ @@ -419,7 +417,7 @@ #define D_TS_MONITOR (2<<10) /* Monitor #define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */ #define D_TS_ANCHOR (7<<10) /* Starting short pipes */ #define D_TS_MON(v) ((v)<<5) /* Monitor Pipe */ -#define D_TS_NEXT(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ +#define D_TS_NEXT(v) ((v)<<0) /* Pipe no.: 0-15 long, 16-21 short */ /* Concentration Highway Interface Modes */ #define D_CHI_CHICM(v) ((v)<<16) /* Clock mode */ @@ -435,7 +433,7 @@ #define D_NT_FBIT (1<<17) /* Frame Bit * #define D_NT_NBF (1<<16) /* Number of bad frames to loose framing */ #define D_NT_IRM_IMM (1<<15) /* Interrupt Report & Mask: Immediate */ #define D_NT_IRM_EN (1<<14) /* Interrupt Report & Mask: Enable */ -#define D_NT_ISNT (1<<13) /* Configfure interface as NT */ +#define D_NT_ISNT (1<<13) /* Configure interface as NT */ #define D_NT_FT (1<<12) /* Fixed Timing */ #define D_NT_EZ (1<<11) /* Echo Channel is Zeros */ #define D_NT_IFA (1<<10) /* Inhibit Final Activation */ @@ -455,7 +453,7 @@ #define D_CDEC_RED(v) ((v)<<0) /* FSCOD #define D_TEST_RAM(v) ((v)<<16) /* RAM Pointer */ #define D_TEST_SIZE(v) ((v)<<11) /* */ #define D_TEST_ROMONOFF 0x5 /* Toggle ROM opcode monitor on/off */ -#define D_TEST_PROC 0x6 /* MicroProcessor test */ +#define D_TEST_PROC 0x6 /* Microprocessor test */ #define D_TEST_SER 0x7 /* Serial-Controller test */ #define D_TEST_RAMREAD 0x8 /* Copy from Ram to system memory */ #define D_TEST_RAMWRITE 0x9 /* Copy into Ram from system memory */ @@ -464,12 +462,12 @@ #define D_TEST_MCBIST 0xb /* Microcontro #define D_TEST_DUMP 0xe /* ROM Dump */ /* CHI Data Mode */ -#define D_CDM_THI (1<<8) /* Transmit Data on CHIDR Pin */ -#define D_CDM_RHI (1<<7) /* Receive Data on CHIDX Pin */ -#define D_CDM_RCE (1<<6) /* Receive on Rising Edge of CHICK */ -#define D_CDM_XCE (1<<2) /* Transmit Data on Rising Edge of CHICK */ -#define D_CDM_XEN (1<<1) /* Transmit Highway Enable */ -#define D_CDM_REN (1<<0) /* Receive Highway Enable */ +#define D_CDM_THI (1 << 8) /* Transmit Data on CHIDR Pin */ +#define D_CDM_RHI (1 << 7) /* Receive Data on CHIDX Pin */ +#define D_CDM_RCE (1 << 6) /* Receive on Rising Edge of CHICK */ +#define D_CDM_XCE (1 << 2) /* Transmit Data on Rising Edge of CHICK */ +#define D_CDM_XEN (1 << 1) /* Transmit Highway Enable */ +#define D_CDM_REN (1 << 0) /* Receive Highway Enable */ /* The Interrupts */ #define D_INTR_BRDY 1 /* Buffer Ready for processing */ @@ -493,9 +491,9 @@ #define D_INTR_NT 34 #define D_INTR_CHI 36 #define D_INTR_CMD 38 -#define D_INTR_GETCHAN(v) (((v)>>24) & 0x3f) -#define D_INTR_GETCODE(v) (((v)>>20) & 0xf) -#define D_INTR_GETCMD(v) (((v)>>16) & 0xf) +#define D_INTR_GETCHAN(v) (((v) >> 24) & 0x3f) +#define D_INTR_GETCODE(v) (((v) >> 20) & 0xf) +#define D_INTR_GETCMD(v) (((v) >> 16) & 0xf) #define D_INTR_GETVAL(v) ((v) & 0xffff) #define D_INTR_GETRVAL(v) ((v) & 0xfffff) @@ -533,43 +531,42 @@ #define D_P_30 30 /* */ #define D_P_31 31 /* */ /* Transmit descriptor defines */ -#define DBRI_TD_F (1<<31) /* End of Frame */ -#define DBRI_TD_D (1<<30) /* Do not append CRC */ -#define DBRI_TD_CNT(v) ((v)<<16) /* Number of valid bytes in the buffer */ -#define DBRI_TD_B (1<<15) /* Final interrupt */ -#define DBRI_TD_M (1<<14) /* Marker interrupt */ -#define DBRI_TD_I (1<<13) /* Transmit Idle Characters */ -#define DBRI_TD_FCNT(v) (v) /* Flag Count */ -#define DBRI_TD_UNR (1<<3) /* Underrun: transmitter is out of data */ -#define DBRI_TD_ABT (1<<2) /* Abort: frame aborted */ -#define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ -#define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ - /* Maximum buffer size per TD: almost 8Kb */ +#define DBRI_TD_F (1 << 31) /* End of Frame */ +#define DBRI_TD_D (1 << 30) /* Do not append CRC */ +#define DBRI_TD_CNT(v) ((v) << 16) /* Number of valid bytes in the buffer */ +#define DBRI_TD_B (1 << 15) /* Final interrupt */ +#define DBRI_TD_M (1 << 14) /* Marker interrupt */ +#define DBRI_TD_I (1 << 13) /* Transmit Idle Characters */ +#define DBRI_TD_FCNT(v) (v) /* Flag Count */ +#define DBRI_TD_UNR (1 << 3) /* Underrun: transmitter is out of data */ +#define DBRI_TD_ABT (1 << 2) /* Abort: frame aborted */ +#define DBRI_TD_TBC (1 << 0) /* Transmit buffer Complete */ +#define DBRI_TD_STATUS(v) ((v) & 0xff) /* Transmit status */ + /* Maximum buffer size per TD: almost 8KB */ #define DBRI_TD_MAXCNT ((1 << 13) - 4) /* Receive descriptor defines */ -#define DBRI_RD_F (1<<31) /* End of Frame */ -#define DBRI_RD_C (1<<30) /* Completed buffer */ -#define DBRI_RD_B (1<<15) /* Final interrupt */ -#define DBRI_RD_M (1<<14) /* Marker interrupt */ -#define DBRI_RD_BCNT(v) (v) /* Buffer size */ -#define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */ -#define DBRI_RD_BBC (1<<6) /* 1: Bad Byte received */ -#define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */ -#define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */ -#define DBRI_RD_STATUS(v) ((v)&0xff) /* Receive status */ -#define DBRI_RD_CNT(v) (((v)>>16)&0x1fff) /* Valid bytes in the buffer */ +#define DBRI_RD_F (1 << 31) /* End of Frame */ +#define DBRI_RD_C (1 << 30) /* Completed buffer */ +#define DBRI_RD_B (1 << 15) /* Final interrupt */ +#define DBRI_RD_M (1 << 14) /* Marker interrupt */ +#define DBRI_RD_BCNT(v) (v) /* Buffer size */ +#define DBRI_RD_CRC (1 << 7) /* 0: CRC is correct */ +#define DBRI_RD_BBC (1 << 6) /* 1: Bad Byte received */ +#define DBRI_RD_ABT (1 << 5) /* Abort: frame aborted */ +#define DBRI_RD_OVRN (1 << 3) /* Overrun: data lost */ +#define DBRI_RD_STATUS(v) ((v) & 0xff) /* Receive status */ +#define DBRI_RD_CNT(v) (((v) >> 16) & 0x1fff) /* Valid bytes in the buffer */ /* stream_info[] access */ /* Translate the ALSA direction into the array index */ #define DBRI_STREAMNO(substream) \ - (substream->stream == \ - SNDRV_PCM_STREAM_PLAYBACK? DBRI_PLAY: DBRI_REC) + (substream->stream == \ + SNDRV_PCM_STREAM_PLAYBACK ? DBRI_PLAY: DBRI_REC) /* Return a pointer to dbri_streaminfo */ -#define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)] - -static struct snd_dbri *dbri_list; /* All DBRI devices */ +#define DBRI_STREAM(dbri, substream) \ + &dbri->stream_info[DBRI_STREAMNO(substream)] /* * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. @@ -609,21 +606,21 @@ The list is terminated with a WAIT comma CPU interrupt to signal completion. Since the DBRI can run in parallel with the CPU, several means of -synchronization present themselves. The method implemented here is only -use of the dbri_cmdwait() to wait for execution of batch of sent commands. +synchronization present themselves. The method implemented here uses +the dbri_cmdwait() to wait for execution of batch of sent commands. -A circular command buffer is used here. A new command is being added +A circular command buffer is used here. A new command is being added while another can be executed. The scheme works by adding two WAIT commands after each sent batch of commands. When the next batch is prepared it is added after the WAIT commands then the WAITs are replaced with single JUMP -command to the new batch. The the DBRI is forced to reread the last WAIT -command (replaced by the JUMP by then). If the DBRI is still executing +command to the new batch. The the DBRI is forced to reread the last WAIT +command (replaced by the JUMP by then). If the DBRI is still executing previous commands the request to reread the WAIT command is ignored. Every time a routine wants to write commands to the DBRI, it must -first call dbri_cmdlock() and get pointer to a free space in -dbri->dma->cmd buffer. After this, the commands can be written to -the buffer, and dbri_cmdsend() is called with the final pointer value +first call dbri_cmdlock() and get pointer to a free space in +dbri->dma->cmd buffer. After this, the commands can be written to +the buffer, and dbri_cmdsend() is called with the final pointer value to send them to the DBRI. */ @@ -646,18 +643,17 @@ static void dbri_cmdwait(struct snd_dbri } spin_unlock_irqrestore(&dbri->lock, flags); - if (maxloops == 0) { + if (maxloops == 0) printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); - } else { + else dprintk(D_CMD, "Chip completed command buffer (%d)\n", MAXLOOPS - maxloops - 1); - } } /* - * Lock the command queue and returns pointer to a space for len cmd words + * Lock the command queue and return pointer to space for len cmd words * It locks the cmdlock spinlock. */ -static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) +static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len) { /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */ len += 2; @@ -680,7 +676,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * * Lock must be held before calling this. */ -static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) +static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len) { s32 tmp, addr; static int wait_id = 0; @@ -700,16 +696,17 @@ #ifdef DBRI_DEBUG s32 *ptr; for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++) - dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); + dprintk(D_CMD, "cmd: %lx:%08x\n", + (unsigned long)ptr, *ptr); } else { s32 *ptr = dbri->cmdptr; dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); ptr++; dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); - for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) { - dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); - } + for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) + dprintk(D_CMD, "cmd: %lx:%08x\n", + (unsigned long)ptr, *ptr); } #endif @@ -723,7 +720,7 @@ #endif } /* Lock must be held when calling this */ -static void dbri_reset(struct snd_dbri * dbri) +static void dbri_reset(struct snd_dbri *dbri) { int i; u32 tmp; @@ -746,7 +743,7 @@ static void dbri_reset(struct snd_dbri * } /* Lock must not be held before calling this */ -static void dbri_initialize(struct snd_dbri * dbri) +static void __devinit dbri_initialize(struct snd_dbri *dbri) { s32 *cmd; u32 dma_addr; @@ -763,7 +760,7 @@ static void dbri_initialize(struct snd_d spin_lock_init(&dbri->cmdlock); /* - * Initialize the interrupt ringbuffer. + * Initialize the interrupt ring buffer. */ dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); dbri->dma->intr[0] = dma_addr; @@ -801,7 +798,7 @@ list ordering, among other things. The here interface closely with the transmit and receive interrupt code. */ -static int pipe_active(struct snd_dbri * dbri, int pipe) +static inline int pipe_active(struct snd_dbri *dbri, int pipe) { return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1)); } @@ -811,20 +808,22 @@ static int pipe_active(struct snd_dbri * * Called on an in-use pipe to clear anything being transmitted or received * Lock must be held before calling this. */ -static void reset_pipe(struct snd_dbri * dbri, int pipe) +static void reset_pipe(struct snd_dbri *dbri, int pipe) { int sdp; int desc; s32 *cmd; if (pipe < 0 || pipe > DBRI_MAX_PIPE) { - printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: reset_pipe called with " + "illegal pipe number\n"); return; } sdp = dbri->pipes[pipe].sdp; if (sdp == 0) { - printk(KERN_ERR "DBRI: reset_pipe called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: reset_pipe called " + "on uninitialized pipe\n"); return; } @@ -835,9 +834,10 @@ static void reset_pipe(struct snd_dbri * dbri_cmdsend(dbri, cmd, 3); desc = dbri->pipes[pipe].first_desc; - if ( desc >= 0) + if (desc >= 0) do { - dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].nda = 0; desc = dbri->next_desc[desc]; } while (desc != -1 && desc != dbri->pipes[pipe].first_desc); @@ -848,15 +848,17 @@ static void reset_pipe(struct snd_dbri * /* * Lock must be held before calling this. */ -static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) +static void setup_pipe(struct snd_dbri *dbri, int pipe, int sdp) { if (pipe < 0 || pipe > DBRI_MAX_PIPE) { - printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: setup_pipe called " + "with illegal pipe number\n"); return; } if ((sdp & 0xf800) != sdp) { - printk(KERN_ERR "DBRI: setup_pipe called with strange SDP value\n"); + printk(KERN_ERR "DBRI: setup_pipe called " + "with strange SDP value\n"); /* sdp &= 0xf800; */ } @@ -877,25 +879,26 @@ static void setup_pipe(struct snd_dbri * /* * Lock must be held before calling this. */ -static void link_time_slot(struct snd_dbri * dbri, int pipe, +static void link_time_slot(struct snd_dbri *dbri, int pipe, int prevpipe, int nextpipe, int length, int cycle) { s32 *cmd; int val; - if (pipe < 0 || pipe > DBRI_MAX_PIPE + if (pipe < 0 || pipe > DBRI_MAX_PIPE || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { - printk(KERN_ERR + printk(KERN_ERR "DBRI: link_time_slot called with illegal pipe number\n"); return; } - if (dbri->pipes[pipe].sdp == 0 + if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0 || dbri->pipes[nextpipe].sdp == 0) { - printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: link_time_slot called " + "on uninitialized pipe\n"); return; } @@ -935,17 +938,17 @@ #if 0 /* * Lock must be held before calling this. */ -static void unlink_time_slot(struct snd_dbri * dbri, int pipe, +static void unlink_time_slot(struct snd_dbri *dbri, int pipe, enum in_or_out direction, int prevpipe, int nextpipe) { s32 *cmd; int val; - if (pipe < 0 || pipe > DBRI_MAX_PIPE + if (pipe < 0 || pipe > DBRI_MAX_PIPE || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { - printk(KERN_ERR + printk(KERN_ERR "DBRI: unlink_time_slot called with illegal pipe number\n"); return; } @@ -985,7 +988,7 @@ #endif * * Lock must not be held before calling it. */ -static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) +static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data) { s32 *cmd; unsigned long flags; @@ -996,7 +999,8 @@ static void xmit_fixed(struct snd_dbri * } if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) { - printk(KERN_ERR "DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: " + "Uninitialized pipe %d\n", pipe); return; } @@ -1006,7 +1010,8 @@ static void xmit_fixed(struct snd_dbri * } if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { - printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", + pipe); return; } @@ -1028,20 +1033,23 @@ static void xmit_fixed(struct snd_dbri * } -static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) +static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr) { if (pipe < 16 || pipe > DBRI_MAX_PIPE) { - printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: recv_fixed called with " + "illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { - printk(KERN_ERR "DBRI: recv_fixed called on non-fixed pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on " + "non-fixed pipe %d\n", pipe); return; } if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { - printk(KERN_ERR "DBRI: recv_fixed called on transmit pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on " + "transmit pipe %d\n", pipe); return; } @@ -1064,7 +1072,7 @@ static void recv_fixed(struct snd_dbri * * * Lock must be held before calling this. */ -static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) +static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period) { struct dbri_streaminfo *info = &dbri->stream_info[streamno]; __u32 dvma_buffer; @@ -1089,21 +1097,23 @@ static int setup_descs(struct snd_dbri * if (streamno == DBRI_PLAY) { if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) { - printk(KERN_ERR "DBRI: setup_descs: Called on receive pipe %d\n", - info->pipe); + printk(KERN_ERR "DBRI: setup_descs: " + "Called on receive pipe %d\n", info->pipe); return -2; } } else { if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) { - printk(KERN_ERR + printk(KERN_ERR "DBRI: setup_descs: Called on transmit pipe %d\n", info->pipe); return -2; } - /* Should be able to queue multiple buffers to receive on a pipe */ + /* Should be able to queue multiple buffers + * to receive on a pipe + */ if (pipe_active(dbri, info->pipe)) { - printk(KERN_ERR "DBRI: recv_on_pipe: Called on active pipe %d\n", - info->pipe); + printk(KERN_ERR "DBRI: recv_on_pipe: " + "Called on active pipe %d\n", info->pipe); return -2; } @@ -1113,11 +1123,13 @@ static int setup_descs(struct snd_dbri * /* Free descriptors if pipe has any */ desc = dbri->pipes[info->pipe].first_desc; - if ( desc >= 0) + if (desc >= 0) do { - dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].nda = 0; desc = dbri->next_desc[desc]; - } while (desc != -1 && desc != dbri->pipes[info->pipe].first_desc); + } while (desc != -1 && + desc != dbri->pipes[info->pipe].first_desc); dbri->pipes[info->pipe].desc = -1; dbri->pipes[info->pipe].first_desc = -1; @@ -1130,6 +1142,7 @@ static int setup_descs(struct snd_dbri * if (!dbri->dma->desc[desc].ba) break; } + if (desc == DBRI_NO_DESCS) { printk(KERN_ERR "DBRI: setup_descs: No descriptors\n"); return -1; @@ -1150,8 +1163,7 @@ static int setup_descs(struct snd_dbri * if (streamno == DBRI_PLAY) { dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); dbri->dma->desc[desc].word4 = 0; - dbri->dma->desc[desc].word1 |= - DBRI_TD_F | DBRI_TD_B; + dbri->dma->desc[desc].word1 |= DBRI_TD_F | DBRI_TD_B; } else { dbri->dma->desc[desc].word1 = 0; dbri->dma->desc[desc].word4 = @@ -1172,7 +1184,8 @@ static int setup_descs(struct snd_dbri * } if (first_desc == -1 || last_desc == -1) { - printk(KERN_ERR "DBRI: setup_descs: Not enough descriptors available\n"); + printk(KERN_ERR "DBRI: setup_descs: " + " Not enough descriptors available\n"); return -1; } @@ -1183,14 +1196,14 @@ static int setup_descs(struct snd_dbri * dbri->pipes[info->pipe].desc = first_desc; #ifdef DBRI_DEBUG - for (desc = first_desc; desc != -1; ) { + for (desc = first_desc; desc != -1;) { dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", desc, dbri->dma->desc[desc].word1, dbri->dma->desc[desc].ba, dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); desc = dbri->next_desc[desc]; - if ( desc == first_desc ) + if (desc == first_desc) break; } #endif @@ -1213,7 +1226,8 @@ enum master_or_slave { CHImaster, CHIsla /* * Lock must not be held before calling it. */ -static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, +static void reset_chi(struct snd_dbri *dbri, + enum master_or_slave master_or_slave, int bits_per_frame) { s32 *cmd; @@ -1222,7 +1236,7 @@ static void reset_chi(struct snd_dbri * /* Set CHI Anchor: Pipe 16 */ cmd = dbri_cmdlock(dbri, 4); - val = D_DTS_VO | D_DTS_VI | D_DTS_INS + val = D_DTS_VO | D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); @@ -1246,15 +1260,16 @@ static void reset_chi(struct snd_dbri * } else { /* Setup DBRI for CHI Master - generate clock, FS * - * BPF = bits per 8 kHz frame - * 12.288 MHz / CHICM_divisor = clock rate - * FD = 1 - drive CHIFS on rising edge of CHICK + * BPF = bits per 8 kHz frame + * 12.288 MHz / CHICM_divisor = clock rate + * FD = 1 - drive CHIFS on rising edge of CHICK */ int clockrate = bits_per_frame * 8; int divisor = 12288 / clockrate; if (divisor > 255 || divisor * clockrate != 12288) - printk(KERN_ERR "DBRI: illegal bits_per_frame in setup_chi\n"); + printk(KERN_ERR "DBRI: illegal bits_per_frame " + "in setup_chi\n"); *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD | D_CHI_BPF(bits_per_frame)); @@ -1288,7 +1303,7 @@ to the DBRI via the CHI interface and fe * Lock must not be held before calling it. */ -static void cs4215_setup_pipes(struct snd_dbri * dbri) +static __devinit void cs4215_setup_pipes(struct snd_dbri *dbri) { unsigned long flags; @@ -1303,9 +1318,9 @@ static void cs4215_setup_pipes(struct sn * not relevant for us (only for doublechecking). * * Control mode: - * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly) + * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) * Pipe 18: Receive timeslot 1 (clb). - * Pipe 19: Receive timeslot 7 (version). + * Pipe 19: Receive timeslot 7 (version). */ setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB); @@ -1321,7 +1336,7 @@ static void cs4215_setup_pipes(struct sn dbri_cmdwait(dbri); } -static int cs4215_init_data(struct cs4215 *mm) +static __devinit int cs4215_init_data(struct cs4215 *mm) { /* * No action, memory resetting only. @@ -1355,7 +1370,7 @@ static int cs4215_init_data(struct cs421 return 0; } -static void cs4215_setdata(struct snd_dbri * dbri, int muted) +static void cs4215_setdata(struct snd_dbri *dbri, int muted) { if (muted) { dbri->mm.data[0] |= 63; @@ -1387,7 +1402,7 @@ static void cs4215_setdata(struct snd_db /* * Set the CS4215 to data mode. */ -static void cs4215_open(struct snd_dbri * dbri) +static void cs4215_open(struct snd_dbri *dbri) { int data_width; u32 tmp; @@ -1452,7 +1467,7 @@ static void cs4215_open(struct snd_dbri /* * Send the control information (i.e. audio format) */ -static int cs4215_setctrl(struct snd_dbri * dbri) +static int cs4215_setctrl(struct snd_dbri *dbri) { int i, val; u32 tmp; @@ -1502,9 +1517,9 @@ static int cs4215_setctrl(struct snd_dbr /* * Control mode: - * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly) + * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) * Pipe 18: Receive timeslot 1 (clb). - * Pipe 19: Receive timeslot 7 (version). + * Pipe 19: Receive timeslot 7 (version). */ link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset); @@ -1522,9 +1537,9 @@ static int cs4215_setctrl(struct snd_dbr sbus_writel(tmp, dbri->regs + REG0); spin_unlock_irqrestore(&dbri->lock, flags); - for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { + for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) msleep_interruptible(1); - } + if (i == 0) { dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n", dbri->mm.status); @@ -1556,7 +1571,7 @@ static int cs4215_setctrl(struct snd_dbr * As part of the process we resend the settings for the data * timeslots as well. */ -static int cs4215_prepare(struct snd_dbri * dbri, unsigned int rate, +static int cs4215_prepare(struct snd_dbri *dbri, unsigned int rate, snd_pcm_format_t format, unsigned int channels) { int freq_idx; @@ -1613,7 +1628,7 @@ static int cs4215_prepare(struct snd_dbr /* * */ -static int cs4215_init(struct snd_dbri * dbri) +static __devinit int cs4215_init(struct snd_dbri *dbri) { u32 reg2 = sbus_readl(dbri->regs + REG2); dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2); @@ -1674,7 +1689,7 @@ interrupts are disabled. /* xmit_descs() * - * Starts transmiting the current TD's for recording/playing. + * Starts transmitting the current TD's for recording/playing. * For playback, ALSA has filled the DMA memory with new data (we hope). */ static void xmit_descs(struct snd_dbri *dbri) @@ -1701,7 +1716,8 @@ static void xmit_descs(struct snd_dbri * *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[info->pipe].sdp | D_SDP_P | D_SDP_EVERY | D_SDP_C); - *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); + *(cmd++) = dbri->dma_dvma + + dbri_dma_off(desc, first_td); dbri_cmdsend(dbri, cmd, 2); /* Reset our admin of the pipe. */ @@ -1722,7 +1738,8 @@ static void xmit_descs(struct snd_dbri * *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[info->pipe].sdp | D_SDP_P | D_SDP_EVERY | D_SDP_C); - *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); + *(cmd++) = dbri->dma_dvma + + dbri_dma_off(desc, first_td); dbri_cmdsend(dbri, cmd, 2); /* Reset our admin of the pipe. */ @@ -1747,15 +1764,12 @@ static void xmit_descs(struct snd_dbri * * */ -static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) +static void transmission_complete_intr(struct snd_dbri *dbri, int pipe) { - struct dbri_streaminfo *info; - int td; + struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; + int td = dbri->pipes[pipe].desc; int status; - info = &dbri->stream_info[DBRI_PLAY]; - - td = dbri->pipes[pipe].desc; while (td >= 0) { if (td >= DBRI_NO_DESCS) { printk(KERN_ERR "DBRI: invalid td on pipe %d\n", pipe); @@ -1763,9 +1777,8 @@ static void transmission_complete_intr(s } status = DBRI_TD_STATUS(dbri->dma->desc[td].word4); - if (!(status & DBRI_TD_TBC)) { + if (!(status & DBRI_TD_TBC)) break; - } dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); @@ -1777,15 +1790,12 @@ static void transmission_complete_intr(s } /* Notify ALSA */ - if (spin_is_locked(&dbri->lock)) { - spin_unlock(&dbri->lock); - snd_pcm_period_elapsed(info->substream); - spin_lock(&dbri->lock); - } else - snd_pcm_period_elapsed(info->substream); + spin_unlock(&dbri->lock); + snd_pcm_period_elapsed(info->substream); + spin_lock(&dbri->lock); } -static void reception_complete_intr(struct snd_dbri * dbri, int pipe) +static void reception_complete_intr(struct snd_dbri *dbri, int pipe) { struct dbri_streaminfo *info; int rd = dbri->pipes[pipe].desc; @@ -1809,15 +1819,12 @@ static void reception_complete_intr(stru rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); /* Notify ALSA */ - if (spin_is_locked(&dbri->lock)) { - spin_unlock(&dbri->lock); - snd_pcm_period_elapsed(info->substream); - spin_lock(&dbri->lock); - } else - snd_pcm_period_elapsed(info->substream); + spin_unlock(&dbri->lock); + snd_pcm_period_elapsed(info->substream); + spin_lock(&dbri->lock); } -static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) +static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x) { int val = D_INTR_GETVAL(x); int channel = D_INTR_GETCHAN(x); @@ -1889,7 +1896,7 @@ #endif * right now). Non-zero words require processing and are handed off * to dbri_process_one_interrupt AFTER advancing the pointer. */ -static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) +static void dbri_process_interrupt_buffer(struct snd_dbri *dbri) { s32 x; @@ -1965,20 +1972,20 @@ static irqreturn_t snd_dbri_interrupt(in PCM Interface ****************************************************************************/ static struct snd_pcm_hardware snd_dbri_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_MU_LAW | - SNDRV_PCM_FMTBIT_A_LAW | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_BE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512, + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_MU_LAW | + SNDRV_PCM_FMTBIT_A_LAW | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512, .rate_min = 5512, .rate_max = 48000, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = (64 * 1024), + .buffer_bytes_max = 64 * 1024, .period_bytes_min = 1, .period_bytes_max = DBRI_TD_MAXCNT, .periods_min = 1, @@ -2011,7 +2018,8 @@ static int snd_hw_rule_channels(struct s snd_interval_any(&ch); if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) { - ch.min = ch.max = 1; + ch.min = 1; + ch.max = 1; ch.integer = 1; return snd_interval_refine(c, &ch); } @@ -2035,14 +2043,14 @@ static int snd_dbri_open(struct snd_pcm_ info->pipe = -1; spin_unlock_irqrestore(&dbri->lock, flags); - snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_CHANNELS, + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_hw_rule_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT, -1); - snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_FORMAT, - snd_hw_rule_channels, NULL, + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + snd_hw_rule_channels, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); - + cs4215_open(dbri); return 0; @@ -2145,7 +2153,7 @@ static int snd_dbri_prepare(struct snd_p spin_lock_irq(&dbri->lock); info->offset = 0; - /* Setup the all the transmit/receive desciptors to cover the + /* Setup the all the transmit/receive descriptors to cover the * whole DMA buffer. */ ret = setup_descs(dbri, DBRI_STREAMNO(substream), @@ -2205,12 +2213,12 @@ static struct snd_pcm_ops snd_dbri_ops = .pointer = snd_dbri_pointer, }; -static int __devinit snd_dbri_pcm(struct snd_dbri * dbri) +static int __devinit snd_dbri_pcm(struct snd_card *card) { struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(dbri->card, + if ((err = snd_pcm_new(card, /* ID */ "sun_dbri", /* device */ 0, /* playback count */ 1, @@ -2221,16 +2229,15 @@ static int __devinit snd_dbri_pcm(struct snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops); - pcm->private_data = dbri; + pcm->private_data = card->private_data; pcm->info_flags = 0; - strcpy(pcm->name, dbri->card->shortname); + strcpy(pcm->name, card->shortname); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), - 64 * 1024, 64 * 1024)) < 0) { + 64 * 1024, 64 * 1024)) < 0) return err; - } return 0; } @@ -2245,11 +2252,10 @@ static int snd_cs4215_info_volume(struct uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - if (kcontrol->private_value == DBRI_PLAY) { + if (kcontrol->private_value == DBRI_PLAY) uinfo->value.integer.max = DBRI_MAX_VOLUME; - } else { + else uinfo->value.integer.max = DBRI_MAX_GAIN; - } return 0; } @@ -2271,7 +2277,8 @@ static int snd_cs4215_put_volume(struct struct snd_ctl_elem_value *ucontrol) { struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); - struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; + struct dbri_streaminfo *info = + &dbri->stream_info[kcontrol->private_value]; int changed = 0; if (info->left_gain != ucontrol->value.integer.value[0]) { @@ -2282,7 +2289,7 @@ static int snd_cs4215_put_volume(struct info->right_gain = ucontrol->value.integer.value[1]; changed = 1; } - if (changed == 1) { + if (changed) { /* First mute outputs, and wait 1/8000 sec (125 us) * to make sure this takes. This avoids clicking noises. */ @@ -2316,18 +2323,16 @@ static int snd_cs4215_get_single(struct int invert = (kcontrol->private_value >> 24) & 1; snd_assert(dbri != NULL, return -EINVAL); - if (elem < 4) { + if (elem < 4) ucontrol->value.integer.value[0] = (dbri->mm.data[elem] >> shift) & mask; - } else { + else ucontrol->value.integer.value[0] = (dbri->mm.ctrl[elem - 4] >> shift) & mask; - } - if (invert == 1) { + if (invert == 1) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - } return 0; } @@ -2378,11 +2383,12 @@ static int snd_cs4215_put_single(struct timeslots. Shift is the bit offset in the timeslot, mask defines the number of bits. invert is a boolean for use with attenuation. */ -#define CS4215_SINGLE(xname, entry, shift, mask, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_cs4215_info_single, \ - .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \ - .private_value = entry | (shift << 8) | (mask << 16) | (invert << 24) }, +#define CS4215_SINGLE(xname, entry, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_cs4215_info_single, \ + .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \ + .private_value = (entry) | ((shift) << 8) | ((mask) << 16) | \ + ((invert) << 24) }, static struct snd_kcontrol_new dbri_controls[] __devinitdata = { { @@ -2411,19 +2417,20 @@ static struct snd_kcontrol_new dbri_cont CS4215_SINGLE("Mic boost", 4, 4, 1, 1) }; -static int __init snd_dbri_mixer(struct snd_dbri * dbri) +static int __devinit snd_dbri_mixer(struct snd_card *card) { - struct snd_card *card; int idx, err; + struct snd_dbri *dbri; - snd_assert(dbri != NULL && dbri->card != NULL, return -EINVAL); + snd_assert(card != NULL && card->private_data != NULL, return -EINVAL); + dbri = card->private_data; - card = dbri->card; strcpy(card->mixername, card->shortname); for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) { - if ((err = snd_ctl_add(card, - snd_ctl_new1(&dbri_controls[idx], dbri))) < 0) + err = snd_ctl_add(card, + snd_ctl_new1(&dbri_controls[idx], dbri)); + if (err < 0) return err; } @@ -2438,7 +2445,8 @@ static int __init snd_dbri_mixer(struct /**************************************************************************** /proc interface ****************************************************************************/ -static void dbri_regs_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) +static void dbri_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct snd_dbri *dbri = entry->private_data; @@ -2449,7 +2457,7 @@ static void dbri_regs_read(struct snd_in } #ifdef DBRI_DEBUG -static void dbri_debug_read(struct snd_info_entry * entry, +static void dbri_debug_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_dbri *dbri = entry->private_data; @@ -2463,7 +2471,8 @@ static void dbri_debug_read(struct snd_i "Pipe %d: %s SDP=0x%x desc=%d, " "len=%d next %d\n", pipe, - ((pptr->sdp & D_SDP_TO_SER) ? "output" : "input"), + (pptr->sdp & D_SDP_TO_SER) ? "output" : + "input", pptr->sdp, pptr->desc, pptr->length, pptr->nextpipe); } @@ -2471,15 +2480,16 @@ static void dbri_debug_read(struct snd_i } #endif -void snd_dbri_proc(struct snd_dbri * dbri) +void __devinit snd_dbri_proc(struct snd_card *card) { + struct snd_dbri *dbri = card->private_data; struct snd_info_entry *entry; - if (! snd_card_proc_new(dbri->card, "regs", &entry)) + if (!snd_card_proc_new(card, "regs", &entry)) snd_info_set_text_ops(entry, dbri, dbri_regs_read); #ifdef DBRI_DEBUG - if (! snd_card_proc_new(dbri->card, "debug", &entry)) { + if (!snd_card_proc_new(card, "debug", &entry)) { snd_info_set_text_ops(entry, dbri, dbri_debug_read); entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ } @@ -2491,19 +2501,18 @@ #endif **************************** Initialization ******************************** **************************************************************************** */ -static void snd_dbri_free(struct snd_dbri * dbri); +static void snd_dbri_free(struct snd_dbri *dbri); -static int __init snd_dbri_create(struct snd_card *card, +static int __devinit snd_dbri_create(struct snd_card *card, struct sbus_dev *sdev, - struct linux_prom_irqs *irq, int dev) + int irq, int dev) { struct snd_dbri *dbri = card->private_data; int err; spin_lock_init(&dbri->lock); - dbri->card = card; dbri->sdev = sdev; - dbri->irq = irq->pri; + dbri->irq = irq; dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), &dbri->dma_dvma); @@ -2541,13 +2550,10 @@ static int __init snd_dbri_create(struct return err; } - dbri->next = dbri_list; - dbri_list = dbri; - return 0; } -static void snd_dbri_free(struct snd_dbri * dbri) +static void snd_dbri_free(struct snd_dbri *dbri) { dprintk(D_GEN, "snd_dbri_free\n"); dbri_reset(dbri); @@ -2563,20 +2569,19 @@ static void snd_dbri_free(struct snd_dbr (void *)dbri->dma, dbri->dma_dvma); } -static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) +static int __devinit dbri_probe(struct of_device *of_dev, + const struct of_device_id *match) { + struct sbus_dev *sdev = to_sbus_device(&of_dev->dev); struct snd_dbri *dbri; - struct linux_prom_irqs irq; + int irq; struct resource *rp; struct snd_card *card; static int dev = 0; int err; - if (sdev->prom_name[9] < 'e') { - printk(KERN_ERR "DBRI: unsupported chip version %c found.\n", - sdev->prom_name[9]); - return -EIO; - } + dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n", + sdev->prom_name, sdev->slot); if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2585,9 +2590,9 @@ static int __init dbri_attach(int prom_n return -ENOENT; } - err = prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq)); - if (err < 0) { - printk(KERN_ERR "DBRI-%d: Firmware node lacks IRQ property.\n", dev); + irq = sdev->irqs[0]; + if (irq <= 0) { + printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev); return -ENODEV; } @@ -2601,24 +2606,29 @@ static int __init dbri_attach(int prom_n rp = &sdev->resource[0]; sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d", card->shortname, - rp->flags & 0xffL, (unsigned long long)rp->start, irq.pri); + rp->flags & 0xffL, (unsigned long long)rp->start, irq); - if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) { + err = snd_dbri_create(card, sdev, irq, dev); + if (err < 0) { snd_card_free(card); return err; } dbri = card->private_data; - if ((err = snd_dbri_pcm(dbri)) < 0) + err = snd_dbri_pcm(card); + if (err < 0) goto _err; - if ((err = snd_dbri_mixer(dbri)) < 0) + err = snd_dbri_mixer(card); + if (err < 0) goto _err; /* /proc file handling */ - snd_dbri_proc(dbri); + snd_dbri_proc(card); + dev_set_drvdata(&of_dev->dev, card); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto _err; printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", @@ -2628,49 +2638,52 @@ static int __init dbri_attach(int prom_n return 0; - _err: +_err: snd_dbri_free(dbri); snd_card_free(card); return err; } -/* Probe for the dbri chip and then attach the driver. */ -static int __init dbri_init(void) +static int __devexit dbri_remove(struct of_device *dev) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; - int found = 0; - - /* Probe each SBUS for the DBRI chip(s). */ - for_all_sbusdev(sdev, sbus) { - /* - * The version is coded in the last character - */ - if (!strncmp(sdev->prom_name, "SUNW,DBRI", 9)) { - dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n", - sdev->prom_name, sdev->slot); + struct snd_card *card = dev_get_drvdata(&dev->dev); - if (dbri_attach(sdev->prom_node, sdev) == 0) - found++; - } - } + snd_dbri_free(card->private_data); + snd_card_free(card); + + dev_set_drvdata(&dev->dev, NULL); + + return 0; +} + +static struct of_device_id dbri_match[] = { + { + .name = "SUNW,DBRIe", + }, + { + .name = "SUNW,DBRIf", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dbri_match); + +static struct of_platform_driver dbri_sbus_driver = { + .name = "dbri", + .match_table = dbri_match, + .probe = dbri_probe, + .remove = __devexit_p(dbri_remove), +}; - return (found > 0) ? 0 : -EIO; +/* Probe for the dbri chip and then attach the driver. */ +static int __init dbri_init(void) +{ + return of_register_driver(&dbri_sbus_driver, &sbus_bus_type); } static void __exit dbri_exit(void) { - struct snd_dbri *this = dbri_list; - - while (this != NULL) { - struct snd_dbri *next = this->next; - struct snd_card *card = this->card; - - snd_dbri_free(this); - snd_card_free(card); - this = next; - } - dbri_list = NULL; + of_unregister_driver(&dbri_sbus_driver); } module_init(dbri_init); diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig new file mode 100644 index 0000000..0d08c29 --- /dev/null +++ b/sound/spi/Kconfig @@ -0,0 +1,31 @@ +#SPI drivers + +menu "SPI devices" + depends on SND != n + +config SND_AT73C213 + tristate "Atmel AT73C213 DAC driver" + depends on ATMEL_SSC + select SND_PCM + help + Say Y here if you want to use the Atmel AT73C213 external DAC. This + DAC can be found on Atmel development boards. + + This driver requires the Atmel SSC driver for sound sink, a + peripheral found on most AT91 and AVR32 microprocessors. + + To compile this driver as a module, choose M here: the module will be + called snd-at73c213. + +config SND_AT73C213_TARGET_BITRATE + int "Target bitrate for AT73C213" + depends on SND_AT73C213 + default "48000" + range 8000 50000 + help + Sets the target bitrate for the bitrate calculator in the driver. + Limited by hardware to be between 8000 Hz and 50000 Hz. + + Set to 48000 Hz by default. + +endmenu diff --git a/sound/spi/Makefile b/sound/spi/Makefile new file mode 100644 index 0000000..026fb73 --- /dev/null +++ b/sound/spi/Makefile @@ -0,0 +1,5 @@ +# Makefile for SPI drivers + +snd-at73c213-objs := at73c213.o + +obj-$(CONFIG_SND_AT73C213) += snd-at73c213.o diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c new file mode 100644 index 0000000..fee869b --- /dev/null +++ b/sound/spi/at73c213.c @@ -0,0 +1,1129 @@ +/* + * Driver for AT73C213 16-bit stereo DAC connected to Atmel SSC + * + * Copyright (C) 2006-2007 Atmel Norway + * + * 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. + */ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "at73c213.h" + +#define BITRATE_MIN 8000 /* Hardware limit? */ +#define BITRATE_TARGET CONFIG_SND_AT73C213_TARGET_BITRATE +#define BITRATE_MAX 50000 /* Hardware limit. */ + +/* Initial (hardware reset) AT73C213 register values. */ +static u8 snd_at73c213_original_image[18] = +{ + 0x00, /* 00 - CTRL */ + 0x05, /* 01 - LLIG */ + 0x05, /* 02 - RLIG */ + 0x08, /* 03 - LPMG */ + 0x08, /* 04 - RPMG */ + 0x00, /* 05 - LLOG */ + 0x00, /* 06 - RLOG */ + 0x22, /* 07 - OLC */ + 0x09, /* 08 - MC */ + 0x00, /* 09 - CSFC */ + 0x00, /* 0A - MISC */ + 0x00, /* 0B - */ + 0x00, /* 0C - PRECH */ + 0x05, /* 0D - AUXG */ + 0x00, /* 0E - */ + 0x00, /* 0F - */ + 0x00, /* 10 - RST */ + 0x00, /* 11 - PA_CTRL */ +}; + +struct snd_at73c213 { + struct snd_card *card; + struct snd_pcm *pcm; + struct snd_pcm_substream *substream; + struct at73c213_board_info *board; + int irq; + int period; + unsigned long bitrate; + struct clk *bitclk; + struct ssc_device *ssc; + struct spi_device *spi; + u8 spi_wbuffer[2]; + u8 spi_rbuffer[2]; + /* Image of the SPI registers in AT73C213. */ + u8 reg_image[18]; + /* Protect registers against concurrent access. */ + spinlock_t lock; +}; + +#define get_chip(card) ((struct snd_at73c213 *)card->private_data) + +static int +snd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val) +{ + struct spi_message msg; + struct spi_transfer msg_xfer = { + .len = 2, + .cs_change = 0, + }; + int retval; + + spi_message_init(&msg); + + chip->spi_wbuffer[0] = reg; + chip->spi_wbuffer[1] = val; + + msg_xfer.tx_buf = chip->spi_wbuffer; + msg_xfer.rx_buf = chip->spi_rbuffer; + spi_message_add_tail(&msg_xfer, &msg); + + retval = spi_sync(chip->spi, &msg); + + if (!retval) + chip->reg_image[reg] = val; + + return retval; +} + +static struct snd_pcm_hardware snd_at73c213_playback_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, /* Replaced by chip->bitrate later. */ + .rate_max = 50000, /* Replaced by chip->bitrate later. */ + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 64 * 1024 - 1, + .period_bytes_min = 512, + .period_bytes_max = 64 * 1024 - 1, + .periods_min = 4, + .periods_max = 1024, +}; + +/* + * Calculate and set bitrate and divisions. + */ +static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip) +{ + unsigned long ssc_rate = clk_get_rate(chip->ssc->clk); + unsigned long dac_rate_new, ssc_div, status; + unsigned long ssc_div_max, ssc_div_min; + int max_tries; + + /* + * We connect two clocks here, picking divisors so the I2S clocks + * out data at the same rate the DAC clocks it in ... and as close + * as practical to the desired target rate. + * + * The DAC master clock (MCLK) is programmable, and is either 256 + * or (not here) 384 times the I2S output clock (BCLK). + */ + + /* SSC clock / (bitrate * stereo * 16-bit). */ + ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16); + ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16); + ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16); + max_tries = (ssc_div_max - ssc_div_min) / 2; + + if (max_tries < 1) + max_tries = 1; + + /* ssc_div must be a power of 2. */ + ssc_div = (ssc_div + 1) & ~1UL; + + if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) { + ssc_div -= 2; + if ((ssc_rate / (ssc_div * 2 * 16)) > BITRATE_MAX) + return -ENXIO; + } + + /* Search for a possible bitrate. */ + do { + /* SSC clock / (ssc divider * 16-bit * stereo). */ + if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) + return -ENXIO; + + /* 256 / (2 * 16) = 8 */ + dac_rate_new = 8 * (ssc_rate / ssc_div); + + status = clk_round_rate(chip->board->dac_clk, dac_rate_new); + if (status < 0) + return status; + + /* Ignore difference smaller than 256 Hz. */ + if ((status/256) == (dac_rate_new/256)) + goto set_rate; + + ssc_div += 2; + } while (--max_tries); + + /* Not able to find a valid bitrate. */ + return -ENXIO; + +set_rate: + status = clk_set_rate(chip->board->dac_clk, status); + if (status < 0) + return status; + + /* Set divider in SSC device. */ + ssc_writel(chip->ssc->regs, CMR, ssc_div/2); + + /* SSC clock / (ssc divider * 16-bit * stereo). */ + chip->bitrate = ssc_rate / (ssc_div * 16 * 2); + + dev_info(&chip->spi->dev, + "at73c213: supported bitrate is %lu (%lu divider)\n", + chip->bitrate, ssc_div); + + return 0; +} + +static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + snd_at73c213_playback_hw.rate_min = chip->bitrate; + snd_at73c213_playback_hw.rate_max = chip->bitrate; + runtime->hw = snd_at73c213_playback_hw; + chip->substream = substream; + + return 0; +} + +static int snd_at73c213_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + chip->substream = NULL; + return 0; +} + +static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int snd_at73c213_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int block_size; + + block_size = frames_to_bytes(runtime, runtime->period_size); + + chip->period = 0; + + ssc_writel(chip->ssc->regs, PDC_TPR, + (long)runtime->dma_addr); + ssc_writel(chip->ssc->regs, PDC_TCR, runtime->period_size * 2); + ssc_writel(chip->ssc->regs, PDC_TNPR, + (long)runtime->dma_addr + block_size); + ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2); + + return 0; +} + +static int snd_at73c213_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + int retval = 0; + + spin_lock(&chip->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ssc_writel(chip->ssc->regs, IER, SSC_BIT(IER_ENDTX)); + ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN)); + break; + case SNDRV_PCM_TRIGGER_STOP: + ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS)); + ssc_writel(chip->ssc->regs, IDR, SSC_BIT(IDR_ENDTX)); + break; + default: + dev_dbg(&chip->spi->dev, "spurious command %x\n", cmd); + retval = -EINVAL; + break; + } + + spin_unlock(&chip->lock); + + return retval; +} + +static snd_pcm_uframes_t +snd_at73c213_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t pos; + unsigned long bytes; + + bytes = ssc_readl(chip->ssc->regs, PDC_TPR) + - (unsigned long)runtime->dma_addr; + + pos = bytes_to_frames(runtime, bytes); + if (pos >= runtime->buffer_size) + pos -= runtime->buffer_size; + + return pos; +} + +static struct snd_pcm_ops at73c213_playback_ops = { + .open = snd_at73c213_pcm_open, + .close = snd_at73c213_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_at73c213_pcm_hw_params, + .hw_free = snd_at73c213_pcm_hw_free, + .prepare = snd_at73c213_pcm_prepare, + .trigger = snd_at73c213_pcm_trigger, + .pointer = snd_at73c213_pcm_pointer, +}; + +static void snd_at73c213_pcm_free(struct snd_pcm *pcm) +{ + struct snd_at73c213 *chip = snd_pcm_chip(pcm); + if (chip->pcm) { + snd_pcm_lib_preallocate_free_for_all(chip->pcm); + chip->pcm = NULL; + } +} + +static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) +{ + struct snd_pcm *pcm; + int retval; + + retval = snd_pcm_new(chip->card, chip->card->shortname, + device, 1, 0, &pcm); + if (retval < 0) + goto out; + + pcm->private_data = chip; + pcm->private_free = snd_at73c213_pcm_free; + pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER; + strcpy(pcm->name, "at73c213"); + chip->pcm = pcm; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); + + retval = snd_pcm_lib_preallocate_pages_for_all(chip->pcm, + SNDRV_DMA_TYPE_DEV, &chip->ssc->pdev->dev, + 64 * 1024, 64 * 1024); +out: + return retval; +} + +static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id) +{ + struct snd_at73c213 *chip = dev_id; + struct snd_pcm_runtime *runtime = chip->substream->runtime; + u32 status; + int offset; + int block_size; + int next_period; + int retval = IRQ_NONE; + + spin_lock(&chip->lock); + + block_size = frames_to_bytes(runtime, runtime->period_size); + status = ssc_readl(chip->ssc->regs, IMR); + + if (status & SSC_BIT(IMR_ENDTX)) { + chip->period++; + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + ssc_writel(chip->ssc->regs, PDC_TNPR, + (long)runtime->dma_addr + offset); + ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2); + retval = IRQ_HANDLED; + } + + ssc_readl(chip->ssc->regs, IMR); + spin_unlock(&chip->lock); + + if (status & SSC_BIT(IMR_ENDTX)) + snd_pcm_period_elapsed(chip->substream); + + return retval; +} + +/* + * Mixer functions. + */ +static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + 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_irq(&chip->lock); + + ucontrol->value.integer.value[0] = + (chip->reg_image[reg] >> shift) & mask; + + if (invert) + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + + spin_unlock_irq(&chip->lock); + + return 0; +} + +static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + 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, retval; + unsigned short val; + + val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = mask - val; + val <<= shift; + + spin_lock_irq(&chip->lock); + + val = (chip->reg_image[reg] & ~(mask << shift)) | val; + change = val != chip->reg_image[reg]; + retval = snd_at73c213_write_reg(chip, reg, val); + + spin_unlock_irq(&chip->lock); + + if (retval) + return retval; + + return change; +} + +static int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 24) & 0xff; + + if (mask == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + + return 0; +} + +static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + 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_irq(&chip->lock); + + ucontrol->value.integer.value[0] = + (chip->reg_image[left_reg] >> shift_left) & mask; + ucontrol->value.integer.value[1] = + (chip->reg_image[right_reg] >> shift_right) & mask; + + if (invert) { + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + ucontrol->value.integer.value[1] = + mask - ucontrol->value.integer.value[1]; + } + + spin_unlock_irq(&chip->lock); + + return 0; +} + +static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + 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, retval; + 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_irq(&chip->lock); + + val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; + val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; + change = val1 != chip->reg_image[left_reg] + || val2 != chip->reg_image[right_reg]; + retval = snd_at73c213_write_reg(chip, left_reg, val1); + if (retval) { + spin_unlock_irq(&chip->lock); + goto out; + } + retval = snd_at73c213_write_reg(chip, right_reg, val2); + if (retval) { + spin_unlock_irq(&chip->lock); + goto out; + } + + spin_unlock_irq(&chip->lock); + + return change; + +out: + return retval; +} + +static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irq(&chip->lock); + + ucontrol->value.integer.value[0] = + (chip->reg_image[reg] >> shift) & 0x01; + + if (invert) + ucontrol->value.integer.value[0] = + 0x01 - ucontrol->value.integer.value[0]; + + spin_unlock_irq(&chip->lock); + + return 0; +} + +static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + 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, retval; + unsigned short val; + + if (ucontrol->value.integer.value[0]) + val = mask; + else + val = 0; + + if (invert) + val = mask - val; + val <<= shift; + + spin_lock_irq(&chip->lock); + + val |= (chip->reg_image[reg] & ~(mask << shift)); + change = val != chip->reg_image[reg]; + + retval = snd_at73c213_write_reg(chip, reg, val); + + spin_unlock_irq(&chip->lock); + + if (retval) + return retval; + + return change; +} + +static int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xff) - 1; + + return 0; +} + +static int snd_at73c213_line_capture_volume_info( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + /* When inverted will give values 0x10001 => 0. */ + uinfo->value.integer.min = 14; + uinfo->value.integer.max = 31; + + return 0; +} + +static int snd_at73c213_aux_capture_volume_info( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + /* When inverted will give values 0x10001 => 0. */ + uinfo->value.integer.min = 14; + uinfo->value.integer.max = 31; + + return 0; +} + +#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_at73c213_mono_switch_info, \ + .get = snd_at73c213_mono_switch_get, \ + .put = snd_at73c213_mono_switch_put, \ + .private_value = (reg | (shift << 8) | (mask << 16) | (invert << 24)) \ +} + +#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_at73c213_stereo_info, \ + .get = snd_at73c213_stereo_get, \ + .put = snd_at73c213_stereo_put, \ + .private_value = (left_reg | (right_reg << 8) \ + | (shift_left << 16) | (shift_right << 19) \ + | (mask << 24) | (invert << 22)) \ +} + +static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = { +AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1), +AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1), +AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1), +AT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1), +AT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV, + 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PA Playback Volume", + .index = 0, + .info = snd_at73c213_pa_volume_info, + .get = snd_at73c213_mono_get, + .put = snd_at73c213_mono_put, + .private_value = PA_CTRL | (PA_CTRL_APAGAIN << 8) | \ + (0x0f << 16) | (1 << 24), +}, +AT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP, + 0x01, 1), +AT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Aux Capture Volume", + .index = 0, + .info = snd_at73c213_aux_capture_volume_info, + .get = snd_at73c213_mono_get, + .put = snd_at73c213_mono_put, + .private_value = DAC_AUXG | (0 << 8) | (0x1f << 16) | (1 << 24), +}, +AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, + 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line Capture Volume", + .index = 0, + .info = snd_at73c213_line_capture_volume_info, + .get = snd_at73c213_stereo_get, + .put = snd_at73c213_stereo_put, + .private_value = DAC_LLIG | (DAC_RLIG << 8) | (0 << 16) | (0 << 19) + | (0x1f << 24) | (1 << 22), +}, +AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0), +}; + +static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip) +{ + struct snd_card *card; + int errval, idx; + + if (chip == NULL || chip->pcm == NULL) + return -EINVAL; + + card = chip->card; + + strcpy(card->mixername, chip->pcm->name); + + for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) { + errval = snd_ctl_add(card, + snd_ctl_new1(&snd_at73c213_controls[idx], + chip)); + if (errval < 0) + goto cleanup; + } + + return 0; + +cleanup: + for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_find_numid(card, idx); + if (kctl) + snd_ctl_remove(card, kctl); + } + return errval; +} + +/* + * Device functions + */ +static int snd_at73c213_ssc_init(struct snd_at73c213 *chip) +{ + /* + * Continuous clock output. + * Starts on falling TF. + * Delay 1 cycle (1 bit). + * Periode is 16 bit (16 - 1). + */ + ssc_writel(chip->ssc->regs, TCMR, + SSC_BF(TCMR_CKO, 1) + | SSC_BF(TCMR_START, 4) + | SSC_BF(TCMR_STTDLY, 1) + | SSC_BF(TCMR_PERIOD, 16 - 1)); + /* + * Data length is 16 bit (16 - 1). + * Transmit MSB first. + * Transmit 2 words each transfer. + * Frame sync length is 16 bit (16 - 1). + * Frame starts on negative pulse. + */ + ssc_writel(chip->ssc->regs, TFMR, + SSC_BF(TFMR_DATLEN, 16 - 1) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATNB, 1) + | SSC_BF(TFMR_FSLEN, 16 - 1) + | SSC_BF(TFMR_FSOS, 1)); + + return 0; +} + +static int snd_at73c213_chip_init(struct snd_at73c213 *chip) +{ + int retval; + unsigned char dac_ctrl = 0; + + retval = snd_at73c213_set_bitrate(chip); + if (retval) + goto out; + + /* Enable DAC master clock. */ + clk_enable(chip->board->dac_clk); + + /* Initialize at73c213 on SPI bus. */ + retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); + if (retval) + goto out_clk; + msleep(1); + retval = snd_at73c213_write_reg(chip, DAC_RST, 0x03); + if (retval) + goto out_clk; + + /* Precharge everything. */ + retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0xff); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, PA_CTRL, (1<ssc->regs, CR, SSC_BIT(CR_TXEN)); + + goto out; + +out_clk: + clk_disable(chip->board->dac_clk); +out: + return retval; +} + +static int snd_at73c213_dev_free(struct snd_device *device) +{ + struct snd_at73c213 *chip = device->device_data; + + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); + if (chip->irq >= 0) { + free_irq(chip->irq, chip); + chip->irq = -1; + } + + return 0; +} + +static int __devinit snd_at73c213_dev_init(struct snd_card *card, + struct spi_device *spi) +{ + static struct snd_device_ops ops = { + .dev_free = snd_at73c213_dev_free, + }; + struct snd_at73c213 *chip = get_chip(card); + int irq, retval; + + irq = chip->ssc->irq; + if (irq < 0) + return irq; + + spin_lock_init(&chip->lock); + chip->card = card; + chip->irq = -1; + + retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); + if (retval) { + dev_dbg(&chip->spi->dev, "unable to request irq %d\n", irq); + goto out; + } + chip->irq = irq; + + memcpy(&chip->reg_image, &snd_at73c213_original_image, + sizeof(snd_at73c213_original_image)); + + retval = snd_at73c213_ssc_init(chip); + if (retval) + goto out_irq; + + retval = snd_at73c213_chip_init(chip); + if (retval) + goto out_irq; + + retval = snd_at73c213_pcm_new(chip, 0); + if (retval) + goto out_irq; + + retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (retval) + goto out_irq; + + retval = snd_at73c213_mixer(chip); + if (retval) + goto out_snd_dev; + + snd_card_set_dev(card, &spi->dev); + + goto out; + +out_snd_dev: + snd_device_free(card, chip); +out_irq: + free_irq(chip->irq, chip); + chip->irq = -1; +out: + return retval; +} + +static int snd_at73c213_probe(struct spi_device *spi) +{ + struct snd_card *card; + struct snd_at73c213 *chip; + struct at73c213_board_info *board; + int retval; + char id[16]; + + board = spi->dev.platform_data; + if (!board) { + dev_dbg(&spi->dev, "no platform_data\n"); + return -ENXIO; + } + + if (!board->dac_clk) { + dev_dbg(&spi->dev, "no DAC clk\n"); + return -ENXIO; + } + + if (IS_ERR(board->dac_clk)) { + dev_dbg(&spi->dev, "no DAC clk\n"); + return PTR_ERR(board->dac_clk); + } + + retval = -ENOMEM; + + /* Allocate "card" using some unused identifiers. */ + snprintf(id, sizeof id, "at73c213_%d", board->ssc_id); + card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213)); + if (!card) + goto out; + + chip = card->private_data; + chip->spi = spi; + chip->board = board; + + chip->ssc = ssc_request(board->ssc_id); + if (IS_ERR(chip->ssc)) { + dev_dbg(&spi->dev, "could not get ssc%d device\n", + board->ssc_id); + retval = PTR_ERR(chip->ssc); + goto out_card; + } + + retval = snd_at73c213_dev_init(card, spi); + if (retval) + goto out_ssc; + + strcpy(card->driver, "at73c213"); + strcpy(card->shortname, board->shortname); + sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq); + + retval = snd_card_register(card); + if (retval) + goto out_ssc; + + dev_set_drvdata(&spi->dev, card); + + goto out; + +out_ssc: + ssc_free(chip->ssc); +out_card: + snd_card_free(card); +out: + return retval; +} + +static int __devexit snd_at73c213_remove(struct spi_device *spi) +{ + struct snd_card *card = dev_get_drvdata(&spi->dev); + struct snd_at73c213 *chip = card->private_data; + int retval; + + /* Stop playback. */ + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); + + /* Mute sound. */ + retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); + if (retval) + goto out; + + /* Turn off PA. */ + retval = snd_at73c213_write_reg(chip, PA_CTRL, + chip->reg_image[PA_CTRL] | 0x0f); + if (retval) + goto out; + msleep(10); + retval = snd_at73c213_write_reg(chip, PA_CTRL, + (1 << PA_CTRL_APALP) | 0x0f); + if (retval) + goto out; + + /* Turn off external DAC. */ + retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x0c); + if (retval) + goto out; + msleep(2); + retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x00); + if (retval) + goto out; + + /* Turn off master power. */ + retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0x00); + if (retval) + goto out; + +out: + /* Stop DAC master clock. */ + clk_disable(chip->board->dac_clk); + + ssc_free(chip->ssc); + snd_card_free(card); + dev_set_drvdata(&spi->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg) +{ + struct snd_card *card = dev_get_drvdata(&spi->dev); + struct snd_at73c213 *chip = card->private_data; + + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); + clk_disable(chip->board->dac_clk); + + return 0; +} + +static int snd_at73c213_resume(struct spi_device *spi) +{ + struct snd_card *card = dev_get_drvdata(&spi->dev); + struct snd_at73c213 *chip = card->private_data; + + clk_enable(chip->board->dac_clk); + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); + + return 0; +} +#else +#define snd_at73c213_suspend NULL +#define snd_at73c213_resume NULL +#endif + +static struct spi_driver at73c213_driver = { + .driver = { + .name = "at73c213", + }, + .probe = snd_at73c213_probe, + .suspend = snd_at73c213_suspend, + .resume = snd_at73c213_resume, + .remove = __devexit_p(snd_at73c213_remove), +}; + +static int __init at73c213_init(void) +{ + return spi_register_driver(&at73c213_driver); +} +module_init(at73c213_init); + +static void __exit at73c213_exit(void) +{ + spi_unregister_driver(&at73c213_driver); +} +module_exit(at73c213_exit); + +MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); +MODULE_LICENSE("GPL"); diff --git a/sound/spi/at73c213.h b/sound/spi/at73c213.h new file mode 100644 index 0000000..fd8b372 --- /dev/null +++ b/sound/spi/at73c213.h @@ -0,0 +1,119 @@ +/* + * Driver for the AT73C213 16-bit stereo DAC on Atmel ATSTK1000 + * + * Copyright (C) 2006 - 2007 Atmel Corporation + * + * 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. + * + * The full GNU General Public License is included in this + * distribution in the file called COPYING. + */ + +#ifndef _SND_AT73C213_H +#define _SND_AT73C213_H + +/* DAC control register */ +#define DAC_CTRL 0x00 +#define DAC_CTRL_ONPADRV 7 +#define DAC_CTRL_ONAUXIN 6 +#define DAC_CTRL_ONDACR 5 +#define DAC_CTRL_ONDACL 4 +#define DAC_CTRL_ONLNOR 3 +#define DAC_CTRL_ONLNOL 2 +#define DAC_CTRL_ONLNIR 1 +#define DAC_CTRL_ONLNIL 0 + +/* DAC left line in gain register */ +#define DAC_LLIG 0x01 +#define DAC_LLIG_LLIG 0 + +/* DAC right line in gain register */ +#define DAC_RLIG 0x02 +#define DAC_RLIG_RLIG 0 + +/* DAC Left Master Playback Gain Register */ +#define DAC_LMPG 0x03 +#define DAC_LMPG_LMPG 0 + +/* DAC Right Master Playback Gain Register */ +#define DAC_RMPG 0x04 +#define DAC_RMPG_RMPG 0 + +/* DAC Left Line Out Gain Register */ +#define DAC_LLOG 0x05 +#define DAC_LLOG_LLOG 0 + +/* DAC Right Line Out Gain Register */ +#define DAC_RLOG 0x06 +#define DAC_RLOG_RLOG 0 + +/* DAC Output Level Control Register */ +#define DAC_OLC 0x07 +#define DAC_OLC_RSHORT 7 +#define DAC_OLC_ROLC 4 +#define DAC_OLC_LSHORT 3 +#define DAC_OLC_LOLC 0 + +/* DAC Mixer Control Register */ +#define DAC_MC 0x08 +#define DAC_MC_INVR 5 +#define DAC_MC_INVL 4 +#define DAC_MC_RMSMIN2 3 +#define DAC_MC_RMSMIN1 2 +#define DAC_MC_LMSMIN2 1 +#define DAC_MC_LMSMIN1 0 + +/* DAC Clock and Sampling Frequency Control Register */ +#define DAC_CSFC 0x09 +#define DAC_CSFC_OVRSEL 4 + +/* DAC Miscellaneous Register */ +#define DAC_MISC 0x0A +#define DAC_MISC_VCMCAPSEL 7 +#define DAC_MISC_DINTSEL 4 +#define DAC_MISC_DITHEN 3 +#define DAC_MISC_DEEMPEN 2 +#define DAC_MISC_NBITS 0 + +/* DAC Precharge Control Register */ +#define DAC_PRECH 0x0C +#define DAC_PRECH_PRCHGPDRV 7 +#define DAC_PRECH_PRCHGAUX1 6 +#define DAC_PRECH_PRCHGLNOR 5 +#define DAC_PRECH_PRCHGLNOL 4 +#define DAC_PRECH_PRCHGLNIR 3 +#define DAC_PRECH_PRCHGLNIL 2 +#define DAC_PRECH_PRCHG 1 +#define DAC_PRECH_ONMSTR 0 + +/* DAC Auxiliary Input Gain Control Register */ +#define DAC_AUXG 0x0D +#define DAC_AUXG_AUXG 0 + +/* DAC Reset Register */ +#define DAC_RST 0x10 +#define DAC_RST_RESMASK 2 +#define DAC_RST_RESFILZ 1 +#define DAC_RST_RSTZ 0 + +/* Power Amplifier Control Register */ +#define PA_CTRL 0x11 +#define PA_CTRL_APAON 6 +#define PA_CTRL_APAPRECH 5 +#define PA_CTRL_APALP 4 +#define PA_CTRL_APAGAIN 0 + +#endif /* _SND_AT73C213_H */ diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c index 1d9b11f..6fc3d2b 100644 --- a/sound/synth/util_mem.c +++ b/sound/synth/util_mem.c @@ -116,7 +116,7 @@ __snd_util_memblk_new(struct snd_util_me if (blk == NULL) return NULL; - if (! prev || prev == &hdr->block) + if (prev == &hdr->block) blk->offset = 0; else { struct snd_util_memblk *p = get_memblk(prev); diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 315360f..7061438 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -40,6 +40,7 @@ config SND_USB_CAIAQ namely: * Native Instruments RigKontrol2 + * Native Instruments RigKontrol3 * Native Instruments Kore Controller * Native Instruments Audio Kontrol 1 * Native Instruments Audio 8 DJ @@ -55,6 +56,7 @@ config SND_USB_CAIAQ_INPUT alpha dials and analog pedals on the following products: * Native Instruments RigKontrol2 + * Native Instruments RigKontrol3 * Native Instruments Audio Kontrol 1 endmenu diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index 0414d76..0666908 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c @@ -648,6 +648,7 @@ int __devinit snd_usb_caiaq_audio_init(s dev->samplerates = dev->pcm_info.rates; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): dev->samplerates |= SNDRV_PCM_RATE_88200; dev->samplerates |= SNDRV_PCM_RATE_192000; break; diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 4709347..58af814 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -41,9 +41,10 @@ #include "caiaq-input.h" #endif MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.1.0"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.2.0"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," + "{Native Instruments, RigKontrol3}," "{Native Instruments, Kore Controller}," "{Native Instruments, Audio Kontrol 1}" "{Native Instruments, Audio 8 DJ}}"); @@ -85,6 +86,11 @@ static struct usb_device_id snd_usb_id_t { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_RIGKONTROL3 + }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_KORECONTROLLER }, { @@ -226,7 +232,7 @@ int snd_usb_caiaq_set_auto_msg (struct s static void setup_card(struct snd_usb_caiaqdev *dev) { int ret; - char val[3]; + char val[4]; /* device-specific startup specials */ switch (dev->chip.usb_id) { @@ -237,6 +243,14 @@ static void setup_card(struct snd_usb_ca val[2] = 0x01; send_command(dev, EP1_CMD_WRITE_IO, val, 3); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + /* RigKontrol2 - display two centered dashes ('--') */ + val[0] = 0x00; + val[1] = 0x40; + val[2] = 0x40; + val[3] = 0x00; + send_command(dev, EP1_CMD_WRITE_IO, val, 4); + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): /* Audio Kontrol 1 - make USB-LED stop blinking */ val[0] = 0x00; diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index 088d5ec..79bc5be 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h @@ -6,6 +6,7 @@ #include "../usbaudio.h" #define USB_VID_NATIVEINSTRUMENTS 0x17cc #define USB_PID_RIGKONTROL2 0x1969 +#define USB_PID_RIGKONTROL3 0x1940 #define USB_PID_KORECONTROLLER 0x4711 #define USB_PID_AK1 0x0815 #define USB_PID_AUDIO8DJ 0x1978 diff --git a/sound/usb/caiaq/caiaq-input.c b/sound/usb/caiaq/caiaq-input.c index 3acd12d..a1de0c6 100644 --- a/sound/usb/caiaq/caiaq-input.c +++ b/sound/usb/caiaq/caiaq-input.c @@ -34,6 +34,8 @@ #ifdef CONFIG_SND_USB_CAIAQ_INPUT static unsigned char keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; static unsigned char keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7 }; +static unsigned char keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, + KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; #define DEG90 (range/2) #define DEG180 (range) @@ -107,7 +109,8 @@ #undef LOW_PEAK static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, - const char *buf, unsigned int len) + const unsigned char *buf, + unsigned int len) { switch(dev->input_dev->id.product) { case USB_PID_RIGKONTROL2: @@ -116,6 +119,12 @@ static void snd_caiaq_input_read_analog( input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]); input_sync(dev->input_dev); break; + case USB_PID_RIGKONTROL3: + input_report_abs(dev->input_dev, ABS_X, (buf[0] << 8) |buf[1]); + input_report_abs(dev->input_dev, ABS_Y, (buf[2] << 8) |buf[3]); + input_report_abs(dev->input_dev, ABS_Z, (buf[4] << 8) |buf[5]); + input_sync(dev->input_dev); + break; } } @@ -128,7 +137,7 @@ static void snd_caiaq_input_read_erp(str case USB_PID_AK1: i = decode_erp(buf[0], buf[1]); input_report_abs(dev->input_dev, ABS_X, i); - input_sync(dev->input_dev); + input_sync(dev->input_dev); break; } } @@ -204,6 +213,20 @@ int snd_usb_caiaq_input_init(struct snd_ input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); + input->keycode = keycode_rk3; + input->keycodesize = sizeof(char); + input->keycodemax = ARRAY_SIZE(keycode_rk3); + for (i=0; ikeybit); + + input_set_abs_params(input, ABS_X, 0, 1024, 0, 10); + input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10); + input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10); + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input->absbit[0] = BIT(ABS_X); @@ -238,7 +261,6 @@ void snd_usb_caiaq_input_free(struct snd return; input_unregister_device(dev->input_dev); - input_free_device(dev->input_dev); dev->input_dev = NULL; } diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 7bd5852..a480683 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -123,7 +123,6 @@ struct audioformat { unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */ - unsigned int needs_knot; /* any unusual rates? */ }; struct snd_usb_substream; @@ -1309,7 +1308,11 @@ static int set_format(struct snd_usb_sub /* close the old interface */ if (subs->interface >= 0 && subs->interface != fmt->iface) { - usb_set_interface(subs->dev, subs->interface, 0); + if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", + dev->devnum, fmt->iface, fmt->altsetting); + return -EIO; + } subs->interface = -1; subs->format = 0; } @@ -1761,7 +1764,7 @@ static int check_hw_params_convention(st channels[f->format] |= (1 << f->channels); rates[f->format] |= f->rates; /* needs knot? */ - if (f->needs_knot) + if (f->rates & SNDRV_PCM_RATE_KNOT) goto __out; } /* check whether channels and rates match for all formats */ @@ -1817,7 +1820,7 @@ static int snd_usb_pcm_check_knot(struct if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) return 0; count += fp->nr_rates; - if (fp->needs_knot) + if (fp->rates & SNDRV_PCM_RATE_KNOT) needs_knot = 1; } if (!needs_knot) @@ -2453,7 +2456,7 @@ static int parse_audio_format_rates(stru unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; - int found; + if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", chip->dev->devnum, fp->iface, fp->altsetting); @@ -2464,20 +2467,15 @@ static int parse_audio_format_rates(stru /* * build the rate table and bitmap flags */ - int r, idx, c; + int r, idx; unsigned int nonzero_rates = 0; - /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ - static unsigned int conv_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 - }; + fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); if (fp->rate_table == NULL) { snd_printk(KERN_ERR "cannot malloc\n"); return -1; } - fp->needs_knot = 0; fp->nr_rates = nr_rates; fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { @@ -2493,23 +2491,12 @@ static int parse_audio_format_rates(stru fp->rate_min = rate; else if (rate > fp->rate_max) fp->rate_max = rate; - found = 0; - for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { - if (rate == conv_rates[c]) { - found = 1; - fp->rates |= (1 << c); - break; - } - } - if (!found) - fp->needs_knot = 1; + fp->rates |= snd_pcm_rate_to_rate_bit(rate); } if (!nonzero_rates) { hwc_debug("All rates were zero. Skipping format!\n"); return -1; } - if (fp->needs_knot) - fp->rates |= SNDRV_PCM_RATE_KNOT; } else { /* continuous rates */ fp->rates = SNDRV_PCM_RATE_CONTINUOUS; @@ -2857,6 +2844,10 @@ static int snd_usb_create_streams(struct /* skip non-supported classes */ continue; } + if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { + snd_printk(KERN_ERR "low speed audio streaming not supported\n"); + continue; + } if (! parse_audio_endpoints(chip, j)) { usb_set_interface(dev, j, 0); /* reset the current interface */ usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); @@ -3399,7 +3390,8 @@ static int snd_usb_audio_create(struct u *rchip = NULL; - if (snd_usb_get_speed(dev) != USB_SPEED_FULL && + if (snd_usb_get_speed(dev) != USB_SPEED_LOW && + snd_usb_get_speed(dev) != USB_SPEED_FULL && snd_usb_get_speed(dev) != USB_SPEED_HIGH) { snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); return -ENXIO; @@ -3473,7 +3465,9 @@ static int snd_usb_audio_create(struct u usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); strlcat(card->longname, - snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed", + snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : + snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : + ", high speed", sizeof(card->longname)); snd_usb_audio_create_proc(chip); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 99295f9..6330788 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -407,6 +407,20 @@ static void snd_usbmidi_maudio_broken_ru } /* + * CME protocol: like the standard protocol, but SysEx commands are sent as a + * single USB packet preceded by a 0x0F byte. + */ +static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) + snd_usbmidi_standard_input(ep, buffer, buffer_length); + else + snd_usbmidi_input_data(ep, buffer[0] >> 4, + &buffer[1], buffer_length - 1); +} + +/* * Adds one USB MIDI packet to the output buffer. */ static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, @@ -572,6 +586,12 @@ static struct usb_protocol_ops snd_usbmi .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_cme_ops = { + .input = snd_usbmidi_cme_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * Novation USB MIDI protocol: number of data bytes is in the first byte * (when receiving) (+1!) or in the second byte (when sending); data begins @@ -963,8 +983,10 @@ static int snd_usbmidi_out_endpoint_crea snd_usbmidi_out_endpoint_delete(ep); return -ENOMEM; } - /* we never use interrupt output pipes */ - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); + if (ep_info->out_interval) + pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + else + pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ /* FIXME: we need more URBs to get reasonable bandwidth here: */ ep->max_transfer = 4; @@ -976,8 +998,14 @@ static int snd_usbmidi_out_endpoint_crea snd_usbmidi_out_endpoint_delete(ep); return -ENOMEM; } - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - ep->max_transfer, snd_usbmidi_out_urb_complete, ep); + if (ep_info->out_interval) + usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, + ep->max_transfer, snd_usbmidi_out_urb_complete, + ep, ep_info->out_interval); + else + usb_fill_bulk_urb(ep->urb, umidi->chip->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, ep); ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; spin_lock_init(&ep->buffer_lock); @@ -1323,6 +1351,13 @@ static int snd_usbmidi_get_ms_info(struc endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) endpoints[epidx].out_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + /* + * Low speed bulk transfers don't exist, so + * force interrupt transfers for devices like + * ESI MIDI Mate that try to use them anyway. + */ + endpoints[epidx].out_interval = 1; endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1336,6 +1371,8 @@ static int snd_usbmidi_get_ms_info(struc endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) endpoints[epidx].in_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1690,6 +1727,7 @@ int snd_usb_create_midi_interface(struct err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); break; case QUIRK_MIDI_CME: + umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 325d4b6..5e32969 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1483,7 +1483,7 @@ static int parse_audio_selector_unit(str struct snd_kcontrol *kctl; char **namelist; - if (! num_ins || desc[0] < 6 + num_ins) { + if (! num_ins || desc[0] < 5 + num_ins) { snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); return -EINVAL; } @@ -1888,14 +1888,7 @@ static int snd_usb_soundblaster_remote_i return 0; } -static int snd_audigy2nx_led_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_audigy2nx_led_info snd_ctl_boolean_mono_info static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 5a2f518..5e69e88 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1254,7 +1254,28 @@ #undef YAMAHA_INTERFACE } }, /* TODO: add Edirol PC-80 support */ - /* TODO: add Edirol UA-1EX support */ +{ + USB_DEVICE(0x0582, 0x0096), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "EDIROL", + .product_name = "UA-1EX", + .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 = -1 + } + } + } +}, { USB_DEVICE(0x0582, 0x009a), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1567,6 +1588,40 @@ #undef YAMAHA_INTERFACE } } }, +{ + USB_DEVICE(0x0763, 0x2019), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Ozone Academic", */ + .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_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_MIDIMAN, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, /* Casio devices */ { @@ -1709,6 +1764,24 @@ #undef YAMAHA_INTERFACE } }, +/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ +{ + USB_DEVICE(0x103d, 0x0100), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Stanton", + .product_name = "ScratchAmp", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ + USB_DEVICE(0x103d, 0x0101), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Stanton", + .product_name = "ScratchAmp", + .ifnum = QUIRK_NO_INTERFACE + } +}, + /* Novation EMS devices */ { USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001), @@ -1738,6 +1811,17 @@ #undef YAMAHA_INTERFACE } }, +/* */ +{ + /* aka. Serato Scratch Live DJ Box */ + USB_DEVICE(0x13e5, 0x0001), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Rane", + .product_name = "SL-1", + .ifnum = QUIRK_NO_INTERFACE + } +}, + /* Miditech devices */ { USB_DEVICE(0x4752, 0x0011),