diff options
author | Andreas Mohr <andim2@users.sourceforge.net> | 2009-07-12 16:17:54 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-07-15 06:03:26 -0400 |
commit | 78df617acf83745908ae71f322e084284054ea66 (patch) | |
tree | f32d64d18cc18de52440740ce91be6f5ca5379dd | |
parent | dfbf9511155d3584b8747c935216077f46eb9a4f (diff) |
ALSA: azt3328: fix previous breakage, improve suspend, cleanups
- fix my previous codec activity breakage (_non-warned_ variable assignment
issue)
- convert suspend/resume to 32bit I/O access (I/O is painful; to improve
suspend/resume performance)
- change DEBUG_PLAY_REC to DEBUG_CODEC for consistency
- printk cleanup
- some logging improvements
- minor cleanup/improvements
The variable assignment issue above was a conditional assignment to the
call_function variable (this ended with the non-preinitialized variable
not getting assigned in some cases, thus a dangling stack value, yet gcc 4.3.3
unbelievably did _NOT_ warn about it in this case!!),
needed to change this into _always_ assigning the check result.
Practical result of this bug was that when shutting down
_either_ playback or capture, _both_ streams dropped dead :P
Tested, working (plus resume) and checkpatch.pl:ed on 2.6.30-rc5,
applies cleanly to 2.6.30 proper with my previous (committed)
patches applied.
Signed-off-by: Andreas Mohr <andi@lisas.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/azt3328.c | 200 | ||||
-rw-r--r-- | sound/pci/azt3328.h | 16 |
2 files changed, 135 insertions, 81 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 39dfdaa6a56f..8451a0169f32 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * has very good support out of the box; | 15 | * has very good support out of the box; |
16 | * just to make sure that the right people hit this and get to know that, | 16 | * just to make sure that the right people hit this and get to know that, |
17 | * despite the high level of Internet ignorance - as usual :-P - | 17 | * despite the high level of Internet ignorance - as usual :-P - |
18 | * about Linux support for this card) | 18 | * about very good support for this card - on Linux!) |
19 | * | 19 | * |
20 | * GPL LICENSE | 20 | * GPL LICENSE |
21 | * This program is free software; you can redistribute it and/or modify | 21 | * This program is free software; you can redistribute it and/or modify |
@@ -222,22 +222,23 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
222 | #define DEBUG_MISC 0 | 222 | #define DEBUG_MISC 0 |
223 | #define DEBUG_CALLS 0 | 223 | #define DEBUG_CALLS 0 |
224 | #define DEBUG_MIXER 0 | 224 | #define DEBUG_MIXER 0 |
225 | #define DEBUG_PLAY_REC 0 | 225 | #define DEBUG_CODEC 0 |
226 | #define DEBUG_IO 0 | 226 | #define DEBUG_IO 0 |
227 | #define DEBUG_TIMER 0 | 227 | #define DEBUG_TIMER 0 |
228 | #define DEBUG_GAME 0 | 228 | #define DEBUG_GAME 0 |
229 | #define DEBUG_PM 0 | ||
229 | #define MIXER_TESTING 0 | 230 | #define MIXER_TESTING 0 |
230 | 231 | ||
231 | #if DEBUG_MISC | 232 | #if DEBUG_MISC |
232 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) | 233 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args) |
233 | #else | 234 | #else |
234 | #define snd_azf3328_dbgmisc(format, args...) | 235 | #define snd_azf3328_dbgmisc(format, args...) |
235 | #endif | 236 | #endif |
236 | 237 | ||
237 | #if DEBUG_CALLS | 238 | #if DEBUG_CALLS |
238 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) | 239 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) |
239 | #define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__) | 240 | #define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__) |
240 | #define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__) | 241 | #define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__) |
241 | #else | 242 | #else |
242 | #define snd_azf3328_dbgcalls(format, args...) | 243 | #define snd_azf3328_dbgcalls(format, args...) |
243 | #define snd_azf3328_dbgcallenter() | 244 | #define snd_azf3328_dbgcallenter() |
@@ -250,10 +251,10 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
250 | #define snd_azf3328_dbgmixer(format, args...) | 251 | #define snd_azf3328_dbgmixer(format, args...) |
251 | #endif | 252 | #endif |
252 | 253 | ||
253 | #if DEBUG_PLAY_REC | 254 | #if DEBUG_CODEC |
254 | #define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args) | 255 | #define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args) |
255 | #else | 256 | #else |
256 | #define snd_azf3328_dbgplay(format, args...) | 257 | #define snd_azf3328_dbgcodec(format, args...) |
257 | #endif | 258 | #endif |
258 | 259 | ||
259 | #if DEBUG_MISC | 260 | #if DEBUG_MISC |
@@ -268,6 +269,12 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
268 | #define snd_azf3328_dbggame(format, args...) | 269 | #define snd_azf3328_dbggame(format, args...) |
269 | #endif | 270 | #endif |
270 | 271 | ||
272 | #if DEBUG_PM | ||
273 | #define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args) | ||
274 | #else | ||
275 | #define snd_azf3328_dbgpm(format, args...) | ||
276 | #endif | ||
277 | |||
271 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 278 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
272 | module_param_array(index, int, NULL, 0444); | 279 | module_param_array(index, int, NULL, 0444); |
273 | MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); | 280 | MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); |
@@ -334,12 +341,12 @@ struct snd_azf3328 { | |||
334 | 341 | ||
335 | #ifdef CONFIG_PM | 342 | #ifdef CONFIG_PM |
336 | /* register value containers for power management | 343 | /* register value containers for power management |
337 | * Note: not always full I/O range preserved (just like Win driver!) */ | 344 | * Note: not always full I/O range preserved (similar to Win driver!) */ |
338 | u16 saved_regs_ctrl[AZF_IO_SIZE_CTRL_PM / 2]; | 345 | u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4]; |
339 | u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; | 346 | u32 saved_regs_game[AZF_ALIGN(AZF_IO_SIZE_GAME_PM) / 4]; |
340 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | 347 | u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4]; |
341 | u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; | 348 | u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4]; |
342 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | 349 | u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4]; |
343 | #endif | 350 | #endif |
344 | }; | 351 | }; |
345 | 352 | ||
@@ -1029,19 +1036,20 @@ snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip, | |||
1029 | bool enable | 1036 | bool enable |
1030 | ) | 1037 | ) |
1031 | { | 1038 | { |
1032 | if (enable) | 1039 | bool do_mask = !enable; |
1033 | chip->shadow_reg_ctrl_6AH &= ~bitmask; | 1040 | if (do_mask) |
1034 | else | ||
1035 | chip->shadow_reg_ctrl_6AH |= bitmask; | 1041 | chip->shadow_reg_ctrl_6AH |= bitmask; |
1036 | snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", | 1042 | else |
1037 | bitmask, enable, chip->shadow_reg_ctrl_6AH); | 1043 | chip->shadow_reg_ctrl_6AH &= ~bitmask; |
1044 | snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n", | ||
1045 | bitmask, do_mask, chip->shadow_reg_ctrl_6AH); | ||
1038 | snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); | 1046 | snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); |
1039 | } | 1047 | } |
1040 | 1048 | ||
1041 | static inline void | 1049 | static inline void |
1042 | snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) | 1050 | snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) |
1043 | { | 1051 | { |
1044 | snd_azf3328_dbgplay("codec_enable %d\n", enable); | 1052 | snd_azf3328_dbgcodec("codec_enable %d\n", enable); |
1045 | /* no idea what exactly is being done here, but I strongly assume it's | 1053 | /* no idea what exactly is being done here, but I strongly assume it's |
1046 | * PM related */ | 1054 | * PM related */ |
1047 | snd_azf3328_ctrl_reg_6AH_update( | 1055 | snd_azf3328_ctrl_reg_6AH_update( |
@@ -1058,7 +1066,7 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, | |||
1058 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | 1066 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; |
1059 | bool need_change = (codec->running != enable); | 1067 | bool need_change = (codec->running != enable); |
1060 | 1068 | ||
1061 | snd_azf3328_dbgplay( | 1069 | snd_azf3328_dbgcodec( |
1062 | "codec_activity: %s codec, enable %d, need_change %d\n", | 1070 | "codec_activity: %s codec, enable %d, need_change %d\n", |
1063 | codec->name, enable, need_change | 1071 | codec->name, enable, need_change |
1064 | ); | 1072 | ); |
@@ -1081,11 +1089,11 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, | |||
1081 | (which globally shuts down operation of codecs) | 1089 | (which globally shuts down operation of codecs) |
1082 | only in case the other codecs are currently | 1090 | only in case the other codecs are currently |
1083 | not active either! */ | 1091 | not active either! */ |
1084 | if ((!chip->codecs[peer_codecs[codec_type].other1] | 1092 | call_function = |
1085 | .running) | 1093 | ((!chip->codecs[peer_codecs[codec_type].other1] |
1086 | && (!chip->codecs[peer_codecs[codec_type].other2] | 1094 | .running) |
1087 | .running)) | 1095 | && (!chip->codecs[peer_codecs[codec_type].other2] |
1088 | call_function = 1; | 1096 | .running)); |
1089 | } | 1097 | } |
1090 | if (call_function) | 1098 | if (call_function) |
1091 | snd_azf3328_ctrl_enable_codecs(chip, enable); | 1099 | snd_azf3328_ctrl_enable_codecs(chip, enable); |
@@ -1097,8 +1105,8 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, | |||
1097 | chip, | 1105 | chip, |
1098 | codec_type | 1106 | codec_type |
1099 | ); | 1107 | ); |
1108 | codec->running = enable; | ||
1100 | } | 1109 | } |
1101 | codec->running = enable; | ||
1102 | } | 1110 | } |
1103 | 1111 | ||
1104 | static void | 1112 | static void |
@@ -1114,15 +1122,16 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, | |||
1114 | if (!codec->running) { | 1122 | if (!codec->running) { |
1115 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ | 1123 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ |
1116 | 1124 | ||
1117 | unsigned long flags; | 1125 | unsigned long flags, addr_area2; |
1118 | 1126 | ||
1119 | /* width 32bit (prevent overflow): */ | 1127 | /* width 32bit (prevent overflow): */ |
1120 | u32 addr_area2, count_areas, lengths; | 1128 | u32 count_areas, lengths; |
1121 | 1129 | ||
1122 | count_areas = size/2; | 1130 | count_areas = size/2; |
1123 | addr_area2 = addr+count_areas; | 1131 | addr_area2 = addr+count_areas; |
1124 | count_areas--; /* max. index */ | 1132 | count_areas--; /* max. index */ |
1125 | snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); | 1133 | snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", |
1134 | addr, count_areas, addr_area2, count_areas); | ||
1126 | 1135 | ||
1127 | /* build combined I/O buffer length word */ | 1136 | /* build combined I/O buffer length word */ |
1128 | lengths = (count_areas << 16) | (count_areas); | 1137 | lengths = (count_areas << 16) | (count_areas); |
@@ -1176,7 +1185,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1176 | 1185 | ||
1177 | switch (cmd) { | 1186 | switch (cmd) { |
1178 | case SNDRV_PCM_TRIGGER_START: | 1187 | case SNDRV_PCM_TRIGGER_START: |
1179 | snd_azf3328_dbgplay("START %s\n", codec->name); | 1188 | snd_azf3328_dbgcodec("START %s\n", codec->name); |
1180 | 1189 | ||
1181 | if (is_playback_codec) { | 1190 | if (is_playback_codec) { |
1182 | /* mute WaveOut (avoid clicking during setup) */ | 1191 | /* mute WaveOut (avoid clicking during setup) */ |
@@ -1243,10 +1252,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1243 | ); | 1252 | ); |
1244 | } | 1253 | } |
1245 | 1254 | ||
1246 | snd_azf3328_dbgplay("STARTED %s\n", codec->name); | 1255 | snd_azf3328_dbgcodec("STARTED %s\n", codec->name); |
1247 | break; | 1256 | break; |
1248 | case SNDRV_PCM_TRIGGER_RESUME: | 1257 | case SNDRV_PCM_TRIGGER_RESUME: |
1249 | snd_azf3328_dbgplay("RESUME %s\n", codec->name); | 1258 | snd_azf3328_dbgcodec("RESUME %s\n", codec->name); |
1250 | /* resume codec if we were active */ | 1259 | /* resume codec if we were active */ |
1251 | spin_lock(&chip->reg_lock); | 1260 | spin_lock(&chip->reg_lock); |
1252 | if (codec->running) | 1261 | if (codec->running) |
@@ -1258,7 +1267,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1258 | spin_unlock(&chip->reg_lock); | 1267 | spin_unlock(&chip->reg_lock); |
1259 | break; | 1268 | break; |
1260 | case SNDRV_PCM_TRIGGER_STOP: | 1269 | case SNDRV_PCM_TRIGGER_STOP: |
1261 | snd_azf3328_dbgplay("STOP %s\n", codec->name); | 1270 | snd_azf3328_dbgcodec("STOP %s\n", codec->name); |
1262 | 1271 | ||
1263 | if (is_playback_codec) { | 1272 | if (is_playback_codec) { |
1264 | /* mute WaveOut (avoid clicking during setup) */ | 1273 | /* mute WaveOut (avoid clicking during setup) */ |
@@ -1294,10 +1303,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1294 | ); | 1303 | ); |
1295 | } | 1304 | } |
1296 | 1305 | ||
1297 | snd_azf3328_dbgplay("STOPPED %s\n", codec->name); | 1306 | snd_azf3328_dbgcodec("STOPPED %s\n", codec->name); |
1298 | break; | 1307 | break; |
1299 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1308 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1300 | snd_azf3328_dbgplay("SUSPEND %s\n", codec->name); | 1309 | snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name); |
1301 | /* make sure codec is stopped */ | 1310 | /* make sure codec is stopped */ |
1302 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, | 1311 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1303 | snd_azf3328_codec_inw( | 1312 | snd_azf3328_codec_inw( |
@@ -1312,7 +1321,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1312 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | 1321 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
1313 | break; | 1322 | break; |
1314 | default: | 1323 | default: |
1315 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | 1324 | snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n"); |
1316 | return -EINVAL; | 1325 | return -EINVAL; |
1317 | } | 1326 | } |
1318 | 1327 | ||
@@ -1358,7 +1367,7 @@ snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, | |||
1358 | /* calculate offset */ | 1367 | /* calculate offset */ |
1359 | result -= bufptr; | 1368 | result -= bufptr; |
1360 | frmres = bytes_to_frames( substream->runtime, result); | 1369 | frmres = bytes_to_frames( substream->runtime, result); |
1361 | snd_azf3328_dbgplay("%s @ 0x%8lx, frames %8ld\n", | 1370 | snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n", |
1362 | codec->name, result, frmres); | 1371 | codec->name, result, frmres); |
1363 | return frmres; | 1372 | return frmres; |
1364 | } | 1373 | } |
@@ -1607,7 +1616,7 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) | |||
1607 | static inline void | 1616 | static inline void |
1608 | snd_azf3328_irq_log_unknown_type(u8 which) | 1617 | snd_azf3328_irq_log_unknown_type(u8 which) |
1609 | { | 1618 | { |
1610 | snd_azf3328_dbgplay( | 1619 | snd_azf3328_dbgcodec( |
1611 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", | 1620 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", |
1612 | which | 1621 | which |
1613 | ); | 1622 | ); |
@@ -1636,12 +1645,9 @@ snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) | |||
1636 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); | 1645 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); |
1637 | spin_unlock(&chip->reg_lock); | 1646 | spin_unlock(&chip->reg_lock); |
1638 | 1647 | ||
1639 | if ((chip->pcm[codec_type]) | 1648 | if ((chip->pcm[codec_type]) && (codec->substream)) { |
1640 | && (chip->codecs[codec_type].substream)) { | 1649 | snd_pcm_period_elapsed(codec->substream); |
1641 | snd_pcm_period_elapsed( | 1650 | snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", |
1642 | chip->codecs[codec_type].substream | ||
1643 | ); | ||
1644 | snd_azf3328_dbgplay("%s period done (#%x), @ %x\n", | ||
1645 | codec->name, | 1651 | codec->name, |
1646 | which, | 1652 | which, |
1647 | snd_azf3328_codec_inl( | 1653 | snd_azf3328_codec_inl( |
@@ -1660,7 +1666,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1660 | { | 1666 | { |
1661 | struct snd_azf3328 *chip = dev_id; | 1667 | struct snd_azf3328 *chip = dev_id; |
1662 | u8 status; | 1668 | u8 status; |
1663 | #if DEBUG_PLAY_REC | 1669 | #if DEBUG_CODEC |
1664 | static unsigned long irq_count; | 1670 | static unsigned long irq_count; |
1665 | #endif | 1671 | #endif |
1666 | 1672 | ||
@@ -1673,14 +1679,14 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1673 | )) | 1679 | )) |
1674 | return IRQ_NONE; /* must be interrupt for another device */ | 1680 | return IRQ_NONE; /* must be interrupt for another device */ |
1675 | 1681 | ||
1676 | snd_azf3328_dbgplay( | 1682 | snd_azf3328_dbgcodec( |
1677 | "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", | 1683 | "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", |
1678 | irq_count++ /* debug-only */, | 1684 | irq_count++ /* debug-only */, |
1679 | status | 1685 | status |
1680 | ); | 1686 | ); |
1681 | 1687 | ||
1682 | if (status & IRQ_TIMER) { | 1688 | if (status & IRQ_TIMER) { |
1683 | /* snd_azf3328_dbgplay("timer %ld\n", | 1689 | /* snd_azf3328_dbgcodec("timer %ld\n", |
1684 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) | 1690 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) |
1685 | & TIMER_VALUE_MASK | 1691 | & TIMER_VALUE_MASK |
1686 | ); */ | 1692 | ); */ |
@@ -1690,7 +1696,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1690 | spin_lock(&chip->reg_lock); | 1696 | spin_lock(&chip->reg_lock); |
1691 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); | 1697 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); |
1692 | spin_unlock(&chip->reg_lock); | 1698 | spin_unlock(&chip->reg_lock); |
1693 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); | 1699 | snd_azf3328_dbgcodec("azt3328: timer IRQ\n"); |
1694 | } | 1700 | } |
1695 | 1701 | ||
1696 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) | 1702 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) |
@@ -1706,7 +1712,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1706 | 1712 | ||
1707 | /* hmm, do we have to ack the IRQ here somehow? | 1713 | /* hmm, do we have to ack the IRQ here somehow? |
1708 | * If so, then I don't know how yet... */ | 1714 | * If so, then I don't know how yet... */ |
1709 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); | 1715 | snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n"); |
1710 | } | 1716 | } |
1711 | return IRQ_HANDLED; | 1717 | return IRQ_HANDLED; |
1712 | } | 1718 | } |
@@ -2091,7 +2097,7 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit) | |||
2091 | 2097 | ||
2092 | outb(val, reg); | 2098 | outb(val, reg); |
2093 | 2099 | ||
2094 | printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", | 2100 | printk(KERN_DEBUG "reg %04x bit %d: %02x %02x %02x\n", |
2095 | reg, bit, val, valoff, valon | 2101 | reg, bit, val, valoff, valon |
2096 | ); | 2102 | ); |
2097 | } | 2103 | } |
@@ -2298,8 +2304,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2298 | 2304 | ||
2299 | card->private_data = chip; | 2305 | card->private_data = chip; |
2300 | 2306 | ||
2307 | /* chose to use MPU401_HW_AZT2320 ID instead of MPU401_HW_MPU401, | ||
2308 | since our hardware ought to be similar, thus use same ID. */ | ||
2301 | err = snd_mpu401_uart_new( | 2309 | err = snd_mpu401_uart_new( |
2302 | card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED, | 2310 | card, 0, |
2311 | MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED, | ||
2303 | pci->irq, 0, &chip->rmidi | 2312 | pci->irq, 0, &chip->rmidi |
2304 | ); | 2313 | ); |
2305 | if (err < 0) { | 2314 | if (err < 0) { |
@@ -2342,7 +2351,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2342 | goto out_err; | 2351 | goto out_err; |
2343 | 2352 | ||
2344 | #ifdef MODULE | 2353 | #ifdef MODULE |
2345 | printk( | 2354 | printk(KERN_INFO |
2346 | "azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" | 2355 | "azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" |
2347 | "azt3328: Hardware was completely undocumented, unfortunately.\n" | 2356 | "azt3328: Hardware was completely undocumented, unfortunately.\n" |
2348 | "azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" | 2357 | "azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" |
@@ -2377,37 +2386,52 @@ snd_azf3328_remove(struct pci_dev *pci) | |||
2377 | } | 2386 | } |
2378 | 2387 | ||
2379 | #ifdef CONFIG_PM | 2388 | #ifdef CONFIG_PM |
2389 | static inline void | ||
2390 | snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs) | ||
2391 | { | ||
2392 | unsigned reg; | ||
2393 | |||
2394 | for (reg = 0; reg < count; ++reg) { | ||
2395 | *saved_regs = inl(io_addr); | ||
2396 | snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n", | ||
2397 | io_addr, *saved_regs); | ||
2398 | ++saved_regs; | ||
2399 | io_addr += sizeof(*saved_regs); | ||
2400 | } | ||
2401 | } | ||
2402 | |||
2380 | static int | 2403 | static int |
2381 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | 2404 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) |
2382 | { | 2405 | { |
2383 | struct snd_card *card = pci_get_drvdata(pci); | 2406 | struct snd_card *card = pci_get_drvdata(pci); |
2384 | struct snd_azf3328 *chip = card->private_data; | 2407 | struct snd_azf3328 *chip = card->private_data; |
2385 | unsigned reg; | 2408 | u16 *saved_regs_ctrl_u16; |
2386 | 2409 | ||
2387 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2410 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2388 | 2411 | ||
2389 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); | 2412 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); |
2390 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); | 2413 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); |
2391 | 2414 | ||
2392 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | 2415 | snd_azf3328_suspend_regs(chip->mixer_io, |
2393 | chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); | 2416 | ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer); |
2394 | 2417 | ||
2395 | /* make sure to disable master volume etc. to prevent looping sound */ | 2418 | /* make sure to disable master volume etc. to prevent looping sound */ |
2396 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | 2419 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); |
2397 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 2420 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); |
2398 | 2421 | ||
2399 | for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) | 2422 | snd_azf3328_suspend_regs(chip->ctrl_io, |
2400 | chip->saved_regs_ctrl[reg] = inw(chip->ctrl_io + reg * 2); | 2423 | ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl); |
2401 | 2424 | ||
2402 | /* manually store the one currently relevant write-only reg, too */ | 2425 | /* manually store the one currently relevant write-only reg, too */ |
2403 | chip->saved_regs_ctrl[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; | 2426 | saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl; |
2427 | saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; | ||
2404 | 2428 | ||
2405 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) | 2429 | snd_azf3328_suspend_regs(chip->game_io, |
2406 | chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); | 2430 | ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game); |
2407 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | 2431 | snd_azf3328_suspend_regs(chip->mpu_io, |
2408 | chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); | 2432 | ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); |
2409 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | 2433 | snd_azf3328_suspend_regs(chip->opl3_io, |
2410 | chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); | 2434 | ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); |
2411 | 2435 | ||
2412 | pci_disable_device(pci); | 2436 | pci_disable_device(pci); |
2413 | pci_save_state(pci); | 2437 | pci_save_state(pci); |
@@ -2415,12 +2439,28 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
2415 | return 0; | 2439 | return 0; |
2416 | } | 2440 | } |
2417 | 2441 | ||
2442 | static inline void | ||
2443 | snd_azf3328_resume_regs(const u32 *saved_regs, | ||
2444 | unsigned long io_addr, | ||
2445 | unsigned count | ||
2446 | ) | ||
2447 | { | ||
2448 | unsigned reg; | ||
2449 | |||
2450 | for (reg = 0; reg < count; ++reg) { | ||
2451 | outl(*saved_regs, io_addr); | ||
2452 | snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n", | ||
2453 | io_addr, *saved_regs, inl(io_addr)); | ||
2454 | ++saved_regs; | ||
2455 | io_addr += sizeof(*saved_regs); | ||
2456 | } | ||
2457 | } | ||
2458 | |||
2418 | static int | 2459 | static int |
2419 | snd_azf3328_resume(struct pci_dev *pci) | 2460 | snd_azf3328_resume(struct pci_dev *pci) |
2420 | { | 2461 | { |
2421 | struct snd_card *card = pci_get_drvdata(pci); | 2462 | struct snd_card *card = pci_get_drvdata(pci); |
2422 | const struct snd_azf3328 *chip = card->private_data; | 2463 | const struct snd_azf3328 *chip = card->private_data; |
2423 | unsigned reg; | ||
2424 | 2464 | ||
2425 | pci_set_power_state(pci, PCI_D0); | 2465 | pci_set_power_state(pci, PCI_D0); |
2426 | pci_restore_state(pci); | 2466 | pci_restore_state(pci); |
@@ -2432,16 +2472,24 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
2432 | } | 2472 | } |
2433 | pci_set_master(pci); | 2473 | pci_set_master(pci); |
2434 | 2474 | ||
2435 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) | 2475 | snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io, |
2436 | outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); | 2476 | ARRAY_SIZE(chip->saved_regs_game)); |
2437 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | 2477 | snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io, |
2438 | outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); | 2478 | ARRAY_SIZE(chip->saved_regs_mpu)); |
2439 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | 2479 | snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io, |
2440 | outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); | 2480 | ARRAY_SIZE(chip->saved_regs_opl3)); |
2441 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | 2481 | |
2442 | outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); | 2482 | snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io, |
2443 | for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) | 2483 | ARRAY_SIZE(chip->saved_regs_mixer)); |
2444 | outw(chip->saved_regs_ctrl[reg], chip->ctrl_io + reg * 2); | 2484 | |
2485 | /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02) | ||
2486 | and IDX_MIXER_RESET (offset 0x00) get touched at the same time, | ||
2487 | resulting in a mixer reset condition persisting until _after_ | ||
2488 | master vol was restored. Thus master vol needs an extra restore. */ | ||
2489 | outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2); | ||
2490 | |||
2491 | snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io, | ||
2492 | ARRAY_SIZE(chip->saved_regs_ctrl)); | ||
2445 | 2493 | ||
2446 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2494 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
2447 | return 0; | 2495 | return 0; |
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 11d4b108b8db..6f46b97650cc 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h | |||
@@ -120,8 +120,10 @@ enum azf_freq_t { | |||
120 | #define IDX_IO_IRQSTATUS 0x64 | 120 | #define IDX_IO_IRQSTATUS 0x64 |
121 | /* some IRQ bit in here might also be used to signal a power-management timer | 121 | /* some IRQ bit in here might also be used to signal a power-management timer |
122 | * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). | 122 | * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). |
123 | * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which | 123 | * OPL3 hardware contains several timers which confusingly in most cases |
124 | * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ | 124 | * are NOT routed to an IRQ, but some designs (e.g. LM4560) DO support that, |
125 | * so I wouldn't be surprised at all to discover that AZF3328 | ||
126 | * supports that thing as well... */ | ||
125 | 127 | ||
126 | #define IRQ_PLAYBACK 0x0001 | 128 | #define IRQ_PLAYBACK 0x0001 |
127 | #define IRQ_RECORDING 0x0002 | 129 | #define IRQ_RECORDING 0x0002 |
@@ -129,8 +131,8 @@ enum azf_freq_t { | |||
129 | #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ | 131 | #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ |
130 | #define IRQ_MPU401 0x0010 | 132 | #define IRQ_MPU401 0x0010 |
131 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | 133 | #define IRQ_TIMER 0x0020 /* DirectX timer */ |
132 | #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ | 134 | #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly OPL3 timer? */ |
133 | #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ | 135 | #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly OPL3 timer? */ |
134 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ | 136 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ |
135 | /* this is set to e.g. 0x3ff or 0x300, and writable; | 137 | /* this is set to e.g. 0x3ff or 0x300, and writable; |
136 | * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ | 138 | * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ |
@@ -193,7 +195,7 @@ enum azf_freq_t { | |||
193 | /*** Gameport area port indices ***/ | 195 | /*** Gameport area port indices ***/ |
194 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | 196 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ |
195 | #define AZF_IO_SIZE_GAME 0x08 | 197 | #define AZF_IO_SIZE_GAME 0x08 |
196 | #define AZF_IO_SIZE_GAME_PM 0x06 | 198 | #define AZF_IO_SIZE_GAME_PM 0x06 |
197 | 199 | ||
198 | enum { | 200 | enum { |
199 | AZF_GAME_LEGACY_IO_PORT = 0x200 | 201 | AZF_GAME_LEGACY_IO_PORT = 0x200 |
@@ -274,6 +276,7 @@ enum { | |||
274 | #define AZF_IO_SIZE_MPU_PM 0x04 | 276 | #define AZF_IO_SIZE_MPU_PM 0x04 |
275 | 277 | ||
276 | /*** OPL3 synth ***/ | 278 | /*** OPL3 synth ***/ |
279 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | ||
277 | #define AZF_IO_SIZE_OPL3 0x08 | 280 | #define AZF_IO_SIZE_OPL3 0x08 |
278 | #define AZF_IO_SIZE_OPL3_PM 0x06 | 281 | #define AZF_IO_SIZE_OPL3_PM 0x06 |
279 | /* hmm, given that a standard OPL3 has 4 registers only, | 282 | /* hmm, given that a standard OPL3 has 4 registers only, |
@@ -333,4 +336,7 @@ enum { | |||
333 | #define SET_CHAN_LEFT 1 | 336 | #define SET_CHAN_LEFT 1 |
334 | #define SET_CHAN_RIGHT 2 | 337 | #define SET_CHAN_RIGHT 2 |
335 | 338 | ||
339 | /* helper macro to align I/O port ranges to 32bit I/O width */ | ||
340 | #define AZF_ALIGN(x) (((x) + 3) & (~3)) | ||
341 | |||
336 | #endif /* __SOUND_AZT3328_H */ | 342 | #endif /* __SOUND_AZT3328_H */ |