📄 cs4231.c
字号:
chip->next = cs4231_list; cs4231_list = chip; dev++; return 0;out_err: snd_card_free(card); return err;}#ifdef SBUS_SUPPORTstatic irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id){ unsigned long flags; unsigned char status; u32 csr; struct snd_cs4231 *chip = dev_id; /*This is IRQ is not raised by the cs4231*/ if (!(__cs4231_readb(chip, CS4231U(chip, STATUS)) & CS4231_GLOBALIRQ)) return IRQ_NONE; /* ACK the APC interrupt. */ csr = sbus_readl(chip->port + APCCSR); sbus_writel(csr, chip->port + APCCSR); if ((csr & APC_PDMA_READY) && (csr & APC_PLAY_INT) && (csr & APC_XINT_PNVA) && !(csr & APC_XINT_EMPT)) snd_cs4231_play_callback(chip); if ((csr & APC_CDMA_READY) && (csr & APC_CAPT_INT) && (csr & APC_XINT_CNVA) && !(csr & APC_XINT_EMPT)) snd_cs4231_capture_callback(chip); status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); if (status & CS4231_TIMER_IRQ) { if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); } if ((status & CS4231_RECORD_IRQ) && (csr & APC_CDMA_READY)) snd_cs4231_overrange(chip); /* ACK the CS4231 interrupt. */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); spin_unlock_irqrestore(&chip->lock, flags); return IRQ_HANDLED;}/* * SBUS DMA routines */static int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len){ unsigned long flags; u32 test, csr; int err; struct sbus_dma_info *base = &dma_cont->sbus_info; if (len >= (1 << 24)) return -EINVAL; spin_lock_irqsave(&base->lock, flags); csr = sbus_readl(base->regs + APCCSR); err = -EINVAL; test = APC_CDMA_READY; if (base->dir == APC_PLAY) test = APC_PDMA_READY; if (!(csr & test)) goto out; err = -EBUSY; test = APC_XINT_CNVA; if (base->dir == APC_PLAY) test = APC_XINT_PNVA; if (!(csr & test)) goto out; err = 0; sbus_writel(bus_addr, base->regs + base->dir + APCNVA); sbus_writel(len, base->regs + base->dir + APCNC);out: spin_unlock_irqrestore(&base->lock, flags); return err;}static void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d){ unsigned long flags; u32 csr, test; struct sbus_dma_info *base = &dma_cont->sbus_info; spin_lock_irqsave(&base->lock, flags); csr = sbus_readl(base->regs + APCCSR); test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL | APC_XINT_PENA; if (base->dir == APC_RECORD) test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL; csr |= test; sbus_writel(csr, base->regs + APCCSR); spin_unlock_irqrestore(&base->lock, flags);}static void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on){ unsigned long flags; u32 csr, shift; struct sbus_dma_info *base = &dma_cont->sbus_info; spin_lock_irqsave(&base->lock, flags); if (!on) { sbus_writel(0, base->regs + base->dir + APCNC); sbus_writel(0, base->regs + base->dir + APCNVA); if (base->dir == APC_PLAY) { sbus_writel(0, base->regs + base->dir + APCC); sbus_writel(0, base->regs + base->dir + APCVA); } udelay(1200); } csr = sbus_readl(base->regs + APCCSR); shift = 0; if (base->dir == APC_PLAY) shift = 1; if (on) csr &= ~(APC_CPAUSE << shift); else csr |= (APC_CPAUSE << shift); sbus_writel(csr, base->regs + APCCSR); if (on) csr |= (APC_CDMA_READY << shift); else csr &= ~(APC_CDMA_READY << shift); sbus_writel(csr, base->regs + APCCSR); spin_unlock_irqrestore(&base->lock, flags);}static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont){ struct sbus_dma_info *base = &dma_cont->sbus_info; return sbus_readl(base->regs + base->dir + APCVA);}static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm){ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, snd_dma_sbus_data(chip->dev_u.sdev), 64 * 1024, 128 * 1024);}/* * Init and exit routines */static int snd_cs4231_sbus_free(struct snd_cs4231 *chip){ if (chip->irq[0]) free_irq(chip->irq[0], chip); if (chip->port) sbus_iounmap(chip->port, chip->regs_size); return 0;}static int snd_cs4231_sbus_dev_free(struct snd_device *device){ struct snd_cs4231 *cp = device->device_data; return snd_cs4231_sbus_free(cp);}static struct snd_device_ops snd_cs4231_sbus_dev_ops = { .dev_free = snd_cs4231_sbus_dev_free,};static int __init snd_cs4231_sbus_create(struct snd_card *card, struct sbus_dev *sdev, int dev){ struct snd_cs4231 *chip = card->private_data; int err; spin_lock_init(&chip->lock); spin_lock_init(&chip->c_dma.sbus_info.lock); spin_lock_init(&chip->p_dma.sbus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); chip->dev_u.sdev = sdev; chip->regs_size = sdev->reg_addrs[0].reg_size; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); chip->port = sbus_ioremap(&sdev->resource[0], 0, chip->regs_size, "cs4231"); if (!chip->port) { snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; } chip->c_dma.sbus_info.regs = chip->port; chip->p_dma.sbus_info.regs = chip->port; chip->c_dma.sbus_info.dir = APC_RECORD; chip->p_dma.sbus_info.dir = APC_PLAY; chip->p_dma.prepare = sbus_dma_prepare; chip->p_dma.enable = sbus_dma_enable; chip->p_dma.request = sbus_dma_request; chip->p_dma.address = sbus_dma_addr; chip->p_dma.preallocate = sbus_dma_preallocate; chip->c_dma.prepare = sbus_dma_prepare; chip->c_dma.enable = sbus_dma_enable; chip->c_dma.request = sbus_dma_request; chip->c_dma.address = sbus_dma_addr; chip->c_dma.preallocate = sbus_dma_preallocate; if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, IRQF_SHARED, "cs4231", chip)) { snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", dev, sdev->irqs[0]); snd_cs4231_sbus_free(chip); return -EBUSY; } chip->irq[0] = sdev->irqs[0]; if (snd_cs4231_probe(chip) < 0) { snd_cs4231_sbus_free(chip); return -ENODEV; } snd_cs4231_init(chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &snd_cs4231_sbus_dev_ops)) < 0) { snd_cs4231_sbus_free(chip); return err; } return 0;}static int __init cs4231_sbus_attach(struct sbus_dev *sdev){ struct resource *rp = &sdev->resource[0]; struct snd_card *card; int err; err = cs4231_attach_begin(&card); if (err) return err; sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d", card->shortname, rp->flags & 0xffL, (unsigned long long)rp->start, sdev->irqs[0]); err = snd_cs4231_sbus_create(card, sdev, dev); if (err < 0) { snd_card_free(card); return err; } return cs4231_attach_finish(card);}#endif#ifdef EBUS_SUPPORTstatic void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie){ struct snd_cs4231 *chip = cookie; snd_cs4231_play_callback(chip);}static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie){ struct snd_cs4231 *chip = cookie; snd_cs4231_capture_callback(chip);}/* * EBUS DMA wrappers */static int _ebus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len){ return ebus_dma_request(&dma_cont->ebus_info, bus_addr, len);}static void _ebus_dma_enable(struct cs4231_dma_control *dma_cont, int on){ ebus_dma_enable(&dma_cont->ebus_info, on);}static void _ebus_dma_prepare(struct cs4231_dma_control *dma_cont, int dir){ ebus_dma_prepare(&dma_cont->ebus_info, dir);}static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont){ return ebus_dma_addr(&dma_cont->ebus_info);}static void _ebus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm){ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->dev_u.pdev), 64*1024, 128*1024);}/* * Init and exit routines */static int snd_cs4231_ebus_free(struct snd_cs4231 *chip){ if (chip->c_dma.ebus_info.regs) { ebus_dma_unregister(&chip->c_dma.ebus_info); iounmap(chip->c_dma.ebus_info.regs); } if (chip->p_dma.ebus_info.regs) { ebus_dma_unregister(&chip->p_dma.ebus_info); iounmap(chip->p_dma.ebus_info.regs); } if (chip->port) iounmap(chip->port); return 0;}static int snd_cs4231_ebus_dev_free(struct snd_device *device){ struct snd_cs4231 *cp = device->device_data; return snd_cs4231_ebus_free(cp);}static struct snd_device_ops snd_cs4231_ebus_dev_ops = { .dev_free = snd_cs4231_ebus_dev_free,};static int __init snd_cs4231_ebus_create(struct snd_card *card, struct linux_ebus_device *edev, int dev){ struct snd_cs4231 *chip = card->private_data; int err; spin_lock_init(&chip->lock); spin_lock_init(&chip->c_dma.ebus_info.lock); spin_lock_init(&chip->p_dma.ebus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); chip->flags |= CS4231_FLAG_EBUS; chip->dev_u.pdev = edev->bus->self; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)"); chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback; chip->c_dma.ebus_info.client_cookie = chip; chip->c_dma.ebus_info.irq = edev->irqs[0]; strcpy(chip->p_dma.ebus_info.name, "cs4231(play)"); chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback; chip->p_dma.ebus_info.client_cookie = chip; chip->p_dma.ebus_info.irq = edev->irqs[1]; chip->p_dma.prepare = _ebus_dma_prepare; chip->p_dma.enable = _ebus_dma_enable; chip->p_dma.request = _ebus_dma_request; chip->p_dma.address = _ebus_dma_addr; chip->p_dma.preallocate = _ebus_dma_preallocate; chip->c_dma.prepare = _ebus_dma_prepare; chip->c_dma.enable = _ebus_dma_enable; chip->c_dma.request = _ebus_dma_request; chip->c_dma.address = _ebus_dma_addr; chip->c_dma.preallocate = _ebus_dma_preallocate; chip->port = ioremap(edev->resource[0].start, 0x10); chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10); chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10); if (!chip->port || !chip->p_dma.ebus_info.regs || !chip->c_dma.ebus_info.regs) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; } if (ebus_dma_register(&chip->c_dma.ebus_info)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev); return -EBUSY; } if (ebus_dma_irq_enable(&chip->c_dma.ebus_info, 1)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev); return -EBUSY; } if (ebus_dma_register(&chip->p_dma.ebus_info)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev); return -EBUSY; } if (ebus_dma_irq_enable(&chip->p_dma.ebus_info, 1)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev); return -EBUSY; } if (snd_cs4231_probe(chip) < 0) { snd_cs4231_ebus_free(chip); return -ENODEV; } snd_cs4231_init(chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &snd_cs4231_ebus_dev_ops)) < 0) { snd_cs4231_ebus_free(chip); return err; } return 0;}static int __init cs4231_ebus_attach(struct linux_ebus_device *edev){ struct snd_card *card; int err; err = cs4231_attach_begin(&card); if (err) return err; sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, edev->resource[0].start, edev->irqs[0]); err = snd_cs4231_ebus_create(card, edev, dev); if (err < 0) { snd_card_free(card); return err; } return cs4231_attach_finish(card);}#endifstatic int __init cs4231_init(void){#ifdef SBUS_SUPPORT struct sbus_bus *sbus; struct sbus_dev *sdev;#endif#ifdef EBUS_SUPPORT struct linux_ebus *ebus; struct linux_ebus_device *edev;#endif int found; found = 0;#ifdef SBUS_SUPPORT for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "SUNW,CS4231")) { if (cs4231_sbus_attach(sdev) == 0) found++; } }#endif#ifdef EBUS_SUPPORT for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { int match = 0; if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) { match = 1; } else if (!strcmp(edev->prom_node->name, "audio")) { const char *compat; compat = of_get_property(edev->prom_node, "compatible", NULL); if (compat && !strcmp(compat, "SUNW,CS4231")) match = 1; } if (match && cs4231_ebus_attach(edev) == 0) found++; } }#endif return (found > 0) ? 0 : -EIO;}static void __exit cs4231_exit(void){ struct snd_cs4231 *p = cs4231_list; while (p != NULL) { struct snd_cs4231 *next = p->next; snd_card_free(p->card); p = next; } cs4231_list = NULL;}module_init(cs4231_init);module_exit(cs4231_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -