ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / char / drm / gamma_lock.h
1 /* lock.c -- IOCTLs for locking -*- linux-c -*-
2  * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
3  *
4  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Rickard E. (Rik) Faith <faith@valinux.com>
29  *    Gareth Hughes <gareth@valinux.com>
30  */
31
32
33 /* Gamma-specific code extracted from drm_lock.h:
34  */
35 static int DRM(flush_queue)(drm_device_t *dev, int context)
36 {
37         DECLARE_WAITQUEUE(entry, current);
38         int               ret   = 0;
39         drm_queue_t       *q    = dev->queuelist[context];
40
41         DRM_DEBUG("\n");
42
43         atomic_inc(&q->use_count);
44         if (atomic_read(&q->use_count) > 1) {
45                 atomic_inc(&q->block_write);
46                 add_wait_queue(&q->flush_queue, &entry);
47                 atomic_inc(&q->block_count);
48                 for (;;) {
49                         current->state = TASK_INTERRUPTIBLE;
50                         if (!DRM_BUFCOUNT(&q->waitlist)) break;
51                         schedule();
52                         if (signal_pending(current)) {
53                                 ret = -EINTR; /* Can't restart */
54                                 break;
55                         }
56                 }
57                 atomic_dec(&q->block_count);
58                 current->state = TASK_RUNNING;
59                 remove_wait_queue(&q->flush_queue, &entry);
60         }
61         atomic_dec(&q->use_count);
62
63                                 /* NOTE: block_write is still incremented!
64                                    Use drm_flush_unlock_queue to decrement. */
65         return ret;
66 }
67
68 static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
69 {
70         drm_queue_t       *q    = dev->queuelist[context];
71
72         DRM_DEBUG("\n");
73
74         atomic_inc(&q->use_count);
75         if (atomic_read(&q->use_count) > 1) {
76                 if (atomic_read(&q->block_write)) {
77                         atomic_dec(&q->block_write);
78                         wake_up_interruptible(&q->write_queue);
79                 }
80         }
81         atomic_dec(&q->use_count);
82         return 0;
83 }
84
85 int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
86                                drm_lock_flags_t flags)
87 {
88         int ret = 0;
89         int i;
90
91         DRM_DEBUG("\n");
92
93         if (flags & _DRM_LOCK_FLUSH) {
94                 ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
95                 if (!ret) ret = DRM(flush_queue)(dev, context);
96         }
97         if (flags & _DRM_LOCK_FLUSH_ALL) {
98                 for (i = 0; !ret && i < dev->queue_count; i++) {
99                         ret = DRM(flush_queue)(dev, i);
100                 }
101         }
102         return ret;
103 }
104
105 int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
106 {
107         int ret = 0;
108         int i;
109
110         DRM_DEBUG("\n");
111
112         if (flags & _DRM_LOCK_FLUSH) {
113                 ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
114                 if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
115         }
116         if (flags & _DRM_LOCK_FLUSH_ALL) {
117                 for (i = 0; !ret && i < dev->queue_count; i++) {
118                         ret = DRM(flush_unblock_queue)(dev, i);
119                 }
120         }
121
122         return ret;
123 }
124
125 int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd,
126                 unsigned long arg)
127 {
128         drm_file_t        *priv   = filp->private_data;
129         drm_device_t      *dev    = priv->dev;
130         int               ret     = 0;
131         drm_lock_t        lock;
132
133         DRM_DEBUG("\n");
134
135         if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
136                 return -EFAULT;
137         ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
138         DRM(flush_unblock)(dev, lock.context, lock.flags);
139         return ret;
140 }