diff options
author | Andreas Mohr <andi@lisas.de> | 2011-02-18 18:49:32 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-02-19 10:02:24 -0500 |
commit | b5dc20cd21357ea3663d428e42fcf9d167bb7aa2 (patch) | |
tree | 819bfb1b033be6a444b622cd63177c756d42c7d5 /sound/pci/azt3328.c | |
parent | 03c2d87a2112a6548aa3f9635e76d3611c3df53c (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.c | 450 |
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 | ||
194 | MODULE_AUTHOR("Andreas Mohr <andi AT lisas.de>"); | 210 | MODULE_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 | ||
508 | static bool | 528 | static bool |
509 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, | 529 | snd_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 | ||
544 | static inline bool | ||
545 | snd_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 | |||
556 | static inline bool | ||
557 | snd_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 | |||
568 | static inline void | ||
569 | snd_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 | |||
580 | static inline void | ||
581 | snd_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) | ||
603 | static unsigned short | ||
604 | snd_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 | |||
678 | static const unsigned short | ||
679 | azf_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 | |||
694 | static const unsigned short | ||
695 | azf_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 | */ | ||
709 | static const unsigned int | ||
710 | azf_emulated_ac97_vendor_id = 0x415a5401; | ||
711 | |||
712 | static unsigned short | ||
713 | snd_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 | |||
773 | static void | ||
774 | snd_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 | |||
820 | static int __devinit | ||
821 | snd_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 */ | ||
524 | static void | 861 | static void |
525 | snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, | 862 | snd_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 | ||
949 | static int | 1287 | static int |
950 | snd_azf3328_hw_params(struct snd_pcm_substream *substream, | 1288 | snd_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 | ||
2750 | static inline void | ||
2751 | snd_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 | |||
2767 | static inline void | ||
2768 | snd_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 | |||
2782 | static inline void | ||
2783 | snd_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 | |||
2416 | static int | 2799 | static int |
2417 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | 2800 | snd_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 | ||
2456 | static inline void | ||
2457 | snd_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 | |||
2473 | static int | 2834 | static int |
2474 | snd_azf3328_resume(struct pci_dev *pci) | 2835 | snd_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)); |