aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorAndreas Mohr <andi@lisas.de>2006-05-17 05:02:24 -0400
committerJaroslav Kysela <perex@suse.cz>2006-06-22 15:33:38 -0400
commitca54bde3634360afecd0dada9c59399bbe88bd32 (patch)
tree217d8c5f617da88191552433be734831edb6e6ed /sound/pci
parent746df94898554b3d8e91d855e934852e626c701c (diff)
[ALSA] azt3328.c: add suspend/resume support
- add suspend/resume handlers - fix problem (private_data members not set) Playing a file while suspending will resume correctly with this patch, so I assume the hardware to get fully correctly reinitialized with this patch. Signed-off-by: Andreas Mohr <andi@lisas.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/azt3328.c119
-rw-r--r--sound/pci/azt3328.h20
2 files changed, 133 insertions, 6 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 52a364524262..f197fbac10ab 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -90,9 +90,11 @@
90 * 90 *
91 * TODO 91 * TODO
92 * - test MPU401 MIDI playback etc. 92 * - test MPU401 MIDI playback etc.
93 * - power management. See e.g. intel8x0 or cs4281. 93 * - add some power micro-management (disable various units of the card
94 * This would be nice since the chip runs a bit hot, and it's *required* 94 * as long as they're unused). However this requires I/O ports which I
95 * anyway for proper ACPI power management. 95 * haven't figured out yet and which thus might not even exist...
96 * The standard suspend/resume functionality could probably make use of
97 * some improvement, too...
96 * - figure out what all unknown port bits are responsible for 98 * - figure out what all unknown port bits are responsible for
97 */ 99 */
98 100
@@ -214,6 +216,16 @@ struct snd_azf3328 {
214 216
215 struct pci_dev *pci; 217 struct pci_dev *pci;
216 int irq; 218 int irq;
219
220#ifdef CONFIG_PM
221 /* register value containers for power management
222 * Note: not always full I/O range preserved (just like Win driver!) */
223 u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2];
224 u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2];
225 u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2];
226 u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2];
227 u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2];
228#endif
217}; 229};
218 230
219static const struct pci_device_id snd_azf3328_ids[] __devinitdata = { 231static const struct pci_device_id snd_azf3328_ids[] __devinitdata = {
@@ -961,6 +973,13 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
961 chip->is_playing = 1; 973 chip->is_playing = 1;
962 snd_azf3328_dbgplay("STARTED PLAYBACK\n"); 974 snd_azf3328_dbgplay("STARTED PLAYBACK\n");
963 break; 975 break;
976 case SNDRV_PCM_TRIGGER_RESUME:
977 snd_azf3328_dbgplay("RESUME PLAYBACK\n");
978 /* resume playback if we were active */
979 if (chip->is_playing)
980 snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
981 snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME);
982 break;
964 case SNDRV_PCM_TRIGGER_STOP: 983 case SNDRV_PCM_TRIGGER_STOP:
965 snd_azf3328_dbgplay("STOP PLAYBACK\n"); 984 snd_azf3328_dbgplay("STOP PLAYBACK\n");
966 985
@@ -988,6 +1007,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
988 chip->is_playing = 0; 1007 chip->is_playing = 0;
989 snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); 1008 snd_azf3328_dbgplay("STOPPED PLAYBACK\n");
990 break; 1009 break;
1010 case SNDRV_PCM_TRIGGER_SUSPEND:
1011 snd_azf3328_dbgplay("SUSPEND PLAYBACK\n");
1012 /* make sure playback is stopped */
1013 snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
1014 snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME);
1015 break;
991 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1016 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
992 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); 1017 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
993 break; 1018 break;
@@ -995,6 +1020,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
995 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); 1020 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
996 break; 1021 break;
997 default: 1022 default:
1023 printk(KERN_ERR "FIXME: unknown trigger mode!\n");
998 return -EINVAL; 1024 return -EINVAL;
999 } 1025 }
1000 1026
@@ -1068,6 +1094,13 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
1068 chip->is_recording = 1; 1094 chip->is_recording = 1;
1069 snd_azf3328_dbgplay("STARTED CAPTURE\n"); 1095 snd_azf3328_dbgplay("STARTED CAPTURE\n");
1070 break; 1096 break;
1097 case SNDRV_PCM_TRIGGER_RESUME:
1098 snd_azf3328_dbgplay("RESUME CAPTURE\n");
1099 /* resume recording if we were active */
1100 if (chip->is_recording)
1101 snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
1102 snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME);
1103 break;
1071 case SNDRV_PCM_TRIGGER_STOP: 1104 case SNDRV_PCM_TRIGGER_STOP:
1072 snd_azf3328_dbgplay("STOP CAPTURE\n"); 1105 snd_azf3328_dbgplay("STOP CAPTURE\n");
1073 1106
@@ -1088,6 +1121,12 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
1088 chip->is_recording = 0; 1121 chip->is_recording = 0;
1089 snd_azf3328_dbgplay("STOPPED CAPTURE\n"); 1122 snd_azf3328_dbgplay("STOPPED CAPTURE\n");
1090 break; 1123 break;
1124 case SNDRV_PCM_TRIGGER_SUSPEND:
1125 snd_azf3328_dbgplay("SUSPEND CAPTURE\n");
1126 /* make sure recording is stopped */
1127 snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
1128 snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME);
1129 break;
1091 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1130 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1092 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); 1131 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
1093 break; 1132 break;
@@ -1095,6 +1134,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
1095 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); 1134 snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
1096 break; 1135 break;
1097 default: 1136 default:
1137 printk(KERN_ERR "FIXME: unknown trigger mode!\n");
1098 return -EINVAL; 1138 return -EINVAL;
1099 } 1139 }
1100 1140
@@ -1766,6 +1806,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
1766 goto out_err; 1806 goto out_err;
1767 } 1807 }
1768 1808
1809 card->private_data = chip;
1810
1769 if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, 1811 if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401,
1770 chip->mpu_port, 1, pci->irq, 0, 1812 chip->mpu_port, 1, pci->irq, 0,
1771 &chip->rmidi)) < 0) { 1813 &chip->rmidi)) < 0) {
@@ -1791,6 +1833,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
1791 } 1833 }
1792 } 1834 }
1793 1835
1836 opl3->private_data = chip;
1837
1794 sprintf(card->longname, "%s at 0x%lx, irq %i", 1838 sprintf(card->longname, "%s at 0x%lx, irq %i",
1795 card->shortname, chip->codec_port, chip->irq); 1839 card->shortname, chip->codec_port, chip->irq);
1796 1840
@@ -1834,11 +1878,80 @@ snd_azf3328_remove(struct pci_dev *pci)
1834 snd_azf3328_dbgcallleave(); 1878 snd_azf3328_dbgcallleave();
1835} 1879}
1836 1880
1881#ifdef CONFIG_PM
1882static int
1883snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
1884{
1885 struct snd_card *card = pci_get_drvdata(pci);
1886 struct snd_azf3328 *chip = card->private_data;
1887 int reg;
1888
1889 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
1890
1891 snd_pcm_suspend_all(chip->pcm);
1892
1893 for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
1894 chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2);
1895
1896 /* make sure to disable master volume etc. to prevent looping sound */
1897 snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
1898 snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
1899
1900 for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
1901 chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2);
1902 for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
1903 chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2);
1904 for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
1905 chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2);
1906 for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
1907 chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2);
1908
1909 pci_set_power_state(pci, PCI_D3hot);
1910 pci_disable_device(pci);
1911 pci_save_state(pci);
1912 return 0;
1913}
1914
1915static int
1916snd_azf3328_resume(struct pci_dev *pci)
1917{
1918 struct snd_card *card = pci_get_drvdata(pci);
1919 struct snd_azf3328 *chip = card->private_data;
1920 int reg;
1921
1922 pci_restore_state(pci);
1923 pci_enable_device(pci);
1924 pci_set_power_state(pci, PCI_D0);
1925 pci_set_master(pci);
1926
1927 for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
1928 outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2);
1929 for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
1930 outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2);
1931 for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
1932 outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2);
1933 for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
1934 outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2);
1935 for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
1936 outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2);
1937
1938 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
1939 return 0;
1940}
1941#endif
1942
1943
1944
1945
1837static struct pci_driver driver = { 1946static struct pci_driver driver = {
1838 .name = "AZF3328", 1947 .name = "AZF3328",
1839 .id_table = snd_azf3328_ids, 1948 .id_table = snd_azf3328_ids,
1840 .probe = snd_azf3328_probe, 1949 .probe = snd_azf3328_probe,
1841 .remove = __devexit_p(snd_azf3328_remove), 1950 .remove = __devexit_p(snd_azf3328_remove),
1951#ifdef CONFIG_PM
1952 .suspend = snd_azf3328_suspend,
1953 .resume = snd_azf3328_resume,
1954#endif
1842}; 1955};
1843 1956
1844static int __init 1957static int __init
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h
index f489bdaf6d40..560a4653c0b2 100644
--- a/sound/pci/azt3328.h
+++ b/sound/pci/azt3328.h
@@ -5,6 +5,9 @@
5 5
6/*** main I/O area port indices ***/ 6/*** main I/O area port indices ***/
7/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ 7/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
8#define AZF_IO_SIZE_CODEC 0x80
9#define AZF_IO_SIZE_CODEC_PM 0x70
10
8/* the driver initialisation suggests a layout of 4 main areas: 11/* the driver initialisation suggests a layout of 4 main areas:
9 * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??). 12 * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??).
10 * And another area from 0x60 to 0x6f (DirectX timer, IRQ management, 13 * And another area from 0x60 to 0x6f (DirectX timer, IRQ management,
@@ -107,7 +110,8 @@
107 #define IRQ_UNKNOWN2 0x0080 /* probably unused */ 110 #define IRQ_UNKNOWN2 0x0080 /* probably unused */
108#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ 111#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */
109#define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ 112#define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */
110#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback!!! maybe power management?? */ 113#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */
114 #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */
111#define IDX_IO_6CH 0x6C 115#define IDX_IO_6CH 0x6C
112#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ 116#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */
113/* further I/O indices not saved/restored, so probably not used */ 117/* further I/O indices not saved/restored, so probably not used */
@@ -115,15 +119,25 @@
115 119
116/*** I/O 2 area port indices ***/ 120/*** I/O 2 area port indices ***/
117/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ 121/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */
122#define AZF_IO_SIZE_IO2 0x08
123#define AZF_IO_SIZE_IO2_PM 0x06
124
118#define IDX_IO2_LEGACY_ADDR 0x04 125#define IDX_IO2_LEGACY_ADDR 0x04
119 #define LEGACY_SOMETHING 0x01 /* OPL3?? */ 126 #define LEGACY_SOMETHING 0x01 /* OPL3?? */
120 #define LEGACY_JOY 0x08 127 #define LEGACY_JOY 0x08
121 128
129#define AZF_IO_SIZE_MPU 0x04
130#define AZF_IO_SIZE_MPU_PM 0x04
131
132#define AZF_IO_SIZE_SYNTH 0x08
133#define AZF_IO_SIZE_SYNTH_PM 0x06
122 134
123/*** mixer I/O area port indices ***/ 135/*** mixer I/O area port indices ***/
124/* (only 0x22 of 0x40 bytes saved/restored by Windows driver) 136/* (only 0x22 of 0x40 bytes saved/restored by Windows driver)
125 * generally spoken: AC97 register index = AZF3328 mixer reg index + 2 137 * UNFORTUNATELY azf3328 is NOT truly AC97 compliant: see main file intro */
126 * (in other words: AZF3328 NOT fully AC97 compliant) */ 138#define AZF_IO_SIZE_MIXER 0x40
139#define AZF_IO_SIZE_MIXER_PM 0x22
140
127 #define MIXER_VOLUME_RIGHT_MASK 0x001f 141 #define MIXER_VOLUME_RIGHT_MASK 0x001f
128 #define MIXER_VOLUME_LEFT_MASK 0x1f00 142 #define MIXER_VOLUME_LEFT_MASK 0x1f00
129 #define MIXER_MUTE_MASK 0x8000 143 #define MIXER_MUTE_MASK 0x8000