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

📄 ymfpci.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		spin_unlock_irqrestore(&state->card->lock, flags);		return put_user(val, (int *)arg);#endif	case SOUND_PCM_READ_RATE:		return put_user(state->format.rate, (int *)arg);	case SOUND_PCM_READ_CHANNELS:		return put_user(state->format.voices,	(int *)arg);	case SOUND_PCM_READ_BITS:		return put_user(AFMT_S16_LE, (int *)arg);	case SNDCTL_DSP_MAPINBUF:	case SNDCTL_DSP_MAPOUTBUF:	case SNDCTL_DSP_SETSYNCRO:	case SOUND_PCM_WRITE_FILTER:	case SOUND_PCM_READ_FILTER:		return -ENOTTY;	default:		/*		 * Some programs mix up audio devices and ioctls		 * or perhaps they expect "universal" ioctls,		 * for instance we get SNDCTL_TMR_CONTINUE here.		 * XXX Is there sound_generic_ioctl() around?		 */	}	return -ENOTTY;}static int ymf_open(struct inode *inode, struct file *file){	struct list_head *list;	ymfpci_t *unit;	int minor;	struct ymf_state *state;	int nvirt;	int err;	/*	 * This is how we do it currently: only one channel is used	 * in every board, so that we could use several boards in one machine.	 * We waste 63 out of 64 playback slots, but so what.	 * OSS model is constructed for devices with single playback channel.	 */	minor = MINOR(inode->i_rdev);	if ((minor & 0x0F) == 3) {	/* /dev/dspN */		;	} else {		return -ENXIO;	}	nvirt = 0;			/* Such is the partitioning of minor */	for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {		unit = list_entry(list, ymfpci_t, ymf_devs);		if (((unit->dev_audio ^ minor) & ~0x0F) == 0)			break;	}	if (list == &ymf_devs)		return -ENODEV;	down(&unit->open_sem);	if (unit->states[nvirt] != NULL) {		up(&unit->open_sem);		return -EBUSY;	}	if ((err = ymf_state_alloc(unit, nvirt)) != 0) {		up(&unit->open_sem);		return err;	}	state = unit->states[nvirt];	file->private_data = state;	/*	 * XXX This ymf_playback_prepare is totally unneeded here.	 * The question is if we want to allow write to fail if	 * prog_dmabuf fails... Say, no memory in DMA zone?	 */	if ((err = ymf_playback_prepare(unit, state)) != 0) {		/* XXX This recovery is ugly as hell. */		ymf_pcm_free_substream(&state->ypcm);		unit->states[state->virt] = NULL;		kfree(state);		up(&unit->open_sem);		return err;	}#if 0 /* test if interrupts work */	ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe);	/* ~ 680ms */	ymfpci_writeb(codec, YDSXGR_TIMERCTRL,	    (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));#endif	up(&unit->open_sem);	/* XXX Is it correct to have MOD_INC_USE_COUNT outside of sem.? */	MOD_INC_USE_COUNT;	return 0;}static int ymf_release(struct inode *inode, struct file *file){	struct ymf_state *state = (struct ymf_state *)file->private_data;	ymfpci_t *codec = state->unit;#if 0 /* test if interrupts work */	ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);#endif	if (state != codec->states[state->virt]) {		printk(KERN_ERR "ymfpci%d.%d: state mismatch\n",		    state->unit->dev_audio, state->virt);		return -EIO;	}	down(&codec->open_sem);	/*	 * XXX Solve the case of O_NONBLOCK close - don't deallocate here.	 * Deallocate when unloading the driver and we can wait.	 */	ymf_wait_dac(state);	dealloc_dmabuf(state);	ymf_pcm_free_substream(&state->ypcm);	codec->states[state->virt] = NULL;	kfree(state);	up(&codec->open_sem);	MOD_DEC_USE_COUNT;	return 0;}/* * Mixer operations are based on cs46xx. */static int ymf_open_mixdev(struct inode *inode, struct file *file){	int i;	int minor = MINOR(inode->i_rdev);	struct list_head *list;	ymfpci_t *unit;	for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {		unit = list_entry(list, ymfpci_t, ymf_devs);		for (i = 0; i < NR_AC97; i++) {			if (unit->ac97_codec[i] != NULL &&			    unit->ac97_codec[i]->dev_mixer == minor) {				goto match;			}		}	}	return -ENODEV; match:	file->private_data = unit->ac97_codec[i];	MOD_INC_USE_COUNT;	return 0;}static int ymf_ioctl_mixdev(struct inode *inode, struct file *file,    unsigned int cmd, unsigned long arg){	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;	return codec->mixer_ioctl(codec, cmd, arg);}static int ymf_release_mixdev(struct inode *inode, struct file *file){	MOD_DEC_USE_COUNT;	return 0;}static /*const*/ struct file_operations ymf_fops = {	llseek:		ymf_llseek,	read:		ymf_read,	write:		ymf_write,	poll:		ymf_poll,	ioctl:		ymf_ioctl,	mmap:		ymf_mmap,	open:		ymf_open,	release:	ymf_release,};static /*const*/ struct file_operations ymf_mixer_fops = {	llseek:		ymf_llseek,	ioctl:		ymf_ioctl_mixdev,	open:		ymf_open_mixdev,	release:	ymf_release_mixdev,};/* *  initialization routines */static void ymfpci_aclink_reset(struct pci_dev * pci){	u8 cmd;	pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);	if (cmd & 0x03) {		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);	}}static void ymfpci_enable_dsp(ymfpci_t *codec){	ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000001);}static void ymfpci_disable_dsp(ymfpci_t *codec){	u32 val;	int timeout = 1000;	val = ymfpci_readl(codec, YDSXGR_CONFIG);	if (val)		ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000);	while (timeout-- > 0) {		val = ymfpci_readl(codec, YDSXGR_STATUS);		if ((val & 0x00000002) == 0)			break;	}}#include "ymfpci_image.h"static void ymfpci_download_image(ymfpci_t *codec){	int i, ver_1e;	u16 ctrl;	ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x00000000);	ymfpci_disable_dsp(codec);	ymfpci_writel(codec, YDSXGR_MODE, 0x00010000);	ymfpci_writel(codec, YDSXGR_MODE, 0x00000000);	ymfpci_writel(codec, YDSXGR_MAPOFREC, 0x00000000);	ymfpci_writel(codec, YDSXGR_MAPOFEFFECT, 0x00000000);	ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0x00000000);	ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0x00000000);	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0x00000000);	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);	/* setup DSP instruction code */	for (i = 0; i < YDSXG_DSPLENGTH; i++)		ymfpci_writel(codec, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2]);	switch (codec->pci->device) {	case PCI_DEVICE_ID_YAMAHA_724F:	case PCI_DEVICE_ID_YAMAHA_740C:	case PCI_DEVICE_ID_YAMAHA_744:	case PCI_DEVICE_ID_YAMAHA_754:		ver_1e = 1;		break;	default:		ver_1e = 0;	}	if (ver_1e) {		/* setup control instruction code */		for (i = 0; i < YDSXG_CTRLLENGTH; i++)			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst1E[i >> 2]);	} else {		for (i = 0; i < YDSXG_CTRLLENGTH; i++)			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst[i >> 2]);	}	ymfpci_enable_dsp(codec);}static int ymfpci_memalloc(ymfpci_t *codec){	long size, playback_ctrl_size;	int voice, bank;	u8 *ptr;	playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;	codec->bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;	codec->bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;	codec->bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;	codec->work_size = YDSXG_DEFAULT_WORK_SIZE;	size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +	    ((codec->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +	    ((codec->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +	    ((codec->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +	    codec->work_size;	ptr = (u8 *)kmalloc(size + 0x00ff, GFP_KERNEL);	if (ptr == NULL)		return -ENOMEM;	codec->work_ptr = ptr;	ptr += 0x00ff;	(long)ptr &= ~0x00ff;	codec->bank_base_playback = ptr;	codec->ctrl_playback = (u32 *)ptr;	codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES;	ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;	for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {		for (bank = 0; bank < 2; bank++) {			codec->bank_playback[voice][bank] = (ymfpci_playback_bank_t *)ptr;			ptr += codec->bank_size_playback;		}		codec->voices[voice].number = voice;		codec->voices[voice].bank = codec->bank_playback[voice][0];	}	ptr += (codec->bank_size_playback + 0x00ff) & ~0x00ff;	codec->bank_base_capture = ptr;	for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)		for (bank = 0; bank < 2; bank++) {			codec->bank_capture[voice][bank] = (ymfpci_capture_bank_t *)ptr;			ptr += codec->bank_size_capture;		}	ptr += (codec->bank_size_capture + 0x00ff) & ~0x00ff;	codec->bank_base_effect = ptr;	for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)		for (bank = 0; bank < 2; bank++) {			codec->bank_effect[voice][bank] = (ymfpci_effect_bank_t *)ptr;			ptr += codec->bank_size_effect;		}	ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff;	codec->work_base = ptr;	ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, virt_to_bus(codec->bank_base_playback));	ymfpci_writel(codec, YDSXGR_RECCTRLBASE, virt_to_bus(codec->bank_base_capture));	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, virt_to_bus(codec->bank_base_effect));	ymfpci_writel(codec, YDSXGR_WORKBASE, virt_to_bus(codec->work_base));	ymfpci_writel(codec, YDSXGR_WORKSIZE, codec->work_size >> 2);	/* S/PDIF output initialization */	ymfpci_writew(codec, YDSXGR_SPDIFOUTCTRL, 0);	ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,		SND_PCM_AES0_CON_EMPHASIS_NONE |		(SND_PCM_AES1_CON_ORIGINAL << 8) |		(SND_PCM_AES1_CON_PCM_CODER << 8));	/* S/PDIF input initialization */	ymfpci_writew(codec, YDSXGR_SPDIFINCTRL, 0);	/* move this volume setup to mixer */	ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);	ymfpci_writel(codec, YDSXGR_BUF441OUTVOL, 0x3fff3fff);	ymfpci_writel(codec, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);	ymfpci_writel(codec, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);	return 0;}static void ymfpci_memfree(ymfpci_t *codec){	ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0);	ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0);	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);	ymfpci_writel(codec, YDSXGR_WORKBASE, 0);	ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);	kfree(codec->work_ptr);}static int ymf_ac97_init(ymfpci_t *card, int num_ac97){	struct ac97_codec *codec;	u16 eid;	if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)		return -ENOMEM;	memset(codec, 0, sizeof(struct ac97_codec));	/* initialize some basic codec information, other fields will be filled	   in ac97_probe_codec */	codec->private_data = card;	codec->id = num_ac97;	codec->codec_read = ymfpci_codec_read;	codec->codec_write = ymfpci_codec_write;	if (ac97_probe_codec(codec) == 0) {		printk("ymfpci: ac97_probe_codec failed\n");		goto out_kfree;	}	eid = ymfpci_codec_read(codec, AC97_EXTENDED_ID);	if (eid==0xFFFFFF) {		printk(KERN_WARNING "ymfpci: no codec attached ?\n");		goto out_kfree;	}	card->ac97_features = eid;	if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) {		printk(KERN_ERR "ymfpci: couldn't register mixer!\n");		goto out_kfree;	}	card->ac97_codec[num_ac97] = codec;	return 0; out_kfree:	kfree(codec);	return -ENODEV;}static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent){	u16 ctrl;	ymfpci_t *codec;	int err;	if (pci_enable_device(pcidev) < 0) {		printk(KERN_ERR "ymfpci: pci_enable_device failed\n");		return -ENODEV;	}	if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {		printk(KERN_ERR "ymfpci: no core\n");		return -ENOMEM;	}	memset(codec, 0, sizeof(*codec));	spin_lock_init(&codec->reg_lock);	spin_lock_init(&codec->voice_lock);	init_MUTEX(&codec->open_sem);	codec->pci = pcidev;	pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);	codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",	    (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);	ymfpci_aclink_reset(pcidev);	if (ymfpci_codec_ready(codec, 0, 1) < 0)		goto out_unmap;	ymfpci_download_image(codec);	udelay(100); /* seems we need some delay after downloading image.. */	if (ymfpci_memalloc(codec) < 0)		goto out_disable_dsp;	/* ymfpci_proc_init(card, codec); */	if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) {		printk(KERN_ERR "ymfpci%d: unable to request IRQ %d\n",		       codec->dev_audio, pcidev->irq);		goto out

⌨️ 快捷键说明

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