aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Mohr <andim2@users.sourceforge.net>2009-07-12 16:17:54 -0400
committerTakashi Iwai <tiwai@suse.de>2009-07-15 06:03:26 -0400
commit78df617acf83745908ae71f322e084284054ea66 (patch)
treef32d64d18cc18de52440740ce91be6f5ca5379dd
parentdfbf9511155d3584b8747c935216077f46eb9a4f (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.c200
-rw-r--r--sound/pci/azt3328.h16
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
271static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 278static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
272module_param_array(index, int, NULL, 0444); 279module_param_array(index, int, NULL, 0444);
273MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); 280MODULE_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
1041static inline void 1049static inline void
1042snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) 1050snd_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
1104static void 1112static 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)
1607static inline void 1616static inline void
1608snd_azf3328_irq_log_unknown_type(u8 which) 1617snd_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
2389static inline void
2390snd_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
2380static int 2403static int
2381snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) 2404snd_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
2442static inline void
2443snd_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
2418static int 2459static int
2419snd_azf3328_resume(struct pci_dev *pci) 2460snd_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
198enum { 200enum {
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 */