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

📄 atiixp.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	int err;	down(&chip->open_mutex);	if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);	else		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);	up(&chip->open_mutex);	return err;}static int snd_atiixp_spdif_close(snd_pcm_substream_t *substream){	atiixp_t *chip = snd_pcm_substream_chip(substream);	int err;	down(&chip->open_mutex);	if (chip->spdif_over_aclink)		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);	else		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);	up(&chip->open_mutex);	return err;}/* AC97 playback */static snd_pcm_ops_t snd_atiixp_playback_ops = {	.open =		snd_atiixp_playback_open,	.close =	snd_atiixp_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_atiixp_pcm_hw_params,	.hw_free =	snd_atiixp_pcm_hw_free,	.prepare =	snd_atiixp_playback_prepare,	.trigger =	snd_atiixp_pcm_trigger,	.pointer =	snd_atiixp_pcm_pointer,};/* AC97 capture */static snd_pcm_ops_t snd_atiixp_capture_ops = {	.open =		snd_atiixp_capture_open,	.close =	snd_atiixp_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_atiixp_pcm_hw_params,	.hw_free =	snd_atiixp_pcm_hw_free,	.prepare =	snd_atiixp_capture_prepare,	.trigger =	snd_atiixp_pcm_trigger,	.pointer =	snd_atiixp_pcm_pointer,};/* SPDIF playback */static snd_pcm_ops_t snd_atiixp_spdif_ops = {	.open =		snd_atiixp_spdif_open,	.close =	snd_atiixp_spdif_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_atiixp_pcm_hw_params,	.hw_free =	snd_atiixp_pcm_hw_free,	.prepare =	snd_atiixp_spdif_prepare,	.trigger =	snd_atiixp_pcm_trigger,	.pointer =	snd_atiixp_pcm_pointer,};static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = {	/* front PCM */	{		.exclusive = 1,		.r = {	{				.slots = (1 << AC97_SLOT_PCM_LEFT) |					 (1 << AC97_SLOT_PCM_RIGHT) |					 (1 << AC97_SLOT_PCM_CENTER) |					 (1 << AC97_SLOT_PCM_SLEFT) |					 (1 << AC97_SLOT_PCM_SRIGHT) |					 (1 << AC97_SLOT_LFE)			}		}	},	/* PCM IN #1 */	{		.stream = 1,		.exclusive = 1,		.r = {	{				.slots = (1 << AC97_SLOT_PCM_LEFT) |					 (1 << AC97_SLOT_PCM_RIGHT)			}		}	},	/* S/PDIF OUT (optional) */	{		.exclusive = 1,		.spdif = 1,		.r = {	{				.slots = (1 << AC97_SLOT_SPDIF_LEFT2) |					 (1 << AC97_SLOT_SPDIF_RIGHT2)			}		}	},};static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = {	.type = ATI_DMA_PLAYBACK,	.llp_offset = ATI_REG_OUT_DMA_LINKPTR,	.dt_cur = ATI_REG_OUT_DMA_DT_CUR,	.enable_dma = atiixp_out_enable_dma,	.enable_transfer = atiixp_out_enable_transfer,	.flush_dma = atiixp_out_flush_dma,};	static atiixp_dma_ops_t snd_atiixp_capture_dma_ops = {	.type = ATI_DMA_CAPTURE,	.llp_offset = ATI_REG_IN_DMA_LINKPTR,	.dt_cur = ATI_REG_IN_DMA_DT_CUR,	.enable_dma = atiixp_in_enable_dma,	.enable_transfer = atiixp_in_enable_transfer,	.flush_dma = atiixp_in_flush_dma,};	static atiixp_dma_ops_t snd_atiixp_spdif_dma_ops = {	.type = ATI_DMA_SPDIF,	.llp_offset = ATI_REG_SPDF_DMA_LINKPTR,	.dt_cur = ATI_REG_SPDF_DMA_DT_CUR,	.enable_dma = atiixp_spdif_enable_dma,	.enable_transfer = atiixp_spdif_enable_transfer,	.flush_dma = atiixp_spdif_flush_dma,};	static int __devinit snd_atiixp_pcm_new(atiixp_t *chip){	snd_pcm_t *pcm;	ac97_bus_t *pbus = chip->ac97_bus;	int err, i, num_pcms;	/* initialize constants */	chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops;	chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops;	if (! chip->spdif_over_aclink)		chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops;	/* assign AC97 pcm */	if (chip->spdif_over_aclink)		num_pcms = 3;	else		num_pcms = 2;	err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs);	if (err < 0)		return err;	for (i = 0; i < num_pcms; i++)		chip->pcms[i] = &pbus->pcms[i];	chip->max_channels = 2;	if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {		if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_LFE))			chip->max_channels = 6;		else			chip->max_channels = 4;	}	/* PCM #0: analog I/O */	err = snd_pcm_new(chip->card, "ATI IXP AC97", ATI_PCMDEV_ANALOG, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);	pcm->private_data = chip;	strcpy(pcm->name, "ATI IXP AC97");	chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci), 64*1024, 128*1024);	/* no SPDIF support on codec? */	if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates)		return 0;			/* FIXME: non-48k sample rate doesn't work on my test machine with AD1888 */	if (chip->pcms[ATI_PCM_SPDIF])		chip->pcms[ATI_PCM_SPDIF]->rates = SNDRV_PCM_RATE_48000;	/* PCM #1: spdif playback */	err = snd_pcm_new(chip->card, "ATI IXP IEC958", ATI_PCMDEV_DIGITAL, 1, 0, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops);	pcm->private_data = chip;	if (chip->spdif_over_aclink)		strcpy(pcm->name, "ATI IXP IEC958 (AC97)");	else		strcpy(pcm->name, "ATI IXP IEC958 (Direct)");	chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci), 64*1024, 128*1024);	/* pre-select AC97 SPDIF slots 10/11 */	for (i = 0; i < NUM_ATI_CODECS; i++) {		if (chip->ac97[i])			snd_ac97_update_bits(chip->ac97[i], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4);	}	return 0;}/* * interrupt handler */static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs){	atiixp_t *chip = dev_id;	unsigned int status;	status = atiixp_read(chip, ISR);	if (! status)		return IRQ_NONE;	/* process audio DMA */	if (status & ATI_REG_ISR_OUT_XRUN)		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_PLAYBACK]);	else if (status & ATI_REG_ISR_OUT_STATUS)		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]);	if (status & ATI_REG_ISR_IN_XRUN)		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_CAPTURE]);	else if (status & ATI_REG_ISR_IN_STATUS)		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]);	if (! chip->spdif_over_aclink) {		if (status & ATI_REG_ISR_SPDF_XRUN)			snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_SPDIF]);		else if (status & ATI_REG_ISR_SPDF_STATUS)			snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]);	}	/* for codec detection */	if (status & CODEC_CHECK_BITS) {		unsigned int detected;		detected = status & CODEC_CHECK_BITS;		spin_lock(&chip->reg_lock);		chip->codec_not_ready_bits |= detected;		atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */		spin_unlock(&chip->reg_lock);	}	/* ack */	atiixp_write(chip, ISR, status);	return IRQ_HANDLED;}/* * ac97 mixer section */static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock){	ac97_bus_t *pbus;	ac97_template_t ac97;	int i, err;	int codec_count;	static ac97_bus_ops_t ops = {		.write = snd_atiixp_ac97_write,		.read = snd_atiixp_ac97_read,	};	static unsigned int codec_skip[NUM_ATI_CODECS] = {		ATI_REG_ISR_CODEC0_NOT_READY,		ATI_REG_ISR_CODEC1_NOT_READY,		ATI_REG_ISR_CODEC2_NOT_READY,	};	if (snd_atiixp_codec_detect(chip) < 0)		return -ENXIO;	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0)		return err;	pbus->clock = clock;	pbus->shared_type = AC97_SHARED_TYPE_ATIIXP;	/* shared with modem driver */	chip->ac97_bus = pbus;	codec_count = 0;	for (i = 0; i < NUM_ATI_CODECS; i++) {		if (chip->codec_not_ready_bits & codec_skip[i])			continue;		memset(&ac97, 0, sizeof(ac97));		ac97.private_data = chip;		ac97.pci = chip->pci;		ac97.num = i;		ac97.scaps = AC97_SCAP_SKIP_MODEM;		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {			chip->ac97[i] = NULL; /* to be sure */			snd_printdd("atiixp: codec %d not available for audio\n", i);			continue;		}		codec_count++;	}	if (! codec_count) {		snd_printk(KERN_ERR "atiixp: no codec available\n");		return -ENODEV;	}	/* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */	return 0;}#ifdef CONFIG_PM/* * power management */static int snd_atiixp_suspend(snd_card_t *card, unsigned int state){	atiixp_t *chip = card->pm_private_data;	int i;	for (i = 0; i < NUM_ATI_PCMDEVS; i++)		if (chip->pcmdevs[i])			snd_pcm_suspend_all(chip->pcmdevs[i]);	for (i = 0; i < NUM_ATI_CODECS; i++)		if (chip->ac97[i])			snd_ac97_suspend(chip->ac97[i]);	snd_atiixp_aclink_down(chip);	snd_atiixp_chip_stop(chip);	pci_set_power_state(chip->pci, 3);	pci_disable_device(chip->pci);	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	return 0;}static int snd_atiixp_resume(snd_card_t *card, unsigned int state){	atiixp_t *chip = card->pm_private_data;	int i;	pci_enable_device(chip->pci);	pci_set_power_state(chip->pci, 0);	snd_atiixp_aclink_reset(chip);	snd_atiixp_chip_start(chip);	for (i = 0; i < NUM_ATI_CODECS; i++)		if (chip->ac97[i])			snd_ac97_resume(chip->ac97[i]);	snd_power_change_state(card, SNDRV_CTL_POWER_D0);	return 0;}#endif /* CONFIG_PM *//* * proc interface for register dump */static void snd_atiixp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer){	atiixp_t *chip = entry->private_data;	int i;	for (i = 0; i < 256; i += 4)		snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i));}static void __devinit snd_atiixp_proc_init(atiixp_t *chip){	snd_info_entry_t *entry;	if (! snd_card_proc_new(chip->card, "atiixp", &entry))		snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);}/* * destructor */static int snd_atiixp_free(atiixp_t *chip){	if (chip->irq < 0)		goto __hw_end;	snd_atiixp_chip_stop(chip);	synchronize_irq(chip->irq);      __hw_end:	if (chip->irq >= 0)		free_irq(chip->irq, (void *)chip);	if (chip->remap_addr)		iounmap(chip->remap_addr);	pci_release_regions(chip->pci);	kfree(chip);	return 0;}static int snd_atiixp_dev_free(snd_device_t *device){	atiixp_t *chip = device->device_data;	return snd_atiixp_free(chip);}/* * constructor for chip instance */static int __devinit snd_atiixp_create(snd_card_t *card,				      struct pci_dev *pci,				      atiixp_t **r_chip){	static snd_device_ops_t ops = {		.dev_free =	snd_atiixp_dev_free,	};	atiixp_t *chip;	int err;	if ((err = pci_enable_device(pci)) < 0)		return err;	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);	if (chip == NULL)		return -ENOMEM;	spin_lock_init(&chip->reg_lock);	spin_lock_init(&chip->ac97_lock);	init_MUTEX(&chip->open_mutex);	chip->card = card;	chip->pci = pci;	chip->irq = -1;	if ((err = pci_request_regions(pci, "ATI IXP AC97")) < 0) {		kfree(chip);		return err;	}	chip->addr = pci_resource_start(pci, 0);	chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci, 0));	if (chip->remap_addr == 0) {		snd_printk(KERN_ERR "AC'97 space ioremap problem\n");		snd_atiixp_free(chip);		return -EIO;	}	if (request_irq(pci->irq, snd_atiixp_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) {		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);		snd_atiixp_free(chip);		return -EBUSY;	}	chip->irq = pci->irq;	pci_set_master(pci);	synchronize_irq(chip->irq);	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {		snd_atiixp_free(chip);		return err;	}	snd_card_set_dev(card, &pci->dev);	*r_chip = chip;	return 0;}static int __devinit snd_atiixp_probe(struct pci_dev *pci,				     const struct pci_device_id *pci_id){	static int dev;	snd_card_t *card;	atiixp_t *chip;	unsigned char revision;	int err;	if (dev >= SNDRV_CARDS)		return -ENODEV;	if (!enable[dev]) {		dev++;		return -ENOENT;	}	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	pci_read_config_byte(pci, PCI_REVISION_ID, &revision);	strcpy(card->driver, spdif_aclink[dev] ? "ATIIXP" : "ATIIXP-SPDMA");	strcpy(card->shortname, "ATI IXP");	if ((err = snd_atiixp_create(card, pci, &chip)) < 0)		goto __error;	if ((err = snd_atiixp_aclink_reset(chip)) < 0)		goto __error;	chip->spdif_over_aclink = spdif_aclink[dev];	if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev])) < 0)		goto __error;	if ((err = snd_atiixp_pcm_new(chip)) < 0)		goto __error;		snd_atiixp_proc_init(chip);	snd_atiixp_chip_start(chip);	sprintf(card->longname, "%s rev %x at 0x%lx, irq %i",		card->shortname, revision, chip->addr, chip->irq);	snd_card_set_pm_callback(card, snd_atiixp_suspend, snd_atiixp_resume, chip);	if ((err = snd_card_register(card)) < 0)		goto __error;	pci_set_drvdata(pci, card);	dev++;	return 0; __error:	snd_card_free(card);	return err;}static void __devexit snd_atiixp_remove(struct pci_dev *pci){	snd_card_free(pci_get_drvdata(pci));	pci_set_drvdata(pci, NULL);}static struct pci_driver driver = {	.name = "ATI IXP AC97 controller",	.id_table = snd_atiixp_ids,	.probe = snd_atiixp_probe,	.remove = __devexit_p(snd_atiixp_remove),	SND_PCI_PM_CALLBACKS};static int __init alsa_card_atiixp_init(void){	return pci_module_init(&driver);}static void __exit alsa_card_atiixp_exit(void){	pci_unregister_driver(&driver);}module_init(alsa_card_atiixp_init)module_exit(alsa_card_atiixp_exit)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -