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

📄 nm256.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
 * if it timed out. */static intsnd_nm256_ac97_ready(nm256_t *chip){	int timeout = 10;	u32 testaddr;	u16 testb;	testaddr = chip->mixer_status_offset;	testb = chip->mixer_status_mask;	/* 	 * Loop around waiting for the mixer to become ready. 	 */	while (timeout-- > 0) {		if ((snd_nm256_readw(chip, testaddr) & testb) == 0)			return 1;		udelay(100);	}	return 0;}/* */static unsigned shortsnd_nm256_ac97_read(ac97_t *ac97, unsigned short reg){	nm256_t *chip = ac97->private_data;	int res;	if (reg >= 128)		return 0;	if (! snd_nm256_ac97_ready(chip))		return 0;	res = snd_nm256_readw(chip, chip->mixer_base + reg);	/* Magic delay.  Bleah yucky.  */	msleep(1);	return res;}/*  */static voidsnd_nm256_ac97_write(ac97_t *ac97,		     unsigned short reg, unsigned short val){	nm256_t *chip = ac97->private_data;	int tries = 2;	u32 base;	base = chip->mixer_base;	snd_nm256_ac97_ready(chip);	/* Wait for the write to take, too. */	while (tries-- > 0) {		snd_nm256_writew(chip, base + reg, val);		msleep(1);  /* a little delay here seems better.. */		if (snd_nm256_ac97_ready(chip))			return;	}	snd_printd("nm256: ac97 codec not ready..\n");}/* initialize the ac97 into a known state */static voidsnd_nm256_ac97_reset(ac97_t *ac97){	nm256_t *chip = ac97->private_data;	/* Reset the mixer.  'Tis magic!  */	snd_nm256_writeb(chip, 0x6c0, 1);	if (! chip->reset_workaround) {		/* Dell latitude LS will lock up by this */		snd_nm256_writeb(chip, 0x6cc, 0x87);	}	if (! chip->reset_workaround_2) {		/* Dell latitude CSx will lock up by this */		snd_nm256_writeb(chip, 0x6cc, 0x80);		snd_nm256_writeb(chip, 0x6cc, 0x0);	}}/* create an ac97 mixer interface */static int __devinitsnd_nm256_mixer(nm256_t *chip){	ac97_bus_t *pbus;	ac97_template_t ac97;	int i, err;	static ac97_bus_ops_t ops = {		.reset = snd_nm256_ac97_reset,		.write = snd_nm256_ac97_write,		.read = snd_nm256_ac97_read,	};	/* looks like nm256 hangs up when unexpected registers are touched... */	static int mixer_regs[] = {		AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO,		AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,		AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,		AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,		/*AC97_EXTENDED_ID,*/		AC97_VENDOR_ID1, AC97_VENDOR_ID2,		-1	};	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)		return err;	memset(&ac97, 0, sizeof(ac97));	ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */	ac97.limited_regs = 1;	for (i = 0; mixer_regs[i] >= 0; i++)		set_bit(mixer_regs[i], ac97.reg_accessed);	ac97.private_data = chip;	pbus->no_vra = 1;	err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);	if (err < 0)		return err;	if (! (chip->ac97->id & (0xf0000000))) {		/* looks like an invalid id */		sprintf(chip->card->mixername, "%s AC97", chip->card->driver);	}	return 0;}/*  * 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(nm256_t *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(snd_card_t *card, pm_message_t state){	nm256_t *chip = card->pm_private_data;	snd_pcm_suspend_all(chip->pcm);	snd_ac97_suspend(chip->ac97);	chip->coeffs_current = 0;	pci_disable_device(chip->pci);	return 0;}static int nm256_resume(snd_card_t *card){	nm256_t *chip = card->pm_private_data;	int i;	/* Perform a full reset on the hardware */	pci_enable_device(chip->pci);	snd_nm256_init_chip(chip);	/* restore ac97 */	snd_ac97_resume(chip->ac97);	for (i = 0; i < 2; i++) {		nm256_stream_t *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);		}	}	return 0;}#endif /* CONFIG_PM */static int snd_nm256_free(nm256_t *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, (void*)chip);	pci_disable_device(chip->pci);	kfree(chip);	return 0;}static int snd_nm256_dev_free(snd_device_t *device){	nm256_t *chip = device->device_data;	return snd_nm256_free(chip);}static int __devinitsnd_nm256_create(snd_card_t *card, struct pci_dev *pci,		 int play_bufsize, int capt_bufsize,		 int force_load,		 u32 buffertop,		 int usecache,		 nm256_t **chip_ret){	nm256_t *chip;	int err, pval;	static snd_device_ops_t 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 = usecache;	spin_lock_init(&chip->reg_lock);	chip->irq = -1;	init_MUTEX(&chip->irq_mutex);	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;	chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;	/* 	 * 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_load) {				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 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 (buffertop >= chip->buffer_size && buffertop < chip->buffer_end)		chip->buffer_end = buffertop;	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? */		snd_card_set_pm_callback(card, nm256_suspend, nm256_resume, chip);	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;}struct nm256_quirk {	unsigned short vendor;	unsigned short device;	int type;};enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 };static struct nm256_quirk nm256_quirks[] __devinitdata = {	/* HP omnibook 4150 has cs4232 codec internally */	{ .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED },	/* Sony PCG-F305 */	{ .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND },	/* Dell Latitude LS */	{ .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND },	/* Dell Latitude CSx */	{ .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 },	{ } /* terminator */};static int __devinit snd_nm256_probe(struct pci_dev *pci,				     const struct pci_device_id *pci_id){	snd_card_t *card;	nm256_t *chip;	int err;	unsigned int xbuffer_top;	struct nm256_quirk *q;	u16 subsystem_vendor, subsystem_device;	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);	for (q = nm256_quirks; q->vendor; q++) {		if (q->vendor == subsystem_vendor && q->device == subsystem_device) {			switch (q->type) {			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)		xbuffer_top = 0x25a800;	/* this avoids conflicts with XFree86 server */	else		xbuffer_top = buffer_top;	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,				    playback_bufsize * 1024, /* in bytes */				    capture_bufsize * 1024,  /* in bytes */				    force_ac97,				    xbuffer_top,				    use_cache,				    &chip)) < 0) {		snd_card_free(card);		return err;	}	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),	SND_PCI_PM_CALLBACKS};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 + -