GIT d9068563e8df73bdb81fe10b44612db10fc915aa git+ssh://master.kernel.org/pub/scm/linux/kernel/git/perex/alsa.git#mm commit 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 | 93 + Documentation/sound/alsa/CMIPCI.txt | 10 .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 127 +- Documentation/sound/alsa/OSS-Emulation.txt | 7 Documentation/sound/alsa/hda_codec.txt | 49 + include/linux/i2c-id.h | 1 include/linux/spi/at73c213.h | 25 include/sound/asound.h | 1 include/sound/control.h | 8 include/sound/cs4231.h | 2 include/sound/emu10k1.h | 11 include/sound/hda_hwdep.h | 44 + include/sound/hdspm.h | 16 include/sound/pcm.h | 3 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 | 27 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_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/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 | 9 sound/isa/ad1816a/ad1816a_lib.c | 2 sound/isa/ad1848/Makefile | 7 sound/isa/cs423x/Makefile | 17 sound/isa/cs423x/cs4231_lib.c | 2 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/sb/sb16_csp.c | 9 sound/isa/sb/sb_common.c | 4 sound/isa/wavefront/wavefront_synth.c | 120 +- sound/pci/Kconfig | 95 + sound/pci/ac97/ac97_codec.c | 23 sound/pci/ac97/ac97_patch.c | 19 sound/pci/ali5451/ali5451.c | 10 sound/pci/au88x0/au88x0.c | 1 sound/pci/au88x0/au88x0_eq.c | 10 sound/pci/bt87x.c | 35 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 | 140 +- 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_pcm.c | 6 sound/pci/echoaudio/echoaudio.c | 33 sound/pci/emu10k1/emu10k1_main.c | 128 +- sound/pci/emu10k1/emu10k1x.c | 9 sound/pci/emu10k1/emufx.c | 239 ++- 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/hda/Makefile | 27 sound/pci/hda/hda_codec.c | 709 +++++++--- sound/pci/hda/hda_codec.h | 109 +- sound/pci/hda/hda_generic.c | 75 + sound/pci/hda/hda_hwdep.c | 122 ++ sound/pci/hda/hda_intel.c | 364 ++++- 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 | 420 +++--- 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 | 1436 ++++++++++++++------ sound/pci/hda/patch_si3054.c | 20 sound/pci/hda/patch_sigmatel.c | 683 +++++++--- 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 | 4 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 | 10 sound/pci/ymfpci/ymfpci_main.c | 105 + 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 | 800 +++++++++++ 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/sparc/dbri.c | 390 +++-- 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/caiaq/caiaq-input.c | 1 sound/usb/usbaudio.c | 46 - sound/usb/usbmidi.c | 46 + sound/usb/usbmixer.c | 11 sound/usb/usbquirks.h | 51 + 158 files changed, 7546 insertions(+), 4194 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 241e26c..38e7756 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -365,13 +365,15 @@ 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: + 0x300,0x310,0x320,0x330 = legacy port, + 1 = integrated PCI port (8738 or later), 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 +770,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, default = 10) + power_save_controller - Reset HD-audio controller in power-saving mode + (default = on) This module supports one card and autoprobe. @@ -828,6 +834,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 @@ -843,6 +851,7 @@ Prior to version 0.9.0rc4 options had a 6stack-dig 6-jack digital with SPDIF I/O arima Arima W820Di1 macpro MacPro support + mbp3 Macbook Pro rev3 imac24 iMac 24'' with jack detection w2jc ASUS W2JC auto auto-config reading BIOS (default) @@ -854,6 +863,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 +872,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 +896,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 @@ -945,14 +957,26 @@ 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-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 +988,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 +1003,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 +1018,12 @@ 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"). + When CONFIG_SND_HDA_POWER_SAVE is set, two options, power_save and + power_save_controller become available. power_save specifies the + time to turn off the power automatically at idle status. When + power_save_controller is true, the controller is also turned off. + This might result in more obvious click noise at turning on/off. + 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 @@ -1697,8 +1732,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..664be46 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 @@ -212,7 +212,9 @@ 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. +Choose the value which doesn't conflict with other cards. With +CMI8738 and newer chips, you can use "mpu_port=1" to use a PCI port +address that does not conflict with any other card. There is _no_ hardware wavetable function on this chip (except for OPL3 synth below). @@ -230,6 +232,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..b9d2dbe 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 + July 26, 2007 + 0.3.6.1 @@ -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); @@ -3604,7 +3621,7 @@ #endif Example of info callback type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; @@ -3639,7 +3656,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 +3821,8 @@ #endif @@ -3880,7 +3908,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 +3917,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 +3930,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 +4476,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/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/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.h b/include/sound/cs4231.h index ab51ce1..b195a73 100644 --- a/include/sound/cs4231.h +++ b/include/sound/cs4231.h @@ -210,7 +210,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..acc4277 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1456,6 +1456,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 +1602,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 +1749,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..27f8ef4 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -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..396e98e 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1486,3 +1486,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_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/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..6b6aa2c 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -414,7 +414,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 +430,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/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/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..642bdaa 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -555,6 +555,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/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/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index bacc51c..2da11e8 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); @@ -1938,111 +1938,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 +2196,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..5d0732c 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,95 @@ 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-bound 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_HDSP tristate "RME Hammerfall DSP Audio" depends on SND diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index bbed644..3e5ff29 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2036,11 +2036,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 +2105,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 +2137,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 +2355,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 +2438,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 +2459,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 +2496,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_patch.c b/sound/pci/ac97/ac97_patch.c index 581ebba..630c961 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1880,14 +1880,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 +2179,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/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/bt87x.c b/sound/pci/bt87x.c index 188c7cf..0d3fd8b 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -340,28 +340,9 @@ 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; 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.rates = snd_pcm_rate_to_rate_bit(chip->dig_rate); runtime->hw.rate_min = chip->dig_rate; runtime->hw.rate_max = chip->dig_rate; return 0; @@ -569,15 +550,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) @@ -791,6 +764,10 @@ static struct pci_device_id snd_bt87x_id BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000), /* AVerMedia Studio No. 103, 203, ...? */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), + /* Prolink PixelView PV-M4900 */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1554, 0x4011, 32000), + /* Pinnacle Studio PCTV rave */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0xbd11, 0x1200, 32000), { } }; MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); 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..315ba26 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -424,7 +424,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; @@ -2139,15 +2138,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, @@ -2633,46 +2624,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 1: 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 +2767,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 > 33) { + /* 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 +2818,9 @@ 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; int pcm_index, pcm_spdif_index; static struct pci_device_id intel_82437vx[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, @@ -2931,15 +2920,54 @@ #endif break; } + sprintf(card->shortname, "C-Media %s", card->driver); + if (cm->chip_version < 68) { + val = pci->device < 0x110 ? 8338 : 8738; + sprintf(card->longname, + "C-Media CMI%d (model %d) at 0x%lx, irq %i", + val, cm->chip_version, cm->iobase, cm->irq); + } 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->longname, "C-Media CMI%d at 0x%lx, irq %i", + val, 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 { + val = 0; + if (cm->chip_version > 33 && mpu_port[dev] == 1) { + 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) { iomidi = mpu_port[dev]; switch (iomidi) { case 0x320: val = CM_VMPU_320; break; @@ -2956,8 +2984,11 @@ #endif } } - 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 +3000,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 +3086,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_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 5450a9e..ec920cb 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; @@ -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/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/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..5967e60 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1207,7 +1207,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 +1267,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 +1524,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 +1569,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 +2440,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 +2463,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 +2483,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/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..46d4253 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 = 10; +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; } @@ -387,6 +406,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 +421,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 +512,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 +523,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 +570,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 +624,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 +653,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 +699,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(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) { - memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); - codec->num_amp_entries = 0; - codec->amp_info_size = 0; - codec->amp_info = NULL; + 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 +775,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 +783,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 +797,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 +811,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 +820,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 +867,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 +957,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 +976,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 +985,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 +1040,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 +1058,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 +1126,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 +1329,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 +1366,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 +1423,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 +1467,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 +1521,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 +1540,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,23 +1620,72 @@ 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 */ /** @@ -1376,28 +1700,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 +2109,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 +2161,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 +2186,91 @@ 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) + 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 +2317,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 +2355,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 +2522,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 +2573,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,93 +2775,36 @@ 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; } +#ifndef CONFIG_SND_HDA_POWER_SAVE /** * snd_hda_resume - resume the codecs * @bus: the HDA 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); - } - 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) -{ - struct snd_ctl_elem_value *val; - - 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); - } + hda_call_codec_resume(codec); } - codec->in_resume = 0; - kfree(val); return 0; } +#endif /* !CONFIG_SND_HDA_POWER_SAVE */ -/** - * 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 diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 56c26e7..ca157e5 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,15 @@ 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); +#else +static inline void snd_hda_power_up(struct hda_codec *codec) {} +static inline void snd_hda_power_down(struct hda_codec *codec) {} +#endif + #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 000287f..819c804 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 }; /* @@ -218,9 +225,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 +240,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 +251,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); } /* @@ -379,7 +383,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 +574,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 */ } @@ -684,11 +689,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 +729,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 +738,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 +798,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 +815,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 +851,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 +917,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) @@ -1022,6 +1054,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 +1069,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..3d06ecc 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,7 +553,7 @@ 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); } while (time_after_eq(timeout, jiffies)); @@ -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,6 +678,9 @@ 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) @@ -777,18 +806,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 +828,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 +906,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 +960,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 +982,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 +1002,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 +1039,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 +1095,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 +1109,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 +1163,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 +1196,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 +1239,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 +1289,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 +1308,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 +1359,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; @@ -1327,7 +1395,8 @@ static int __devinit azx_pcm_create(stru 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 */ @@ -1338,10 +1407,12 @@ static int __devinit azx_pcm_create(stru 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++; @@ -1353,13 +1424,15 @@ static int __devinit azx_pcm_create(stru list_for_each(p, &chip->bus->codec_list) { codec = list_entry(p, struct hda_codec, 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,8 +1585,12 @@ static int azx_resume(struct pci_dev *pc chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; + azx_init_pci(chip); +#ifndef CONFIG_SND_HDA_POWER_SAVE + /* the explicit resume is needed only when POWER_SAVE isn't set */ azx_init_chip(chip); snd_hda_resume(chip->bus); +#endif 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; } 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..bc4b797 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -73,6 +73,10 @@ struct ad198x_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 }; /* @@ -144,6 +148,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 +330,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 +345,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 +371,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 +417,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 +498,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,43 +549,6 @@ 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) -{ - 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, - 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; -} - -static int ad1986a_laptop_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); - 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); - return change; -} - static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { .num_items = 3, .items = { @@ -650,23 +559,8 @@ static struct hda_input_mux ad1986a_lapt }; 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), - }, - { - .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, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, 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("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), @@ -855,6 +749,17 @@ static struct snd_pci_quirk ad1986a_cfg_ {} }; +#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 +769,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 +783,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; @@ -982,8 +889,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 +971,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 +987,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 +1002,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 +1128,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 +1168,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 +1191,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 +1243,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 +1383,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 +1398,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 +1808,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 +1832,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 +1977,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 +2154,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 +2601,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 +2707,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 +2866,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 +2900,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 +3284,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 +3332,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..3557865 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, }; @@ -153,6 +156,7 @@ enum { ALC882_TARGA, ALC882_ASUS_A7J, ALC885_MACPRO, + ALC885_MBP3, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -167,12 +171,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 +245,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 +273,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 +454,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 +469,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 +496,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 +529,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 +550,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 +583,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 +633,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 +1302,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 +1568,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 +1583,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 +1616,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 +1625,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 +1853,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 +1885,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 +1956,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 +1982,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 +1996,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 +2040,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 +2279,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 +2378,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 +2428,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 +2875,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 +2907,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 +3393,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 +3745,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 +3795,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 +3845,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 +4067,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 +4472,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 +4554,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 +4764,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 +4830,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 +4898,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 +4960,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), @@ -5119,6 +5183,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 +5278,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 +5293,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 +5339,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) @@ -5265,6 +5405,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 +5433,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 +5532,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 @@ -5393,6 +5551,7 @@ static const char *alc882_models[ALC882_ [ALC882_ARIMA] = "arima", [ALC882_W2JC] = "w2jc", [ALC885_MACPRO] = "macpro", + [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", }; @@ -5455,6 +5614,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 +5638,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 +5651,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, @@ -5608,6 +5782,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 +5816,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 +5861,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 +5890,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 +5920,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 +6001,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; @@ -6235,6 +6445,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 +6505,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 +6602,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 +6658,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 +6671,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 +6701,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 +6720,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 +6733,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 +6759,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 +6771,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 +6787,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 +6837,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 +6910,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 +6931,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 +6964,13 @@ 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, 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 +6983,8 @@ 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), {} }; @@ -6771,8 +7071,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 +7086,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 +7128,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 +7179,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 +7303,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 +7379,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 +7493,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 +7568,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 +7659,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 +7688,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 +7718,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 +7746,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 +7780,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 +7800,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 +7818,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 +7957,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 +8018,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 +8105,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 +8188,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 +8234,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 +8293,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 +8322,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 +8335,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 +8367,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 +8378,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 +8400,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 +8412,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 +8498,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 +8533,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 +8761,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 +9011,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 +9036,17 @@ 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(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), {} }; @@ -8573,6 +9064,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 +9801,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 +10117,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 +10324,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 +10384,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 +10410,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 +10590,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 +10623,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 +10756,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 +10768,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 +10844,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 +10854,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 +10869,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 +10886,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 +10984,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 +11231,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 +11302,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 +11363,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 +11371,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,11 +11586,11 @@ 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)}, @@ -11087,11 +11659,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) @@ -11115,11 +11687,7 @@ static struct hda_verb alc662_auto_init_ /* 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 +11718,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 +11730,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 +11746,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 @@ -11586,6 +12152,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..98144f9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -39,12 +39,25 @@ #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_M43xx, STAC_9205_MODELS }; @@ -60,19 +73,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 +96,7 @@ enum { STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, + STAC_DELL_3ST, STAC_927X_MODELS }; @@ -95,6 +112,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]; @@ -316,17 +335,21 @@ static struct hda_verb stac9205_core_ini {} }; +#define STAC_INPUT_SOURCE \ + { \ + .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, \ + } + + 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, 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,14 +357,7 @@ 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, 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), @@ -350,14 +366,7 @@ static struct snd_kcontrol_new stac925x_ /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac922x_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, 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), @@ -366,28 +375,14 @@ static struct snd_kcontrol_new stac922x_ /* 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, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x1b, 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, - }, + STAC_INPUT_SOURCE, 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), @@ -403,14 +398,7 @@ static struct snd_kcontrol_new stac9205_ .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, - }, + STAC_INPUT_SOURCE, 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), @@ -451,12 +439,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, 0x01a19021, 0x90100140, + 0x01813122, 0x02214030, 0x01014010, 0x02a19020, +}; + +/* + STAC 9200 pin configs for + 102801C0 + 102801C1 +*/ +static unsigned int dell9200_d22_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x02a19021, 0x90100140, + 0x400001f2, 0x0221401f, 0x01014010, 0x01813020, +}; + +/* + STAC 9200 pin configs for + 102801C4 (Dell Dimension E310) + 102801C5 + 102801C7 + 102801D9 + 102801DA + 102801E3 +*/ +static unsigned int dell9200_d23_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140, + 0x400001f2, 0x0221401f, 0x01014010, 0x01813020, +}; + + +/* + STAC 9200-32 pin configs for + 102801B5 (Dell Inspiron 630m) + 102801D8 (Dell Inspiron 640m) +*/ +static unsigned int dell9200_m21_pin_configs[8] = { + 0x40c003fa, 0x03441340, 0x03a11020, 0x401003fc, + 0x403003fd, 0x0321121f, 0x0321121f, 0x408003fb, +}; + +/* + 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, 0x03A11020, 0x401003fb, + 0x40f000fc, 0x0321121f, 0x90170310, 0x90a70321, +}; + +/* + 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, 0x03a11020, 0x401003fd, + 0x403003fe, 0x0321121f, 0x90170310, 0x408003fc, +}; + +/* + STAC 9200-32 pin configs for + 102801BD (Dell Inspiron E1505n) + 102801EE + 102801EF +*/ +static unsigned int dell9200_m25_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x04a11020, 0x401003fc, + 0x403003fd, 0x0421121f, 0x90170310, 0x408003fb, +}; + +/* + STAC 9200-32 pin configs for + 102801F5 (Dell Inspiron 1501) + 102801F6 +*/ +static unsigned int dell9200_m26_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x04a11020, 0x401003fd, + 0x403003fe, 0x0421121f, 0x90170310, 0x408003fc, +}; + +/* + STAC 9200-32 + 102801CD (Dell Inspiron E1705/9400) +*/ +static unsigned int dell9200_m27_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x04a11020, 0x90170310, + 0x40f003fc, 0x0421121f, 0x90170310, 0x408003fb, +}; + + 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 +584,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 +700,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 +787,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 +893,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 +936,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 +981,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 +1004,94 @@ 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, + [STAC_9205_M43xx] = NULL, }; 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_M43xx), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, + "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 +1157,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); } /* @@ -1066,17 +1369,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) { @@ -1282,8 +1579,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); } } @@ -1536,9 +1833,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); } } @@ -1870,7 +2167,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 +2177,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 +2233,13 @@ 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); - + stac92xx_init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); return 0; } #endif @@ -1962,7 +2250,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 }; @@ -2247,7 +2535,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 +2561,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) @@ -2310,20 +2599,26 @@ 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_M43xx: + 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 +2661,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 +2693,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 +2730,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 +2753,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 +2856,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 +2870,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..cd4613a 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; @@ -902,6 +904,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..5faa579 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) diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index ab7a81c..e33e4aa 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -171,17 +171,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 +378,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 +396,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 +414,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 +523,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 +663,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 +673,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 +929,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 +943,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 +1037,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 +1044,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 +1437,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 +1546,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 +1590,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 +1667,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 +1743,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..43d50a4 --- /dev/null +++ b/sound/soc/codecs/cs4270.c @@ -0,0 +1,800 @@ +/* + * 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) +{ + if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) + return -EIO; + + if (i2c_smbus_write_byte_data(codec->control_data, reg, value) == 0) { + /* We've written to the hardware, so update the cache */ + u8 *cache = codec->reg_cache; + cache[reg - CS4270_FIRSTREG] = value; + return 0; + } else { + printk(KERN_ERR "cs4270: I2C write of register %u failed\n", + reg); + return -EIO; + } +} + +/* + * 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, 0) +}; + +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/sparc/dbri.c b/sound/sparc/dbri.c index e07085a..bfc3930 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,6 @@ #include #include #include -#include -#include #include #include @@ -76,7 +76,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 +105,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 +132,7 @@ struct cs4215 { }; /* - * Control mode first + * Control mode first */ /* Time Slot 1, Status register */ @@ -219,7 +220,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) @@ -285,7 +286,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 */ @@ -341,11 +342,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 +377,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 +420,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 +436,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 +456,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 +465,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 +494,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,41 +534,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 == \ + (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)] +#define DBRI_STREAM(dbri, substream) \ + &dbri->stream_info[DBRI_STREAMNO(substream)] static struct snd_dbri *dbri_list; /* All DBRI devices */ @@ -612,18 +614,18 @@ Since the DBRI can run in parallel with synchronization present themselves. The method implemented here is only use of 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. */ @@ -657,7 +659,7 @@ static void dbri_cmdwait(struct snd_dbri * Lock the command queue and returns pointer to a 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 +682,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 +702,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 +726,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 +749,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 dbri_initialize(struct snd_dbri *dbri) { s32 *cmd; u32 dma_addr; @@ -763,7 +766,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 +804,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 int pipe_active(struct snd_dbri *dbri, int pipe) { return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1)); } @@ -811,20 +814,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 +840,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 +854,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 +885,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 +944,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 +994,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 +1005,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 +1016,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 +1039,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 +1078,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 +1103,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 +1129,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; @@ -1150,8 +1168,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 +1189,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 +1201,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 +1231,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 +1241,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 +1265,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 +1308,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 void cs4215_setup_pipes(struct snd_dbri *dbri) { unsigned long flags; @@ -1303,9 +1323,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); @@ -1355,7 +1375,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 +1407,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 +1472,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 +1522,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 +1542,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 +1576,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 +1633,7 @@ static int cs4215_prepare(struct snd_dbr /* * */ -static int cs4215_init(struct snd_dbri * dbri) +static 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 +1694,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 +1721,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 +1743,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,7 +1769,7 @@ 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; @@ -1763,9 +1785,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); @@ -1785,7 +1806,7 @@ static void transmission_complete_intr(s snd_pcm_period_elapsed(info->substream); } -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; @@ -1817,7 +1838,7 @@ static void reception_complete_intr(stru snd_pcm_period_elapsed(info->substream); } -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 +1910,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,15 +1986,15 @@ 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, @@ -2011,7 +2032,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 +2057,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 +2167,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,7 +2227,7 @@ 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_dbri *dbri) { struct snd_pcm *pcm; int err; @@ -2228,9 +2250,8 @@ static int __devinit snd_dbri_pcm(struct 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; } @@ -2271,7 +2292,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]) { @@ -2316,18 +2338,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 +2398,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,7 +2432,7 @@ 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 __init snd_dbri_mixer(struct snd_dbri *dbri) { struct snd_card *card; int idx, err; @@ -2438,7 +2459,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 +2471,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 +2485,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,11 +2494,11 @@ static void dbri_debug_read(struct snd_i } #endif -void snd_dbri_proc(struct snd_dbri * dbri) +void snd_dbri_proc(struct snd_dbri *dbri) { struct snd_info_entry *entry; - if (! snd_card_proc_new(dbri->card, "regs", &entry)) + if (!snd_card_proc_new(dbri->card, "regs", &entry)) snd_info_set_text_ops(entry, dbri, dbri_regs_read); #ifdef DBRI_DEBUG @@ -2491,7 +2514,7 @@ #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, struct sbus_dev *sdev, @@ -2547,7 +2570,7 @@ static int __init snd_dbri_create(struct 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); @@ -2587,7 +2610,8 @@ static int __init dbri_attach(int prom_n 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); + printk(KERN_ERR "DBRI-%d: Firmware node lacks IRQ property.\n", + dev); return -ENODEV; } @@ -2613,12 +2637,14 @@ static int __init dbri_attach(int prom_n goto _err; if ((err = snd_dbri_mixer(dbri)) < 0) + if ((err = snd_dbri_mixer(dbri)) < 0) goto _err; /* /proc file handling */ snd_dbri_proc(dbri); - 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,7 +2654,7 @@ static int __init dbri_attach(int prom_n return 0; - _err: +_err: snd_dbri_free(dbri); snd_card_free(card); return err; 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/caiaq/caiaq-input.c b/sound/usb/caiaq/caiaq-input.c index 3acd12d..6978dab 100644 --- a/sound/usb/caiaq/caiaq-input.c +++ b/sound/usb/caiaq/caiaq-input.c @@ -238,7 +238,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..20a2f6e 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) { @@ -1709,6 +1730,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 +1777,16 @@ #undef YAMAHA_INTERFACE } }, +{ + /* Serato Scratch Live DJ Box */ + USB_DEVICE(0x13e5, 0x0001), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) + { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + } +}, + /* Miditech devices */ { USB_DEVICE(0x4752, 0x0011),