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

📄 dmasound_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (shared_resource_owner == 0) {		/* you can make this AFMT_U8/mono/8K if you want to mimic old		   OSS behaviour - while we still have soft translations ;-) */		dmasound.soft = dmasound.mach.default_soft ;		dmasound.dsp = dmasound.mach.default_soft ;		dmasound.hard = dmasound.mach.default_hard ;	}#ifndef DMASOUND_STRICT_OSS_COMPLIANCE	/* none of the current LL drivers can actually do this "native" at the moment	   OSS does not really require us to supply /dev/audio if we can't do it.	*/	if (dmasound.minDev == SND_DEV_AUDIO) {		sound_set_speed(8000);		sound_set_stereo(0);		sound_set_format(AFMT_MU_LAW);	}#endif	return 0; out:	module_put(dmasound.mach.owner);	return rc;}static void sq_reset_output(void){	sound_silence(); /* this _must_ stop DMA, we might be about to lose the buffers */	write_sq.active = 0;	write_sq.count = 0;	write_sq.rear_size = 0;	/* write_sq.front = (write_sq.rear+1) % write_sq.max_count;*/	write_sq.front = 0 ;	write_sq.rear = -1 ; /* same as for set-up */	/* OK - we can unlock the parameters and fragment settings */	write_sq.locked = 0 ;	write_sq.user_frags = 0 ;	write_sq.user_frag_size = 0 ;}#ifdef HAS_RECORDstatic void sq_reset_input(void){	if (dmasound.mach.record && read_sq.active) {		if (dmasound.mach.abort_read) { /* this routine must really be present */			read_sq.syncing = 1 ;			/* this can use the read_sq.sync_queue to sleep if			   necessary - it should not return until DMA			   is really stopped - because we might deallocate			   the buffers as the next action...			*/			dmasound.mach.abort_read() ;		} else {			printk(KERN_ERR			"dmasound_core: %s has no abort_read()!! all bets are off\n",				dmasound.mach.name) ;		}	}	read_sq.syncing =	read_sq.active =	read_sq.front =	read_sq.count =	read_sq.rear = 0 ;	/* OK - we can unlock the parameters and fragment settings */	read_sq.locked = 0 ;	read_sq.user_frags = 0 ;	read_sq.user_frag_size = 0 ;}#endifstatic void sq_reset(void){	sq_reset_output() ;	sq_reset_input() ;	/* we could consider resetting the shared_resources_owner here... but I	   think it is probably still rather non-obvious to application writer	*/	/* we release everything else though */	shared_resources_initialised = 0 ;}static int sq_fsync(struct file *filp, struct dentry *dentry){	int rc = 0;	int timeout = 5;	write_sq.syncing |= 1;	sq_play();	/* there may be an incomplete frame waiting */	while (write_sq.active) {		SLEEP(write_sq.sync_queue);		if (signal_pending(current)) {			/* While waiting for audio output to drain, an			 * interrupt occurred.  Stop audio output immediately			 * and clear the queue. */			sq_reset_output();			rc = -EINTR;			break;		}		if (!--timeout) {			printk(KERN_WARNING "dmasound: Timeout draining output\n");			sq_reset_output();			rc = -EIO;			break;		}	}	/* flag no sync regardless of whether we had a DSP_POST or not */	write_sq.syncing = 0 ;	return rc;}static int sq_release(struct inode *inode, struct file *file){	int rc = 0;	lock_kernel();#ifdef HAS_RECORD	/* probably best to do the read side first - so that time taken to do it	   overlaps with playing any remaining output samples.	*/	if (file->f_mode & FMODE_READ) {		sq_reset_input() ; /* make sure dma is stopped and all is quiet */		read_sq_release_buffers();		read_sq.busy = 0;	}#endif	if (file->f_mode & FMODE_WRITE) {		if (write_sq.busy)			rc = sq_fsync(file, file->f_dentry);		sq_reset_output() ; /* make sure dma is stopped and all is quiet */		write_sq_release_buffers();		write_sq.busy = 0;	}	if (file->f_mode & shared_resource_owner) { /* it's us that has them */		shared_resource_owner = 0 ;		shared_resources_initialised = 0 ;		dmasound.hard = dmasound.mach.default_hard ;	}	module_put(dmasound.mach.owner);#if 0 /* blocking open() */	/* Wake up a process waiting for the queue being released.	 * Note: There may be several processes waiting for a call	 * to open() returning. */	/* Iain: hmm I don't understand this next comment ... */	/* There is probably a DOS atack here. They change the mode flag. */	/* XXX add check here,*/	read_sq_wake_up(file); /* checks f_mode */	write_sq_wake_up(file); /* checks f_mode */#endif /* blocking open() */	unlock_kernel();	return rc;}/* here we see if we have a right to modify format, channels, size and so on   if no-one else has claimed it already then we do...   TODO: We might change this to mask O_RDWR such that only one or the other channel   is the owner - if we have problems.*/static int shared_resources_are_mine(mode_t md){	if (shared_resource_owner)		return (shared_resource_owner & md ) ;	else {		shared_resource_owner = md ;		return 1 ;	}}/* if either queue is locked we must deny the right to change shared params*/static int queues_are_quiescent(void){#ifdef HAS_RECORD	if (dmasound.mach.record)		if (read_sq.locked)			return 0 ;#endif	if (write_sq.locked)		return 0 ;	return 1 ;}/* check and set a queue's fragments per user's wishes...   we will check against the pre-defined literals and the actual sizes.   This is a bit fraught - because soft translations can mess with our   buffer requirements *after* this call - OSS says "call setfrags first"*//* It is possible to replace all the -EINVAL returns with an override that   just puts the allowable value in.  This may be what many OSS apps require*/static int set_queue_frags(struct sound_queue *sq, int bufs, int size){	if (sq->locked) {#ifdef DEBUG_DMASOUNDprintk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;#endif		return -EINVAL ;	}	if ((size < MIN_FRAG_SIZE) || (size > MAX_FRAG_SIZE))		return -EINVAL ;	size = (1<<size) ; /* now in bytes */	if (size > sq->bufSize)		return -EINVAL ; /* this might still not work */	if (bufs <= 0)		return -EINVAL ;	if (bufs > sq->numBufs) /* the user is allowed say "don't care" with 0x7fff */		bufs = sq->numBufs ;	/* there is, currently, no way to specify max_active separately	   from max_count.  This could be a LL driver issue - I guess	   if there is a requirement for these values to be different then	  we will have to pass that info. up to this level.	*/	sq->user_frags =	sq->max_active = bufs ;	sq->user_frag_size = size ;	return 0 ;}static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,		    u_long arg){	int val, result;	u_long fmt;	int data;	int size, nbufs;	audio_buf_info info;	switch (cmd) {	case SNDCTL_DSP_RESET:		sq_reset();		return 0;		break ;	case SNDCTL_DSP_GETFMTS:		fmt = dmasound.mach.hardware_afmts ; /* this is what OSS says.. */		return IOCTL_OUT(arg, fmt);		break ;	case SNDCTL_DSP_GETBLKSIZE:		/* this should tell the caller about bytes that the app can		   read/write - the app doesn't care about our internal buffers.		   We force sq_setup() here as per OSS 1.1 (which should		   compute the values necessary).		   Since there is no mechanism to specify read/write separately, for		   fds opened O_RDWR, the write_sq values will, arbitrarily, overwrite		   the read_sq ones.		*/		size = 0 ;#ifdef HAS_RECORD		if (dmasound.mach.record && (file->f_mode & FMODE_READ)) {			if ( !read_sq.locked )				sq_setup(&read_sq) ; /* set params */			size = read_sq.user_frag_size ;		}#endif		if (file->f_mode & FMODE_WRITE) {			if ( !write_sq.locked )				sq_setup(&write_sq) ;			size = write_sq.user_frag_size ;		}		return IOCTL_OUT(arg, size);		break ;	case SNDCTL_DSP_POST:		/* all we are going to do is to tell the LL that any		   partial frags can be queued for output.		   The LL will have to clear this flag when last output		   is queued.		*/		write_sq.syncing |= 0x2 ;		sq_play() ;		return 0 ;	case SNDCTL_DSP_SYNC:		/* This call, effectively, has the same behaviour as SNDCTL_DSP_RESET		   except that it waits for output to finish before resetting		   everything - read, however, is killed imediately.		*/		result = 0 ;		if ((file->f_mode & FMODE_READ) && dmasound.mach.record)			sq_reset_input() ;		if (file->f_mode & FMODE_WRITE) {			result = sq_fsync(file, file->f_dentry);			sq_reset_output() ;		}		/* if we are the shared resource owner then release them */		if (file->f_mode & shared_resource_owner)			shared_resources_initialised = 0 ;		return result ;		break ;	case SOUND_PCM_READ_RATE:		return IOCTL_OUT(arg, dmasound.soft.speed);	case SNDCTL_DSP_SPEED:		/* changing this on the fly will have weird effects on the sound.		   Where there are rate conversions implemented in soft form - it		   will cause the _ctx_xxx() functions to be substituted.		   However, there doesn't appear to be any reason to dis-allow it from		   a driver pov.		*/		if (shared_resources_are_mine(file->f_mode)) {			IOCTL_IN(arg, data);			data = sound_set_speed(data) ;			shared_resources_initialised = 0 ;			return IOCTL_OUT(arg, data);		} else			return -EINVAL ;		break ;	/* OSS says these next 4 actions are undefined when the device is	   busy/active - we will just return -EINVAL.	   To be allowed to change one - (a) you have to own the right	    (b) the queue(s) must be quiescent	*/	case SNDCTL_DSP_STEREO:		if (shared_resources_are_mine(file->f_mode) &&		    queues_are_quiescent()) {			IOCTL_IN(arg, data);			shared_resources_initialised = 0 ;			return IOCTL_OUT(arg, sound_set_stereo(data));		} else			return -EINVAL ;		break ;	case SOUND_PCM_WRITE_CHANNELS:		if (shared_resources_are_mine(file->f_mode) &&		    queues_are_quiescent()) {			IOCTL_IN(arg, data);			/* the user might ask for 20 channels, we will return 1 or 2 */			shared_resources_initialised = 0 ;			return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);		} else			return -EINVAL ;		break ;	case SNDCTL_DSP_SETFMT:		if (shared_resources_are_mine(file->f_mode) &&		    queues_are_quiescent()) {		    	int format;			IOCTL_IN(arg, data);			shared_resources_initialised = 0 ;			format = sound_set_format(data);			result = IOCTL_OUT(arg, format);			if (result < 0)				return result;			if (format != data && data != AFMT_QUERY)				return -EINVAL;			return 0;		} else			return -EINVAL ;	case SNDCTL_DSP_SUBDIVIDE:		return -EINVAL ;	case SNDCTL_DSP_SETFRAGMENT:		/* we can do this independently for the two queues - with the		   proviso that for fds opened O_RDWR we cannot separate the		   actions and both queues will be set per the last call.		   NOTE: this does *NOT* actually set the queue up - merely		   registers our intentions.		*/		IOCTL_IN(arg, data);		result = 0 ;		nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */		size = data & 0xffff;#ifdef HAS_RECORD		if ((file->f_mode & FMODE_READ) && dmasound.mach.record) {			result = set_queue_frags(&read_sq, nbufs, size) ;			if (result)				return result ;		}#endif		if (file->f_mode & FMODE_WRITE) {			result = set_queue_frags(&write_sq, nbufs, size) ;			if (result)				return result ;		}		/* NOTE: this return value is irrelevant - OSS specifically says that		   the value is 'random' and that the user _must_ check the actual		   frags values using SNDCTL_DSP_GETBLKSIZE or similar */		return IOCTL_OUT(arg, data);		break ;	case SNDCTL_DSP_GETOSPACE:		/*		*/		if (file->f_mode & FMODE_WRITE) {			if ( !write_sq.locked )				sq_setup(&write_sq) ;			info.fragments = write_sq.max_active - write_sq.count;			info.fragstotal = write_sq.max_active;			info.fragsize = write_sq.user_frag_size;			info.bytes = info.fragments * info.fragsize;			if (copy_to_user((void __user *)arg, &info, sizeof(info)))				return -EFAULT;			return 0;		} else			return -EINVAL ;		break ;	case SNDCTL_DSP_GETCAPS:		val = dmasound.mach.capabilities & 0xffffff00;		return IOCTL_OUT(arg,val);	default:		return mixer_ioctl(inode, file, cmd, arg);	}	return -EINVAL;}static struct file_operations sq_fops ={	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.write		= sq_write,	.poll		= sq_poll,	.ioctl		= sq_ioctl,	.open		= sq_open,	.release	= sq_release,#ifdef HAS_RECORD	.read		= NULL	/* default to no read for compat mode */#endif};static int sq_init(void){#ifndef MODULE	int sq_unit;#endif#ifdef HAS_RECORD	if (dmasound.mach.record)		sq_fops.read = sq_read ;#endif	sq_unit = register_sound_dsp(&sq_fops, -1);	if (sq_unit < 0) {		printk(KERN_ERR "dmasound_core: couldn't register fops\n") ;		return sq_unit ;	}	write_sq_init_waitqueue();	read_sq_init_waitqueue();	/* These parameters will be restored for every clean open()	 * in the case of multiple open()s (e.g. dsp0 & dsp1) they

⌨️ 快捷键说明

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