Commit 78df617acf83745908ae71f322e084284054ea66
Committed by
Takashi Iwai
1 parent
dfbf951115
Exists in
master
and in
39 other branches
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>
Showing 2 changed files with 135 additions and 81 deletions Side-by-side Diff
sound/pci/azt3328.c
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | * has very good support out of the box; |
16 | 16 | * just to make sure that the right people hit this and get to know that, |
17 | 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 | 20 | * GPL LICENSE |
21 | 21 | * This program is free software; you can redistribute it and/or modify |
22 | 22 | |
23 | 23 | |
24 | 24 | |
... | ... | @@ -222,22 +222,23 @@ |
222 | 222 | #define DEBUG_MISC 0 |
223 | 223 | #define DEBUG_CALLS 0 |
224 | 224 | #define DEBUG_MIXER 0 |
225 | -#define DEBUG_PLAY_REC 0 | |
225 | +#define DEBUG_CODEC 0 | |
226 | 226 | #define DEBUG_IO 0 |
227 | 227 | #define DEBUG_TIMER 0 |
228 | 228 | #define DEBUG_GAME 0 |
229 | +#define DEBUG_PM 0 | |
229 | 230 | #define MIXER_TESTING 0 |
230 | 231 | |
231 | 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 | 234 | #else |
234 | 235 | #define snd_azf3328_dbgmisc(format, args...) |
235 | 236 | #endif |
236 | 237 | |
237 | 238 | #if DEBUG_CALLS |
238 | 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_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__) | |
240 | +#define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__) | |
241 | +#define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__) | |
241 | 242 | #else |
242 | 243 | #define snd_azf3328_dbgcalls(format, args...) |
243 | 244 | #define snd_azf3328_dbgcallenter() |
244 | 245 | |
... | ... | @@ -250,10 +251,10 @@ |
250 | 251 | #define snd_azf3328_dbgmixer(format, args...) |
251 | 252 | #endif |
252 | 253 | |
253 | -#if DEBUG_PLAY_REC | |
254 | -#define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args) | |
254 | +#if DEBUG_CODEC | |
255 | +#define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args) | |
255 | 256 | #else |
256 | -#define snd_azf3328_dbgplay(format, args...) | |
257 | +#define snd_azf3328_dbgcodec(format, args...) | |
257 | 258 | #endif |
258 | 259 | |
259 | 260 | #if DEBUG_MISC |
... | ... | @@ -268,6 +269,12 @@ |
268 | 269 | #define snd_azf3328_dbggame(format, args...) |
269 | 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 | 278 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
272 | 279 | module_param_array(index, int, NULL, 0444); |
273 | 280 | MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); |
... | ... | @@ -334,12 +341,12 @@ |
334 | 341 | |
335 | 342 | #ifdef CONFIG_PM |
336 | 343 | /* register value containers for power management |
337 | - * Note: not always full I/O range preserved (just like Win driver!) */ | |
338 | - u16 saved_regs_ctrl[AZF_IO_SIZE_CTRL_PM / 2]; | |
339 | - u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; | |
340 | - u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | |
341 | - u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; | |
342 | - u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | |
344 | + * Note: not always full I/O range preserved (similar to Win driver!) */ | |
345 | + u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4]; | |
346 | + u32 saved_regs_game[AZF_ALIGN(AZF_IO_SIZE_GAME_PM) / 4]; | |
347 | + u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4]; | |
348 | + u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4]; | |
349 | + u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4]; | |
343 | 350 | #endif |
344 | 351 | }; |
345 | 352 | |
346 | 353 | |
347 | 354 | |
... | ... | @@ -1029,19 +1036,20 @@ |
1029 | 1036 | bool enable |
1030 | 1037 | ) |
1031 | 1038 | { |
1032 | - if (enable) | |
1033 | - chip->shadow_reg_ctrl_6AH &= ~bitmask; | |
1034 | - else | |
1039 | + bool do_mask = !enable; | |
1040 | + if (do_mask) | |
1035 | 1041 | chip->shadow_reg_ctrl_6AH |= bitmask; |
1036 | - snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", | |
1037 | - bitmask, enable, chip->shadow_reg_ctrl_6AH); | |
1042 | + else | |
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 | 1046 | snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); |
1039 | 1047 | } |
1040 | 1048 | |
1041 | 1049 | static inline void |
1042 | 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 | 1053 | /* no idea what exactly is being done here, but I strongly assume it's |
1046 | 1054 | * PM related */ |
1047 | 1055 | snd_azf3328_ctrl_reg_6AH_update( |
... | ... | @@ -1058,7 +1066,7 @@ |
1058 | 1066 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; |
1059 | 1067 | bool need_change = (codec->running != enable); |
1060 | 1068 | |
1061 | - snd_azf3328_dbgplay( | |
1069 | + snd_azf3328_dbgcodec( | |
1062 | 1070 | "codec_activity: %s codec, enable %d, need_change %d\n", |
1063 | 1071 | codec->name, enable, need_change |
1064 | 1072 | ); |
... | ... | @@ -1081,11 +1089,11 @@ |
1081 | 1089 | (which globally shuts down operation of codecs) |
1082 | 1090 | only in case the other codecs are currently |
1083 | 1091 | not active either! */ |
1084 | - if ((!chip->codecs[peer_codecs[codec_type].other1] | |
1085 | - .running) | |
1086 | - && (!chip->codecs[peer_codecs[codec_type].other2] | |
1087 | - .running)) | |
1088 | - call_function = 1; | |
1092 | + call_function = | |
1093 | + ((!chip->codecs[peer_codecs[codec_type].other1] | |
1094 | + .running) | |
1095 | + && (!chip->codecs[peer_codecs[codec_type].other2] | |
1096 | + .running)); | |
1089 | 1097 | } |
1090 | 1098 | if (call_function) |
1091 | 1099 | snd_azf3328_ctrl_enable_codecs(chip, enable); |
1092 | 1100 | |
... | ... | @@ -1097,8 +1105,8 @@ |
1097 | 1105 | chip, |
1098 | 1106 | codec_type |
1099 | 1107 | ); |
1108 | + codec->running = enable; | |
1100 | 1109 | } |
1101 | - codec->running = enable; | |
1102 | 1110 | } |
1103 | 1111 | |
1104 | 1112 | static void |
1105 | 1113 | |
1106 | 1114 | |
... | ... | @@ -1114,15 +1122,16 @@ |
1114 | 1122 | if (!codec->running) { |
1115 | 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 | 1127 | /* width 32bit (prevent overflow): */ |
1120 | - u32 addr_area2, count_areas, lengths; | |
1128 | + u32 count_areas, lengths; | |
1121 | 1129 | |
1122 | 1130 | count_areas = size/2; |
1123 | 1131 | addr_area2 = addr+count_areas; |
1124 | 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 | 1136 | /* build combined I/O buffer length word */ |
1128 | 1137 | lengths = (count_areas << 16) | (count_areas); |
... | ... | @@ -1176,7 +1185,7 @@ |
1176 | 1185 | |
1177 | 1186 | switch (cmd) { |
1178 | 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 | 1190 | if (is_playback_codec) { |
1182 | 1191 | /* mute WaveOut (avoid clicking during setup) */ |
1183 | 1192 | |
... | ... | @@ -1243,10 +1252,10 @@ |
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 | 1256 | break; |
1248 | 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 | 1259 | /* resume codec if we were active */ |
1251 | 1260 | spin_lock(&chip->reg_lock); |
1252 | 1261 | if (codec->running) |
... | ... | @@ -1258,7 +1267,7 @@ |
1258 | 1267 | spin_unlock(&chip->reg_lock); |
1259 | 1268 | break; |
1260 | 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 | 1272 | if (is_playback_codec) { |
1264 | 1273 | /* mute WaveOut (avoid clicking during setup) */ |
1265 | 1274 | |
... | ... | @@ -1294,10 +1303,10 @@ |
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 | 1307 | break; |
1299 | 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 | 1310 | /* make sure codec is stopped */ |
1302 | 1311 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1303 | 1312 | snd_azf3328_codec_inw( |
... | ... | @@ -1312,7 +1321,7 @@ |
1312 | 1321 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
1313 | 1322 | break; |
1314 | 1323 | default: |
1315 | - printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | |
1324 | + snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | |
1316 | 1325 | return -EINVAL; |
1317 | 1326 | } |
1318 | 1327 | |
... | ... | @@ -1358,7 +1367,7 @@ |
1358 | 1367 | /* calculate offset */ |
1359 | 1368 | result -= bufptr; |
1360 | 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 | 1371 | codec->name, result, frmres); |
1363 | 1372 | return frmres; |
1364 | 1373 | } |
... | ... | @@ -1607,7 +1616,7 @@ |
1607 | 1616 | static inline void |
1608 | 1617 | snd_azf3328_irq_log_unknown_type(u8 which) |
1609 | 1618 | { |
1610 | - snd_azf3328_dbgplay( | |
1619 | + snd_azf3328_dbgcodec( | |
1611 | 1620 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", |
1612 | 1621 | which |
1613 | 1622 | ); |
... | ... | @@ -1636,12 +1645,9 @@ |
1636 | 1645 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); |
1637 | 1646 | spin_unlock(&chip->reg_lock); |
1638 | 1647 | |
1639 | - if ((chip->pcm[codec_type]) | |
1640 | - && (chip->codecs[codec_type].substream)) { | |
1641 | - snd_pcm_period_elapsed( | |
1642 | - chip->codecs[codec_type].substream | |
1643 | - ); | |
1644 | - snd_azf3328_dbgplay("%s period done (#%x), @ %x\n", | |
1648 | + if ((chip->pcm[codec_type]) && (codec->substream)) { | |
1649 | + snd_pcm_period_elapsed(codec->substream); | |
1650 | + snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", | |
1645 | 1651 | codec->name, |
1646 | 1652 | which, |
1647 | 1653 | snd_azf3328_codec_inl( |
... | ... | @@ -1660,7 +1666,7 @@ |
1660 | 1666 | { |
1661 | 1667 | struct snd_azf3328 *chip = dev_id; |
1662 | 1668 | u8 status; |
1663 | -#if DEBUG_PLAY_REC | |
1669 | +#if DEBUG_CODEC | |
1664 | 1670 | static unsigned long irq_count; |
1665 | 1671 | #endif |
1666 | 1672 | |
1667 | 1673 | |
... | ... | @@ -1673,14 +1679,14 @@ |
1673 | 1679 | )) |
1674 | 1680 | return IRQ_NONE; /* must be interrupt for another device */ |
1675 | 1681 | |
1676 | - snd_azf3328_dbgplay( | |
1682 | + snd_azf3328_dbgcodec( | |
1677 | 1683 | "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", |
1678 | 1684 | irq_count++ /* debug-only */, |
1679 | 1685 | status |
1680 | 1686 | ); |
1681 | 1687 | |
1682 | 1688 | if (status & IRQ_TIMER) { |
1683 | - /* snd_azf3328_dbgplay("timer %ld\n", | |
1689 | + /* snd_azf3328_dbgcodec("timer %ld\n", | |
1684 | 1690 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) |
1685 | 1691 | & TIMER_VALUE_MASK |
1686 | 1692 | ); */ |
... | ... | @@ -1690,7 +1696,7 @@ |
1690 | 1696 | spin_lock(&chip->reg_lock); |
1691 | 1697 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); |
1692 | 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 | 1702 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) |
... | ... | @@ -1706,7 +1712,7 @@ |
1706 | 1712 | |
1707 | 1713 | /* hmm, do we have to ack the IRQ here somehow? |
1708 | 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 | 1717 | return IRQ_HANDLED; |
1712 | 1718 | } |
... | ... | @@ -2091,7 +2097,7 @@ |
2091 | 2097 | |
2092 | 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 | 2101 | reg, bit, val, valoff, valon |
2096 | 2102 | ); |
2097 | 2103 | } |
2098 | 2104 | |
... | ... | @@ -2298,8 +2304,11 @@ |
2298 | 2304 | |
2299 | 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 | 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 | 2312 | pci->irq, 0, &chip->rmidi |
2304 | 2313 | ); |
2305 | 2314 | if (err < 0) { |
... | ... | @@ -2342,7 +2351,7 @@ |
2342 | 2351 | goto out_err; |
2343 | 2352 | |
2344 | 2353 | #ifdef MODULE |
2345 | - printk( | |
2354 | + printk(KERN_INFO | |
2346 | 2355 | "azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" |
2347 | 2356 | "azt3328: Hardware was completely undocumented, unfortunately.\n" |
2348 | 2357 | "azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" |
2349 | 2358 | |
2350 | 2359 | |
2351 | 2360 | |
2352 | 2361 | |
2353 | 2362 | |
... | ... | @@ -2377,37 +2386,52 @@ |
2377 | 2386 | } |
2378 | 2387 | |
2379 | 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 | 2403 | static int |
2381 | 2404 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) |
2382 | 2405 | { |
2383 | 2406 | struct snd_card *card = pci_get_drvdata(pci); |
2384 | 2407 | struct snd_azf3328 *chip = card->private_data; |
2385 | - unsigned reg; | |
2408 | + u16 *saved_regs_ctrl_u16; | |
2386 | 2409 | |
2387 | 2410 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2388 | 2411 | |
2389 | 2412 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); |
2390 | 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) | |
2393 | - chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); | |
2415 | + snd_azf3328_suspend_regs(chip->mixer_io, | |
2416 | + ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer); | |
2394 | 2417 | |
2395 | 2418 | /* make sure to disable master volume etc. to prevent looping sound */ |
2396 | 2419 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); |
2397 | 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) | |
2400 | - chip->saved_regs_ctrl[reg] = inw(chip->ctrl_io + reg * 2); | |
2422 | + snd_azf3328_suspend_regs(chip->ctrl_io, | |
2423 | + ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl); | |
2401 | 2424 | |
2402 | 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) | |
2406 | - chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); | |
2407 | - for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | |
2408 | - chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); | |
2409 | - for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | |
2410 | - chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); | |
2429 | + snd_azf3328_suspend_regs(chip->game_io, | |
2430 | + ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game); | |
2431 | + snd_azf3328_suspend_regs(chip->mpu_io, | |
2432 | + ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); | |
2433 | + snd_azf3328_suspend_regs(chip->opl3_io, | |
2434 | + ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); | |
2411 | 2435 | |
2412 | 2436 | pci_disable_device(pci); |
2413 | 2437 | pci_save_state(pci); |
2414 | 2438 | |
... | ... | @@ -2415,12 +2439,28 @@ |
2415 | 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 | 2459 | static int |
2419 | 2460 | snd_azf3328_resume(struct pci_dev *pci) |
2420 | 2461 | { |
2421 | 2462 | struct snd_card *card = pci_get_drvdata(pci); |
2422 | 2463 | const struct snd_azf3328 *chip = card->private_data; |
2423 | - unsigned reg; | |
2424 | 2464 | |
2425 | 2465 | pci_set_power_state(pci, PCI_D0); |
2426 | 2466 | pci_restore_state(pci); |
... | ... | @@ -2432,16 +2472,24 @@ |
2432 | 2472 | } |
2433 | 2473 | pci_set_master(pci); |
2434 | 2474 | |
2435 | - for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) | |
2436 | - outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); | |
2437 | - for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | |
2438 | - outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); | |
2439 | - for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | |
2440 | - outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); | |
2441 | - for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | |
2442 | - outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); | |
2443 | - for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) | |
2444 | - outw(chip->saved_regs_ctrl[reg], chip->ctrl_io + reg * 2); | |
2475 | + snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io, | |
2476 | + ARRAY_SIZE(chip->saved_regs_game)); | |
2477 | + snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io, | |
2478 | + ARRAY_SIZE(chip->saved_regs_mpu)); | |
2479 | + snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io, | |
2480 | + ARRAY_SIZE(chip->saved_regs_opl3)); | |
2481 | + | |
2482 | + snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io, | |
2483 | + ARRAY_SIZE(chip->saved_regs_mixer)); | |
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 | 2494 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
2447 | 2495 | return 0; |
sound/pci/azt3328.h
... | ... | @@ -120,8 +120,10 @@ |
120 | 120 | #define IDX_IO_IRQSTATUS 0x64 |
121 | 121 | /* some IRQ bit in here might also be used to signal a power-management timer |
122 | 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 | |
124 | - * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ | |
123 | + * OPL3 hardware contains several timers which confusingly in most cases | |
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 | 128 | #define IRQ_PLAYBACK 0x0001 |
127 | 129 | #define IRQ_RECORDING 0x0002 |
... | ... | @@ -129,8 +131,8 @@ |
129 | 131 | #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ |
130 | 132 | #define IRQ_MPU401 0x0010 |
131 | 133 | #define IRQ_TIMER 0x0020 /* DirectX timer */ |
132 | - #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ | |
133 | - #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ | |
134 | + #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly OPL3 timer? */ | |
135 | + #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly OPL3 timer? */ | |
134 | 136 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ |
135 | 137 | /* this is set to e.g. 0x3ff or 0x300, and writable; |
136 | 138 | * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ |
... | ... | @@ -193,7 +195,7 @@ |
193 | 195 | /*** Gameport area port indices ***/ |
194 | 196 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ |
195 | 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 | 200 | enum { |
199 | 201 | AZF_GAME_LEGACY_IO_PORT = 0x200 |
... | ... | @@ -274,6 +276,7 @@ |
274 | 276 | #define AZF_IO_SIZE_MPU_PM 0x04 |
275 | 277 | |
276 | 278 | /*** OPL3 synth ***/ |
279 | +/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | |
277 | 280 | #define AZF_IO_SIZE_OPL3 0x08 |
278 | 281 | #define AZF_IO_SIZE_OPL3_PM 0x06 |
279 | 282 | /* hmm, given that a standard OPL3 has 4 registers only, |
... | ... | @@ -332,6 +335,9 @@ |
332 | 335 | /* driver internal flags */ |
333 | 336 | #define SET_CHAN_LEFT 1 |
334 | 337 | #define SET_CHAN_RIGHT 2 |
338 | + | |
339 | +/* helper macro to align I/O port ranges to 32bit I/O width */ | |
340 | +#define AZF_ALIGN(x) (((x) + 3) & (~3)) | |
335 | 341 | |
336 | 342 | #endif /* __SOUND_AZT3328_H */ |