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

📄 amd7930.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_amd7930_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_amd7930_capture_ops);	pcm->private_data = amd;	pcm->info_flags = 0;	strcpy(pcm->name, amd->card->shortname);	amd->pcm = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,					      snd_dma_continuous_data(GFP_KERNEL),					      64*1024, 64*1024);	return 0;}#define VOLUME_MONITOR	0#define VOLUME_CAPTURE	1#define VOLUME_PLAYBACK	2static int snd_amd7930_info_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo){	int type = kctl->private_value;	snd_assert(type == VOLUME_MONITOR ||		   type == VOLUME_CAPTURE ||		   type == VOLUME_PLAYBACK, return -EINVAL);	(void) type;	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 255;	return 0;}static int snd_amd7930_get_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol){	struct snd_amd7930 *amd = snd_kcontrol_chip(kctl);	int type = kctl->private_value;	int *swval;	snd_assert(type == VOLUME_MONITOR ||		   type == VOLUME_CAPTURE ||		   type == VOLUME_PLAYBACK, return -EINVAL);	switch (type) {	case VOLUME_MONITOR:		swval = &amd->mgain;		break;	case VOLUME_CAPTURE:		swval = &amd->rgain;		break;	case VOLUME_PLAYBACK:	default:		swval = &amd->pgain;		break;	};	ucontrol->value.integer.value[0] = *swval;	return 0;}static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol){	struct snd_amd7930 *amd = snd_kcontrol_chip(kctl);	unsigned long flags;	int type = kctl->private_value;	int *swval, change;	snd_assert(type == VOLUME_MONITOR ||		   type == VOLUME_CAPTURE ||		   type == VOLUME_PLAYBACK, return -EINVAL);	switch (type) {	case VOLUME_MONITOR:		swval = &amd->mgain;		break;	case VOLUME_CAPTURE:		swval = &amd->rgain;		break;	case VOLUME_PLAYBACK:	default:		swval = &amd->pgain;		break;	};	spin_lock_irqsave(&amd->lock, flags);	if (*swval != ucontrol->value.integer.value[0]) {		*swval = ucontrol->value.integer.value[0];		__amd7930_update_map(amd);		change = 1;	} else		change = 0;	spin_unlock_irqrestore(&amd->lock, flags);	return change;}static struct snd_kcontrol_new amd7930_controls[] __devinitdata = {	{		.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,		.name		=	"Monitor Volume",		.index		=	0,		.info		=	snd_amd7930_info_volume,		.get		=	snd_amd7930_get_volume,		.put		=	snd_amd7930_put_volume,		.private_value	=	VOLUME_MONITOR,	},	{		.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,		.name		=	"Capture Volume",		.index		=	0,		.info		=	snd_amd7930_info_volume,		.get		=	snd_amd7930_get_volume,		.put		=	snd_amd7930_put_volume,		.private_value	=	VOLUME_CAPTURE,	},	{		.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,		.name		=	"Playback Volume",		.index		=	0,		.info		=	snd_amd7930_info_volume,		.get		=	snd_amd7930_get_volume,		.put		=	snd_amd7930_put_volume,		.private_value	=	VOLUME_PLAYBACK,	},};static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd){	struct snd_card *card;	int idx, err;	snd_assert(amd != NULL && amd->card != NULL, return -EINVAL);	card = amd->card;	strcpy(card->mixername, card->shortname);	for (idx = 0; idx < ARRAY_SIZE(amd7930_controls); idx++) {		if ((err = snd_ctl_add(card,				       snd_ctl_new1(&amd7930_controls[idx], amd))) < 0)			return err;	}	return 0;}static int snd_amd7930_free(struct snd_amd7930 *amd){	amd7930_idle(amd);	if (amd->irq)		free_irq(amd->irq, amd);	if (amd->regs)		sbus_iounmap(amd->regs, amd->regs_size);	kfree(amd);	return 0;}static int snd_amd7930_dev_free(struct snd_device *device){	struct snd_amd7930 *amd = device->device_data;	return snd_amd7930_free(amd);}static struct snd_device_ops snd_amd7930_dev_ops = {	.dev_free	=	snd_amd7930_dev_free,};static int __devinit snd_amd7930_create(struct snd_card *card,					struct resource *rp,					unsigned int reg_size,					int irq, int dev,					struct snd_amd7930 **ramd){	unsigned long flags;	struct snd_amd7930 *amd;	int err;	*ramd = NULL;	amd = kzalloc(sizeof(*amd), GFP_KERNEL);	if (amd == NULL)		return -ENOMEM;	spin_lock_init(&amd->lock);	amd->card = card;	amd->regs_size = reg_size;	amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");	if (!amd->regs) {		snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);		return -EIO;	}	amd7930_idle(amd);	if (request_irq(irq, snd_amd7930_interrupt,			IRQF_DISABLED | IRQF_SHARED, "amd7930", amd)) {		snd_printk("amd7930-%d: Unable to grab IRQ %d\n",			   dev, irq);		snd_amd7930_free(amd);		return -EBUSY;	}	amd->irq = irq;	amd7930_enable_ints(amd);	spin_lock_irqsave(&amd->lock, flags);	amd->rgain = 128;	amd->pgain = 200;	amd->mgain = 0;	memset(&amd->map, 0, sizeof(amd->map));	amd->map.mmr1 = (AM_MAP_MMR1_GX | AM_MAP_MMR1_GER |			 AM_MAP_MMR1_GR | AM_MAP_MMR1_STG);	amd->map.mmr2 = (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);	__amd7930_update_map(amd);	/* Always MUX audio (Ba) to channel Bb. */	sbus_writeb(AMR_MUX_MCR1, amd->regs + AMD7930_CR);	sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4),		    amd->regs + AMD7930_DR);	spin_unlock_irqrestore(&amd->lock, flags);	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,				  amd, &snd_amd7930_dev_ops)) < 0) {		snd_amd7930_free(amd);		return err;	}	*ramd = amd;	return 0;}static int __devinit amd7930_attach_common(struct resource *rp, int irq){	static int dev_num;	struct snd_card *card;	struct snd_amd7930 *amd;	int err;	if (dev_num >= SNDRV_CARDS)		return -ENODEV;	if (!enable[dev_num]) {		dev_num++;		return -ENOENT;	}	card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	strcpy(card->driver, "AMD7930");	strcpy(card->shortname, "Sun AMD7930");	sprintf(card->longname, "%s at 0x%02lx:0x%08Lx, irq %d",		card->shortname,		rp->flags & 0xffL,		(unsigned long long)rp->start,		irq);	if ((err = snd_amd7930_create(card, rp,				      (rp->end - rp->start) + 1,				      irq, dev_num, &amd)) < 0)		goto out_err;	if ((err = snd_amd7930_pcm(amd)) < 0)		goto out_err;	if ((err = snd_amd7930_mixer(amd)) < 0)		goto out_err;	if ((err = snd_card_register(card)) < 0)		goto out_err;	amd->next = amd7930_list;	amd7930_list = amd;	dev_num++;	return 0;out_err:	snd_card_free(card);	return err;}static int __devinit amd7930_obio_attach(struct device_node *dp){	const struct linux_prom_registers *regs;	const struct linux_prom_irqs *irqp;	struct resource res, *rp;	int len;	irqp = of_get_property(dp, "intr", &len);	if (!irqp) {		snd_printk("%s: Firmware node lacks IRQ property.\n",			   dp->full_name);		return -ENODEV;	}	regs = of_get_property(dp, "reg", &len);	if (!regs) {		snd_printk("%s: Firmware node lacks register property.\n",			   dp->full_name);		return -ENODEV;	}	rp = &res;	rp->start = regs->phys_addr;	rp->end = rp->start + regs->reg_size - 1;	rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);	return amd7930_attach_common(rp, irqp->pri);}static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match){	struct sbus_dev *sdev = to_sbus_device(&dev->dev);	return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);}static struct of_device_id amd7930_match[] = {	{		.name = "audio",	},	{},};static struct of_platform_driver amd7930_sbus_driver = {	.name		= "audio",	.match_table	= amd7930_match,	.probe		= amd7930_sbus_probe,};static int __init amd7930_init(void){	struct device_node *dp;	/* Try to find the sun4c "audio" node first. */	dp = of_find_node_by_path("/");	dp = dp->child;	while (dp) {		if (!strcmp(dp->name, "audio"))			amd7930_obio_attach(dp);		dp = dp->sibling;	}	/* Probe each SBUS for amd7930 chips. */	return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);}static void __exit amd7930_exit(void){	struct snd_amd7930 *p = amd7930_list;	while (p != NULL) {		struct snd_amd7930 *next = p->next;		snd_card_free(p->card);		p = next;	}	amd7930_list = NULL;	of_unregister_driver(&amd7930_sbus_driver);}module_init(amd7930_init);module_exit(amd7930_exit);

⌨️ 快捷键说明

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