1235783Skib/*-
2235783Skib * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
3235783Skib * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4235783Skib * All Rights Reserved.
5235783Skib *
6235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
7235783Skib * copy of this software and associated documentation files (the "Software"),
8235783Skib * to deal in the Software without restriction, including without limitation
9235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10235783Skib * and/or sell copies of the Software, and to permit persons to whom the
11235783Skib * Software is furnished to do so, subject to the following conditions:
12235783Skib *
13235783Skib * The above copyright notice and this permission notice (including the next
14235783Skib * paragraph) shall be included in all copies or substantial portions of the
15235783Skib * Software.
16235783Skib *
17235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20235783Skib * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21235783Skib * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22235783Skib * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23235783Skib * OTHER DEALINGS IN THE SOFTWARE.
24235783Skib *
25235783Skib * Authors:
26235783Skib *    Rickard E. (Rik) Faith <faith@valinux.com>
27235783Skib *    Daryll Strauss <daryll@valinux.com>
28235783Skib *    Gareth Hughes <gareth@valinux.com>
29235783Skib *
30235783Skib */
31235783Skib
32235783Skib#include <sys/cdefs.h>
33235783Skib__FBSDID("$FreeBSD$");
34235783Skib
35235783Skib/** @file drm_fops.c
36235783Skib * Support code for dealing with the file privates associated with each
37235783Skib * open of the DRM device.
38235783Skib */
39235783Skib
40235783Skib#include <dev/drm2/drmP.h>
41235783Skib
42235783Skib/* drm_open_helper is called whenever a process opens /dev/drm. */
43235783Skibint drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p,
44235783Skib		    struct drm_device *dev)
45235783Skib{
46235783Skib	struct drm_file *priv;
47235783Skib	int retcode;
48235783Skib
49235783Skib	if (flags & O_EXCL)
50235783Skib		return EBUSY; /* No exclusive opens */
51235783Skib	dev->flags = flags;
52235783Skib
53235783Skib	DRM_DEBUG("pid = %d, device = %s\n", DRM_CURRENTPID, devtoname(kdev));
54235783Skib
55235783Skib	priv = malloc(sizeof(*priv), DRM_MEM_FILES, M_NOWAIT | M_ZERO);
56235783Skib	if (priv == NULL) {
57235783Skib		return ENOMEM;
58235783Skib	}
59235783Skib
60235783Skib	DRM_LOCK(dev);
61235783Skib	priv->dev		= dev;
62235783Skib	priv->uid		= p->td_ucred->cr_svuid;
63235783Skib	priv->pid		= p->td_proc->p_pid;
64235783Skib	priv->ioctl_count 	= 0;
65235783Skib
66235783Skib	/* for compatibility root is always authenticated */
67235783Skib	priv->authenticated	= DRM_SUSER(p);
68235783Skib
69235783Skib	INIT_LIST_HEAD(&priv->fbs);
70235783Skib	INIT_LIST_HEAD(&priv->event_list);
71235783Skib	priv->event_space = 4096; /* set aside 4k for event buffer */
72235783Skib
73235783Skib	if (dev->driver->driver_features & DRIVER_GEM)
74235783Skib		drm_gem_open(dev, priv);
75235783Skib
76235783Skib	if (dev->driver->open) {
77235783Skib		/* shared code returns -errno */
78235783Skib		retcode = -dev->driver->open(dev, priv);
79235783Skib		if (retcode != 0) {
80235783Skib			free(priv, DRM_MEM_FILES);
81235783Skib			DRM_UNLOCK(dev);
82235783Skib			return retcode;
83235783Skib		}
84235783Skib	}
85235783Skib
86235783Skib	/* first opener automatically becomes master */
87235783Skib	priv->master = TAILQ_EMPTY(&dev->files);
88235783Skib
89235783Skib	TAILQ_INSERT_TAIL(&dev->files, priv, link);
90235783Skib	DRM_UNLOCK(dev);
91235783Skib	kdev->si_drv1 = dev;
92241088Shselasky
93241088Shselasky	retcode = devfs_set_cdevpriv(priv, drm_close);
94241088Shselasky	if (retcode != 0)
95241088Shselasky		drm_close(priv);
96241088Shselasky
97241088Shselasky	return (retcode);
98235783Skib}
99235783Skib
100235783Skibstatic bool
101235783Skibdrm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
102235783Skib    struct uio *uio, struct drm_pending_event **out)
103235783Skib{
104235783Skib	struct drm_pending_event *e;
105235783Skib
106235783Skib	if (list_empty(&file_priv->event_list))
107235783Skib		return (false);
108235783Skib	e = list_first_entry(&file_priv->event_list,
109235783Skib	    struct drm_pending_event, link);
110235783Skib	if (e->event->length > uio->uio_resid)
111235783Skib		return (false);
112235783Skib
113235783Skib	file_priv->event_space += e->event->length;
114235783Skib	list_del(&e->link);
115235783Skib	*out = e;
116235783Skib	return (true);
117235783Skib}
118235783Skib
119235783Skibint
120235783Skibdrm_read(struct cdev *kdev, struct uio *uio, int ioflag)
121235783Skib{
122235783Skib	struct drm_file *file_priv;
123235783Skib	struct drm_device *dev;
124235783Skib	struct drm_pending_event *e;
125235783Skib	int error;
126235783Skib
127235783Skib	error = devfs_get_cdevpriv((void **)&file_priv);
128235783Skib	if (error != 0) {
129235783Skib		DRM_ERROR("can't find authenticator\n");
130235783Skib		return (EINVAL);
131235783Skib	}
132235783Skib	dev = drm_get_device_from_kdev(kdev);
133235783Skib	mtx_lock(&dev->event_lock);
134235783Skib	while (list_empty(&file_priv->event_list)) {
135235783Skib		if ((ioflag & O_NONBLOCK) != 0) {
136235783Skib			error = EAGAIN;
137235783Skib			goto out;
138235783Skib		}
139235783Skib		error = msleep(&file_priv->event_space, &dev->event_lock,
140235783Skib	           PCATCH, "drmrea", 0);
141235783Skib	       if (error != 0)
142235783Skib		       goto out;
143235783Skib	}
144235783Skib	while (drm_dequeue_event(dev, file_priv, uio, &e)) {
145235783Skib		mtx_unlock(&dev->event_lock);
146235783Skib		error = uiomove(e->event, e->event->length, uio);
147235783Skib		CTR3(KTR_DRM, "drm_event_dequeued %d %d %d", curproc->p_pid,
148235783Skib		    e->event->type, e->event->length);
149235783Skib		e->destroy(e);
150235783Skib		if (error != 0)
151235783Skib			return (error);
152235783Skib		mtx_lock(&dev->event_lock);
153235783Skib	}
154235783Skibout:
155235783Skib	mtx_unlock(&dev->event_lock);
156235783Skib	return (error);
157235783Skib}
158235783Skib
159235783Skibvoid
160235783Skibdrm_event_wakeup(struct drm_pending_event *e)
161235783Skib{
162235783Skib	struct drm_file *file_priv;
163235783Skib	struct drm_device *dev;
164235783Skib
165235783Skib	file_priv = e->file_priv;
166235783Skib	dev = file_priv->dev;
167235783Skib	mtx_assert(&dev->event_lock, MA_OWNED);
168235783Skib
169235783Skib	wakeup(&file_priv->event_space);
170235783Skib	selwakeup(&file_priv->event_poll);
171235783Skib}
172235783Skib
173235783Skibint
174235783Skibdrm_poll(struct cdev *kdev, int events, struct thread *td)
175235783Skib{
176235783Skib	struct drm_file *file_priv;
177235783Skib	struct drm_device *dev;
178235783Skib	int error, revents;
179235783Skib
180235783Skib	error = devfs_get_cdevpriv((void **)&file_priv);
181235783Skib	if (error != 0) {
182235783Skib		DRM_ERROR("can't find authenticator\n");
183235783Skib		return (EINVAL);
184235783Skib	}
185235783Skib	dev = drm_get_device_from_kdev(kdev);
186235783Skib
187235783Skib	revents = 0;
188235783Skib	mtx_lock(&dev->event_lock);
189235783Skib	if ((events & (POLLIN | POLLRDNORM)) != 0) {
190235783Skib		if (list_empty(&file_priv->event_list)) {
191235783Skib			CTR0(KTR_DRM, "drm_poll empty list");
192235783Skib			selrecord(td, &file_priv->event_poll);
193235783Skib		} else {
194235783Skib			revents |= events & (POLLIN | POLLRDNORM);
195235783Skib			CTR1(KTR_DRM, "drm_poll revents %x", revents);
196235783Skib		}
197235783Skib	}
198235783Skib	mtx_unlock(&dev->event_lock);
199235783Skib	return (revents);
200235783Skib}
201