Skip to content

Commit

Permalink
[ALSA] nm256 - Fix PM and irq handling
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
tiwai authored and Jaroslav Kysela committed Aug 30, 2005
1 parent 1cfe43d commit 1204de3
Showing 1 changed file with 70 additions and 23 deletions.
93 changes: 70 additions & 23 deletions sound/pci/nm256/nm256.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ struct snd_nm256_stream {
nm256_t *chip;
snd_pcm_substream_t *substream;
int running;
int suspended;

u32 buf; /* offset from chip->buffer */
int bufsize; /* buffer size in bytes */
Expand Down Expand Up @@ -231,8 +232,10 @@ struct snd_nm256 {
int mixer_status_mask; /* bit mask to test the mixer status */

int irq;
int irq_acks;
irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
int badintrcount; /* counter to check bogus interrupts */
struct semaphore irq_mutex;

nm256_stream_t streams[2];

Expand Down Expand Up @@ -464,6 +467,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs
}
}

/* acquire interrupt */
static int snd_nm256_acquire_irq(nm256_t *chip)
{
down(&chip->irq_mutex);
if (chip->irq < 0) {
if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
chip->card->driver, (void*)chip)) {
snd_printk("unable to grab IRQ %d\n", chip->pci->irq);
up(&chip->irq_mutex);
return -EBUSY;
}
chip->irq = chip->pci->irq;
}
chip->irq_acks++;
up(&chip->irq_mutex);
return 0;
}

/* release interrupt */
static void snd_nm256_release_irq(nm256_t *chip)
{
down(&chip->irq_mutex);
if (chip->irq_acks > 0)
chip->irq_acks--;
if (chip->irq_acks == 0 && chip->irq >= 0) {
free_irq(chip->irq, (void*)chip);
chip->irq = -1;
}
up(&chip->irq_mutex);
}

/*
* start / stop
*/
Expand Down Expand Up @@ -538,15 +572,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd)

spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
s->suspended = 0;
/* fallthru */
case SNDRV_PCM_TRIGGER_START:
if (! s->running) {
snd_nm256_playback_start(chip, s, substream);
s->running = 1;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
s->suspended = 1;
/* fallthru */
case SNDRV_PCM_TRIGGER_STOP:
if (s->running) {
snd_nm256_playback_stop(chip);
s->running = 0;
Expand Down Expand Up @@ -818,6 +856,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);

if (snd_nm256_acquire_irq(chip) < 0)
return -EBUSY;
snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],
substream, &snd_nm256_playback);
return 0;
Expand All @@ -828,6 +868,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);

if (snd_nm256_acquire_irq(chip) < 0)
return -EBUSY;
snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],
substream, &snd_nm256_capture);
return 0;
Expand All @@ -839,13 +881,19 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
static int
snd_nm256_playback_close(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);

snd_nm256_release_irq(chip);
return 0;
}


static int
snd_nm256_capture_close(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);

snd_nm256_release_irq(chip);
return 0;
}

Expand Down Expand Up @@ -915,18 +963,16 @@ snd_nm256_pcm(nm256_t *chip, int device)
static void
snd_nm256_init_chip(nm256_t *chip)
{
spin_lock_irq(&chip->reg_lock);
/* Reset everything. */
snd_nm256_writeb(chip, 0x0, 0x11);
snd_nm256_writew(chip, 0x214, 0);
/* stop sounds.. */
//snd_nm256_playback_stop(chip);
//snd_nm256_capture_stop(chip);
spin_unlock_irq(&chip->reg_lock);
}


static inline void
static irqreturn_t
snd_nm256_intr_check(nm256_t *chip)
{
if (chip->badintrcount++ > 1000) {
Expand All @@ -947,7 +993,9 @@ snd_nm256_intr_check(nm256_t *chip)
if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
snd_nm256_capture_stop(chip);
chip->badintrcount = 0;
return IRQ_HANDLED;
}
return IRQ_NONE;
}

/*
Expand All @@ -969,10 +1017,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
status = snd_nm256_readw(chip, NM_INT_REG);

/* Not ours. */
if (status == 0) {
snd_nm256_intr_check(chip);
return IRQ_NONE;
}
if (status == 0)
return snd_nm256_intr_check(chip);

chip->badintrcount = 0;

Expand Down Expand Up @@ -1036,10 +1082,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
status = snd_nm256_readl(chip, NM_INT_REG);

/* Not ours. */
if (status == 0) {
snd_nm256_intr_check(chip);
return IRQ_NONE;
}
if (status == 0)
return snd_nm256_intr_check(chip);

chip->badintrcount = 0;

Expand Down Expand Up @@ -1192,7 +1236,7 @@ snd_nm256_mixer(nm256_t *chip)
AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
AC97_EXTENDED_ID,
/*AC97_EXTENDED_ID,*/
AC97_VENDOR_ID1, AC97_VENDOR_ID2,
-1
};
Expand All @@ -1206,6 +1250,7 @@ snd_nm256_mixer(nm256_t *chip)
for (i = 0; mixer_regs[i] >= 0; i++)
set_bit(mixer_regs[i], ac97.reg_accessed);
ac97.private_data = chip;
pbus->no_vra = 1;
err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
if (err < 0)
return err;
Expand Down Expand Up @@ -1281,6 +1326,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state)
static int nm256_resume(snd_card_t *card)
{
nm256_t *chip = card->pm_private_data;
int i;

/* Perform a full reset on the hardware */
pci_enable_device(chip->pci);
Expand All @@ -1289,6 +1335,15 @@ static int nm256_resume(snd_card_t *card)
/* restore ac97 */
snd_ac97_resume(chip->ac97);

for (i = 0; i < 2; i++) {
nm256_stream_t *s = &chip->streams[i];
if (s->substream && s->suspended) {
spin_lock_irq(&chip->reg_lock);
snd_nm256_set_format(chip, s, s->substream);
spin_unlock_irq(&chip->reg_lock);
}
}

return 0;
}
#endif /* CONFIG_PM */
Expand Down Expand Up @@ -1360,6 +1415,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
chip->use_cache = usecache;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
init_MUTEX(&chip->irq_mutex);

chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;
chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;
Expand Down Expand Up @@ -1470,15 +1526,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
}

/* acquire interrupt */
if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
card->driver, (void*)chip)) {
err = -EBUSY;
snd_printk("unable to grab IRQ %d\n", pci->irq);
goto __error;
}
chip->irq = pci->irq;

/* Fixed setting. */
chip->mixer_base = NM_MIXER_OFFSET;

Expand Down

0 comments on commit 1204de3

Please sign in to comment.