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 + -
显示快捷键?