From 1c0a437fa20e8c3fb971cd8947754a9b274bea76 Mon Sep 17 00:00:00 2001 From: Jon Smirl Date: Thu, 30 Sep 2004 19:26:35 +0000 Subject: Move things around to reduce public symbols and even out files. Switch to get_order from drm_order. --- linux-core/drm_lock.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 4 deletions(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 90c9109f..84cc460c 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -35,11 +35,143 @@ #include "drmP.h" -/** No-op ioctl. */ -int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) + +/** + * 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 (;;) { + 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 ); + + 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); + + + 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_DEBUG("\n"); + 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] ); + + if (dev->fn_tbl->kernel_context_switch_unlock) + dev->fn_tbl->kernel_context_switch_unlock(dev); + 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; } -- cgit v1.2.3