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

📄 i810_audio.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
			return -EINVAL;		spin_lock_irqsave(&state->card->lock, flags);		i810_update_ptr(state);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;		cinfo.ptr = dmabuf->hwptr;		if (dmabuf->mapped)			dmabuf->count &= dmabuf->fragsize-1;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));	case SNDCTL_DSP_GETOPTR:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		spin_lock_irqsave(&state->card->lock, flags);		i810_update_ptr(state);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;		cinfo.ptr = dmabuf->hwptr;		if (dmabuf->mapped)			dmabuf->count &= dmabuf->fragsize-1;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));	case SNDCTL_DSP_SETDUPLEX:		return -EINVAL;	case SNDCTL_DSP_GETODELAY:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		spin_lock_irqsave(&state->card->lock, flags);		i810_update_ptr(state);		val = dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		return put_user(val, (int *)arg);	case SOUND_PCM_READ_RATE:		return put_user(dmabuf->rate, (int *)arg);	case SOUND_PCM_READ_CHANNELS:		return put_user((dmabuf->fmt & I810_FMT_STEREO) ? 2 : 1,				(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 -EINVAL;	}	return -EINVAL;}static int i810_open(struct inode *inode, struct file *file){	int i = 0;	struct i810_card *card = devs;	struct i810_state *state = NULL;	struct dmabuf *dmabuf = NULL;	/* find an avaiable virtual channel (instance of /dev/dsp) */	while (card != NULL) {		for (i = 0; i < NR_HW_CH; i++) {			if (card->states[i] == NULL) {				state = card->states[i] = (struct i810_state *)					kmalloc(sizeof(struct i810_state), GFP_KERNEL);				if (state == NULL)					return -ENOMEM;				memset(state, 0, sizeof(struct i810_state));				dmabuf = &state->dmabuf;				goto found_virt;			}		}		card = card->next;	}	/* no more virtual channel avaiable */	if (!state)		return -ENODEV; found_virt:	/* found a free virtual channel, allocate hardware channels */	if(file->f_mode & FMODE_READ)		dmabuf->channel = card->alloc_rec_pcm_channel(card);	else		dmabuf->channel = card->alloc_pcm_channel(card);			if (dmabuf->channel == NULL) {		kfree (card->states[i]);		card->states[i] = NULL;;		return -ENODEV;	}	/* initialize the virtual channel */	state->virt = i;	state->card = card;	state->magic = I810_STATE_MAGIC;	init_waitqueue_head(&dmabuf->wait);	init_MUTEX(&state->open_sem);	file->private_data = state;	down(&state->open_sem);	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and	   /dev/dspW will accept 16-bits sample */	if (file->f_mode & FMODE_WRITE) {		dmabuf->fmt &= ~I810_FMT_MASK;		dmabuf->fmt |= I810_FMT_16BIT;		dmabuf->ossfragshift = 0;		dmabuf->ossmaxfrags  = 0;		dmabuf->subdivision  = 0;		i810_set_dac_rate(state, 48000);	}	if (file->f_mode & FMODE_READ) {		dmabuf->fmt &= ~I810_FMT_MASK;		dmabuf->fmt |= I810_FMT_16BIT;		dmabuf->ossfragshift = 0;		dmabuf->ossmaxfrags  = 0;		dmabuf->subdivision  = 0;		i810_set_adc_rate(state, 48000);	}	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);	up(&state->open_sem);	return 0;}static int i810_release(struct inode *inode, struct file *file){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	lock_kernel();	if (file->f_mode & FMODE_WRITE) {		i810_clear_tail(state);		drain_dac(state, file->f_flags & O_NONBLOCK);	}	/* stop DMA state machine and free DMA buffers/channels */	down(&state->open_sem);	if (file->f_mode & FMODE_WRITE) {		stop_dac(state);		dealloc_dmabuf(state);		state->card->free_pcm_channel(state->card, dmabuf->channel->num);	}	if (file->f_mode & FMODE_READ) {		stop_adc(state);		dealloc_dmabuf(state);		state->card->free_pcm_channel(state->card, dmabuf->channel->num);	}	/* we're covered by the open_sem */	up(&state->open_sem);		kfree(state->card->states[state->virt]);	state->card->states[state->virt] = NULL;	unlock_kernel();	return 0;}static /*const*/ struct file_operations i810_audio_fops = {	owner:		THIS_MODULE,	llseek:		i810_llseek,	read:		i810_read,	write:		i810_write,	poll:		i810_poll,	ioctl:		i810_ioctl,	mmap:		i810_mmap,	open:		i810_open,	release:	i810_release,};/* Write AC97 codec registers */static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg){	struct i810_card *card = dev->private_data;	int count = 100;	while(count-- && (inb(card->iobase + CAS) & 1)) 		udelay(1);	return inw(card->ac97base + (reg&0x7f));}static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data){	struct i810_card *card = dev->private_data;	int count = 100;	while(count-- && (inb(card->iobase + CAS) & 1)) 		udelay(1);	outw(data, card->ac97base + (reg&0x7f));}/* OSS /dev/mixer file operation methods */static int i810_open_mixdev(struct inode *inode, struct file *file){	int i;	int minor = MINOR(inode->i_rdev);	struct i810_card *card = devs;	for (card = devs; card != NULL; card = card->next)		for (i = 0; i < NR_AC97; i++)			if (card->ac97_codec[i] != NULL &&			    card->ac97_codec[i]->dev_mixer == minor)				goto match;	if (!card)		return -ENODEV; match:	file->private_data = card->ac97_codec[i];	return 0;}static int i810_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 /*const*/ struct file_operations i810_mixer_fops = {	owner:		THIS_MODULE,	llseek:		i810_llseek,	ioctl:		i810_ioctl_mixdev,	open:		i810_open_mixdev,};/* AC97 codec initialisation. */static int __init i810_ac97_init(struct i810_card *card){	int num_ac97 = 0;	int ready_2nd = 0;	struct ac97_codec *codec;	u16 eid;	int i=0;	u32 reg;	reg = inl(card->iobase + GLOB_CNT);		if((reg&2)==0)	/* Cold required */		reg|=2;	else		reg|=4;	/* Warm */			reg&=~8;	/* ACLink on */	outl(reg , card->iobase + GLOB_CNT);		while(i<10)	{		if((inl(card->iobase+GLOB_CNT)&4)==0)			break;		current->state = TASK_UNINTERRUPTIBLE;		schedule_timeout(HZ/20);		i++;	}	if(i==10)	{		printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");		return 0;	}	current->state = TASK_UNINTERRUPTIBLE;	schedule_timeout(HZ/5);			inw(card->ac97base);	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {		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 = i810_ac97_get;		codec->codec_write = i810_ac97_set;			if (ac97_probe_codec(codec) == 0)			break;		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);				if(eid==0xFFFFFF)		{			printk(KERN_WARNING "i810_audio: no codec attached ?\n");			kfree(codec);			break;		}				card->ac97_features = eid;						/* Now check the codec for useful features to make up for		   the dumbness of the 810 hardware engine */		if(!(eid&0x0001))			printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");		else		{			/* Enable variable rate mode */			i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);			i810_ac97_set(codec,AC97_EXTENDED_STATUS,				i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);			/* power up everything, modify this when implementing power saving */			i810_ac97_set(codec, AC97_POWER_CONTROL,				i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);			/* wait for analog ready */		        for (i=10;			     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);			     i--)			{				current->state = TASK_UNINTERRUPTIBLE;				schedule_timeout(HZ/20);			}			if(!(i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1))			{				printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n");				card->ac97_features&=~1;			}		}   				if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {			printk(KERN_ERR "i810_audio: couldn't register mixer!\n");			kfree(codec);			break;		}		card->ac97_codec[num_ac97] = codec;		/* if there is no secondary codec at all, don't probe any more */		if (!ready_2nd)			return num_ac97+1;	}	return num_ac97;}/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered    untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */   static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id){	struct i810_card *card;	if (!pci_dma_supported(pci_dev, I810_DMA_MASK)) {		printk(KERN_ERR "intel810: architecture does not support"		       " 32bit PCI busmaster DMA\n");		return -ENODEV;	}	if (pci_enable_device(pci_dev))		return -EIO;	if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {		printk(KERN_ERR "i810_audio: out of memory\n");		return -ENOMEM;	}	memset(card, 0, sizeof(*card));	card->iobase = pci_resource_start (pci_dev, 1);	card->ac97base = pci_resource_start (pci_dev, 0);	card->pci_dev = pci_dev;	card->pci_id = pci_id->device;	card->irq = pci_dev->irq;	card->next = devs;	card->magic = I810_CARD_MAGIC;	spin_lock_init(&card->lock);	devs = card;	pci_set_master(pci_dev);	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",	       card_names[pci_id->driver_data], card->iobase, card->ac97base, 	       card->irq);	card->alloc_pcm_channel = i810_alloc_pcm_channel;	card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;	card->free_pcm_channel = i810_free_pcm_channel;	/* claim our iospace and irq */	request_region(card->iobase, 64, card_names[pci_id->driver_data]);	request_region(card->ac97base, 256, card_names[pci_id->driver_data]);	if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,			card_names[pci_id->driver_data], card)) {		printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);		release_region(card->iobase, 64);		release_region(card->ac97base, 256);		kfree(card);		return -ENODEV;	}	/* register /dev/dsp */	if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {		printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");		release_region(card->iobase, 64);		release_region(card->ac97base, 256);		free_irq(card->irq, card);		kfree(card);		return -ENODEV;	}	/* initialize AC97 codec and register /dev/mixer */	if (i810_ac97_init(card) <= 0) {		unregister_sound_dsp(card->dev_audio);		release_region(card->iobase, 64);		release_region(card->ac97base, 256);		free_irq(card->irq, card);		kfree(card);		return -ENODEV;	}	pci_dev->driver_data = card;	pci_dev->dma_mask = I810_DMA_MASK;	return 0;}static void __exit i810_remove(struct pci_dev *pci_dev){	int i;	struct i810_card *card = pci_dev->driver_data;	/* free hardware resources */	free_irq(card->irq, devs);	release_region(card->iobase, 64);	release_region(card->ac97base, 256);	/* unregister audio devices */	for (i = 0; i < NR_AC97; i++)		if (devs->ac97_codec[i] != NULL) {			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);			kfree (card->ac97_codec[i]);		}	unregister_sound_dsp(card->dev_audio);	kfree(card);}MODULE_AUTHOR("");MODULE_DESCRIPTION("Intel 810 audio support");MODULE_PARM(ftsodell, "i");MODULE_PARM(clocking, "i");#define I810_MODULE_NAME "intel810_audio"static struct pci_driver i810_pci_driver = {	name:		I810_MODULE_NAME,	id_table:	i810_pci_tbl,	probe:		i810_probe,	remove:		i810_remove,};static int __init i810_init_module (void){	if (!pci_present())   /* No PCI bus in this machine! */		return -ENODEV;	if(ftsodell==1)		clocking=41194;			printk(KERN_INFO "Intel 810 + AC97 Audio, version "	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");	if (!pci_register_driver(&i810_pci_driver)) {		pci_unregister_driver(&i810_pci_driver);                return -ENODEV;	}	return 0;}static void __exit i810_cleanup_module (void){	pci_unregister_driver(&i810_pci_driver);}module_init(i810_init_module);module_exit(i810_cleanup_module);

⌨️ 快捷键说明

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