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

📄 nm256.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}/*  * See if the signature left by the NM256 BIOS is intact; if so, we use * the associated address as the end of our audio buffer in the video * RAM. */static int __devinitsnd_nm256_peek_for_sig(struct nm256 *chip){	/* The signature is located 1K below the end of video RAM.  */	void __iomem *temp;	/* Default buffer end is 5120 bytes below the top of RAM.  */	unsigned long pointer_found = chip->buffer_end - 0x1400;	u32 sig;	temp = ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16);	if (temp == NULL) {		snd_printk(KERN_ERR "Unable to scan for card signature in video RAM\n");		return -EBUSY;	}	sig = readl(temp);	if ((sig & NM_SIG_MASK) == NM_SIGNATURE) {		u32 pointer = readl(temp + 4);		/*		 * If it's obviously invalid, don't use it		 */		if (pointer == 0xffffffff ||		    pointer < chip->buffer_size ||		    pointer > chip->buffer_end) {			snd_printk(KERN_ERR "invalid signature found: 0x%x\n", pointer);			iounmap(temp);			return -ENODEV;		} else {			pointer_found = pointer;			printk(KERN_INFO "nm256: found card signature in video RAM: 0x%x\n",			       pointer);		}	}	iounmap(temp);	chip->buffer_end = pointer_found;	return 0;}#ifdef CONFIG_PM/* * APM event handler, so the card is properly reinitialized after a power * event. */static int nm256_suspend(struct pci_dev *pci, pm_message_t state){	struct snd_card *card = pci_get_drvdata(pci);	struct nm256 *chip = card->private_data;	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	snd_pcm_suspend_all(chip->pcm);	snd_ac97_suspend(chip->ac97);	chip->coeffs_current = 0;	pci_disable_device(pci);	pci_save_state(pci);	pci_set_power_state(pci, pci_choose_state(pci, state));	return 0;}static int nm256_resume(struct pci_dev *pci){	struct snd_card *card = pci_get_drvdata(pci);	struct nm256 *chip = card->private_data;	int i;	/* Perform a full reset on the hardware */	chip->in_resume = 1;	pci_set_power_state(pci, PCI_D0);	pci_restore_state(pci);	if (pci_enable_device(pci) < 0) {		printk(KERN_ERR "nm256: pci_enable_device failed, "		       "disabling device\n");		snd_card_disconnect(card);		return -EIO;	}	pci_set_master(pci);	snd_nm256_init_chip(chip);	/* restore ac97 */	snd_ac97_resume(chip->ac97);	for (i = 0; i < 2; i++) {		struct nm256_stream *s = &chip->streams[i];		if (s->substream && s->suspended) {			spin_lock_irq(&chip->reg_lock);			snd_nm256_set_format(chip, s, s->substream);			spin_unlock_irq(&chip->reg_lock);		}	}	snd_power_change_state(card, SNDRV_CTL_POWER_D0);	chip->in_resume = 0;	return 0;}#endif /* CONFIG_PM */static int snd_nm256_free(struct nm256 *chip){	if (chip->streams[SNDRV_PCM_STREAM_PLAYBACK].running)		snd_nm256_playback_stop(chip);	if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)		snd_nm256_capture_stop(chip);	if (chip->irq >= 0)		synchronize_irq(chip->irq);	if (chip->cport)		iounmap(chip->cport);	if (chip->buffer)		iounmap(chip->buffer);	release_and_free_resource(chip->res_cport);	release_and_free_resource(chip->res_buffer);	if (chip->irq >= 0)		free_irq(chip->irq, chip);	pci_disable_device(chip->pci);	kfree(chip->ac97_regs);	kfree(chip);	return 0;}static int snd_nm256_dev_free(struct snd_device *device){	struct nm256 *chip = device->device_data;	return snd_nm256_free(chip);}static int __devinitsnd_nm256_create(struct snd_card *card, struct pci_dev *pci,		 struct nm256 **chip_ret){	struct nm256 *chip;	int err, pval;	static struct snd_device_ops ops = {		.dev_free =	snd_nm256_dev_free,	};	u32 addr;	*chip_ret = NULL;	if ((err = pci_enable_device(pci)) < 0)		return err;	chip = kzalloc(sizeof(*chip), GFP_KERNEL);	if (chip == NULL) {		pci_disable_device(pci);		return -ENOMEM;	}	chip->card = card;	chip->pci = pci;	chip->use_cache = use_cache;	spin_lock_init(&chip->reg_lock);	chip->irq = -1;	mutex_init(&chip->irq_mutex);	/* store buffer sizes in bytes */	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024;	chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capture_bufsize * 1024;	/* 	 * The NM256 has two memory ports.  The first port is nothing	 * more than a chunk of video RAM, which is used as the I/O ring	 * buffer.  The second port has the actual juicy stuff (like the	 * mixer and the playback engine control registers).	 */	chip->buffer_addr = pci_resource_start(pci, 0);	chip->cport_addr = pci_resource_start(pci, 1);	/* Init the memory port info.  */	/* remap control port (#2) */	chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE,					     card->driver);	if (chip->res_cport == NULL) {		snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n",			   chip->cport_addr, NM_PORT2_SIZE);		err = -EBUSY;		goto __error;	}	chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE);	if (chip->cport == NULL) {		snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr);		err = -ENOMEM;		goto __error;	}	if (!strcmp(card->driver, "NM256AV")) {		/* Ok, try to see if this is a non-AC97 version of the hardware. */		pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE);		if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {			if (! force_ac97) {				printk(KERN_ERR "nm256: no ac97 is found!\n");				printk(KERN_ERR "  force the driver to load by "				       "passing in the module parameter\n");				printk(KERN_ERR "    force_ac97=1\n");				printk(KERN_ERR "  or try sb16, opl3sa2, or "				       "cs423x drivers instead.\n");				err = -ENXIO;				goto __error;			}		}		chip->buffer_end = 2560 * 1024;		chip->interrupt = snd_nm256_interrupt;		chip->mixer_status_offset = NM_MIXER_STATUS_OFFSET;		chip->mixer_status_mask = NM_MIXER_READY_MASK;	} else {		/* Not sure if there is any relevant detect for the ZX or not.  */		if (snd_nm256_readb(chip, 0xa0b) != 0)			chip->buffer_end = 6144 * 1024;		else			chip->buffer_end = 4096 * 1024;		chip->interrupt = snd_nm256_interrupt_zx;		chip->mixer_status_offset = NM2_MIXER_STATUS_OFFSET;		chip->mixer_status_mask = NM2_MIXER_READY_MASK;	}		chip->buffer_size = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize +		chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize;	if (chip->use_cache)		chip->buffer_size += NM_TOTAL_COEFF_COUNT * 4;	else		chip->buffer_size += NM_MAX_PLAYBACK_COEF_SIZE + NM_MAX_RECORD_COEF_SIZE;	if (buffer_top >= chip->buffer_size && buffer_top < chip->buffer_end)		chip->buffer_end = buffer_top;	else {		/* get buffer end pointer from signature */		if ((err = snd_nm256_peek_for_sig(chip)) < 0)			goto __error;	}	chip->buffer_start = chip->buffer_end - chip->buffer_size;	chip->buffer_addr += chip->buffer_start;	printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n",	       chip->buffer_start, chip->buffer_end);	chip->res_buffer = request_mem_region(chip->buffer_addr,					      chip->buffer_size,					      card->driver);	if (chip->res_buffer == NULL) {		snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n",			   chip->buffer_addr, chip->buffer_size);		err = -EBUSY;		goto __error;	}	chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size);	if (chip->buffer == NULL) {		err = -ENOMEM;		snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr);		goto __error;	}	/* set offsets */	addr = chip->buffer_start;	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].buf = addr;	addr += chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize;	chip->streams[SNDRV_PCM_STREAM_CAPTURE].buf = addr;	addr += chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize;	if (chip->use_cache) {		chip->all_coeff_buf = addr;	} else {		chip->coeff_buf[SNDRV_PCM_STREAM_PLAYBACK] = addr;		addr += NM_MAX_PLAYBACK_COEF_SIZE;		chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;	}	/* Fixed setting. */	chip->mixer_base = NM_MIXER_OFFSET;	chip->coeffs_current = 0;	snd_nm256_init_chip(chip);	// pci_set_master(pci); /* needed? */		if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)		goto __error;	snd_card_set_dev(card, &pci->dev);	*chip_ret = chip;	return 0;__error:	snd_nm256_free(chip);	return err;}enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 };static struct snd_pci_quirk nm256_quirks[] __devinitdata = {	/* HP omnibook 4150 has cs4232 codec internally */	SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED),	/* Reset workarounds to avoid lock-ups */	SND_PCI_QUIRK(0x104d, 0x8041, "Sony PCG-F305", NM_RESET_WORKAROUND),	SND_PCI_QUIRK(0x1028, 0x0080, "Dell Latitude LS", NM_RESET_WORKAROUND),	SND_PCI_QUIRK(0x1028, 0x0091, "Dell Latitude CSx", NM_RESET_WORKAROUND_2),	{ } /* terminator */};static int __devinit snd_nm256_probe(struct pci_dev *pci,				     const struct pci_device_id *pci_id){	struct snd_card *card;	struct nm256 *chip;	int err;	const struct snd_pci_quirk *q;	q = snd_pci_quirk_lookup(pci, nm256_quirks);	if (q) {		snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);		switch (q->value) {		case NM_BLACKLISTED:			printk(KERN_INFO "nm256: The device is blacklisted. "			       "Loading stopped\n");			return -ENODEV;		case NM_RESET_WORKAROUND_2:			reset_workaround_2 = 1;			/* Fall-through */		case NM_RESET_WORKAROUND:			reset_workaround = 1;			break;		}	}	card = snd_card_new(index, id, THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	switch (pci->device) {	case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO:		strcpy(card->driver, "NM256AV");		break;	case PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO:		strcpy(card->driver, "NM256ZX");		break;	case PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO:		strcpy(card->driver, "NM256XL+");		break;	default:		snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device);		snd_card_free(card);		return -EINVAL;	}	if (vaio_hack)		buffer_top = 0x25a800;	/* this avoids conflicts with XFree86 server */	if (playback_bufsize < 4)		playback_bufsize = 4;	if (playback_bufsize > 128)		playback_bufsize = 128;	if (capture_bufsize < 4)		capture_bufsize = 4;	if (capture_bufsize > 128)		capture_bufsize = 128;	if ((err = snd_nm256_create(card, pci, &chip)) < 0) {		snd_card_free(card);		return err;	}	card->private_data = chip;	if (reset_workaround) {		snd_printdd(KERN_INFO "nm256: reset_workaround activated\n");		chip->reset_workaround = 1;	}	if (reset_workaround_2) {		snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n");		chip->reset_workaround_2 = 1;	}	if ((err = snd_nm256_pcm(chip, 0)) < 0 ||	    (err = snd_nm256_mixer(chip)) < 0) {		snd_card_free(card);		return err;	}	sprintf(card->shortname, "NeoMagic %s", card->driver);	sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %d",		card->shortname,		chip->buffer_addr, chip->cport_addr, chip->irq);	if ((err = snd_card_register(card)) < 0) {		snd_card_free(card);		return err;	}	pci_set_drvdata(pci, card);	return 0;}static void __devexit snd_nm256_remove(struct pci_dev *pci){	snd_card_free(pci_get_drvdata(pci));	pci_set_drvdata(pci, NULL);}static struct pci_driver driver = {	.name = "NeoMagic 256",	.id_table = snd_nm256_ids,	.probe = snd_nm256_probe,	.remove = __devexit_p(snd_nm256_remove),#ifdef CONFIG_PM	.suspend = nm256_suspend,	.resume = nm256_resume,#endif};static int __init alsa_card_nm256_init(void){	return pci_register_driver(&driver);}static void __exit alsa_card_nm256_exit(void){	pci_unregister_driver(&driver);}module_init(alsa_card_nm256_init)module_exit(alsa_card_nm256_exit)

⌨️ 快捷键说明

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