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

📄 via82xx_modem.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * create a pcm instance for via686a/b */static int __devinit snd_via686_pcm_new(struct via82xx_modem *chip){	struct snd_pcm *pcm;	int err;	chip->playback_devno = 0;	chip->capture_devno = 1;	chip->num_devs = 2;	chip->intr_mask = 0x330000; /* FLAGS | EOL for MR, MW */	err = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops);	pcm->dev_class = SNDRV_PCM_CLASS_MODEM;	pcm->private_data = chip;	strcpy(pcm->name, chip->card->shortname);	chip->pcms[0] = pcm;	init_viadev(chip, 0, VIA_REG_MO_STATUS, 0);	init_viadev(chip, 1, VIA_REG_MI_STATUS, 1);	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,							 snd_dma_pci_data(chip->pci),							 64*1024, 128*1024)) < 0)		return err;	return 0;}/* *  Mixer part */static void snd_via82xx_mixer_free_ac97_bus(struct snd_ac97_bus *bus){	struct via82xx_modem *chip = bus->private_data;	chip->ac97_bus = NULL;}static void snd_via82xx_mixer_free_ac97(struct snd_ac97 *ac97){	struct via82xx_modem *chip = ac97->private_data;	chip->ac97 = NULL;}static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip){	struct snd_ac97_template ac97;	int err;	static struct snd_ac97_bus_ops ops = {		.write = snd_via82xx_codec_write,		.read = snd_via82xx_codec_read,		.wait = snd_via82xx_codec_wait,	};	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0)		return err;	chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus;	chip->ac97_bus->clock = chip->ac97_clock;	memset(&ac97, 0, sizeof(ac97));	ac97.private_data = chip;	ac97.private_free = snd_via82xx_mixer_free_ac97;	ac97.pci = chip->pci;	ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;	ac97.num = chip->ac97_secondary;	if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)		return err;	return 0;}/* * proc interface */static void snd_via82xx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){	struct via82xx_modem *chip = entry->private_data;	int i;		snd_iprintf(buffer, "%s\n\n", chip->card->longname);	for (i = 0; i < 0xa0; i += 4) {		snd_iprintf(buffer, "%02x: %08x\n", i, inl(chip->port + i));	}}static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip){	struct snd_info_entry *entry;	if (! snd_card_proc_new(chip->card, "via82xx", &entry))		snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read);}/* * */static int snd_via82xx_chip_init(struct via82xx_modem *chip){	unsigned int val;	unsigned long end_time;	unsigned char pval;	pci_read_config_byte(chip->pci, VIA_MC97_CTRL, &pval);	if((pval & VIA_MC97_CTRL_INIT) != VIA_MC97_CTRL_INIT) {		pci_write_config_byte(chip->pci, 0x44, pval|VIA_MC97_CTRL_INIT);		udelay(100);	}	pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);	if (! (pval & VIA_ACLINK_C00_READY)) { /* codec not ready? */		/* deassert ACLink reset, force SYNC */		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,				      VIA_ACLINK_CTRL_ENABLE |				      VIA_ACLINK_CTRL_RESET |				      VIA_ACLINK_CTRL_SYNC);		udelay(100);#if 1 /* FIXME: should we do full reset here for all chip models? */		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, 0x00);		udelay(100);#else		/* deassert ACLink reset, force SYNC (warm AC'97 reset) */		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,				      VIA_ACLINK_CTRL_RESET|VIA_ACLINK_CTRL_SYNC);		udelay(2);#endif		/* ACLink on, deassert ACLink reset, VSR, SGD data out */		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);		udelay(100);	}		pci_read_config_byte(chip->pci, VIA_ACLINK_CTRL, &pval);	if ((pval & VIA_ACLINK_CTRL_INIT) != VIA_ACLINK_CTRL_INIT) {		/* ACLink on, deassert ACLink reset, VSR, SGD data out */		pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);		udelay(100);	}	/* wait until codec ready */	end_time = jiffies + msecs_to_jiffies(750);	do {		pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);		if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */			break;		schedule_timeout_uninterruptible(1);	} while (time_before(jiffies, end_time));	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)		snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val);	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |				 VIA_REG_AC97_SECONDARY_VALID |				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));	end_time = jiffies + msecs_to_jiffies(750);	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |				 VIA_REG_AC97_SECONDARY_VALID |				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));	do {		if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) {			chip->ac97_secondary = 1;			goto __ac97_ok2;		}		schedule_timeout_uninterruptible(1);	} while (time_before(jiffies, end_time));	/* This is ok, the most of motherboards have only one codec */      __ac97_ok2:	/* route FM trap to IRQ, disable FM trap */	// pci_write_config_byte(chip->pci, VIA_FM_NMI_CTRL, 0);	/* disable all GPI interrupts */	outl(0, VIAREG(chip, GPI_INTR));	return 0;}#ifdef CONFIG_PM/* * power management */static int snd_via82xx_suspend(struct pci_dev *pci, pm_message_t state){	struct snd_card *card = pci_get_drvdata(pci);	struct via82xx_modem *chip = card->private_data;	int i;	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	for (i = 0; i < 2; i++)		snd_pcm_suspend_all(chip->pcms[i]);	for (i = 0; i < chip->num_devs; i++)		snd_via82xx_channel_reset(chip, &chip->devs[i]);	synchronize_irq(chip->irq);	snd_ac97_suspend(chip->ac97);	pci_disable_device(pci);	pci_save_state(pci);	pci_set_power_state(pci, pci_choose_state(pci, state));	return 0;}static int snd_via82xx_resume(struct pci_dev *pci){	struct snd_card *card = pci_get_drvdata(pci);	struct via82xx_modem *chip = card->private_data;	int i;	pci_set_power_state(pci, PCI_D0);	pci_restore_state(pci);	if (pci_enable_device(pci) < 0) {		printk(KERN_ERR "via82xx-modem: pci_enable_device failed, "		       "disabling device\n");		snd_card_disconnect(card);		return -EIO;	}	pci_set_master(pci);	snd_via82xx_chip_init(chip);	snd_ac97_resume(chip->ac97);	for (i = 0; i < chip->num_devs; i++)		snd_via82xx_channel_reset(chip, &chip->devs[i]);	snd_power_change_state(card, SNDRV_CTL_POWER_D0);	return 0;}#endif /* CONFIG_PM */static int snd_via82xx_free(struct via82xx_modem *chip){	unsigned int i;	if (chip->irq < 0)		goto __end_hw;	/* disable interrupts */	for (i = 0; i < chip->num_devs; i++)		snd_via82xx_channel_reset(chip, &chip->devs[i]);	synchronize_irq(chip->irq);      __end_hw:	if (chip->irq >= 0)		free_irq(chip->irq, chip);	pci_release_regions(chip->pci);	pci_disable_device(chip->pci);	kfree(chip);	return 0;}static int snd_via82xx_dev_free(struct snd_device *device){	struct via82xx_modem *chip = device->device_data;	return snd_via82xx_free(chip);}static int __devinit snd_via82xx_create(struct snd_card *card,					struct pci_dev *pci,					int chip_type,					int revision,					unsigned int ac97_clock,					struct via82xx_modem ** r_via){	struct via82xx_modem *chip;	int err;        static struct snd_device_ops ops = {		.dev_free =	snd_via82xx_dev_free,        };	if ((err = pci_enable_device(pci)) < 0)		return err;	if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) {		pci_disable_device(pci);		return -ENOMEM;	}	spin_lock_init(&chip->reg_lock);	chip->card = card;	chip->pci = pci;	chip->irq = -1;	if ((err = pci_request_regions(pci, card->driver)) < 0) {		kfree(chip);		pci_disable_device(pci);		return err;	}	chip->port = pci_resource_start(pci, 0);	if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,			card->driver, chip)) {		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);		snd_via82xx_free(chip);		return -EBUSY;	}	chip->irq = pci->irq;	if (ac97_clock >= 8000 && ac97_clock <= 48000)		chip->ac97_clock = ac97_clock;	synchronize_irq(chip->irq);	if ((err = snd_via82xx_chip_init(chip)) < 0) {		snd_via82xx_free(chip);		return err;	}	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {		snd_via82xx_free(chip);		return err;	}	/* The 8233 ac97 controller does not implement the master bit	 * in the pci command register. IMHO this is a violation of the PCI spec.	 * We call pci_set_master here because it does not hurt. */	pci_set_master(pci);	snd_card_set_dev(card, &pci->dev);	*r_via = chip;	return 0;}static int __devinit snd_via82xx_probe(struct pci_dev *pci,				       const struct pci_device_id *pci_id){	struct snd_card *card;	struct via82xx_modem *chip;	int chip_type = 0, card_type;	unsigned int i;	int err;	card = snd_card_new(index, id, THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	card_type = pci_id->driver_data;	switch (card_type) {	case TYPE_CARD_VIA82XX_MODEM:		strcpy(card->driver, "VIA82XX-MODEM");		sprintf(card->shortname, "VIA 82XX modem");		break;	default:		snd_printk(KERN_ERR "invalid card type %d\n", card_type);		err = -EINVAL;		goto __error;	}			if ((err = snd_via82xx_create(card, pci, chip_type, pci->revision,				      ac97_clock, &chip)) < 0)		goto __error;	card->private_data = chip;	if ((err = snd_via82xx_mixer_new(chip)) < 0)		goto __error;	if ((err = snd_via686_pcm_new(chip)) < 0 )		goto __error;	/* disable interrupts */	for (i = 0; i < chip->num_devs; i++)		snd_via82xx_channel_reset(chip, &chip->devs[i]);	sprintf(card->longname, "%s at 0x%lx, irq %d",		card->shortname, chip->port, chip->irq);	snd_via82xx_proc_init(chip);	if ((err = snd_card_register(card)) < 0) {		snd_card_free(card);		return err;	}	pci_set_drvdata(pci, card);	return 0; __error:	snd_card_free(card);	return err;}static void __devexit snd_via82xx_remove(struct pci_dev *pci){	snd_card_free(pci_get_drvdata(pci));	pci_set_drvdata(pci, NULL);}static struct pci_driver driver = {	.name = "VIA 82xx Modem",	.id_table = snd_via82xx_modem_ids,	.probe = snd_via82xx_probe,	.remove = __devexit_p(snd_via82xx_remove),#ifdef CONFIG_PM	.suspend = snd_via82xx_suspend,	.resume = snd_via82xx_resume,#endif};static int __init alsa_card_via82xx_init(void){	return pci_register_driver(&driver);}static void __exit alsa_card_via82xx_exit(void){	pci_unregister_driver(&driver);}module_init(alsa_card_via82xx_init)module_exit(alsa_card_via82xx_exit)

⌨️ 快捷键说明

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