drm_drv.h

来自「优龙2410linux2.6.8内核源代码」· C头文件 代码 · 共 1,210 行 · 第 1/3 页

H
1,210
字号
	}	return retcode;}/** * Release file. * * \param inode device inode * \param filp file pointer. * \return zero on success or a negative number on failure. * * If the hardware lock is held then free it, and take it again for the kernel * context since it's necessary to reclaim buffers. Unlink the file private * data from its list and free it. Decreases the open count and if it reaches * zero calls takedown(). */int DRM(release)( struct inode *inode, struct file *filp ){	drm_file_t *priv = filp->private_data;	drm_device_t *dev;	int retcode = 0;	lock_kernel();	dev = priv->dev;	DRM_DEBUG( "open_count = %d\n", dev->open_count );	DRIVER_PRERELEASE();	/* ========================================================	 * Begin inline drm_release	 */	DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",		   current->pid, (long)old_encode_dev(dev->device), dev->open_count );	if ( priv->lock_count && dev->lock.hw_lock &&	     _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&	     dev->lock.filp == filp ) {		DRM_DEBUG( "File %p released, freeing lock for context %d\n",			filp,			_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );#if __HAVE_RELEASE		DRIVER_RELEASE();#endif		DRM(lock_free)( dev, &dev->lock.hw_lock->lock,				_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );				/* FIXME: may require heavy-handed reset of                                   hardware at this point, possibly                                   processed via a callback to the X                                   server. */	}#if __HAVE_RELEASE	else if ( priv->lock_count && dev->lock.hw_lock ) {		/* The lock is required to reclaim buffers */		DECLARE_WAITQUEUE( entry, current );		add_wait_queue( &dev->lock.lock_queue, &entry );		for (;;) {			current->state = TASK_INTERRUPTIBLE;			if ( !dev->lock.hw_lock ) {				/* Device has been unregistered */				retcode = -EINTR;				break;			}			if ( DRM(lock_take)( &dev->lock.hw_lock->lock,					     DRM_KERNEL_CONTEXT ) ) {				dev->lock.filp	    = filp;				dev->lock.lock_time = jiffies;                                atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );				break;	/* Got lock */			}				/* Contention */			schedule();			if ( signal_pending( current ) ) {				retcode = -ERESTARTSYS;				break;			}		}		current->state = TASK_RUNNING;		remove_wait_queue( &dev->lock.lock_queue, &entry );		if( !retcode ) {			DRIVER_RELEASE();			DRM(lock_free)( dev, &dev->lock.hw_lock->lock,					DRM_KERNEL_CONTEXT );		}	}#elif __HAVE_DMA	DRM(reclaim_buffers)( filp );#endif	DRM(fasync)( -1, filp, 0 );	down( &dev->ctxlist_sem );	if ( !list_empty( &dev->ctxlist->head ) ) {		drm_ctx_list_t *pos, *n;		list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) {			if ( pos->tag == priv &&			     pos->handle != DRM_KERNEL_CONTEXT ) {#ifdef DRIVER_CTX_DTOR				DRIVER_CTX_DTOR(pos->handle);#endif#if __HAVE_CTX_BITMAP				DRM(ctxbitmap_free)( dev, pos->handle );#endif				list_del( &pos->head );				DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST );			}		}	}	up( &dev->ctxlist_sem );	down( &dev->struct_sem );	if ( priv->remove_auth_on_close == 1 ) {		drm_file_t *temp = dev->file_first;		while ( temp ) {			temp->authenticated = 0;			temp = temp->next;		}	}	if ( priv->prev ) {		priv->prev->next = priv->next;	} else {		dev->file_first	 = priv->next;	}	if ( priv->next ) {		priv->next->prev = priv->prev;	} else {		dev->file_last	 = priv->prev;	}	up( &dev->struct_sem );		DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES );	/* ========================================================	 * End inline drm_release	 */	atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );	spin_lock( &dev->count_lock );	if ( !--dev->open_count ) {		if ( atomic_read( &dev->ioctl_count ) || dev->blocked ) {			DRM_ERROR( "Device busy: %d %d\n",				   atomic_read( &dev->ioctl_count ),				   dev->blocked );			spin_unlock( &dev->count_lock );			unlock_kernel();			return -EBUSY;		}		spin_unlock( &dev->count_lock );		unlock_kernel();		return DRM(takedown)( dev );	}	spin_unlock( &dev->count_lock );	unlock_kernel();	return retcode;}/**  * Called whenever a process performs an ioctl on /dev/drm. * * \param inode device inode. * \param filp file pointer. * \param cmd command. * \param arg user argument. * \return zero on success or negative number on failure. * * Looks up the ioctl function in the ::ioctls table, checking for root * previleges if so required, and dispatches to the respective function. */int DRM(ioctl)( struct inode *inode, struct file *filp,		unsigned int cmd, unsigned long arg ){	drm_file_t *priv = filp->private_data;	drm_device_t *dev = priv->dev;	drm_ioctl_desc_t *ioctl;	drm_ioctl_t *func;	int nr = DRM_IOCTL_NR(cmd);	int retcode = 0;	atomic_inc( &dev->ioctl_count );	atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] );	++priv->ioctl_count;	DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",		   current->pid, cmd, nr, (long)old_encode_dev(dev->device), 		   priv->authenticated );	if ( nr >= DRIVER_IOCTL_COUNT ) {		retcode = -EINVAL;	} else {		ioctl = &DRM(ioctls)[nr];		func = ioctl->func;		if ( !func ) {			DRM_DEBUG( "no function\n" );			retcode = -EINVAL;		} else if ( ( ioctl->root_only && !capable( CAP_SYS_ADMIN ) )||			    ( ioctl->auth_needed && !priv->authenticated ) ) {			retcode = -EACCES;		} else {			retcode = func( inode, filp, cmd, arg );		}	}	atomic_dec( &dev->ioctl_count );	return retcode;}/**  * Lock ioctl. * * \param inode device inode. * \param filp file pointer. * \param cmd command. * \param arg user argument, pointing to a drm_lock structure. * \return zero on success or negative number on failure. * * Add the current task to the lock wait queue, and attempt to take to lock. */int DRM(lock)( struct inode *inode, struct file *filp,	       unsigned int cmd, unsigned long arg ){        drm_file_t *priv = filp->private_data;        drm_device_t *dev = priv->dev;        DECLARE_WAITQUEUE( entry, current );        drm_lock_t lock;        int ret = 0;#if __HAVE_MULTIPLE_DMA_QUEUES	drm_queue_t *q;#endif	++priv->lock_count;        if ( copy_from_user( &lock, (drm_lock_t __user *)arg, sizeof(lock) ) )		return -EFAULT;        if ( lock.context == DRM_KERNEL_CONTEXT ) {                DRM_ERROR( "Process %d using kernel context %d\n",			   current->pid, lock.context );                return -EINVAL;        }        DRM_DEBUG( "%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",		   lock.context, current->pid,		   dev->lock.hw_lock->lock, lock.flags );#if __HAVE_DMA_QUEUE        if ( lock.context < 0 )                return -EINVAL;#elif __HAVE_MULTIPLE_DMA_QUEUES        if ( lock.context < 0 || lock.context >= dev->queue_count )                return -EINVAL;	q = dev->queuelist[lock.context];#endif#if __HAVE_DMA_FLUSH	ret = DRM(flush_block_and_flush)( dev, lock.context, lock.flags );#endif        if ( !ret ) {                add_wait_queue( &dev->lock.lock_queue, &entry );                for (;;) {                        current->state = TASK_INTERRUPTIBLE;                        if ( !dev->lock.hw_lock ) {                                /* Device has been unregistered */                                ret = -EINTR;                                break;                        }                        if ( DRM(lock_take)( &dev->lock.hw_lock->lock,					     lock.context ) ) {                                dev->lock.filp      = filp;                                dev->lock.lock_time = jiffies;                                atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );                                break;  /* Got lock */                        }                                /* Contention */                        schedule();                        if ( signal_pending( current ) ) {                                ret = -ERESTARTSYS;                                break;                        }                }                current->state = TASK_RUNNING;                remove_wait_queue( &dev->lock.lock_queue, &entry );        }#if __HAVE_DMA_FLUSH	DRM(flush_unblock)( dev, lock.context, lock.flags ); /* cleanup phase */#endif        if ( !ret ) {		sigemptyset( &dev->sigmask );		sigaddset( &dev->sigmask, SIGSTOP );		sigaddset( &dev->sigmask, SIGTSTP );		sigaddset( &dev->sigmask, SIGTTIN );		sigaddset( &dev->sigmask, SIGTTOU );		dev->sigdata.context = lock.context;		dev->sigdata.lock    = dev->lock.hw_lock;		block_all_signals( DRM(notifier),				   &dev->sigdata, &dev->sigmask );#if __HAVE_DMA_READY                if ( lock.flags & _DRM_LOCK_READY ) {			DRIVER_DMA_READY();		}#endif#if __HAVE_DMA_QUIESCENT                if ( lock.flags & _DRM_LOCK_QUIESCENT ) {			DRIVER_DMA_QUIESCENT();		}#endif		/* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the		 * drm modules in the DRI cvs tree, but it is required		 * by the Sparc driver.		 */#if __HAVE_KERNEL_CTX_SWITCH		if ( dev->last_context != lock.context ) {			DRM(context_switch)(dev, dev->last_context,					    lock.context);		}#endif        }        DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );        return ret;}/**  * Unlock ioctl. * * \param inode device inode. * \param filp file pointer. * \param cmd command. * \param arg user argument, pointing to a drm_lock structure. * \return zero on success or negative number on failure. * * Transfer and free the lock. */int DRM(unlock)( struct inode *inode, struct file *filp,		 unsigned int cmd, unsigned long arg ){	drm_file_t *priv = filp->private_data;	drm_device_t *dev = priv->dev;	drm_lock_t lock;	if ( copy_from_user( &lock, (drm_lock_t __user *)arg, sizeof(lock) ) )		return -EFAULT;	if ( lock.context == DRM_KERNEL_CONTEXT ) {		DRM_ERROR( "Process %d using kernel context %d\n",			   current->pid, lock.context );		return -EINVAL;	}	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );	/* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm	 * modules in the DRI cvs tree, but it is required by the	 * Sparc driver.	 */#if __HAVE_KERNEL_CTX_SWITCH	/* We no longer really hold it, but if we are the next	 * agent to request it then we should just be able to	 * take it immediately and not eat the ioctl.	 */	dev->lock.filp = NULL;	{		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;		unsigned int old, new, prev, ctx;		ctx = lock.context;		do {			old  = *plock;			new  = ctx;			prev = cmpxchg(plock, old, new);		} while (prev != old);	}	wake_up_interruptible(&dev->lock.lock_queue);#else	DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,			    DRM_KERNEL_CONTEXT );#if __HAVE_DMA_SCHEDULE	DRM(dma_schedule)( dev, 1 );#endif	if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock,			     DRM_KERNEL_CONTEXT ) ) {		DRM_ERROR( "\n" );	}#endif /* !__HAVE_KERNEL_CTX_SWITCH */	unblock_all_signals();	return 0;}

⌨️ 快捷键说明

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