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

📄 audio.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
				audio_devs[dev]->dmap_out->applic_profile = val;			if (audio_devs[dev]->open_mode & OPEN_READ)				audio_devs[dev]->dmap_in->applic_profile = val;			return 0;				case SNDCTL_DSP_GETODELAY:			dmap = audio_devs[dev]->dmap_out;			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))				return -EINVAL;			if (!(dmap->flags & DMA_ALLOC_DONE))			{				val=0;				break;			}					spin_lock_irqsave(&dmap->lock,flags);			/* Compute number of bytes that have been played */			count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);			if (count < dmap->fragment_size && dmap->qhead != 0)				count += dmap->bytes_in_use;	/* Pointer wrap not handled yet */			count += dmap->byte_counter;					/* Substract current count from the number of bytes written by app */			count = dmap->user_counter - count;			if (count < 0)				count = 0;			spin_unlock_irqrestore(&dmap->lock,flags);			val = count;			break;				default:			return dma_ioctl(dev, cmd, arg);	}	return put_user(val, p);}void audio_init_devices(void){	/*	 * NOTE! This routine could be called several times during boot.	 */}void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording){	/*	 * This routine breaks the physical device buffers to logical ones.	 */	struct audio_operations *dsp_dev = audio_devs[dev];	unsigned i, n;	unsigned sr, nc, sz, bsz;	sr = dsp_dev->d->set_speed(dev, 0);	nc = dsp_dev->d->set_channels(dev, 0);	sz = dsp_dev->d->set_bits(dev, 0);	if (sz == 8)		dmap->neutral_byte = NEUTRAL8;	else		dmap->neutral_byte = NEUTRAL16;	if (sr < 1 || nc < 1 || sz < 1)	{/*		printk(KERN_DEBUG "Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);*/		sr = DSP_DEFAULT_SPEED;		nc = 1;		sz = 8;	}		sz = sr * nc * sz;	sz /= 8;		/* #bits -> #bytes */	dmap->data_rate = sz;	if (!dmap->needs_reorg)		return;	dmap->needs_reorg = 0;	if (dmap->fragment_size == 0)	{			/* Compute the fragment size using the default algorithm */		/*		 * Compute a buffer size for time not exceeding 1 second.		 * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds		 * of sound (using the current speed, sample size and #channels).		 */		bsz = dmap->buffsize;		while (bsz > sz)			bsz /= 2;		if (bsz == dmap->buffsize)			bsz /= 2;	/* Needs at least 2 buffers */		/*		 *    Split the computed fragment to smaller parts. After 3.5a9		 *      the default subdivision is 4 which should give better		 *      results when recording.		 */		if (dmap->subdivision == 0)	/* Not already set */		{			dmap->subdivision = 4;	/* Init to the default value */			if ((bsz / dmap->subdivision) > 4096)				dmap->subdivision *= 2;			if ((bsz / dmap->subdivision) < 4096)				dmap->subdivision = 1;		}		bsz /= dmap->subdivision;		if (bsz < 16)			bsz = 16;	/* Just a sanity check */		dmap->fragment_size = bsz;	}	else	{		/*		 * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or		 * the buffer size computation has already been done.		 */		if (dmap->fragment_size > (dmap->buffsize / 2))			dmap->fragment_size = (dmap->buffsize / 2);		bsz = dmap->fragment_size;	}	if (audio_devs[dev]->min_fragment)		if (bsz < (1 << audio_devs[dev]->min_fragment))			bsz = 1 << audio_devs[dev]->min_fragment;	if (audio_devs[dev]->max_fragment)		if (bsz > (1 << audio_devs[dev]->max_fragment))			bsz = 1 << audio_devs[dev]->max_fragment;	bsz &= ~0x07;		/* Force size which is multiple of 8 bytes */#ifdef OS_DMA_ALIGN_CHECK	OS_DMA_ALIGN_CHECK(bsz);#endif	n = dmap->buffsize / bsz;	if (n > MAX_SUB_BUFFERS)		n = MAX_SUB_BUFFERS;	if (n > dmap->max_fragments)		n = dmap->max_fragments;	if (n < 2)	{		n = 2;		bsz /= 2;	}	dmap->nbufs = n;	dmap->bytes_in_use = n * bsz;	dmap->fragment_size = bsz;	dmap->max_byte_counter = (dmap->data_rate * 60 * 60) +			dmap->bytes_in_use;	/* Approximately one hour */	if (dmap->raw_buf)	{		memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use);	}		for (i = 0; i < dmap->nbufs; i++)	{		dmap->counts[i] = 0;	}	dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;}static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact){	if (fact == 0) 	{		fact = dmap->subdivision;		if (fact == 0)			fact = 1;		return fact;	}	if (dmap->subdivision != 0 || dmap->fragment_size)	/* Too late to change */		return -EINVAL;	if (fact > MAX_REALTIME_FACTOR)		return -EINVAL;	if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)		return -EINVAL;	dmap->subdivision = fact;	return fact;}static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact){	int bytes, count;	if (fact == 0)		return -EIO;	if (dmap->subdivision != 0 ||	    dmap->fragment_size)	/* Too late to change */		return -EINVAL;	bytes = fact & 0xffff;	count = (fact >> 16) & 0x7fff;	if (count == 0)		count = MAX_SUB_BUFFERS;	else if (count < MAX_SUB_BUFFERS)		count++;	if (bytes < 4 || bytes > 17)	/* <16 || > 512k */		return -EINVAL;	if (count < 2)		return -EINVAL;	if (audio_devs[dev]->min_fragment > 0)		if (bytes < audio_devs[dev]->min_fragment)			bytes = audio_devs[dev]->min_fragment;	if (audio_devs[dev]->max_fragment > 0)		if (bytes > audio_devs[dev]->max_fragment)			bytes = audio_devs[dev]->max_fragment;#ifdef OS_DMA_MINBITS	if (bytes < OS_DMA_MINBITS)		bytes = OS_DMA_MINBITS;#endif	dmap->fragment_size = (1 << bytes);	dmap->max_fragments = count;	if (dmap->fragment_size > dmap->buffsize)		dmap->fragment_size = dmap->buffsize;	if (dmap->fragment_size == dmap->buffsize &&	    audio_devs[dev]->flags & DMA_AUTOMODE)		dmap->fragment_size /= 2;	/* Needs at least 2 buffers */	dmap->subdivision = 1;	/* Disable SNDCTL_DSP_SUBDIVIDE */	return bytes | ((count - 1) << 16);}int dma_ioctl(int dev, unsigned int cmd, void __user *arg){	struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;	struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;	struct dma_buffparms *dmap;	audio_buf_info info;	count_info cinfo;	int fact, ret, changed, bits, count, err;	unsigned long flags;	switch (cmd) 	{		case SNDCTL_DSP_SUBDIVIDE:			ret = 0;			if (get_user(fact, (int __user *)arg))				return -EFAULT;			if (audio_devs[dev]->open_mode & OPEN_WRITE)				ret = dma_subdivide(dev, dmap_out, fact);			if (ret < 0)				return ret;			if (audio_devs[dev]->open_mode != OPEN_WRITE ||				(audio_devs[dev]->flags & DMA_DUPLEX &&					audio_devs[dev]->open_mode & OPEN_READ))				ret = dma_subdivide(dev, dmap_in, fact);			if (ret < 0)				return ret;			break;		case SNDCTL_DSP_GETISPACE:		case SNDCTL_DSP_GETOSPACE:			dmap = dmap_out;			if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ))				return -EINVAL;			if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE))				return -EINVAL;			if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)				dmap = dmap_in;			if (dmap->mapping_flags & DMA_MAP_MAPPED)				return -EINVAL;			if (!(dmap->flags & DMA_ALLOC_DONE))				reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));			info.fragstotal = dmap->nbufs;			if (cmd == SNDCTL_DSP_GETISPACE)				info.fragments = dmap->qlen;			else 			{				if (!DMAbuf_space_in_queue(dev))					info.fragments = 0;				else				{					info.fragments = DMAbuf_space_in_queue(dev);					if (audio_devs[dev]->d->local_qlen) 					{						int tmp = audio_devs[dev]->d->local_qlen(dev);						if (tmp && info.fragments)							tmp--;	/*								 * This buffer has been counted twice								 */						info.fragments -= tmp;					}				}			}			if (info.fragments < 0)				info.fragments = 0;			else if (info.fragments > dmap->nbufs)				info.fragments = dmap->nbufs;			info.fragsize = dmap->fragment_size;			info.bytes = info.fragments * dmap->fragment_size;			if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)				info.bytes -= dmap->counts[dmap->qhead];			else 			{				info.fragments = info.bytes / dmap->fragment_size;				info.bytes -= dmap->user_counter % dmap->fragment_size;			}			if (copy_to_user(arg, &info, sizeof(info)))				return -EFAULT;			return 0;		case SNDCTL_DSP_SETTRIGGER:			if (get_user(bits, (int __user *)arg))				return -EFAULT;			bits &= audio_devs[dev]->open_mode;			if (audio_devs[dev]->d->trigger == NULL)				return -EINVAL;			if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) &&				(bits & PCM_ENABLE_OUTPUT))				return -EINVAL;			if (bits & PCM_ENABLE_INPUT)			{				spin_lock_irqsave(&dmap_in->lock,flags);				changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_INPUT;				if (changed && audio_devs[dev]->go) 				{					reorganize_buffers(dev, dmap_in, 1);					if ((err = audio_devs[dev]->d->prepare_for_input(dev,						     dmap_in->fragment_size, dmap_in->nbufs)) < 0) {						spin_unlock_irqrestore(&dmap_in->lock,flags);						return -err;					}					dmap_in->dma_mode = DMODE_INPUT;					audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT;					DMAbuf_activate_recording(dev, dmap_in);				} else					audio_devs[dev]->enable_bits &= ~PCM_ENABLE_INPUT;				spin_unlock_irqrestore(&dmap_in->lock,flags);			}			if (bits & PCM_ENABLE_OUTPUT)			{				spin_lock_irqsave(&dmap_out->lock,flags);				changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_OUTPUT;				if (changed &&				    (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&				    audio_devs[dev]->go) 				{					if (!(dmap_out->flags & DMA_ALLOC_DONE))						reorganize_buffers(dev, dmap_out, 0);					dmap_out->dma_mode = DMODE_OUTPUT;					audio_devs[dev]->enable_bits |= PCM_ENABLE_OUTPUT;					dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;					DMAbuf_launch_output(dev, dmap_out);				} else					audio_devs[dev]->enable_bits &= ~PCM_ENABLE_OUTPUT;				spin_unlock_irqrestore(&dmap_out->lock,flags);			}#if 0			if (changed && audio_devs[dev]->d->trigger)				audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);#endif							/* Falls through... */		case SNDCTL_DSP_GETTRIGGER:			ret = audio_devs[dev]->enable_bits;			break;		case SNDCTL_DSP_SETSYNCRO:			if (!audio_devs[dev]->d->trigger)				return -EINVAL;			audio_devs[dev]->d->trigger(dev, 0);			audio_devs[dev]->go = 0;			return 0;		case SNDCTL_DSP_GETIPTR:			if (!(audio_devs[dev]->open_mode & OPEN_READ))				return -EINVAL;			spin_lock_irqsave(&dmap_in->lock,flags);			cinfo.bytes = dmap_in->byte_counter;			cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3;			if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0)				cinfo.bytes += dmap_in->bytes_in_use;	/* Pointer wrap not handled yet */			cinfo.blocks = dmap_in->qlen;			cinfo.bytes += cinfo.ptr;			if (dmap_in->mapping_flags & DMA_MAP_MAPPED)				dmap_in->qlen = 0;	/* Reset interrupt counter */			spin_unlock_irqrestore(&dmap_in->lock,flags);			if (copy_to_user(arg, &cinfo, sizeof(cinfo)))				return -EFAULT;			return 0;		case SNDCTL_DSP_GETOPTR:			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))				return -EINVAL;			spin_lock_irqsave(&dmap_out->lock,flags);			cinfo.bytes = dmap_out->byte_counter;			cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3;			if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0)				cinfo.bytes += dmap_out->bytes_in_use;	/* Pointer wrap not handled yet */			cinfo.blocks = dmap_out->qlen;			cinfo.bytes += cinfo.ptr;			if (dmap_out->mapping_flags & DMA_MAP_MAPPED)				dmap_out->qlen = 0;	/* Reset interrupt counter */			spin_unlock_irqrestore(&dmap_out->lock,flags);			if (copy_to_user(arg, &cinfo, sizeof(cinfo)))				return -EFAULT;			return 0;		case SNDCTL_DSP_GETODELAY:			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))				return -EINVAL;			if (!(dmap_out->flags & DMA_ALLOC_DONE))			{				ret=0;				break;			}			spin_lock_irqsave(&dmap_out->lock,flags);			/* Compute number of bytes that have been played */			count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT);			if (count < dmap_out->fragment_size && dmap_out->qhead != 0)				count += dmap_out->bytes_in_use;	/* Pointer wrap not handled yet */			count += dmap_out->byte_counter;			/* Substract current count from the number of bytes written by app */			count = dmap_out->user_counter - count;			if (count < 0)				count = 0;			spin_unlock_irqrestore(&dmap_out->lock,flags);			ret = count;			break;		case SNDCTL_DSP_POST:			if (audio_devs[dev]->dmap_out->qlen > 0)				if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))					DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);			return 0;		case SNDCTL_DSP_GETBLKSIZE:			dmap = dmap_out;			if (audio_devs[dev]->open_mode & OPEN_WRITE)				reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ));			if (audio_devs[dev]->open_mode == OPEN_READ ||			    (audio_devs[dev]->flags & DMA_DUPLEX &&			     audio_devs[dev]->open_mode & OPEN_READ))				reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ));			if (audio_devs[dev]->open_mode == OPEN_READ)				dmap = dmap_in;			ret = dmap->fragment_size;			break;		case SNDCTL_DSP_SETFRAGMENT:			ret = 0;			if (get_user(fact, (int __user *)arg))				return -EFAULT;			if (audio_devs[dev]->open_mode & OPEN_WRITE)				ret = dma_set_fragment(dev, dmap_out, fact);			if (ret < 0)				return ret;			if (audio_devs[dev]->open_mode == OPEN_READ ||			    (audio_devs[dev]->flags & DMA_DUPLEX &&			     audio_devs[dev]->open_mode & OPEN_READ))				ret = dma_set_fragment(dev, dmap_in, fact);			if (ret < 0)				return ret;			if (!arg) /* don't know what this is good for, but preserve old semantics */				return 0;			break;		default:			if (!audio_devs[dev]->d->ioctl)				return -EINVAL;			return audio_devs[dev]->d->ioctl(dev, cmd, arg);	}	return put_user(ret, (int __user *)arg);}

⌨️ 快捷键说明

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