aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/azt3328.c
diff options
context:
space:
mode:
authorAndreas Mohr <andi@lisas.de>2011-02-18 18:49:32 -0500
committerTakashi Iwai <tiwai@suse.de>2011-02-19 10:02:24 -0500
commitb5dc20cd21357ea3663d428e42fcf9d167bb7aa2 (patch)
tree819bfb1b033be6a444b622cd63177c756d42c7d5 /sound/pci/azt3328.c
parent03c2d87a2112a6548aa3f9635e76d3611c3df53c (diff)
ALSA: azt3328: add custom AC97 semi-emulation use standard ALSA AC97 layer
Make use of the very flexible ALSA ac97 layer (hooks for custom I/O!) on this weird AC97 copycat hardware, via semi-extended I/O translation/emulation. Some 5kB binary/loaded size saved (well... additional huge AC97 module penalty not factored in, of course ;-P). Given that the driver previously had 20kB that's not bad, but the much more important thing is to have AC97 layer stress-tested with a thoroughly weird AC97 copycat (or, simply put, if it were not for this AC97 test aspect, this effort would merely have been a nut job ;). Signed-off-by: Andreas Mohr <andi@lisas.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/azt3328.c')
-rw-r--r--sound/pci/azt3328.c450
1 files changed, 402 insertions, 48 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 6117595fc075..bb84bb68a776 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1,6 +1,5 @@
1/* 1/* azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
2 * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). 2 * Copyright (C) 2002, 2005 - 2011 by Andreas Mohr <andi AT lisas.de>
3 * Copyright (C) 2002, 2005 - 2010 by Andreas Mohr <andi AT lisas.de>
4 * 3 *
5 * Framework borrowed from Bart Hartgers's als4000.c. 4 * Framework borrowed from Bart Hartgers's als4000.c.
6 * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), 5 * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
@@ -66,6 +65,13 @@
66 * addresses illegally. So far unfortunately it looks like the very flexible 65 * addresses illegally. So far unfortunately it looks like the very flexible
67 * ALSA AC97 support is still not enough to easily compensate for such a 66 * ALSA AC97 support is still not enough to easily compensate for such a
68 * grave layout violation despite all tweaks and quirks mechanisms it offers. 67 * grave layout violation despite all tweaks and quirks mechanisms it offers.
68 * Well, not quite: now ac97 layer is much improved (bus-specific ops!),
69 * thus I was able to implement support - it's actually working quite well.
70 * An interesting item might be Aztech AMR 2800-W, since it's an AC97
71 * modem card which might reveal the Aztech-specific codec ID which
72 * we might want to pretend, too. Dito PCI168's brother, PCI368,
73 * where the advertising datasheet says it's AC97-based and has a
74 * Digital Enhanced Game Port.
69 * - builtin genuine OPL3 - verified to work fine, 20080506 75 * - builtin genuine OPL3 - verified to work fine, 20080506
70 * - full duplex 16bit playback/record at independent sampling rate 76 * - full duplex 16bit playback/record at independent sampling rate
71 * - MPU401 (+ legacy address support, claimed by one official spec sheet) 77 * - MPU401 (+ legacy address support, claimed by one official spec sheet)
@@ -189,6 +195,16 @@
189#include <sound/mpu401.h> 195#include <sound/mpu401.h>
190#include <sound/opl3.h> 196#include <sound/opl3.h>
191#include <sound/initval.h> 197#include <sound/initval.h>
198/*
199 * Config switch, to use ALSA's AC97 layer instead of old custom mixer crap.
200 * If the AC97 compatibility parts we needed to implement locally turn out
201 * to work nicely, then remove the old implementation eventually.
202 */
203#define AZF_USE_AC97_LAYER 1
204
205#ifdef AZF_USE_AC97_LAYER
206#include <sound/ac97_codec.h>
207#endif
192#include "azt3328.h" 208#include "azt3328.h"
193 209
194MODULE_AUTHOR("Andreas Mohr <andi AT lisas.de>"); 210MODULE_AUTHOR("Andreas Mohr <andi AT lisas.de>");
@@ -328,6 +344,10 @@ struct snd_azf3328 {
328 /* playback, recording and I2S out codecs */ 344 /* playback, recording and I2S out codecs */
329 struct snd_azf3328_codec_data codecs[3]; 345 struct snd_azf3328_codec_data codecs[3];
330 346
347#ifdef AZF_USE_AC97_LAYER
348 struct snd_ac97 *ac97;
349#endif
350
331 struct snd_card *card; 351 struct snd_card *card;
332 struct snd_rawmidi *rmidi; 352 struct snd_rawmidi *rmidi;
333 353
@@ -506,7 +526,7 @@ snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg)
506#define AZF_MUTE_BIT 0x80 526#define AZF_MUTE_BIT 0x80
507 527
508static bool 528static bool
509snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, 529snd_azf3328_mixer_mute_control(const struct snd_azf3328 *chip,
510 unsigned reg, bool do_mute 530 unsigned reg, bool do_mute
511) 531)
512{ 532{
@@ -521,6 +541,323 @@ snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip,
521 return (do_mute) ? !updated : updated; 541 return (do_mute) ? !updated : updated;
522} 542}
523 543
544static inline bool
545snd_azf3328_mixer_mute_control_master(const struct snd_azf3328 *chip,
546 bool do_mute
547)
548{
549 return snd_azf3328_mixer_mute_control(
550 chip,
551 IDX_MIXER_PLAY_MASTER,
552 do_mute
553 );
554}
555
556static inline bool
557snd_azf3328_mixer_mute_control_pcm(const struct snd_azf3328 *chip,
558 bool do_mute
559)
560{
561 return snd_azf3328_mixer_mute_control(
562 chip,
563 IDX_MIXER_WAVEOUT,
564 do_mute
565 );
566}
567
568static inline void
569snd_azf3328_mixer_reset(const struct snd_azf3328 *chip)
570{
571 /* reset (close) mixer:
572 * first mute master volume, then reset
573 */
574 snd_azf3328_mixer_mute_control_master(chip, 1);
575 snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
576}
577
578#ifdef AZF_USE_AC97_LAYER
579
580static inline void
581snd_azf3328_mixer_ac97_map_unsupported(unsigned short reg, const char *mode)
582{
583 /* need to add some more or less clever emulation? */
584 printk(KERN_WARNING
585 "azt3328: missing %s emulation for AC97 register 0x%02x!\n",
586 mode, reg);
587}
588
589/*
590 * Need to have _special_ AC97 mixer hardware register index mapper,
591 * to compensate for the issue of a rather AC97-incompatible hardware layout.
592 */
593#define AZF_REG_MASK 0x3f
594#define AZF_AC97_REG_UNSUPPORTED 0x8000
595#define AZF_AC97_REG_REAL_IO_READ 0x4000
596#define AZF_AC97_REG_REAL_IO_WRITE 0x2000
597#define AZF_AC97_REG_REAL_IO_RW \
598 (AZF_AC97_REG_REAL_IO_READ | AZF_AC97_REG_REAL_IO_WRITE)
599#define AZF_AC97_REG_EMU_IO_READ 0x0400
600#define AZF_AC97_REG_EMU_IO_WRITE 0x0200
601#define AZF_AC97_REG_EMU_IO_RW \
602 (AZF_AC97_REG_EMU_IO_READ | AZF_AC97_REG_EMU_IO_WRITE)
603static unsigned short
604snd_azf3328_mixer_ac97_map_reg_idx(unsigned short reg)
605{
606 static const struct {
607 unsigned short azf_reg;
608 } azf_reg_mapper[] = {
609 /* Especially when taking into consideration
610 * mono/stereo-based sequence of azf vs. AC97 control series,
611 * it's quite obvious that azf simply got rid
612 * of the AC97_HEADPHONE control at its intended offset,
613 * thus shifted _all_ controls by one,
614 * and _then_ simply added it as an FMSYNTH control at the end,
615 * to make up for the offset.
616 * This means we'll have to translate indices here as
617 * needed and then do some tiny AC97 patch action
618 * (snd_ac97_rename_vol_ctl() etc.) - that's it.
619 */
620 { /* AC97_RESET */ IDX_MIXER_RESET
621 | AZF_AC97_REG_REAL_IO_WRITE
622 | AZF_AC97_REG_EMU_IO_READ },
623 { /* AC97_MASTER */ IDX_MIXER_PLAY_MASTER },
624 /* note large shift: AC97_HEADPHONE to IDX_MIXER_FMSYNTH! */
625 { /* AC97_HEADPHONE */ IDX_MIXER_FMSYNTH },
626 { /* AC97_MASTER_MONO */ IDX_MIXER_MODEMOUT },
627 { /* AC97_MASTER_TONE */ IDX_MIXER_BASSTREBLE },
628 { /* AC97_PC_BEEP */ IDX_MIXER_PCBEEP },
629 { /* AC97_PHONE */ IDX_MIXER_MODEMIN },
630 { /* AC97_MIC */ IDX_MIXER_MIC },
631 { /* AC97_LINE */ IDX_MIXER_LINEIN },
632 { /* AC97_CD */ IDX_MIXER_CDAUDIO },
633 { /* AC97_VIDEO */ IDX_MIXER_VIDEO },
634 { /* AC97_AUX */ IDX_MIXER_AUX },
635 { /* AC97_PCM */ IDX_MIXER_WAVEOUT },
636 { /* AC97_REC_SEL */ IDX_MIXER_REC_SELECT },
637 { /* AC97_REC_GAIN */ IDX_MIXER_REC_VOLUME },
638 { /* AC97_REC_GAIN_MIC */ AZF_AC97_REG_EMU_IO_RW },
639 { /* AC97_GENERAL_PURPOSE */ IDX_MIXER_ADVCTL2 },
640 { /* AC97_3D_CONTROL */ IDX_MIXER_ADVCTL1 },
641 };
642
643 unsigned short reg_azf = AZF_AC97_REG_UNSUPPORTED;
644
645 /* azf3328 supports the low-numbered and low-spec:ed range
646 of AC97 regs only */
647 if (reg <= AC97_3D_CONTROL) {
648 unsigned short reg_idx = reg / 2;
649 reg_azf = azf_reg_mapper[reg_idx].azf_reg;
650 /* a translation-only entry means it's real read/write: */
651 if (!(reg_azf & ~AZF_REG_MASK))
652 reg_azf |= AZF_AC97_REG_REAL_IO_RW;
653 } else {
654 switch (reg) {
655 case AC97_POWERDOWN:
656 reg_azf = AZF_AC97_REG_EMU_IO_RW;
657 break;
658 case AC97_EXTENDED_ID:
659 reg_azf = AZF_AC97_REG_EMU_IO_READ;
660 break;
661 case AC97_EXTENDED_STATUS:
662 /* I don't know what the h*ll AC97 layer
663 * would consult this _extended_ register for
664 * given a base-AC97-advertised card,
665 * but let's just emulate it anyway :-P
666 */
667 reg_azf = AZF_AC97_REG_EMU_IO_RW;
668 break;
669 case AC97_VENDOR_ID1:
670 case AC97_VENDOR_ID2:
671 reg_azf = AZF_AC97_REG_EMU_IO_READ;
672 break;
673 }
674 }
675 return reg_azf;
676}
677
678static const unsigned short
679azf_emulated_ac97_caps =
680 AC97_BC_DEDICATED_MIC |
681 AC97_BC_BASS_TREBLE |
682 /* Headphone is an FM Synth control here */
683 AC97_BC_HEADPHONE |
684 /* no AC97_BC_LOUDNESS! */
685 /* mask 0x7c00 is
686 vendor-specific 3D enhancement
687 vendor indicator.
688 Since there actually _is_ an
689 entry for Aztech Labs
690 (13), make damn sure
691 to indicate it. */
692 (13 << 10);
693
694static const unsigned short
695azf_emulated_ac97_powerdown =
696 /* pretend everything to be active */
697 AC97_PD_ADC_STATUS |
698 AC97_PD_DAC_STATUS |
699 AC97_PD_MIXER_STATUS |
700 AC97_PD_VREF_STATUS;
701
702/*
703 * Emulated, _inofficial_ vendor ID
704 * (there might be some devices such as the MR 2800-W
705 * which could reveal the real Aztech AC97 ID).
706 * We choose to use "AZT" prefix, and then use 1 to indicate PCI168
707 * (better don't use 0x68 since there's a PCI368 as well).
708 */
709static const unsigned int
710azf_emulated_ac97_vendor_id = 0x415a5401;
711
712static unsigned short
713snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
714{
715 const struct snd_azf3328 *chip = ac97->private_data;
716 unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
717 unsigned short reg_val = 0;
718 bool unsupported = 0;
719
720 snd_azf3328_dbgmixer(
721 "snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
722 reg_ac97
723 );
724 if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
725 unsupported = 1;
726 else {
727 if (reg_azf & AZF_AC97_REG_REAL_IO_READ)
728 reg_val = snd_azf3328_mixer_inw(chip,
729 reg_azf & AZF_REG_MASK);
730 else {
731 /*
732 * Proceed with dummy I/O read,
733 * to ensure compatible timing where this may matter.
734 * (ALSA AC97 layer usually doesn't call I/O functions
735 * due to intelligent I/O caching anyway)
736 * Choose a mixer register that's thoroughly unrelated
737 * to common audio (try to minimize distortion).
738 */
739 snd_azf3328_mixer_inw(chip, IDX_MIXER_SOMETHING30H);
740 }
741
742 if (reg_azf & AZF_AC97_REG_EMU_IO_READ) {
743 switch (reg_ac97) {
744 case AC97_RESET:
745 reg_val |= azf_emulated_ac97_caps;
746 break;
747 case AC97_POWERDOWN:
748 reg_val |= azf_emulated_ac97_powerdown;
749 break;
750 case AC97_EXTENDED_ID:
751 case AC97_EXTENDED_STATUS:
752 /* AFAICS we simply can't support anything: */
753 reg_val |= 0;
754 break;
755 case AC97_VENDOR_ID1:
756 reg_val = azf_emulated_ac97_vendor_id >> 16;
757 break;
758 case AC97_VENDOR_ID2:
759 reg_val = azf_emulated_ac97_vendor_id & 0xffff;
760 break;
761 default:
762 unsupported = 1;
763 break;
764 }
765 }
766 }
767 if (unsupported)
768 snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "read");
769
770 return reg_val;
771}
772
773static void
774snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
775 unsigned short reg_ac97, unsigned short val)
776{
777 const struct snd_azf3328 *chip = ac97->private_data;
778 unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
779 bool unsupported = 0;
780
781 snd_azf3328_dbgmixer(
782 "snd_azf3328_mixer_ac97_write reg_ac97 %u val %u\n",
783 reg_ac97, val
784 );
785 if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
786 unsupported = 1;
787 else {
788 if (reg_azf & AZF_AC97_REG_REAL_IO_WRITE)
789 snd_azf3328_mixer_outw(
790 chip,
791 reg_azf & AZF_REG_MASK,
792 val
793 );
794 else
795 if (reg_azf & AZF_AC97_REG_EMU_IO_WRITE) {
796 switch (reg_ac97) {
797 case AC97_REC_GAIN_MIC:
798 case AC97_POWERDOWN:
799 case AC97_EXTENDED_STATUS:
800 /*
801 * Silently swallow these writes.
802 * Since for most registers our card doesn't
803 * actually support a comparable feature,
804 * this is exactly what we should do here.
805 * The AC97 layer's I/O caching probably
806 * automatically takes care of all the rest...
807 * (remembers written values etc.)
808 */
809 break;
810 default:
811 unsupported = 1;
812 break;
813 }
814 }
815 }
816 if (unsupported)
817 snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "write");
818}
819
820static int __devinit
821snd_azf3328_mixer_new(struct snd_azf3328 *chip)
822{
823 struct snd_ac97_bus *bus;
824 struct snd_ac97_template ac97;
825 static struct snd_ac97_bus_ops ops = {
826 .write = snd_azf3328_mixer_ac97_write,
827 .read = snd_azf3328_mixer_ac97_read,
828 };
829 int rc;
830
831 memset(&ac97, 0, sizeof(ac97));
832 ac97.scaps = AC97_SCAP_SKIP_MODEM
833 | AC97_SCAP_AUDIO /* we support audio! */
834 | AC97_SCAP_NO_SPDIF;
835 ac97.private_data = chip;
836 ac97.pci = chip->pci;
837
838 /*
839 * ALSA's AC97 layer has terrible init crackling issues,
840 * unfortunately, and since it makes use of AC97_RESET,
841 * there's no use trying to mute Master Playback proactively.
842 */
843
844 rc = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus);
845 if (!rc)
846 rc = snd_ac97_mixer(bus, &ac97, &chip->ac97);
847 /*
848 * Make sure to complain loudly in case of AC97 init failure,
849 * since failure may happen quite often,
850 * due to this card being a very quirky AC97 "lookalike".
851 */
852 if (rc)
853 printk(KERN_ERR "azt3328: AC97 init failed, err %d!\n", rc);
854
855 /* If we return an error here, then snd_card_free() should
856 * free up any ac97 codecs that got created, as well as the bus.
857 */
858 return rc;
859}
860#else /* AZF_USE_AC97_LAYER */
524static void 861static void
525snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, 862snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
526 unsigned reg, 863 unsigned reg,
@@ -945,6 +1282,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
945 snd_azf3328_dbgcallleave(); 1282 snd_azf3328_dbgcallleave();
946 return 0; 1283 return 0;
947} 1284}
1285#endif /* AZF_USE_AC97_LAYER */
948 1286
949static int 1287static int
950snd_azf3328_hw_params(struct snd_pcm_substream *substream, 1288snd_azf3328_hw_params(struct snd_pcm_substream *substream,
@@ -1239,8 +1577,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1239 if (is_main_mixer_playback_codec) { 1577 if (is_main_mixer_playback_codec) {
1240 /* mute WaveOut (avoid clicking during setup) */ 1578 /* mute WaveOut (avoid clicking during setup) */
1241 previously_muted = 1579 previously_muted =
1242 snd_azf3328_mixer_set_mute( 1580 snd_azf3328_mixer_mute_control_pcm(
1243 chip, IDX_MIXER_WAVEOUT, 1 1581 chip, 1
1244 ); 1582 );
1245 } 1583 }
1246 1584
@@ -1296,8 +1634,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1296 if (is_main_mixer_playback_codec) { 1634 if (is_main_mixer_playback_codec) {
1297 /* now unmute WaveOut */ 1635 /* now unmute WaveOut */
1298 if (!previously_muted) 1636 if (!previously_muted)
1299 snd_azf3328_mixer_set_mute( 1637 snd_azf3328_mixer_mute_control_pcm(
1300 chip, IDX_MIXER_WAVEOUT, 0 1638 chip, 0
1301 ); 1639 );
1302 } 1640 }
1303 1641
@@ -1321,8 +1659,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1321 if (is_main_mixer_playback_codec) { 1659 if (is_main_mixer_playback_codec) {
1322 /* mute WaveOut (avoid clicking during setup) */ 1660 /* mute WaveOut (avoid clicking during setup) */
1323 previously_muted = 1661 previously_muted =
1324 snd_azf3328_mixer_set_mute( 1662 snd_azf3328_mixer_mute_control_pcm(
1325 chip, IDX_MIXER_WAVEOUT, 1 1663 chip, 1
1326 ); 1664 );
1327 } 1665 }
1328 1666
@@ -1347,8 +1685,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1347 if (is_main_mixer_playback_codec) { 1685 if (is_main_mixer_playback_codec) {
1348 /* now unmute WaveOut */ 1686 /* now unmute WaveOut */
1349 if (!previously_muted) 1687 if (!previously_muted)
1350 snd_azf3328_mixer_set_mute( 1688 snd_azf3328_mixer_mute_control_pcm(
1351 chip, IDX_MIXER_WAVEOUT, 0 1689 chip, 0
1352 ); 1690 );
1353 } 1691 }
1354 1692
@@ -2056,11 +2394,7 @@ snd_azf3328_free(struct snd_azf3328 *chip)
2056 if (chip->irq < 0) 2394 if (chip->irq < 0)
2057 goto __end_hw; 2395 goto __end_hw;
2058 2396
2059 /* reset (close) mixer: 2397 snd_azf3328_mixer_reset(chip);
2060 * first mute master volume, then reset
2061 */
2062 snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
2063 snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
2064 2398
2065 snd_azf3328_timer_stop(chip->timer); 2399 snd_azf3328_timer_stop(chip->timer);
2066 snd_azf3328_gameport_free(chip); 2400 snd_azf3328_gameport_free(chip);
@@ -2413,6 +2747,55 @@ snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
2413 } 2747 }
2414} 2748}
2415 2749
2750static inline void
2751snd_azf3328_resume_regs(const u32 *saved_regs,
2752 unsigned long io_addr,
2753 unsigned count
2754)
2755{
2756 unsigned reg;
2757
2758 for (reg = 0; reg < count; ++reg) {
2759 outl(*saved_regs, io_addr);
2760 snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
2761 io_addr, *saved_regs, inl(io_addr));
2762 ++saved_regs;
2763 io_addr += sizeof(*saved_regs);
2764 }
2765}
2766
2767static inline void
2768snd_azf3328_suspend_ac97(struct snd_azf3328 *chip)
2769{
2770#ifdef AZF_USE_AC97_LAYER
2771 snd_ac97_suspend(chip->ac97);
2772#else
2773 snd_azf3328_suspend_regs(chip->mixer_io,
2774 ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
2775
2776 /* make sure to disable master volume etc. to prevent looping sound */
2777 snd_azf3328_mixer_mute_control_master(chip, 1);
2778 snd_azf3328_mixer_mute_control_pcm(chip, 1);
2779#endif /* AZF_USE_AC97_LAYER */
2780}
2781
2782static inline void
2783snd_azf3328_resume_ac97(const struct snd_azf3328 *chip)
2784{
2785#ifdef AZF_USE_AC97_LAYER
2786 snd_ac97_resume(chip->ac97);
2787#else
2788 snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io,
2789 ARRAY_SIZE(chip->saved_regs_mixer));
2790
2791 /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
2792 and IDX_MIXER_RESET (offset 0x00) get touched at the same time,
2793 resulting in a mixer reset condition persisting until _after_
2794 master vol was restored. Thus master vol needs an extra restore. */
2795 outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2);
2796#endif /* AZF_USE_AC97_LAYER */
2797}
2798
2416static int 2799static int
2417snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) 2800snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
2418{ 2801{
@@ -2426,12 +2809,7 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
2426 snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); 2809 snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]);
2427 snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); 2810 snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]);
2428 2811
2429 snd_azf3328_suspend_regs(chip->mixer_io, 2812 snd_azf3328_suspend_ac97(chip);
2430 ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
2431
2432 /* make sure to disable master volume etc. to prevent looping sound */
2433 snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
2434 snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
2435 2813
2436 snd_azf3328_suspend_regs(chip->ctrl_io, 2814 snd_azf3328_suspend_regs(chip->ctrl_io,
2437 ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl); 2815 ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl);
@@ -2453,23 +2831,6 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
2453 return 0; 2831 return 0;
2454} 2832}
2455 2833
2456static inline void
2457snd_azf3328_resume_regs(const u32 *saved_regs,
2458 unsigned long io_addr,
2459 unsigned count
2460)
2461{
2462 unsigned reg;
2463
2464 for (reg = 0; reg < count; ++reg) {
2465 outl(*saved_regs, io_addr);
2466 snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
2467 io_addr, *saved_regs, inl(io_addr));
2468 ++saved_regs;
2469 io_addr += sizeof(*saved_regs);
2470 }
2471}
2472
2473static int 2834static int
2474snd_azf3328_resume(struct pci_dev *pci) 2835snd_azf3328_resume(struct pci_dev *pci)
2475{ 2836{
@@ -2493,14 +2854,7 @@ snd_azf3328_resume(struct pci_dev *pci)
2493 snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io, 2854 snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io,
2494 ARRAY_SIZE(chip->saved_regs_opl3)); 2855 ARRAY_SIZE(chip->saved_regs_opl3));
2495 2856
2496 snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io, 2857 snd_azf3328_resume_ac97(chip);
2497 ARRAY_SIZE(chip->saved_regs_mixer));
2498
2499 /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
2500 and IDX_MIXER_RESET (offset 0x00) get touched at the same time,
2501 resulting in a mixer reset condition persisting until _after_
2502 master vol was restored. Thus master vol needs an extra restore. */
2503 outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2);
2504 2858
2505 snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io, 2859 snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io,
2506 ARRAY_SIZE(chip->saved_regs_ctrl)); 2860 ARRAY_SIZE(chip->saved_regs_ctrl));