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

📄 ali5451.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int __devinit snd_ali_build_pcms(struct snd_ali *codec){	int i, err;	for (i = 0; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms); i++) {		err = snd_ali_pcm(codec, i, &ali_pcms[i]);		if (err < 0)			return err;	}	return 0;}#define ALI5451_SPDIF(xname, xindex, value) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\.info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \.put = snd_ali5451_spdif_put, .private_value = value}#define snd_ali5451_spdif_info		snd_ctl_boolean_mono_infostatic int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_ali *codec = kcontrol->private_data;	unsigned int enable;	enable = ucontrol->value.integer.value[0] ? 1 : 0;	spin_lock_irq(&codec->reg_lock);	switch (kcontrol->private_value) {	case 0:		enable = (codec->spdif_mask & 0x02) ? 1 : 0;		break;	case 1:		enable = ((codec->spdif_mask & 0x02) &&			  (codec->spdif_mask & 0x04)) ? 1 : 0;		break;	case 2:		enable = (codec->spdif_mask & 0x01) ? 1 : 0;		break;	default:		break;	}	ucontrol->value.integer.value[0] = enable;	spin_unlock_irq(&codec->reg_lock);	return 0;}static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_ali *codec = kcontrol->private_data;	unsigned int change = 0, enable = 0;	enable = ucontrol->value.integer.value[0] ? 1 : 0;	spin_lock_irq(&codec->reg_lock);	switch (kcontrol->private_value) {	case 0:		change = (codec->spdif_mask & 0x02) ? 1 : 0;		change = change ^ enable;		if (change) {			if (enable) {				codec->spdif_mask |= 0x02;				snd_ali_enable_spdif_out(codec);			} else {				codec->spdif_mask &= ~(0x02);				codec->spdif_mask &= ~(0x04);				snd_ali_disable_spdif_out(codec);			}		}		break;	case 1: 		change = (codec->spdif_mask & 0x04) ? 1 : 0;		change = change ^ enable;		if (change && (codec->spdif_mask & 0x02)) {			if (enable) {				codec->spdif_mask |= 0x04;				snd_ali_enable_spdif_chnout(codec);			} else {				codec->spdif_mask &= ~(0x04);				snd_ali_disable_spdif_chnout(codec);			}		}		break;	case 2:		change = (codec->spdif_mask & 0x01) ? 1 : 0;		change = change ^ enable;		if (change) {			if (enable) {				codec->spdif_mask |= 0x01;				snd_ali_enable_spdif_in(codec);			} else {				codec->spdif_mask &= ~(0x01);				snd_ali_disable_spdif_in(codec);			}		}		break;	default:		break;	}	spin_unlock_irq(&codec->reg_lock);		return change;}static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = {	/* spdif aplayback switch */	/* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */	ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0),	/* spdif out to spdif channel */	ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1),	/* spdif in from spdif channel */	ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)};static int __devinit snd_ali_mixer(struct snd_ali * codec){	struct snd_ac97_template ac97;	unsigned int idx;	int i, err;	static struct snd_ac97_bus_ops ops = {		.write = snd_ali_codec_write,		.read = snd_ali_codec_read,	};	err = snd_ac97_bus(codec->card, 0, &ops, codec, &codec->ac97_bus);	if (err < 0)		return err;	memset(&ac97, 0, sizeof(ac97));	ac97.private_data = codec;	for (i = 0; i < codec->num_of_codecs; i++) {		ac97.num = i;		err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i]);		if (err < 0) {			snd_printk(KERN_ERR				   "ali mixer %d creating error.\n", i);			if (i == 0)				return err;			codec->num_of_codecs = 1;			break;		}	}	if (codec->spdif_support) {		for (idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) {			err = snd_ctl_add(codec->card,					  snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec));			if (err < 0)				return err;		}	}	return 0;}#ifdef CONFIG_PMstatic int ali_suspend(struct pci_dev *pci, pm_message_t state){	struct snd_card *card = pci_get_drvdata(pci);	struct snd_ali *chip = card->private_data;	struct snd_ali_image *im;	int i, j;	im = chip->image;	if (!im)		return 0;	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	for (i = 0; i < chip->num_of_codecs; i++) {		snd_pcm_suspend_all(chip->pcm[i]);		snd_ac97_suspend(chip->ac97[i]);	}	spin_lock_irq(&chip->reg_lock);		im->regs[ALI_MISCINT >> 2] = inl(ALI_REG(chip, ALI_MISCINT));	/* im->regs[ALI_START >> 2] = inl(ALI_REG(chip, ALI_START)); */	im->regs[ALI_STOP >> 2] = inl(ALI_REG(chip, ALI_STOP));		/* disable all IRQ bits */	outl(0, ALI_REG(chip, ALI_MISCINT));		for (i = 0; i < ALI_GLOBAL_REGS; i++) {			if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP))			continue;		im->regs[i] = inl(ALI_REG(chip, i*4));	}		for (i = 0; i < ALI_CHANNELS; i++) {		outb(i, ALI_REG(chip, ALI_GC_CIR));		for (j = 0; j < ALI_CHANNEL_REGS; j++) 			im->channel_regs[i][j] = inl(ALI_REG(chip, j*4 + 0xe0));	}	/* stop all HW channel */	outl(0xffffffff, ALI_REG(chip, ALI_STOP));	spin_unlock_irq(&chip->reg_lock);	pci_disable_device(pci);	pci_save_state(pci);	pci_set_power_state(pci, pci_choose_state(pci, state));	return 0;}static int ali_resume(struct pci_dev *pci){	struct snd_card *card = pci_get_drvdata(pci);	struct snd_ali *chip = card->private_data;	struct snd_ali_image *im;	int i, j;	im = chip->image;	if (!im)		return 0;	pci_set_power_state(pci, PCI_D0);	pci_restore_state(pci);	if (pci_enable_device(pci) < 0) {		printk(KERN_ERR "ali5451: pci_enable_device failed, "		       "disabling device\n");		snd_card_disconnect(card);		return -EIO;	}	pci_set_master(pci);	spin_lock_irq(&chip->reg_lock);		for (i = 0; i < ALI_CHANNELS; i++) {		outb(i, ALI_REG(chip, ALI_GC_CIR));		for (j = 0; j < ALI_CHANNEL_REGS; j++) 			outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0));	}		for (i = 0; i < ALI_GLOBAL_REGS; i++) {			if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) ||		    (i*4 == ALI_START))			continue;		outl(im->regs[i], ALI_REG(chip, i*4));	}		/* start HW channel */	outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START));	/* restore IRQ enable bits */	outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT));		spin_unlock_irq(&chip->reg_lock);	for (i = 0 ; i < chip->num_of_codecs; i++)		snd_ac97_resume(chip->ac97[i]);		snd_power_change_state(card, SNDRV_CTL_POWER_D0);	return 0;}#endif /* CONFIG_PM */static int snd_ali_free(struct snd_ali * codec){	if (codec->hw_initialized)		snd_ali_disable_address_interrupt(codec);	if (codec->irq >= 0) {		synchronize_irq(codec->irq);		free_irq(codec->irq, codec);	}	if (codec->port)		pci_release_regions(codec->pci);	pci_disable_device(codec->pci);#ifdef CONFIG_PM	kfree(codec->image);#endif	pci_dev_put(codec->pci_m1533);	pci_dev_put(codec->pci_m7101);	kfree(codec);	return 0;}static int snd_ali_chip_init(struct snd_ali *codec){	unsigned int legacy;	unsigned char temp;	struct pci_dev *pci_dev;	snd_ali_printk("chip initializing ... \n");	if (snd_ali_reset_5451(codec)) {		snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.\n");		return -1;	}	if (codec->revision == ALI_5451_V02) {        	pci_dev = codec->pci_m1533;		pci_read_config_byte(pci_dev, 0x59, &temp);		temp |= 0x80;		pci_write_config_byte(pci_dev, 0x59, temp);			pci_dev = codec->pci_m7101;		pci_read_config_byte(pci_dev, 0xb8, &temp);		temp |= 0x20;		pci_write_config_byte(pci_dev, 0xB8, temp);	}	pci_read_config_dword(codec->pci, 0x44, &legacy);	legacy &= 0xff00ff00;	legacy |= 0x000800aa;	pci_write_config_dword(codec->pci, 0x44, legacy);	outl(0x80000001, ALI_REG(codec, ALI_GLOBAL_CONTROL));	outl(0x00000000, ALI_REG(codec, ALI_AINTEN));	outl(0xffffffff, ALI_REG(codec, ALI_AINT));	outl(0x00000000, ALI_REG(codec, ALI_VOLUME));	outb(0x10, 	 ALI_REG(codec, ALI_MPUR2));	codec->ac97_ext_id = snd_ali_codec_peek(codec, 0, AC97_EXTENDED_ID);	codec->ac97_ext_status = snd_ali_codec_peek(codec, 0,						    AC97_EXTENDED_STATUS);	if (codec->spdif_support) {		snd_ali_enable_spdif_out(codec);		codec->spdif_mask = 0x00000002;	}	codec->num_of_codecs = 1;	/* secondary codec - modem */	if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) {		codec->num_of_codecs++;		outl(inl(ALI_REG(codec, ALI_SCTRL)) |		     (ALI_SCTRL_LINE_IN2 | ALI_SCTRL_GPIO_IN2 |		      ALI_SCTRL_LINE_OUT_EN),		     ALI_REG(codec, ALI_SCTRL));	}	snd_ali_printk("chip initialize succeed.\n");	return 0;}/* proc for register dump */static void snd_ali_proc_read(struct snd_info_entry *entry,			      struct snd_info_buffer *buf){	struct snd_ali *codec = entry->private_data;	int i;	for (i = 0; i < 256 ; i+= 4)		snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i)));}static void __devinit snd_ali_proc_init(struct snd_ali *codec){	struct snd_info_entry *entry;	if (!snd_card_proc_new(codec->card, "ali5451", &entry))		snd_info_set_text_ops(entry, codec, snd_ali_proc_read);}static int __devinit snd_ali_resources(struct snd_ali *codec){	int err;	snd_ali_printk("resouces allocation ...\n");	err = pci_request_regions(codec->pci, "ALI 5451");	if (err < 0)		return err;	codec->port = pci_resource_start(codec->pci, 0);	if (request_irq(codec->pci->irq, snd_ali_card_interrupt,			IRQF_SHARED, "ALI 5451", codec)) {		snd_printk(KERN_ERR "Unable to request irq.\n");		return -EBUSY;	}	codec->irq = codec->pci->irq;	snd_ali_printk("resouces allocated.\n");	return 0;}static int snd_ali_dev_free(struct snd_device *device){	struct snd_ali *codec = device->device_data;	snd_ali_free(codec);	return 0;}static int __devinit snd_ali_create(struct snd_card *card,				    struct pci_dev *pci,				    int pcm_streams,				    int spdif_support,				    struct snd_ali ** r_ali){	struct snd_ali *codec;	int i, err;	unsigned short cmdw;	static struct snd_device_ops ops = {		.dev_free = snd_ali_dev_free,        };	*r_ali = NULL;	snd_ali_printk("creating ...\n");	/* enable PCI device */	err = pci_enable_device(pci);	if (err < 0)		return err;	/* check, if we can restrict PCI DMA transfers to 31 bits */	if (pci_set_dma_mask(pci, DMA_31BIT_MASK) < 0 ||	    pci_set_consistent_dma_mask(pci, DMA_31BIT_MASK) < 0) {		snd_printk(KERN_ERR "architecture does not support "			   "31bit PCI busmaster DMA\n");		pci_disable_device(pci);		return -ENXIO;	}	codec = kzalloc(sizeof(*codec), GFP_KERNEL);	if (!codec) {		pci_disable_device(pci);		return -ENOMEM;	}	spin_lock_init(&codec->reg_lock);	spin_lock_init(&codec->voice_alloc);	codec->card = card;	codec->pci = pci;	codec->irq = -1;	codec->revision = pci->revision;	codec->spdif_support = spdif_support;	if (pcm_streams < 1)		pcm_streams = 1;	if (pcm_streams > 32)		pcm_streams = 32;		pci_set_master(pci);	pci_read_config_word(pci, PCI_COMMAND, &cmdw);	if ((cmdw & PCI_COMMAND_IO) != PCI_COMMAND_IO) {		cmdw |= PCI_COMMAND_IO;		pci_write_config_word(pci, PCI_COMMAND, cmdw);	}	pci_set_master(pci);		if (snd_ali_resources(codec)) {		snd_ali_free(codec);		return -EBUSY;	}	synchronize_irq(pci->irq);	codec->synth.chmap = 0;	codec->synth.chcnt = 0;	codec->spdif_mask = 0;	codec->synth.synthcount = 0;	if (codec->revision == ALI_5451_V02)		codec->chregs.regs.ac97read = ALI_AC97_WRITE;	else		codec->chregs.regs.ac97read = ALI_AC97_READ;	codec->chregs.regs.ac97write = ALI_AC97_WRITE;	codec->chregs.regs.start  = ALI_START;	codec->chregs.regs.stop   = ALI_STOP;	codec->chregs.regs.aint   = ALI_AINT;	codec->chregs.regs.ainten = ALI_AINTEN;	codec->chregs.data.start  = 0x00;	codec->chregs.data.stop   = 0x00;	codec->chregs.data.aint   = 0x00;	codec->chregs.data.ainten = 0x00;	/* M1533: southbridge */	codec->pci_m1533 = pci_get_device(0x10b9, 0x1533, NULL);	if (!codec->pci_m1533) {		snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n");		snd_ali_free(codec);		return -ENODEV;	}	/* M7101: power management */	codec->pci_m7101 = pci_get_device(0x10b9, 0x7101, NULL);	if (!codec->pci_m7101 && codec->revision == ALI_5451_V02) {		snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n");		snd_ali_free(codec);		return -ENODEV;	}	snd_ali_printk("snd_device_new is called.\n");	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops);	if (err < 0) {		snd_ali_free(codec);		return err;	}	snd_card_set_dev(card, &pci->dev);	/* initialise synth voices*/	for (i = 0; i < ALI_CHANNELS; i++)		codec->synth.voices[i].number = i;	err = snd_ali_chip_init(codec);	if (err < 0) {		snd_printk(KERN_ERR "ali create: chip init error.\n");		return err;	}#ifdef CONFIG_PM	codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);	if (!codec->image)		snd_printk(KERN_WARNING "can't allocate apm buffer\n");#endif	snd_ali_enable_address_interrupt(codec);	codec->hw_initialized = 1;	*r_ali = codec;	snd_ali_printk("created.\n");	return 0;}static int __devinit snd_ali_probe(struct pci_dev *pci,				   const struct pci_device_id *pci_id){	struct snd_card *card;	struct snd_ali *codec;	int err;	snd_ali_printk("probe ...\n");	card = snd_card_new(index, id, THIS_MODULE, 0);	if (!card)		return -ENOMEM;	err = snd_ali_create(card, pci, pcm_channels, spdif, &codec);	if (err < 0)		goto error;	card->private_data = codec;	snd_ali_printk("mixer building ...\n");	err = snd_ali_mixer(codec);	if (err < 0)		goto error;		snd_ali_printk("pcm building ...\n");	err = snd_ali_build_pcms(codec);	if (err < 0)		goto error;	snd_ali_proc_init(codec);	strcpy(card->driver, "ALI5451");	strcpy(card->shortname, "ALI 5451");		sprintf(card->longname, "%s at 0x%lx, irq %i",		card->shortname, codec->port, codec->irq);	snd_ali_printk("register card.\n");	err = snd_card_register(card);	if (err < 0)		goto error;	pci_set_drvdata(pci, card);	return 0; error:	snd_card_free(card);	return err;}static void __devexit snd_ali_remove(struct pci_dev *pci){	snd_card_free(pci_get_drvdata(pci));	pci_set_drvdata(pci, NULL);}static struct pci_driver driver = {	.name = "ALI 5451",	.id_table = snd_ali_ids,	.probe = snd_ali_probe,	.remove = __devexit_p(snd_ali_remove),#ifdef CONFIG_PM	.suspend = ali_suspend,	.resume = ali_resume,#endif};                                static int __init alsa_card_ali_init(void){	return pci_register_driver(&driver);}static void __exit alsa_card_ali_exit(void){	pci_unregister_driver(&driver);}module_init(alsa_card_ali_init)module_exit(alsa_card_ali_exit)

⌨️ 快捷键说明

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