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

📄 i810_audio.c

📁 本书是一本介绍Linux设备驱动开发理论、框架与实例的书
💻 C
📖 第 1 页 / 共 5 页
字号:
        set_current_state(TASK_RUNNING);        remove_wait_queue(&dmabuf->wait, &waita);	return ret;}/* No kernel lock - we have our own spinlock */static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	unsigned int mask = 0;	if(!dmabuf->ready)		return 0;	poll_wait(file, &dmabuf->wait, wait);	spin_lock_irqsave(&state->card->lock, flags);	if (dmabuf->enable & ADC_RUNNING ||	    dmabuf->trigger & PCM_ENABLE_INPUT) {		if (i810_get_available_read_data(state) >= 		    (signed)dmabuf->userfragsize)			mask |= POLLIN | POLLRDNORM;	}	if (dmabuf->enable & DAC_RUNNING ||	    dmabuf->trigger & PCM_ENABLE_OUTPUT) {		if (i810_get_free_write_space(state) >=		    (signed)dmabuf->userfragsize)			mask |= POLLOUT | POLLWRNORM;	}	spin_unlock_irqrestore(&state->card->lock, flags);	return mask;}static int i810_mmap(struct file *file, struct vm_area_struct *vma){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	int ret = -EINVAL;	unsigned long size;	lock_kernel();	if (vma->vm_flags & VM_WRITE) {		if (!dmabuf->write_channel &&		    (dmabuf->write_channel =		     state->card->alloc_pcm_channel(state->card)) == NULL) {			ret = -EBUSY;			goto out;		}	}	if (vma->vm_flags & VM_READ) {		if (!dmabuf->read_channel &&		    (dmabuf->read_channel = 		     state->card->alloc_rec_pcm_channel(state->card)) == NULL) {			ret = -EBUSY;			goto out;		}	}	if ((ret = prog_dmabuf(state, 0)) != 0)		goto out;	ret = -EINVAL;	if (vma->vm_pgoff != 0)		goto out;	size = vma->vm_end - vma->vm_start;	if (size > (PAGE_SIZE << dmabuf->buforder))		goto out;	ret = -EAGAIN;	if (remap_pfn_range(vma, vma->vm_start,			     virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,			     size, vma->vm_page_prot))		goto out;	dmabuf->mapped = 1;	dmabuf->trigger = 0;	ret = 0;#ifdef DEBUG_MMAP	printk("i810_audio: mmap'ed %ld bytes of data space\n", size);#endifout:	unlock_kernel();	return ret;}static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct i810_state *state = (struct i810_state *)file->private_data;	struct i810_channel *c = NULL;	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	audio_buf_info abinfo;	count_info cinfo;	unsigned int i_glob_cnt;	int val = 0, ret;	struct ac97_codec *codec = state->card->ac97_codec[0];	void __user *argp = (void __user *)arg;	int __user *p = argp;#ifdef DEBUG	printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0);#endif	switch (cmd) 	{	case OSS_GETVERSION:#ifdef DEBUG		printk("OSS_GETVERSION\n");#endif		return put_user(SOUND_VERSION, p);	case SNDCTL_DSP_RESET:#ifdef DEBUG		printk("SNDCTL_DSP_RESET\n");#endif		spin_lock_irqsave(&state->card->lock, flags);		if (dmabuf->enable == DAC_RUNNING) {			c = dmabuf->write_channel;			__stop_dac(state);		}		if (dmabuf->enable == ADC_RUNNING) {			c = dmabuf->read_channel;			__stop_adc(state);		}		if (c != NULL) {			I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA machine */			while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )				cpu_relax();			I810_IOWRITEL((u32)state->card->chandma +			    c->num*sizeof(struct i810_channel),			    state->card, c->port+OFF_BDBAR);			CIV_TO_LVI(state->card, c->port, 0);		}		spin_unlock_irqrestore(&state->card->lock, flags);		synchronize_irq(state->card->pci_dev->irq);		dmabuf->ready = 0;		dmabuf->swptr = dmabuf->hwptr = 0;		dmabuf->count = dmabuf->total_bytes = 0;		return 0;	case SNDCTL_DSP_SYNC:#ifdef DEBUG		printk("SNDCTL_DSP_SYNC\n");#endif		if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)			return 0;		if((val = drain_dac(state, 1)))			return val;		dmabuf->total_bytes = 0;		return 0;	case SNDCTL_DSP_SPEED: /* set smaple rate */#ifdef DEBUG		printk("SNDCTL_DSP_SPEED\n");#endif		if (get_user(val, p))			return -EFAULT;		if (val >= 0) {			if (file->f_mode & FMODE_WRITE) {				if ( (state->card->ac97_status & SPDIF_ON) ) {  /* S/PDIF Enabled */					/* AD1886 only supports 48000, need to check that */					if ( i810_valid_spdif_rate ( codec, val ) ) {						/* Set DAC rate */                                        	i810_set_spdif_output ( state, -1, 0 );						stop_dac(state);						dmabuf->ready = 0;						spin_lock_irqsave(&state->card->lock, flags);						i810_set_dac_rate(state, val);						spin_unlock_irqrestore(&state->card->lock, flags);						/* Set S/PDIF transmitter rate. */						i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );	                                        if ( ! (state->card->ac97_status & SPDIF_ON) ) {							val = dmabuf->rate;						}					} else { /* Not a valid rate for S/PDIF, ignore it */						val = dmabuf->rate;					}				} else {					stop_dac(state);					dmabuf->ready = 0;					spin_lock_irqsave(&state->card->lock, flags);					i810_set_dac_rate(state, val);					spin_unlock_irqrestore(&state->card->lock, flags);				}			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;				spin_lock_irqsave(&state->card->lock, flags);				i810_set_adc_rate(state, val);				spin_unlock_irqrestore(&state->card->lock, flags);			}		}		return put_user(dmabuf->rate, p);	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */#ifdef DEBUG		printk("SNDCTL_DSP_STEREO\n");#endif		if (dmabuf->enable & DAC_RUNNING) {			stop_dac(state);		}		if (dmabuf->enable & ADC_RUNNING) {			stop_adc(state);		}		return put_user(1, p);	case SNDCTL_DSP_GETBLKSIZE:		if (file->f_mode & FMODE_WRITE) {			if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))				return val;		}		if (file->f_mode & FMODE_READ) {			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))				return val;		}#ifdef DEBUG		printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);#endif		return put_user(dmabuf->userfragsize, p);	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/#ifdef DEBUG		printk("SNDCTL_DSP_GETFMTS\n");#endif		return put_user(AFMT_S16_LE, p);	case SNDCTL_DSP_SETFMT: /* Select sample format */#ifdef DEBUG		printk("SNDCTL_DSP_SETFMT\n");#endif		return put_user(AFMT_S16_LE, p);	case SNDCTL_DSP_CHANNELS:#ifdef DEBUG		printk("SNDCTL_DSP_CHANNELS\n");#endif		if (get_user(val, p))			return -EFAULT;		if (val > 0) {			if (dmabuf->enable & DAC_RUNNING) {				stop_dac(state);			}			if (dmabuf->enable & ADC_RUNNING) {				stop_adc(state);			}		} else {			return put_user(state->card->channels, p);		}		/* ICH and ICH0 only support 2 channels */		if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5		     || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5) 			return put_user(2, p);			/* Multi-channel support was added with ICH2. Bits in */		/* Global Status and Global Control register are now  */		/* used to indicate this.                             */                i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);		/* Current # of channels enabled */		if ( i_glob_cnt & 0x0100000 )			ret = 4;		else if ( i_glob_cnt & 0x0200000 )			ret = 6;		else			ret = 2;		switch ( val ) {			case 2: /* 2 channels is always supported */				I810_IOWRITEL(i_glob_cnt & 0xffcfffff,				     state->card, GLOB_CNT);				/* Do we need to change mixer settings????  */				break;			case 4: /* Supported on some chipsets, better check first */				if ( state->card->channels >= 4 ) {					I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000,					      state->card, GLOB_CNT);					/* Do we need to change mixer settings??? */				} else {					val = ret;				}				break;			case 6: /* Supported on some chipsets, better check first */				if ( state->card->channels >= 6 ) {					I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000,					      state->card, GLOB_CNT);					/* Do we need to change mixer settings??? */				} else {					val = ret;				}				break;			default: /* nothing else is ever supported by the chipset */				val = ret;				break;		}		return put_user(val, p);	case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */		/* we update the swptr to the end of the last sg segment then return */#ifdef DEBUG		printk("SNDCTL_DSP_POST\n");#endif		if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))			return 0;		if((dmabuf->swptr % dmabuf->fragsize) != 0) {			val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);			dmabuf->swptr += val;			dmabuf->count += val;		}		return 0;	case SNDCTL_DSP_SUBDIVIDE:		if (dmabuf->subdivision)			return -EINVAL;		if (get_user(val, p))			return -EFAULT;		if (val != 1 && val != 2 && val != 4)			return -EINVAL;#ifdef DEBUG		printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);#endif		dmabuf->subdivision = val;		dmabuf->ready = 0;		return 0;	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(val, p))			return -EFAULT;		dmabuf->ossfragsize = 1<<(val & 0xffff);		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)			return -EINVAL;		/*		 * Bound the frag size into our allowed range of 256 - 4096		 */		if (dmabuf->ossfragsize < 256)			dmabuf->ossfragsize = 256;		else if (dmabuf->ossfragsize > 4096)			dmabuf->ossfragsize = 4096;		/*		 * The numfrags could be something reasonable, or it could		 * be 0xffff meaning "Give me as much as possible".  So,		 * we check the numfrags * fragsize doesn't exceed our		 * 64k buffer limit, nor is it less than our 8k minimum.		 * If it fails either one of these checks, then adjust the		 * number of fragments, not the size of them.  It's OK if		 * our number of fragments doesn't equal 32 or anything		 * like our hardware based number now since we are using		 * a different frag count for the hardware.  Before we get		 * into this though, bound the maxfrags to avoid overflow		 * issues.  A reasonable bound would be 64k / 256 since our		 * maximum buffer size is 64k and our minimum frag size is		 * 256.  On the other end, our minimum buffer size is 8k and		 * our maximum frag size is 4k, so the lower bound should		 * be 2.		 */		if(dmabuf->ossmaxfrags > 256)			dmabuf->ossmaxfrags = 256;		else if (dmabuf->ossmaxfrags < 2)			dmabuf->ossmaxfrags = 2;		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;		while (val < 8192) {		    val <<= 1;		    dmabuf->ossmaxfrags <<= 1;		}		while (val > 65536) {		    val >>= 1;		    dmabuf->ossmaxfrags >>= 1;		}		dmabuf->ready = 0;#ifdef DEBUG		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,			dmabuf->ossfragsize, dmabuf->ossmaxfrags);#endif		return 0;	case SNDCTL_DSP_GETOSPACE:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		i810_update_ptr(state);		abinfo.fragsize = dmabuf->userfragsize;		abinfo.fragstotal = dmabuf->userfrags;		if (dmabuf->mapped) 			abinfo.bytes = dmabuf->dmasize;  		else 			abinfo.bytes = i810_get_free_write_space(state);		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;		spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP)		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);#endif		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETOPTR:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		val = i810_get_free_write_space(state);		cinfo.bytes = dmabuf->total_bytes;		cinfo.ptr = dmabuf->hwptr;		cinfo.blocks = val/dmabuf->userfragsize;		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {			dmabuf->count += val;			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;			__i810_update_lvi(state, 0);		}		spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP)		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,			cinfo.blocks, cinfo.ptr, dmabuf->count);#endif		return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETISPACE:		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		abinfo.bytes = i810_get_available_read_data(state);		abinfo.fragsize = dmabuf->userfragsize;		abinfo.fragstotal = dmabuf->userfrags;		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;		spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP)		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);#endif		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETIPTR:		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		val = i810_get_available_read_data(state);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = val/dmabuf->userfragsize;		cinfo.ptr

⌨️ 快捷键说明

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