static int snd_ad1889_free(struct snd_ad1889 *chip) { if (chip->irq < 0) goto skip_hw; spin_lock_irq(&chip->lock); ad1889_mute(chip); /* Turn off interrupt on count and zero DMA registers */ ad1889_channel_reset(chip, AD_CHAN_WAV | AD_CHAN_ADC); /* clear DISR. If we don't, we'd better jump off the Eiffel Tower */ ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI); ad1889_readl(chip, AD_DMA_DISR); /* flush, dammit! */ spin_unlock_irq(&chip->lock); synchronize_irq(chip->irq); if (chip->irq >= 0) free_irq(chip->irq, chip); skip_hw: if (chip->iobase) iounmap(chip->iobase); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); return 0; }
static irqreturn_t snd_ad1889_interrupt(int irq, void *dev_id) { unsigned long st; struct snd_ad1889 *chip = dev_id; st = ad1889_readl(chip, AD_DMA_DISR); /* clear ISR */ ad1889_writel(chip, AD_DMA_DISR, st); st &= AD_INTR_MASK; if (unlikely(!st)) return IRQ_NONE; if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI)) ad1889_debug("Unexpected master or target abort interrupt!\n"); if ((st & AD_DMA_DISR_WAVI) && chip->psubs) snd_pcm_period_elapsed(chip->psubs); if ((st & AD_DMA_DISR_ADCI) && chip->csubs) snd_pcm_period_elapsed(chip->csubs); return IRQ_HANDLED; }
static int snd_ad1889_free(struct snd_ad1889 *chip) { if (chip->irq < 0) goto skip_hw; spin_lock_irq(&chip->lock); ad1889_mute(chip); ad1889_channel_reset(chip, AD_CHAN_WAV | AD_CHAN_ADC); ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI); ad1889_readl(chip, AD_DMA_DISR); spin_unlock_irq(&chip->lock); if (chip->irq >= 0) free_irq(chip->irq, chip); skip_hw: if (chip->iobase) iounmap(chip->iobase); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); return 0; }
/* Called in atomic context with IRQ disabled */ static snd_pcm_uframes_t snd_ad1889_capture_pointer(struct snd_pcm_substream *ss) { size_t ptr = 0; struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); if (unlikely(!(chip->ramc.reg & AD_DS_RAMC_ADEN))) return 0; ptr = ad1889_readl(chip, AD_DMA_ADCCA); ptr -= chip->ramc.addr; snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0); return bytes_to_frames(ss->runtime, ptr); }
/* Called in atomic context with IRQ disabled */ static snd_pcm_uframes_t snd_ad1889_playback_pointer(struct snd_pcm_substream *ss) { size_t ptr = 0; struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); if (unlikely(!(chip->wave.reg & AD_DS_WSMC_WAEN))) return 0; ptr = ad1889_readl(chip, AD_DMA_WAVCA); ptr -= chip->wave.addr; snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0); return bytes_to_frames(ss->runtime, ptr); }