2005-04-17 02:20:36 +04:00
/**
2005-09-25 08:28:13 +04:00
* \ file drm_fops . c
2005-04-17 02:20:36 +04:00
* File operations for DRM
2005-09-25 08:28:13 +04:00
*
2005-04-17 02:20:36 +04:00
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
* \ author Daryll Strauss < daryll @ valinux . com >
* \ author Gareth Hughes < gareth @ valinux . com >
*/
/*
* Created : Mon Jan 4 08 : 58 : 31 1999 by faith @ valinux . com
*
* Copyright 1999 Precision Insight , Inc . , Cedar Park , Texas .
* Copyright 2000 VA Linux Systems , Inc . , Sunnyvale , California .
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* VA LINUX SYSTEMS AND / OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*/
# include "drmP.h"
# include <linux/poll.h>
2008-05-15 21:34:16 +04:00
# include <linux/smp_lock.h>
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
static int drm_open_helper ( struct inode * inode , struct file * filp ,
2007-07-11 09:53:27 +04:00
struct drm_device * dev ) ;
2005-07-07 15:03:38 +04:00
2007-07-11 09:53:27 +04:00
static int drm_setup ( struct drm_device * dev )
2005-04-17 02:20:36 +04:00
{
int i ;
int ret ;
2005-11-10 14:16:34 +03:00
if ( dev - > driver - > firstopen ) {
ret = dev - > driver - > firstopen ( dev ) ;
2005-09-25 08:28:13 +04:00
if ( ret ! = 0 )
2005-04-17 02:20:36 +04:00
return ret ;
}
2005-09-25 08:28:13 +04:00
atomic_set ( & dev - > ioctl_count , 0 ) ;
atomic_set ( & dev - > vma_count , 0 ) ;
2005-04-17 02:20:36 +04:00
2008-11-08 01:05:41 +03:00
if ( drm_core_check_feature ( dev , DRIVER_HAVE_DMA ) & &
! drm_core_check_feature ( dev , DRIVER_MODESET ) ) {
dev - > buf_use = 0 ;
atomic_set ( & dev - > buf_alloc , 0 ) ;
2005-09-25 08:28:13 +04:00
i = drm_dma_setup ( dev ) ;
if ( i < 0 )
2005-04-17 02:20:36 +04:00
return i ;
}
2006-08-07 14:07:43 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( dev - > counts ) ; i + + )
2005-09-25 08:28:13 +04:00
atomic_set ( & dev - > counts [ i ] , 0 ) ;
2005-04-17 02:20:36 +04:00
2007-02-18 09:13:39 +03:00
dev - > sigdata . lock = NULL ;
2008-11-28 07:22:24 +03:00
2005-04-17 02:20:36 +04:00
dev - > queue_count = 0 ;
dev - > queue_reserved = 0 ;
dev - > queue_slots = 0 ;
dev - > queuelist = NULL ;
dev - > context_flag = 0 ;
dev - > interrupt_flag = 0 ;
dev - > dma_flag = 0 ;
dev - > last_context = 0 ;
dev - > last_switch = 0 ;
dev - > last_checked = 0 ;
2005-09-25 08:28:13 +04:00
init_waitqueue_head ( & dev - > context_wait ) ;
2005-04-17 02:20:36 +04:00
dev - > if_version = 0 ;
dev - > ctx_start = 0 ;
dev - > lck_start = 0 ;
dev - > buf_async = NULL ;
2005-09-25 08:28:13 +04:00
init_waitqueue_head ( & dev - > buf_readers ) ;
init_waitqueue_head ( & dev - > buf_writers ) ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
DRM_DEBUG ( " \n " ) ;
2005-04-17 02:20:36 +04:00
/*
* The kernel ' s context could be created here , but is now created
2005-09-25 08:28:13 +04:00
* in drm_dma_enqueue . This is more resource - efficient for
2005-04-17 02:20:36 +04:00
* hardware that does not do DMA , but may mean that
* drm_select_queue fails between the time the interrupt is
* initialized and the time the queues are initialized .
*/
return 0 ;
}
/**
* Open file .
2005-09-25 08:28:13 +04:00
*
2005-04-17 02:20:36 +04:00
* \ 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 ( ) .
*/
2005-09-25 08:28:13 +04:00
int drm_open ( struct inode * inode , struct file * filp )
2005-04-17 02:20:36 +04:00
{
2007-07-11 09:53:27 +04:00
struct drm_device * dev = NULL ;
2008-04-21 10:47:32 +04:00
int minor_id = iminor ( inode ) ;
struct drm_minor * minor ;
2005-04-17 02:20:36 +04:00
int retcode = 0 ;
2008-04-21 10:47:32 +04:00
minor = idr_find ( & drm_minors_idr , minor_id ) ;
if ( ! minor )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2005-09-25 08:28:13 +04:00
2008-04-21 10:47:32 +04:00
if ( ! ( dev = minor - > dev ) )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2005-09-25 08:28:13 +04:00
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 ) ;
2008-11-05 21:31:53 +03:00
retcode = drm_setup ( dev ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2005-09-25 08:28:13 +04:00
spin_unlock ( & dev - > count_lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-11-05 21:31:53 +03:00
out :
mutex_lock ( & dev - > struct_mutex ) ;
2008-11-08 01:05:41 +03:00
if ( minor - > type = = DRM_MINOR_LEGACY ) {
BUG_ON ( ( dev - > dev_mapping ! = NULL ) & &
( dev - > dev_mapping ! = inode - > i_mapping ) ) ;
if ( dev - > dev_mapping = = NULL )
dev - > dev_mapping = inode - > i_mapping ;
}
2008-11-05 21:31:53 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-17 02:20:36 +04:00
return retcode ;
}
EXPORT_SYMBOL ( drm_open ) ;
2006-01-02 13:32:48 +03:00
/**
* File \ c open operation .
*
* \ param inode device inode .
* \ param filp file pointer .
*
* Puts the dev - > fops corresponding to the device minor number into
* \ p filp , call the \ c open method , and restore the file operations .
*/
int drm_stub_open ( struct inode * inode , struct file * filp )
{
2007-07-11 09:53:27 +04:00
struct drm_device * dev = NULL ;
2008-04-21 10:47:32 +04:00
struct drm_minor * minor ;
int minor_id = iminor ( inode ) ;
2006-01-02 13:32:48 +03:00
int err = - ENODEV ;
2006-03-28 13:56:41 +04:00
const struct file_operations * old_fops ;
2006-01-02 13:32:48 +03:00
DRM_DEBUG ( " \n " ) ;
2008-05-15 21:34:16 +04:00
/* BKL pushdown: note that nothing else serializes idr_find() */
lock_kernel ( ) ;
2008-04-21 10:47:32 +04:00
minor = idr_find ( & drm_minors_idr , minor_id ) ;
if ( ! minor )
2008-05-15 21:34:16 +04:00
goto out ;
2006-01-02 13:32:48 +03:00
2008-04-21 10:47:32 +04:00
if ( ! ( dev = minor - > dev ) )
2008-05-15 21:34:16 +04:00
goto out ;
2006-01-02 13:32:48 +03:00
old_fops = filp - > f_op ;
filp - > f_op = fops_get ( & dev - > driver - > fops ) ;
2009-01-07 01:40:40 +03:00
if ( filp - > f_op = = NULL ) {
filp - > f_op = old_fops ;
goto out ;
}
2006-01-02 13:32:48 +03:00
if ( filp - > f_op - > open & & ( err = filp - > f_op - > open ( inode , filp ) ) ) {
fops_put ( filp - > f_op ) ;
filp - > f_op = fops_get ( old_fops ) ;
}
fops_put ( old_fops ) ;
2008-05-15 21:34:16 +04:00
out :
unlock_kernel ( ) ;
2006-01-02 13:32:48 +03:00
return err ;
}
/**
* Check whether DRI will run on this CPU .
*
* \ return non - zero if the DRI will run on this CPU , or zero otherwise .
*/
static int drm_cpu_valid ( void )
{
# if defined(__i386__)
if ( boot_cpu_data . x86 = = 3 )
return 0 ; /* No cmpxchg on a 386 */
# endif
# if defined(__sparc__) && !defined(__sparc_v9__)
return 0 ; /* No cmpxchg before v9 sparc. */
# endif
return 1 ;
}
/**
* Called whenever a process opens / dev / drm .
*
* \ param inode device inode .
* \ param filp file pointer .
* \ param dev device .
* \ return zero on success or a negative number on failure .
*
* Creates and initializes a drm_file structure for the file private data in \ p
* filp and add it into the double linked list in \ p dev .
*/
static int drm_open_helper ( struct inode * inode , struct file * filp ,
2007-07-11 09:53:27 +04:00
struct drm_device * dev )
2006-01-02 13:32:48 +03:00
{
2008-04-21 10:47:32 +04:00
int minor_id = iminor ( inode ) ;
2007-07-11 09:53:27 +04:00
struct drm_file * priv ;
2006-01-02 13:32:48 +03:00
int ret ;
if ( filp - > f_flags & O_EXCL )
return - EBUSY ; /* No exclusive opens */
if ( ! drm_cpu_valid ( ) )
return - EINVAL ;
2008-04-21 10:47:32 +04:00
DRM_DEBUG ( " pid = %d, minor = %d \n " , task_pid_nr ( current ) , minor_id ) ;
2006-01-02 13:32:48 +03:00
priv = drm_alloc ( sizeof ( * priv ) , DRM_MEM_FILES ) ;
if ( ! priv )
return - ENOMEM ;
memset ( priv , 0 , sizeof ( * priv ) ) ;
filp - > private_data = priv ;
2007-08-25 14:23:09 +04:00
priv - > filp = filp ;
2008-09-02 05:03:14 +04:00
priv - > uid = current_euid ( ) ;
2007-10-19 10:40:40 +04:00
priv - > pid = task_pid_nr ( current ) ;
2008-04-21 10:47:32 +04:00
priv - > minor = idr_find ( & drm_minors_idr , minor_id ) ;
2006-01-02 13:32:48 +03:00
priv - > ioctl_count = 0 ;
/* for compatibility root is always authenticated */
priv - > authenticated = capable ( CAP_SYS_ADMIN ) ;
priv - > lock_count = 0 ;
2007-05-25 23:01:51 +04:00
INIT_LIST_HEAD ( & priv - > lhead ) ;
2008-11-08 01:05:41 +03:00
INIT_LIST_HEAD ( & priv - > fbs ) ;
2007-05-25 23:01:51 +04:00
2008-07-30 23:06:12 +04:00
if ( dev - > driver - > driver_features & DRIVER_GEM )
drm_gem_open ( dev , priv ) ;
2006-01-02 13:32:48 +03:00
if ( dev - > driver - > open ) {
ret = dev - > driver - > open ( dev , priv ) ;
if ( ret < 0 )
goto out_free ;
}
2008-11-28 07:22:24 +03:00
/* if there is no current master make this fd it */
2006-02-02 11:37:46 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
2008-11-28 07:22:24 +03:00
if ( ! priv - > minor - > master ) {
/* create a new master */
priv - > minor - > master = drm_master_create ( priv - > minor ) ;
if ( ! priv - > minor - > master ) {
2009-03-27 13:34:28 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2008-11-28 07:22:24 +03:00
ret = - ENOMEM ;
goto out_free ;
}
priv - > is_master = 1 ;
/* take another reference for the copy in the local file priv */
priv - > master = drm_master_get ( priv - > minor - > master ) ;
priv - > authenticated = 1 ;
mutex_unlock ( & dev - > struct_mutex ) ;
if ( dev - > driver - > master_create ) {
ret = dev - > driver - > master_create ( dev , priv - > master ) ;
if ( ret ) {
mutex_lock ( & dev - > struct_mutex ) ;
/* drop both references if this fails */
drm_master_put ( & priv - > minor - > master ) ;
drm_master_put ( & priv - > master ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
goto out_free ;
}
}
} else {
/* get a reference to the master */
priv - > master = drm_master_get ( priv - > minor - > master ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
}
2007-05-25 23:01:51 +04:00
2008-11-28 07:22:24 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
2007-05-25 23:01:51 +04:00
list_add ( & priv - > lhead , & dev - > filelist ) ;
2006-02-02 11:37:46 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2006-01-02 13:32:48 +03:00
# ifdef __alpha__
/*
* Default the hose
*/
if ( ! dev - > hose ) {
struct pci_dev * pci_dev ;
pci_dev = pci_get_class ( PCI_CLASS_DISPLAY_VGA < < 8 , NULL ) ;
if ( pci_dev ) {
dev - > hose = pci_dev - > sysdata ;
pci_dev_put ( pci_dev ) ;
}
if ( ! dev - > hose ) {
struct pci_bus * b = pci_bus_b ( pci_root_buses . next ) ;
if ( b )
dev - > hose = b - > sysdata ;
}
}
# endif
return 0 ;
out_free :
drm_free ( priv , sizeof ( * priv ) , DRM_MEM_FILES ) ;
filp - > private_data = NULL ;
return ret ;
}
/** No-op. */
int drm_fasync ( int fd , struct file * filp , int on )
{
2007-07-11 09:53:27 +04:00
struct drm_file * priv = filp - > private_data ;
2008-04-21 10:47:32 +04:00
struct drm_device * dev = priv - > minor - > dev ;
2006-01-02 13:32:48 +03:00
DRM_DEBUG ( " fd = %d, device = 0x%lx \n " , fd ,
2008-04-21 10:47:32 +04:00
( long ) old_encode_dev ( priv - > minor - > device ) ) ;
2009-02-02 00:52:56 +03:00
return fasync_helper ( fd , filp , on , & dev - > buf_async ) ;
2006-01-02 13:32:48 +03:00
}
EXPORT_SYMBOL ( drm_fasync ) ;
2008-11-28 07:22:24 +03:00
/*
* Reclaim locked buffers ; note that this may be a bad idea if the current
* context doesn ' t have the hw lock . . .
*/
static void drm_reclaim_locked_buffers ( struct drm_device * dev , struct file * f )
{
struct drm_file * file_priv = f - > private_data ;
if ( drm_i_have_hw_lock ( dev , file_priv ) ) {
dev - > driver - > reclaim_buffers_locked ( dev , file_priv ) ;
} else {
unsigned long _end = jiffies + 3 * DRM_HZ ;
int locked = 0 ;
drm_idlelock_take ( & file_priv - > master - > lock ) ;
/*
* Wait for a while .
*/
do {
spin_lock_bh ( & file_priv - > master - > lock . spinlock ) ;
locked = file_priv - > master - > lock . idle_has_lock ;
spin_unlock_bh ( & file_priv - > master - > lock . spinlock ) ;
if ( locked )
break ;
schedule ( ) ;
} while ( ! time_after_eq ( jiffies , _end ) ) ;
if ( ! locked ) {
DRM_ERROR ( " reclaim_buffers_locked() deadlock. Please rework this \n "
" \t driver to use reclaim_buffers_idlelocked() instead. \n "
" \t I will go on reclaiming the buffers anyway. \n " ) ;
}
dev - > driver - > reclaim_buffers_locked ( dev , file_priv ) ;
drm_idlelock_release ( & file_priv - > master - > lock ) ;
}
}
static void drm_master_release ( struct drm_device * dev , struct file * filp )
{
struct drm_file * file_priv = filp - > private_data ;
if ( dev - > driver - > reclaim_buffers_locked & &
file_priv - > master - > lock . hw_lock )
drm_reclaim_locked_buffers ( dev , filp ) ;
if ( dev - > driver - > reclaim_buffers_idlelocked & &
file_priv - > master - > lock . hw_lock ) {
drm_idlelock_take ( & file_priv - > master - > lock ) ;
dev - > driver - > reclaim_buffers_idlelocked ( dev , file_priv ) ;
drm_idlelock_release ( & file_priv - > master - > lock ) ;
}
if ( drm_i_have_hw_lock ( dev , file_priv ) ) {
DRM_DEBUG ( " File %p released, freeing lock for context %d \n " ,
filp , _DRM_LOCKING_CONTEXT ( file_priv - > master - > lock . hw_lock - > lock ) ) ;
drm_lock_free ( & file_priv - > master - > lock ,
_DRM_LOCKING_CONTEXT ( file_priv - > master - > lock . hw_lock - > lock ) ) ;
}
if ( drm_core_check_feature ( dev , DRIVER_HAVE_DMA ) & &
! dev - > driver - > reclaim_buffers_locked ) {
dev - > driver - > reclaim_buffers ( dev , file_priv ) ;
}
}
2005-04-17 02:20:36 +04:00
/**
* Release file .
*
* \ param inode device inode
2007-08-25 14:23:09 +04:00
* \ param file_priv DRM file private .
2005-04-17 02:20:36 +04:00
* \ 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
2005-11-10 14:16:34 +03:00
* zero calls drm_lastclose ( ) .
2005-04-17 02:20:36 +04:00
*/
2005-09-25 08:28:13 +04:00
int drm_release ( struct inode * inode , struct file * filp )
2005-04-17 02:20:36 +04:00
{
2007-08-25 14:23:09 +04:00
struct drm_file * file_priv = filp - > private_data ;
2008-04-21 10:47:32 +04:00
struct drm_device * dev = file_priv - > minor - > dev ;
2005-04-17 02:20:36 +04:00
int retcode = 0 ;
lock_kernel ( ) ;
2005-09-25 08:28:13 +04:00
DRM_DEBUG ( " open_count = %d \n " , dev - > open_count ) ;
2005-04-17 02:20:36 +04:00
2005-11-10 14:16:34 +03:00
if ( dev - > driver - > preclose )
2007-08-25 14:23:09 +04:00
dev - > driver - > preclose ( dev , file_priv ) ;
2005-04-17 02:20:36 +04:00
/* ========================================================
* Begin inline drm_release
*/
2005-09-25 08:28:13 +04:00
DRM_DEBUG ( " pid = %d, device = 0x%lx, open_count = %d \n " ,
2007-10-19 10:40:40 +04:00
task_pid_nr ( current ) ,
2008-04-21 10:47:32 +04:00
( long ) old_encode_dev ( file_priv - > minor - > device ) ,
2005-09-25 08:28:13 +04:00
dev - > open_count ) ;
2008-11-28 07:22:24 +03:00
/* if the master has gone away we can't do anything with the lock */
if ( file_priv - > minor - > master )
drm_master_release ( dev , filp ) ;
2005-04-17 02:20:36 +04:00
2008-07-30 23:06:12 +04:00
if ( dev - > driver - > driver_features & DRIVER_GEM )
drm_gem_release ( dev , file_priv ) ;
2009-02-12 22:37:56 +03:00
if ( dev - > driver - > driver_features & DRIVER_MODESET )
drm_fb_release ( file_priv ) ;
2006-02-02 11:37:46 +03:00
mutex_lock ( & dev - > ctxlist_mutex ) ;
2007-05-25 23:01:51 +04:00
if ( ! list_empty ( & dev - > ctxlist ) ) {
2007-07-11 10:53:40 +04:00
struct drm_ctx_list * pos , * n ;
2005-04-17 02:20:36 +04:00
2007-05-25 23:01:51 +04:00
list_for_each_entry_safe ( pos , n , & dev - > ctxlist , head ) {
2007-08-25 14:23:09 +04:00
if ( pos - > tag = = file_priv & &
2005-09-25 08:28:13 +04:00
pos - > handle ! = DRM_KERNEL_CONTEXT ) {
2005-04-17 02:20:36 +04:00
if ( dev - > driver - > context_dtor )
2005-09-25 08:28:13 +04:00
dev - > driver - > context_dtor ( dev ,
pos - > handle ) ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
drm_ctxbitmap_free ( dev , pos - > handle ) ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
list_del ( & pos - > head ) ;
drm_free ( pos , sizeof ( * pos ) , DRM_MEM_CTXLIST ) ;
2005-04-17 02:20:36 +04:00
- - dev - > ctx_count ;
}
}
}
2006-02-02 11:37:46 +03:00
mutex_unlock ( & dev - > ctxlist_mutex ) ;
2005-04-17 02:20:36 +04:00
2006-02-02 11:37:46 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
2008-11-28 07:22:24 +03:00
if ( file_priv - > is_master ) {
2009-03-02 13:10:56 +03:00
struct drm_master * master = file_priv - > master ;
2007-07-11 09:53:27 +04:00
struct drm_file * temp ;
2008-11-28 07:22:24 +03:00
list_for_each_entry ( temp , & dev - > filelist , lhead ) {
if ( ( temp - > master = = file_priv - > master ) & &
( temp ! = file_priv ) )
temp - > authenticated = 0 ;
}
2007-05-25 23:01:51 +04:00
2009-03-02 13:10:56 +03:00
/**
* Since the master is disappearing , so is the
* possibility to lock .
*/
if ( master - > lock . hw_lock ) {
if ( dev - > sigdata . lock = = master - > lock . hw_lock )
dev - > sigdata . lock = NULL ;
master - > lock . hw_lock = NULL ;
master - > lock . file_priv = NULL ;
wake_up_interruptible_all ( & master - > lock . lock_queue ) ;
}
2008-11-28 07:22:24 +03:00
if ( file_priv - > minor - > master = = file_priv - > master ) {
/* drop the reference held my the minor */
drm_master_put ( & file_priv - > minor - > master ) ;
}
2005-04-17 02:20:36 +04:00
}
2008-11-28 07:22:24 +03:00
/* drop the reference held my the file priv */
drm_master_put ( & file_priv - > master ) ;
file_priv - > is_master = 0 ;
2007-08-25 14:23:09 +04:00
list_del ( & file_priv - > lhead ) ;
2006-02-02 11:37:46 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-09-25 08:28:13 +04:00
2005-11-10 14:16:34 +03:00
if ( dev - > driver - > postclose )
2007-08-25 14:23:09 +04:00
dev - > driver - > postclose ( dev , file_priv ) ;
drm_free ( file_priv , sizeof ( * file_priv ) , DRM_MEM_FILES ) ;
2005-04-17 02:20:36 +04:00
/* ========================================================
* End inline drm_release
*/
2005-09-25 08:28:13 +04:00
atomic_inc ( & dev - > counts [ _DRM_STAT_CLOSES ] ) ;
spin_lock ( & dev - > count_lock ) ;
if ( ! - - dev - > open_count ) {
2008-11-28 07:22:24 +03:00
if ( atomic_read ( & dev - > ioctl_count ) ) {
DRM_ERROR ( " Device busy: %d \n " ,
atomic_read ( & dev - > ioctl_count ) ) ;
2005-09-25 08:28:13 +04:00
spin_unlock ( & dev - > count_lock ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return - EBUSY ;
}
2005-09-25 08:28:13 +04:00
spin_unlock ( & dev - > count_lock ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
2005-11-10 14:16:34 +03:00
return drm_lastclose ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-25 08:28:13 +04:00
spin_unlock ( & dev - > count_lock ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return retcode ;
}
EXPORT_SYMBOL ( drm_release ) ;
/** No-op. */
unsigned int drm_poll ( struct file * filp , struct poll_table_struct * wait )
{
return 0 ;
}
2005-09-25 08:28:13 +04:00
EXPORT_SYMBOL ( drm_poll ) ;