drm_drv.h

来自「Linux Kernel 2.6.9 for OMAP1710」· C头文件 代码 · 共 1,062 行 · 第 1/2 页

H
1,062
字号
}/** * Module initialization. Called via init_module at module load time, or via * linux/init/main.c (this is not currently supported). * * \return zero on success or a negative number on failure. * * Initializes an array of drm_device structures, and attempts to * initialize all available devices, using consecutive minors, registering the * stubs and initializing the AGP device. *  * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and * after the initialization for driver customization. */static int __init drm_init( void ){	struct pci_dev *pdev = NULL;	DRM_DEBUG( "\n" );#ifdef MODULE	DRM(parse_options)( drm_opts );#endif	DRM(mem_init)();	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {		DRM(probe)(pdev);	}	return 0;}/** * Called via cleanup_module() at module unload time. * * Cleans up all DRM device, calling takedown(). *  * \sa drm_init(). */static void __exit drm_cleanup( void ){	drm_device_t *dev;	int i;	DRM_DEBUG( "\n" );	for (i = DRM(numdevs) - 1; i >= 0; i--) {		dev = &(DRM(device)[i]);		if ( DRM(stub_unregister)(dev->minor) ) {			DRM_ERROR( "Cannot unload module\n" );		} else {			DRM_DEBUG("minor %d unregistered\n", dev->minor);			if (i == 0) {				DRM_INFO( "Module unloaded\n" );			}		}		DRM(ctxbitmap_cleanup)( dev );		if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&		    dev->agp && dev->agp->agp_mtrr >= 0) {			int retval;			retval = mtrr_del( dev->agp->agp_mtrr,				   dev->agp->agp_info.aper_base,				   dev->agp->agp_info.aper_size*1024*1024 );			DRM_DEBUG( "mtrr_del=%d\n", retval );		}		DRM(takedown)( dev );		if (drm_core_has_AGP(dev) && dev->agp ) {			DRM(agp_uninit)();			DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );			dev->agp = NULL;		}		if (dev->fn_tbl.postcleanup)		  dev->fn_tbl.postcleanup(dev);	}	DRM(numdevs) = 0;}module_init( drm_init );module_exit( drm_cleanup );/** * Get version information * * \param inode device inode. * \param filp file pointer. * \param cmd command. * \param arg user argument, pointing to a drm_version structure. * \return zero on success or negative number on failure. * * Fills in the version information in \p arg. */int DRM(version)( struct inode *inode, struct file *filp,		  unsigned int cmd, unsigned long arg ){	drm_version_t __user *argp = (void __user *)arg;	drm_version_t version;	int len;	if ( copy_from_user( &version, argp, sizeof(version) ) )		return -EFAULT;#define DRM_COPY( name, value )						\	len = strlen( value );						\	if ( len > name##_len ) len = name##_len;			\	name##_len = strlen( value );					\	if ( len && name ) {						\		if ( copy_to_user( name, value, len ) )			\			return -EFAULT;					\	}	version.version_major = DRIVER_MAJOR;	version.version_minor = DRIVER_MINOR;	version.version_patchlevel = DRIVER_PATCHLEVEL;	DRM_COPY( version.name, DRIVER_NAME );	DRM_COPY( version.date, DRIVER_DATE );	DRM_COPY( version.desc, DRIVER_DESC );	if ( copy_to_user( argp, &version, sizeof(version) ) )		return -EFAULT;	return 0;}/** * Open file. *  * \param inode device inode * \param filp file pointer. * \return zero on success or a negative number on failure. * * Searches the DRM device with the same minor number, calls open_helper(), and * increments the device open count. If the open count was previous at zero, * i.e., it's the first that the device is open, then calls setup(). */int DRM(open)( struct inode *inode, struct file *filp ){	drm_device_t *dev = NULL;	int retcode = 0;	int i;	for (i = 0; i < DRM(numdevs); i++) {		if (iminor(inode) == DRM(device)[i].minor) {			dev = &(DRM(device)[i]);			break;		}	}	if (!dev) {		return -ENODEV;	}	retcode = DRM(open_helper)( inode, filp, dev );	if ( !retcode ) {		atomic_inc( &dev->counts[_DRM_STAT_OPENS] );		spin_lock( &dev->count_lock );		if ( !dev->open_count++ ) {			spin_unlock( &dev->count_lock );			return DRM(setup)( dev );		}		spin_unlock( &dev->count_lock );	}	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 );	if (dev->fn_tbl.prerelease)		dev->fn_tbl.prerelease(dev, filp);	/* ========================================================	 * 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 (dev->fn_tbl.release)			dev->fn_tbl.release(dev, filp);		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. */	}	else if ( dev->fn_tbl.release && 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 (;;) {			__set_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;			}		}		__set_current_state(TASK_RUNNING);		remove_wait_queue( &dev->lock.lock_queue, &entry );		if( !retcode ) {			if (dev->fn_tbl.release)				dev->fn_tbl.release(dev, filp);			DRM(lock_free)( dev, &dev->lock.hw_lock->lock,					DRM_KERNEL_CONTEXT );		}	}		if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))	{		dev->fn_tbl.reclaim_buffers(filp);	}	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 ) {				if (dev->fn_tbl.context_dtor)					dev->fn_tbl.context_dtor(dev, pos->handle);				DRM(ctxbitmap_free)( dev, pos->handle );				list_del( &pos->head );				DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST );				--dev->ctx_count;			}		}	}	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 );		if (dev->fn_tbl.free_filp_priv)		dev->fn_tbl.free_filp_priv(dev, priv);	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;	++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 (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))		if ( lock.context < 0 )			return -EINVAL;	add_wait_queue( &dev->lock.lock_queue, &entry );	for (;;) {		__set_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;		}	}	__set_current_state(TASK_RUNNING);	remove_wait_queue( &dev->lock.lock_queue, &entry );	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 (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY))		dev->fn_tbl.dma_ready(dev);		if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT ))		return dev->fn_tbl.dma_quiescent(dev);		/* dev->fn_tbl.kernel_context_switch isn't used by any of the x86 	 *  drivers but is used by the Sparc driver.	 */		if (dev->fn_tbl.kernel_context_switch && 	    dev->last_context != lock.context) {	  dev->fn_tbl.kernel_context_switch(dev, dev->last_context, 					    lock.context);	}        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] );	/* kernel_context_switch isn't used by any of the x86 drm	 * modules but is required by the Sparc driver.	 */	if (dev->fn_tbl.kernel_context_switch_unlock)		dev->fn_tbl.kernel_context_switch_unlock(dev, &lock);	else {		DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, 				    DRM_KERNEL_CONTEXT );				if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock,				     DRM_KERNEL_CONTEXT ) ) {			DRM_ERROR( "\n" );		}	}	unblock_all_signals();	return 0;}

⌨️ 快捷键说明

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