drm: Import linux/types.h from the FreeBSD OFED stack
[dragonfly.git] / sys / dev / drm / drm_fops.c
1 /*-
2  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
3  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Rickard E. (Rik) Faith <faith@valinux.com>
27  *    Daryll Strauss <daryll@valinux.com>
28  *    Gareth Hughes <gareth@valinux.com>
29  *
30  * $FreeBSD: src/sys/dev/drm2/drm_fops.c,v 1.1 2012/05/22 11:07:44 kib Exp $
31  */
32
33 /** @file drm_fops.c
34  * Support code for dealing with the file privates associated with each
35  * open of the DRM device.
36  */
37
38 #include <sys/types.h>
39 #include <sys/conf.h>
40
41 #include <drm/drmP.h>
42
43 struct drm_file *drm_find_file_by_proc(struct drm_device *dev, DRM_STRUCTPROC *p)
44 {
45         uid_t uid = p->td_proc->p_ucred->cr_svuid;
46         pid_t pid = p->td_proc->p_pid;
47         struct drm_file *priv;
48
49         TAILQ_FOREACH(priv, &dev->files, link)
50                 if (priv->pid == pid && priv->uid == uid)
51                         return priv;
52         return NULL;
53 }
54
55 /* drm_open_helper is called whenever a process opens /dev/drm. */
56 int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p,
57                     struct drm_device *dev)
58 {
59         struct drm_file *priv;
60         int retcode;
61
62         if (flags & O_EXCL)
63                 return EBUSY; /* No exclusive opens */
64         dev->flags = flags;
65
66         DRM_DEBUG("pid = %d, device = %s\n", DRM_CURRENTPID, devtoname(kdev));
67         DRM_LOCK(dev);
68
69         priv = drm_find_file_by_proc(dev, p);
70         if (priv) {
71                 goto priv_found;
72         }
73
74         priv = kmalloc(sizeof(*priv), DRM_MEM_FILES, M_NOWAIT | M_ZERO);
75         if (priv == NULL) {
76                 return ENOMEM;
77         }
78         
79 priv_found:
80
81         priv->dev               = dev;
82         priv->uid               = p->td_proc->p_ucred->cr_svuid;
83         priv->uid               = p->td_ucred->cr_svuid;
84         priv->pid               = p->td_proc->p_pid;
85         priv->ioctl_count       = 0;
86
87         /* for compatibility root is always authenticated */
88         priv->authenticated     = DRM_SUSER(p);
89
90         INIT_LIST_HEAD(&priv->fbs);
91         INIT_LIST_HEAD(&priv->event_list);
92         priv->event_space = 4096; /* set aside 4k for event buffer */
93
94         if (dev->driver->driver_features & DRIVER_GEM)
95                 drm_gem_open(dev, priv);
96
97         if (dev->driver->open) {
98                 /* shared code returns -errno */
99                 retcode = -dev->driver->open(dev, priv);
100                 if (retcode != 0) {
101                         drm_free(priv, DRM_MEM_FILES);
102                         DRM_UNLOCK(dev);
103                         return retcode;
104                 }
105         }
106
107         /* first opener automatically becomes master */
108         priv->master = TAILQ_EMPTY(&dev->files);
109
110         TAILQ_INSERT_TAIL(&dev->files, priv, link);
111         DRM_UNLOCK(dev);
112         kdev->si_drv1 = dev;
113         return 0;
114 }
115
116 static bool
117 drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
118     struct uio *uio, struct drm_pending_event **out)
119 {
120         struct drm_pending_event *e;
121
122         if (list_empty(&file_priv->event_list))
123                 return (false);
124         e = list_first_entry(&file_priv->event_list,
125             struct drm_pending_event, link);
126         if (e->event->length > uio->uio_resid)
127                 return (false);
128
129         file_priv->event_space += e->event->length;
130         list_del(&e->link);
131         *out = e;
132         return (true);
133 }
134
135 int
136 drm_read(struct dev_read_args *ap)
137 {
138         struct cdev *kdev = ap->a_head.a_dev;
139         struct uio *uio = ap->a_uio;
140         int ioflag = ap->a_ioflag;
141         struct drm_file *file_priv;
142         struct drm_device *dev;
143         struct drm_pending_event *e;
144         int error;
145
146         dev = drm_get_device_from_kdev(kdev);
147         file_priv = drm_find_file_by_proc(dev, curthread);
148
149         lockmgr(&dev->event_lock, LK_EXCLUSIVE);
150         while (list_empty(&file_priv->event_list)) {
151                 if ((ioflag & O_NONBLOCK) != 0) {
152                         error = EAGAIN;
153                         goto out;
154                 }
155                 error = lksleep(&file_priv->event_space, &dev->event_lock,
156                    PCATCH, "drmrea", 0);
157                if (error != 0)
158                        goto out;
159         }
160         while (drm_dequeue_event(dev, file_priv, uio, &e)) {
161                 lockmgr(&dev->event_lock, LK_RELEASE);
162                 error = uiomove((caddr_t)e->event, e->event->length, uio);
163                 e->destroy(e);
164                 if (error != 0)
165                         return (error);
166                 lockmgr(&dev->event_lock, LK_EXCLUSIVE);
167         }
168 out:
169         lockmgr(&dev->event_lock, LK_RELEASE);
170         return (error);
171 }
172
173 void
174 drm_event_wakeup(struct drm_pending_event *e)
175 {
176         struct drm_file *file_priv;
177         struct drm_device *dev;
178
179         file_priv = e->file_priv;
180         dev = file_priv->dev;
181         KKASSERT(lockstatus(&dev->event_lock, curthread) != 0);
182
183         wakeup(&file_priv->event_space);
184 }
185
186 static int
187 drmfilt(struct knote *kn, long hint)
188 {
189         return (0);
190 }
191
192 static void
193 drmfilt_detach(struct knote *kn) {}
194
195 static struct filterops drmfiltops =
196         { FILTEROP_ISFD, NULL, drmfilt_detach, drmfilt };
197
198 int
199 drm_kqfilter(struct dev_kqfilter_args *ap)
200 {
201         struct knote *kn = ap->a_kn;
202
203         ap->a_result = 0;
204
205         switch (kn->kn_filter) {
206         case EVFILT_READ:
207         case EVFILT_WRITE:
208                 kn->kn_fop = &drmfiltops;
209                 break;
210         default:
211                 ap->a_result = EOPNOTSUPP;
212                 return (0);
213         }
214
215         return (0);
216 }