aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/nm256
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-08-16 10:54:12 -0400
committerJaroslav Kysela <perex@suse.cz>2005-08-30 02:46:29 -0400
commit1204de32d0df87892e56062042e25c775ca0e08c (patch)
tree4a5ea83086b0b35cbb63b19a902b293302334bc4 /sound/pci/nm256
parent1cfe43d21bc5ff751e95b6a62410e05956c09e38 (diff)
[ALSA] nm256 - Fix PM and irq handling
NM256 driver - Fixed the PCM resume - restoring the rate setting - Fixed the handling of buggy irqs - Dynamically acquire/release irq handler to make the driver more robust to unknown irq storms (as OSS driver does). Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/nm256')
-rw-r--r--sound/pci/nm256/nm256.c93
1 files changed, 70 insertions, 23 deletions
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 7eb20b8f89f6..2bbeb10ff7c4 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -189,6 +189,7 @@ struct snd_nm256_stream {
189 nm256_t *chip; 189 nm256_t *chip;
190 snd_pcm_substream_t *substream; 190 snd_pcm_substream_t *substream;
191 int running; 191 int running;
192 int suspended;
192 193
193 u32 buf; /* offset from chip->buffer */ 194 u32 buf; /* offset from chip->buffer */
194 int bufsize; /* buffer size in bytes */ 195 int bufsize; /* buffer size in bytes */
@@ -231,8 +232,10 @@ struct snd_nm256 {
231 int mixer_status_mask; /* bit mask to test the mixer status */ 232 int mixer_status_mask; /* bit mask to test the mixer status */
232 233
233 int irq; 234 int irq;
235 int irq_acks;
234 irqreturn_t (*interrupt)(int, void *, struct pt_regs *); 236 irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
235 int badintrcount; /* counter to check bogus interrupts */ 237 int badintrcount; /* counter to check bogus interrupts */
238 struct semaphore irq_mutex;
236 239
237 nm256_stream_t streams[2]; 240 nm256_stream_t streams[2];
238 241
@@ -464,6 +467,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs
464 } 467 }
465} 468}
466 469
470/* acquire interrupt */
471static int snd_nm256_acquire_irq(nm256_t *chip)
472{
473 down(&chip->irq_mutex);
474 if (chip->irq < 0) {
475 if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
476 chip->card->driver, (void*)chip)) {
477 snd_printk("unable to grab IRQ %d\n", chip->pci->irq);
478 up(&chip->irq_mutex);
479 return -EBUSY;
480 }
481 chip->irq = chip->pci->irq;
482 }
483 chip->irq_acks++;
484 up(&chip->irq_mutex);
485 return 0;
486}
487
488/* release interrupt */
489static void snd_nm256_release_irq(nm256_t *chip)
490{
491 down(&chip->irq_mutex);
492 if (chip->irq_acks > 0)
493 chip->irq_acks--;
494 if (chip->irq_acks == 0 && chip->irq >= 0) {
495 free_irq(chip->irq, (void*)chip);
496 chip->irq = -1;
497 }
498 up(&chip->irq_mutex);
499}
500
467/* 501/*
468 * start / stop 502 * start / stop
469 */ 503 */
@@ -538,15 +572,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd)
538 572
539 spin_lock(&chip->reg_lock); 573 spin_lock(&chip->reg_lock);
540 switch (cmd) { 574 switch (cmd) {
541 case SNDRV_PCM_TRIGGER_START:
542 case SNDRV_PCM_TRIGGER_RESUME: 575 case SNDRV_PCM_TRIGGER_RESUME:
576 s->suspended = 0;
577 /* fallthru */
578 case SNDRV_PCM_TRIGGER_START:
543 if (! s->running) { 579 if (! s->running) {
544 snd_nm256_playback_start(chip, s, substream); 580 snd_nm256_playback_start(chip, s, substream);
545 s->running = 1; 581 s->running = 1;
546 } 582 }
547 break; 583 break;
548 case SNDRV_PCM_TRIGGER_STOP:
549 case SNDRV_PCM_TRIGGER_SUSPEND: 584 case SNDRV_PCM_TRIGGER_SUSPEND:
585 s->suspended = 1;
586 /* fallthru */
587 case SNDRV_PCM_TRIGGER_STOP:
550 if (s->running) { 588 if (s->running) {
551 snd_nm256_playback_stop(chip); 589 snd_nm256_playback_stop(chip);
552 s->running = 0; 590 s->running = 0;
@@ -818,6 +856,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream)
818{ 856{
819 nm256_t *chip = snd_pcm_substream_chip(substream); 857 nm256_t *chip = snd_pcm_substream_chip(substream);
820 858
859 if (snd_nm256_acquire_irq(chip) < 0)
860 return -EBUSY;
821 snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK], 861 snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],
822 substream, &snd_nm256_playback); 862 substream, &snd_nm256_playback);
823 return 0; 863 return 0;
@@ -828,6 +868,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
828{ 868{
829 nm256_t *chip = snd_pcm_substream_chip(substream); 869 nm256_t *chip = snd_pcm_substream_chip(substream);
830 870
871 if (snd_nm256_acquire_irq(chip) < 0)
872 return -EBUSY;
831 snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE], 873 snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],
832 substream, &snd_nm256_capture); 874 substream, &snd_nm256_capture);
833 return 0; 875 return 0;
@@ -839,6 +881,9 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
839static int 881static int
840snd_nm256_playback_close(snd_pcm_substream_t *substream) 882snd_nm256_playback_close(snd_pcm_substream_t *substream)
841{ 883{
884 nm256_t *chip = snd_pcm_substream_chip(substream);
885
886 snd_nm256_release_irq(chip);
842 return 0; 887 return 0;
843} 888}
844 889
@@ -846,6 +891,9 @@ snd_nm256_playback_close(snd_pcm_substream_t *substream)
846static int 891static int
847snd_nm256_capture_close(snd_pcm_substream_t *substream) 892snd_nm256_capture_close(snd_pcm_substream_t *substream)
848{ 893{
894 nm256_t *chip = snd_pcm_substream_chip(substream);
895
896 snd_nm256_release_irq(chip);
849 return 0; 897 return 0;
850} 898}
851 899
@@ -915,18 +963,16 @@ snd_nm256_pcm(nm256_t *chip, int device)
915static void 963static void
916snd_nm256_init_chip(nm256_t *chip) 964snd_nm256_init_chip(nm256_t *chip)
917{ 965{
918 spin_lock_irq(&chip->reg_lock);
919 /* Reset everything. */ 966 /* Reset everything. */
920 snd_nm256_writeb(chip, 0x0, 0x11); 967 snd_nm256_writeb(chip, 0x0, 0x11);
921 snd_nm256_writew(chip, 0x214, 0); 968 snd_nm256_writew(chip, 0x214, 0);
922 /* stop sounds.. */ 969 /* stop sounds.. */
923 //snd_nm256_playback_stop(chip); 970 //snd_nm256_playback_stop(chip);
924 //snd_nm256_capture_stop(chip); 971 //snd_nm256_capture_stop(chip);
925 spin_unlock_irq(&chip->reg_lock);
926} 972}
927 973
928 974
929static inline void 975static irqreturn_t
930snd_nm256_intr_check(nm256_t *chip) 976snd_nm256_intr_check(nm256_t *chip)
931{ 977{
932 if (chip->badintrcount++ > 1000) { 978 if (chip->badintrcount++ > 1000) {
@@ -947,7 +993,9 @@ snd_nm256_intr_check(nm256_t *chip)
947 if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running) 993 if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
948 snd_nm256_capture_stop(chip); 994 snd_nm256_capture_stop(chip);
949 chip->badintrcount = 0; 995 chip->badintrcount = 0;
996 return IRQ_HANDLED;
950 } 997 }
998 return IRQ_NONE;
951} 999}
952 1000
953/* 1001/*
@@ -969,10 +1017,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
969 status = snd_nm256_readw(chip, NM_INT_REG); 1017 status = snd_nm256_readw(chip, NM_INT_REG);
970 1018
971 /* Not ours. */ 1019 /* Not ours. */
972 if (status == 0) { 1020 if (status == 0)
973 snd_nm256_intr_check(chip); 1021 return snd_nm256_intr_check(chip);
974 return IRQ_NONE;
975 }
976 1022
977 chip->badintrcount = 0; 1023 chip->badintrcount = 0;
978 1024
@@ -1036,10 +1082,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
1036 status = snd_nm256_readl(chip, NM_INT_REG); 1082 status = snd_nm256_readl(chip, NM_INT_REG);
1037 1083
1038 /* Not ours. */ 1084 /* Not ours. */
1039 if (status == 0) { 1085 if (status == 0)
1040 snd_nm256_intr_check(chip); 1086 return snd_nm256_intr_check(chip);
1041 return IRQ_NONE;
1042 }
1043 1087
1044 chip->badintrcount = 0; 1088 chip->badintrcount = 0;
1045 1089
@@ -1192,7 +1236,7 @@ snd_nm256_mixer(nm256_t *chip)
1192 AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD, 1236 AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
1193 AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL, 1237 AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
1194 AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL, 1238 AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
1195 AC97_EXTENDED_ID, 1239 /*AC97_EXTENDED_ID,*/
1196 AC97_VENDOR_ID1, AC97_VENDOR_ID2, 1240 AC97_VENDOR_ID1, AC97_VENDOR_ID2,
1197 -1 1241 -1
1198 }; 1242 };
@@ -1206,6 +1250,7 @@ snd_nm256_mixer(nm256_t *chip)
1206 for (i = 0; mixer_regs[i] >= 0; i++) 1250 for (i = 0; mixer_regs[i] >= 0; i++)
1207 set_bit(mixer_regs[i], ac97.reg_accessed); 1251 set_bit(mixer_regs[i], ac97.reg_accessed);
1208 ac97.private_data = chip; 1252 ac97.private_data = chip;
1253 pbus->no_vra = 1;
1209 err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); 1254 err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
1210 if (err < 0) 1255 if (err < 0)
1211 return err; 1256 return err;
@@ -1281,6 +1326,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state)
1281static int nm256_resume(snd_card_t *card) 1326static int nm256_resume(snd_card_t *card)
1282{ 1327{
1283 nm256_t *chip = card->pm_private_data; 1328 nm256_t *chip = card->pm_private_data;
1329 int i;
1284 1330
1285 /* Perform a full reset on the hardware */ 1331 /* Perform a full reset on the hardware */
1286 pci_enable_device(chip->pci); 1332 pci_enable_device(chip->pci);
@@ -1289,6 +1335,15 @@ static int nm256_resume(snd_card_t *card)
1289 /* restore ac97 */ 1335 /* restore ac97 */
1290 snd_ac97_resume(chip->ac97); 1336 snd_ac97_resume(chip->ac97);
1291 1337
1338 for (i = 0; i < 2; i++) {
1339 nm256_stream_t *s = &chip->streams[i];
1340 if (s->substream && s->suspended) {
1341 spin_lock_irq(&chip->reg_lock);
1342 snd_nm256_set_format(chip, s, s->substream);
1343 spin_unlock_irq(&chip->reg_lock);
1344 }
1345 }
1346
1292 return 0; 1347 return 0;
1293} 1348}
1294#endif /* CONFIG_PM */ 1349#endif /* CONFIG_PM */
@@ -1360,6 +1415,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
1360 chip->use_cache = usecache; 1415 chip->use_cache = usecache;
1361 spin_lock_init(&chip->reg_lock); 1416 spin_lock_init(&chip->reg_lock);
1362 chip->irq = -1; 1417 chip->irq = -1;
1418 init_MUTEX(&chip->irq_mutex);
1363 1419
1364 chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize; 1420 chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;
1365 chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize; 1421 chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;
@@ -1470,15 +1526,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
1470 chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr; 1526 chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
1471 } 1527 }
1472 1528
1473 /* acquire interrupt */
1474 if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
1475 card->driver, (void*)chip)) {
1476 err = -EBUSY;
1477 snd_printk("unable to grab IRQ %d\n", pci->irq);
1478 goto __error;
1479 }
1480 chip->irq = pci->irq;
1481
1482 /* Fixed setting. */ 1529 /* Fixed setting. */
1483 chip->mixer_base = NM_MIXER_OFFSET; 1530 chip->mixer_base = NM_MIXER_OFFSET;
1484 1531