static int reset_controller(struct lola *chip) { unsigned int gctl = lola_readl(chip, BAR0, GCTL); unsigned long end_time; if (gctl) { /* */ lola_writel(chip, BAR1, BOARD_MODE, 0); return 0; } chip->cold_reset = 1; lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET); end_time = jiffies + msecs_to_jiffies(200); do { msleep(1); gctl = lola_readl(chip, BAR0, GCTL); if (gctl) break; } while (time_before(jiffies, end_time)); if (!gctl) { printk(KERN_ERR SFX "cannot reset controller\n"); return -EIO; } return 0; }
static unsigned int lola_get_lrc(struct lola *chip) { return lola_readl(chip, BAR1, LRC); }
static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, int dev, struct lola **rchip) { struct lola *chip; int err; unsigned int dever; static struct snd_device_ops ops = { .dev_free = lola_dev_free, }; *rchip = NULL; err = pci_enable_device(pci); if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { snd_printk(KERN_ERR SFX "cannot allocate chip\n"); pci_disable_device(pci); return -ENOMEM; } spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; chip->granularity = granularity[dev]; switch (chip->granularity) { case 8: chip->sample_rate_max = 48000; break; case 16: chip->sample_rate_max = 96000; break; case 32: chip->sample_rate_max = 192000; break; default: snd_printk(KERN_WARNING SFX "Invalid granularity %d, reset to %d\n", chip->granularity, LOLA_GRANULARITY_MAX); chip->granularity = LOLA_GRANULARITY_MAX; chip->sample_rate_max = 192000; break; } chip->sample_rate_min = sample_rate_min[dev]; if (chip->sample_rate_min > chip->sample_rate_max) { snd_printk(KERN_WARNING SFX "Invalid sample_rate_min %d, reset to 16000\n", chip->sample_rate_min); chip->sample_rate_min = 16000; } err = pci_request_regions(pci, DRVNAME); if (err < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->bar[0].addr = pci_resource_start(pci, 0); chip->bar[0].remap_addr = pci_ioremap_bar(pci, 0); chip->bar[1].addr = pci_resource_start(pci, 2); chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2); if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) { snd_printk(KERN_ERR SFX "ioremap error\n"); err = -ENXIO; goto errout; } pci_set_master(pci); err = reset_controller(chip); if (err < 0) goto errout; if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto errout; } chip->irq = pci->irq; synchronize_irq(chip->irq); dever = lola_readl(chip, BAR1, DEVER); chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff; chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff; chip->version = (dever >> 24) & 0xff; snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n", chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams, chip->version); /* */ if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT || chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT || (!chip->pcm[CAPT].num_streams && !chip->pcm[PLAY].num_streams)) { printk(KERN_ERR SFX "invalid DEVER = %x\n", dever); err = -EINVAL; goto errout; } err = setup_corb_rirb(chip); if (err < 0) goto errout; err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); goto errout; } strcpy(card->driver, "Lola"); strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx irq %i", card->shortname, chip->bar[0].addr, chip->irq); strcpy(card->mixername, card->shortname); lola_irq_enable(chip); chip->initialized = 1; *rchip = chip; return 0; errout: lola_free(chip); return err; }
static irqreturn_t lola_interrupt(int irq, void *dev_id) { struct lola *chip = dev_id; unsigned int notify_ins, notify_outs, error_ins, error_outs; int handled = 0; int i; notify_ins = notify_outs = error_ins = error_outs = 0; spin_lock(&chip->reg_lock); for (;;) { unsigned int status, in_sts, out_sts; unsigned int reg; status = lola_readl(chip, BAR1, DINTSTS); if (!status || status == -1) break; in_sts = lola_readl(chip, BAR1, DIINTSTS); out_sts = lola_readl(chip, BAR1, DOINTSTS); /* */ for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) { if (!(in_sts & (1 << i))) continue; in_sts &= ~(1 << i); reg = lola_dsd_read(chip, i, STS); if (reg & LOLA_DSD_STS_DESE) /* */ error_ins |= (1 << i); if (reg & LOLA_DSD_STS_BCIS) /* */ notify_ins |= (1 << i); /* */ lola_dsd_write(chip, i, STS, reg); } /* */ for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) { if (!(out_sts & (1 << i))) continue; out_sts &= ~(1 << i); reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS); if (reg & LOLA_DSD_STS_DESE) /* */ error_outs |= (1 << i); if (reg & LOLA_DSD_STS_BCIS) /* */ notify_outs |= (1 << i); lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg); } if (status & LOLA_DINT_CTRL) { unsigned char rbsts; /* */ rbsts = lola_readb(chip, BAR0, RIRBSTS); rbsts &= LOLA_RIRB_INT_MASK; if (rbsts) lola_writeb(chip, BAR0, RIRBSTS, rbsts); rbsts = lola_readb(chip, BAR0, CORBSTS); rbsts &= LOLA_CORB_INT_MASK; if (rbsts) lola_writeb(chip, BAR0, CORBSTS, rbsts); lola_update_rirb(chip); } if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) { /* */ lola_writel(chip, BAR1, DINTSTS, (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR))); } handled = 1; } spin_unlock(&chip->reg_lock); lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins); lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs); return IRQ_RETVAL(handled); }