⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs4231.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -