xref: /freebsd/sys/dev/drm2/drm_ioctl.c (revision 592ffb217505586a6c69e91549a3c14132875f16)
1*592ffb21SWarner Losh /**
2*592ffb21SWarner Losh  * \file drm_ioctl.c
3*592ffb21SWarner Losh  * IOCTL processing for DRM
4*592ffb21SWarner Losh  *
5*592ffb21SWarner Losh  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6*592ffb21SWarner Losh  * \author Gareth Hughes <gareth@valinux.com>
7*592ffb21SWarner Losh  */
8*592ffb21SWarner Losh 
9*592ffb21SWarner Losh /*
10*592ffb21SWarner Losh  * Created: Fri Jan  8 09:01:26 1999 by faith@valinux.com
11*592ffb21SWarner Losh  *
12*592ffb21SWarner Losh  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
13*592ffb21SWarner Losh  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14*592ffb21SWarner Losh  * All Rights Reserved.
15*592ffb21SWarner Losh  *
16*592ffb21SWarner Losh  * Permission is hereby granted, free of charge, to any person obtaining a
17*592ffb21SWarner Losh  * copy of this software and associated documentation files (the "Software"),
18*592ffb21SWarner Losh  * to deal in the Software without restriction, including without limitation
19*592ffb21SWarner Losh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20*592ffb21SWarner Losh  * and/or sell copies of the Software, and to permit persons to whom the
21*592ffb21SWarner Losh  * Software is furnished to do so, subject to the following conditions:
22*592ffb21SWarner Losh  *
23*592ffb21SWarner Losh  * The above copyright notice and this permission notice (including the next
24*592ffb21SWarner Losh  * paragraph) shall be included in all copies or substantial portions of the
25*592ffb21SWarner Losh  * Software.
26*592ffb21SWarner Losh  *
27*592ffb21SWarner Losh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28*592ffb21SWarner Losh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29*592ffb21SWarner Losh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30*592ffb21SWarner Losh  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31*592ffb21SWarner Losh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32*592ffb21SWarner Losh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33*592ffb21SWarner Losh  * OTHER DEALINGS IN THE SOFTWARE.
34*592ffb21SWarner Losh  */
35*592ffb21SWarner Losh 
36*592ffb21SWarner Losh #include <sys/cdefs.h>
37*592ffb21SWarner Losh __FBSDID("$FreeBSD$");
38*592ffb21SWarner Losh 
39*592ffb21SWarner Losh #include <dev/drm2/drmP.h>
40*592ffb21SWarner Losh #include <dev/drm2/drm_core.h>
41*592ffb21SWarner Losh 
42*592ffb21SWarner Losh /**
43*592ffb21SWarner Losh  * Get the bus id.
44*592ffb21SWarner Losh  *
45*592ffb21SWarner Losh  * \param inode device inode.
46*592ffb21SWarner Losh  * \param file_priv DRM file private.
47*592ffb21SWarner Losh  * \param cmd command.
48*592ffb21SWarner Losh  * \param arg user argument, pointing to a drm_unique structure.
49*592ffb21SWarner Losh  * \return zero on success or a negative number on failure.
50*592ffb21SWarner Losh  *
51*592ffb21SWarner Losh  * Copies the bus id from drm_device::unique into user space.
52*592ffb21SWarner Losh  */
53*592ffb21SWarner Losh int drm_getunique(struct drm_device *dev, void *data,
54*592ffb21SWarner Losh 		  struct drm_file *file_priv)
55*592ffb21SWarner Losh {
56*592ffb21SWarner Losh 	struct drm_unique *u = data;
57*592ffb21SWarner Losh 	struct drm_master *master = file_priv->master;
58*592ffb21SWarner Losh 
59*592ffb21SWarner Losh 	if (u->unique_len >= master->unique_len) {
60*592ffb21SWarner Losh 		if (copy_to_user(u->unique, master->unique, master->unique_len))
61*592ffb21SWarner Losh 			return -EFAULT;
62*592ffb21SWarner Losh 	}
63*592ffb21SWarner Losh 	u->unique_len = master->unique_len;
64*592ffb21SWarner Losh 
65*592ffb21SWarner Losh 	return 0;
66*592ffb21SWarner Losh }
67*592ffb21SWarner Losh 
68*592ffb21SWarner Losh static void
69*592ffb21SWarner Losh drm_unset_busid(struct drm_device *dev,
70*592ffb21SWarner Losh 		struct drm_master *master)
71*592ffb21SWarner Losh {
72*592ffb21SWarner Losh 
73*592ffb21SWarner Losh 	free(master->unique, DRM_MEM_DRIVER);
74*592ffb21SWarner Losh 	master->unique = NULL;
75*592ffb21SWarner Losh 	master->unique_len = 0;
76*592ffb21SWarner Losh 	master->unique_size = 0;
77*592ffb21SWarner Losh }
78*592ffb21SWarner Losh 
79*592ffb21SWarner Losh /**
80*592ffb21SWarner Losh  * Set the bus id.
81*592ffb21SWarner Losh  *
82*592ffb21SWarner Losh  * \param inode device inode.
83*592ffb21SWarner Losh  * \param file_priv DRM file private.
84*592ffb21SWarner Losh  * \param cmd command.
85*592ffb21SWarner Losh  * \param arg user argument, pointing to a drm_unique structure.
86*592ffb21SWarner Losh  * \return zero on success or a negative number on failure.
87*592ffb21SWarner Losh  *
88*592ffb21SWarner Losh  * Copies the bus id from userspace into drm_device::unique, and verifies that
89*592ffb21SWarner Losh  * it matches the device this DRM is attached to (EINVAL otherwise).  Deprecated
90*592ffb21SWarner Losh  * in interface version 1.1 and will return EBUSY when setversion has requested
91*592ffb21SWarner Losh  * version 1.1 or greater.
92*592ffb21SWarner Losh  */
93*592ffb21SWarner Losh int drm_setunique(struct drm_device *dev, void *data,
94*592ffb21SWarner Losh 		  struct drm_file *file_priv)
95*592ffb21SWarner Losh {
96*592ffb21SWarner Losh 	struct drm_unique *u = data;
97*592ffb21SWarner Losh 	struct drm_master *master = file_priv->master;
98*592ffb21SWarner Losh 	int ret;
99*592ffb21SWarner Losh 
100*592ffb21SWarner Losh 	if (master->unique_len || master->unique)
101*592ffb21SWarner Losh 		return -EBUSY;
102*592ffb21SWarner Losh 
103*592ffb21SWarner Losh 	if (!u->unique_len || u->unique_len > 1024)
104*592ffb21SWarner Losh 		return -EINVAL;
105*592ffb21SWarner Losh 
106*592ffb21SWarner Losh 	if (!dev->driver->bus->set_unique)
107*592ffb21SWarner Losh 		return -EINVAL;
108*592ffb21SWarner Losh 
109*592ffb21SWarner Losh 	ret = dev->driver->bus->set_unique(dev, master, u);
110*592ffb21SWarner Losh 	if (ret)
111*592ffb21SWarner Losh 		goto err;
112*592ffb21SWarner Losh 
113*592ffb21SWarner Losh 	return 0;
114*592ffb21SWarner Losh 
115*592ffb21SWarner Losh err:
116*592ffb21SWarner Losh 	drm_unset_busid(dev, master);
117*592ffb21SWarner Losh 	return ret;
118*592ffb21SWarner Losh }
119*592ffb21SWarner Losh 
120*592ffb21SWarner Losh static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
121*592ffb21SWarner Losh {
122*592ffb21SWarner Losh 	struct drm_master *master = file_priv->master;
123*592ffb21SWarner Losh 	int ret;
124*592ffb21SWarner Losh 
125*592ffb21SWarner Losh 	if (master->unique != NULL)
126*592ffb21SWarner Losh 		drm_unset_busid(dev, master);
127*592ffb21SWarner Losh 
128*592ffb21SWarner Losh 	ret = dev->driver->bus->set_busid(dev, master);
129*592ffb21SWarner Losh 	if (ret)
130*592ffb21SWarner Losh 		goto err;
131*592ffb21SWarner Losh 	return 0;
132*592ffb21SWarner Losh err:
133*592ffb21SWarner Losh 	drm_unset_busid(dev, master);
134*592ffb21SWarner Losh 	return ret;
135*592ffb21SWarner Losh }
136*592ffb21SWarner Losh 
137*592ffb21SWarner Losh /**
138*592ffb21SWarner Losh  * Get a mapping information.
139*592ffb21SWarner Losh  *
140*592ffb21SWarner Losh  * \param inode device inode.
141*592ffb21SWarner Losh  * \param file_priv DRM file private.
142*592ffb21SWarner Losh  * \param cmd command.
143*592ffb21SWarner Losh  * \param arg user argument, pointing to a drm_map structure.
144*592ffb21SWarner Losh  *
145*592ffb21SWarner Losh  * \return zero on success or a negative number on failure.
146*592ffb21SWarner Losh  *
147*592ffb21SWarner Losh  * Searches for the mapping with the specified offset and copies its information
148*592ffb21SWarner Losh  * into userspace
149*592ffb21SWarner Losh  */
150*592ffb21SWarner Losh int drm_getmap(struct drm_device *dev, void *data,
151*592ffb21SWarner Losh 	       struct drm_file *file_priv)
152*592ffb21SWarner Losh {
153*592ffb21SWarner Losh 	struct drm_map *map = data;
154*592ffb21SWarner Losh 	struct drm_map_list *r_list = NULL;
155*592ffb21SWarner Losh 	struct list_head *list;
156*592ffb21SWarner Losh 	int idx;
157*592ffb21SWarner Losh 	int i;
158*592ffb21SWarner Losh 
159*592ffb21SWarner Losh 	idx = map->offset;
160*592ffb21SWarner Losh 	if (idx < 0)
161*592ffb21SWarner Losh 		return -EINVAL;
162*592ffb21SWarner Losh 
163*592ffb21SWarner Losh 	i = 0;
164*592ffb21SWarner Losh 	DRM_LOCK(dev);
165*592ffb21SWarner Losh 	list_for_each(list, &dev->maplist) {
166*592ffb21SWarner Losh 		if (i == idx) {
167*592ffb21SWarner Losh 			r_list = list_entry(list, struct drm_map_list, head);
168*592ffb21SWarner Losh 			break;
169*592ffb21SWarner Losh 		}
170*592ffb21SWarner Losh 		i++;
171*592ffb21SWarner Losh 	}
172*592ffb21SWarner Losh 	if (!r_list || !r_list->map) {
173*592ffb21SWarner Losh 		DRM_UNLOCK(dev);
174*592ffb21SWarner Losh 		return -EINVAL;
175*592ffb21SWarner Losh 	}
176*592ffb21SWarner Losh 
177*592ffb21SWarner Losh 	map->offset = r_list->map->offset;
178*592ffb21SWarner Losh 	map->size = r_list->map->size;
179*592ffb21SWarner Losh 	map->type = r_list->map->type;
180*592ffb21SWarner Losh 	map->flags = r_list->map->flags;
181*592ffb21SWarner Losh 	map->handle = (void *)(unsigned long) r_list->user_token;
182*592ffb21SWarner Losh 	map->mtrr = r_list->map->mtrr;
183*592ffb21SWarner Losh 	DRM_UNLOCK(dev);
184*592ffb21SWarner Losh 
185*592ffb21SWarner Losh 	return 0;
186*592ffb21SWarner Losh }
187*592ffb21SWarner Losh 
188*592ffb21SWarner Losh /**
189*592ffb21SWarner Losh  * Get client information.
190*592ffb21SWarner Losh  *
191*592ffb21SWarner Losh  * \param inode device inode.
192*592ffb21SWarner Losh  * \param file_priv DRM file private.
193*592ffb21SWarner Losh  * \param cmd command.
194*592ffb21SWarner Losh  * \param arg user argument, pointing to a drm_client structure.
195*592ffb21SWarner Losh  *
196*592ffb21SWarner Losh  * \return zero on success or a negative number on failure.
197*592ffb21SWarner Losh  *
198*592ffb21SWarner Losh  * Searches for the client with the specified index and copies its information
199*592ffb21SWarner Losh  * into userspace
200*592ffb21SWarner Losh  */
201*592ffb21SWarner Losh int drm_getclient(struct drm_device *dev, void *data,
202*592ffb21SWarner Losh 		  struct drm_file *file_priv)
203*592ffb21SWarner Losh {
204*592ffb21SWarner Losh 	struct drm_client *client = data;
205*592ffb21SWarner Losh 	struct drm_file *pt;
206*592ffb21SWarner Losh 	int idx;
207*592ffb21SWarner Losh 	int i;
208*592ffb21SWarner Losh 
209*592ffb21SWarner Losh 	idx = client->idx;
210*592ffb21SWarner Losh 	i = 0;
211*592ffb21SWarner Losh 
212*592ffb21SWarner Losh 	DRM_LOCK(dev);
213*592ffb21SWarner Losh 	list_for_each_entry(pt, &dev->filelist, lhead) {
214*592ffb21SWarner Losh 		if (i++ >= idx) {
215*592ffb21SWarner Losh 			client->auth = pt->authenticated;
216*592ffb21SWarner Losh 			client->pid = pt->pid;
217*592ffb21SWarner Losh 			client->uid = pt->uid;
218*592ffb21SWarner Losh 			client->magic = pt->magic;
219*592ffb21SWarner Losh 			client->iocs = pt->ioctl_count;
220*592ffb21SWarner Losh 			DRM_UNLOCK(dev);
221*592ffb21SWarner Losh 
222*592ffb21SWarner Losh 			return 0;
223*592ffb21SWarner Losh 		}
224*592ffb21SWarner Losh 	}
225*592ffb21SWarner Losh 	DRM_UNLOCK(dev);
226*592ffb21SWarner Losh 
227*592ffb21SWarner Losh 	return -EINVAL;
228*592ffb21SWarner Losh }
229*592ffb21SWarner Losh 
230*592ffb21SWarner Losh /**
231*592ffb21SWarner Losh  * Get statistics information.
232*592ffb21SWarner Losh  *
233*592ffb21SWarner Losh  * \param inode device inode.
234*592ffb21SWarner Losh  * \param file_priv DRM file private.
235*592ffb21SWarner Losh  * \param cmd command.
236*592ffb21SWarner Losh  * \param arg user argument, pointing to a drm_stats structure.
237*592ffb21SWarner Losh  *
238*592ffb21SWarner Losh  * \return zero on success or a negative number on failure.
239*592ffb21SWarner Losh  */
240*592ffb21SWarner Losh int drm_getstats(struct drm_device *dev, void *data,
241*592ffb21SWarner Losh 		 struct drm_file *file_priv)
242*592ffb21SWarner Losh {
243*592ffb21SWarner Losh 	struct drm_stats *stats = data;
244*592ffb21SWarner Losh 	int i;
245*592ffb21SWarner Losh 
246*592ffb21SWarner Losh 	memset(stats, 0, sizeof(*stats));
247*592ffb21SWarner Losh 
248*592ffb21SWarner Losh 	for (i = 0; i < dev->counters; i++) {
249*592ffb21SWarner Losh 		if (dev->types[i] == _DRM_STAT_LOCK)
250*592ffb21SWarner Losh 			stats->data[i].value =
251*592ffb21SWarner Losh 			    (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0);
252*592ffb21SWarner Losh 		else
253*592ffb21SWarner Losh 			stats->data[i].value = atomic_read(&dev->counts[i]);
254*592ffb21SWarner Losh 		stats->data[i].type = dev->types[i];
255*592ffb21SWarner Losh 	}
256*592ffb21SWarner Losh 
257*592ffb21SWarner Losh 	stats->count = dev->counters;
258*592ffb21SWarner Losh 
259*592ffb21SWarner Losh 	return 0;
260*592ffb21SWarner Losh }
261*592ffb21SWarner Losh 
262*592ffb21SWarner Losh /**
263*592ffb21SWarner Losh  * Get device/driver capabilities
264*592ffb21SWarner Losh  */
265*592ffb21SWarner Losh int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
266*592ffb21SWarner Losh {
267*592ffb21SWarner Losh 	struct drm_get_cap *req = data;
268*592ffb21SWarner Losh 
269*592ffb21SWarner Losh 	req->value = 0;
270*592ffb21SWarner Losh 	switch (req->capability) {
271*592ffb21SWarner Losh 	case DRM_CAP_DUMB_BUFFER:
272*592ffb21SWarner Losh 		if (dev->driver->dumb_create)
273*592ffb21SWarner Losh 			req->value = 1;
274*592ffb21SWarner Losh 		break;
275*592ffb21SWarner Losh 	case DRM_CAP_VBLANK_HIGH_CRTC:
276*592ffb21SWarner Losh 		req->value = 1;
277*592ffb21SWarner Losh 		break;
278*592ffb21SWarner Losh 	case DRM_CAP_DUMB_PREFERRED_DEPTH:
279*592ffb21SWarner Losh 		req->value = dev->mode_config.preferred_depth;
280*592ffb21SWarner Losh 		break;
281*592ffb21SWarner Losh 	case DRM_CAP_DUMB_PREFER_SHADOW:
282*592ffb21SWarner Losh 		req->value = dev->mode_config.prefer_shadow;
283*592ffb21SWarner Losh 		break;
284*592ffb21SWarner Losh 	case DRM_CAP_PRIME:
285*592ffb21SWarner Losh 		req->value |= false /* XXXKIB dev->driver->prime_fd_to_handle */ ? DRM_PRIME_CAP_IMPORT : 0;
286*592ffb21SWarner Losh 		req->value |= false /* XXXKIB dev->driver->prime_handle_to_fd */ ? DRM_PRIME_CAP_EXPORT : 0;
287*592ffb21SWarner Losh 		break;
288*592ffb21SWarner Losh 	case DRM_CAP_TIMESTAMP_MONOTONIC:
289*592ffb21SWarner Losh 		req->value = drm_timestamp_monotonic;
290*592ffb21SWarner Losh 		break;
291*592ffb21SWarner Losh 	default:
292*592ffb21SWarner Losh 		return -EINVAL;
293*592ffb21SWarner Losh 	}
294*592ffb21SWarner Losh 	return 0;
295*592ffb21SWarner Losh }
296*592ffb21SWarner Losh 
297*592ffb21SWarner Losh /**
298*592ffb21SWarner Losh  * Setversion ioctl.
299*592ffb21SWarner Losh  *
300*592ffb21SWarner Losh  * \param inode device inode.
301*592ffb21SWarner Losh  * \param file_priv DRM file private.
302*592ffb21SWarner Losh  * \param cmd command.
303*592ffb21SWarner Losh  * \param arg user argument, pointing to a drm_lock structure.
304*592ffb21SWarner Losh  * \return zero on success or negative number on failure.
305*592ffb21SWarner Losh  *
306*592ffb21SWarner Losh  * Sets the requested interface version
307*592ffb21SWarner Losh  */
308*592ffb21SWarner Losh int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
309*592ffb21SWarner Losh {
310*592ffb21SWarner Losh 	struct drm_set_version *sv = data;
311*592ffb21SWarner Losh 	int if_version, retcode = 0;
312*592ffb21SWarner Losh 
313*592ffb21SWarner Losh 	if (sv->drm_di_major != -1) {
314*592ffb21SWarner Losh 		if (sv->drm_di_major != DRM_IF_MAJOR ||
315*592ffb21SWarner Losh 		    sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
316*592ffb21SWarner Losh 			retcode = -EINVAL;
317*592ffb21SWarner Losh 			goto done;
318*592ffb21SWarner Losh 		}
319*592ffb21SWarner Losh 		if_version = DRM_IF_VERSION(sv->drm_di_major,
320*592ffb21SWarner Losh 					    sv->drm_di_minor);
321*592ffb21SWarner Losh 		dev->if_version = max(if_version, dev->if_version);
322*592ffb21SWarner Losh 		if (sv->drm_di_minor >= 1) {
323*592ffb21SWarner Losh 			/*
324*592ffb21SWarner Losh 			 * Version 1.1 includes tying of DRM to specific device
325*592ffb21SWarner Losh 			 * Version 1.4 has proper PCI domain support
326*592ffb21SWarner Losh 			 */
327*592ffb21SWarner Losh 			retcode = drm_set_busid(dev, file_priv);
328*592ffb21SWarner Losh 			if (retcode)
329*592ffb21SWarner Losh 				goto done;
330*592ffb21SWarner Losh 		}
331*592ffb21SWarner Losh 	}
332*592ffb21SWarner Losh 
333*592ffb21SWarner Losh 	if (sv->drm_dd_major != -1) {
334*592ffb21SWarner Losh 		if (sv->drm_dd_major != dev->driver->major ||
335*592ffb21SWarner Losh 		    sv->drm_dd_minor < 0 || sv->drm_dd_minor >
336*592ffb21SWarner Losh 		    dev->driver->minor) {
337*592ffb21SWarner Losh 			retcode = -EINVAL;
338*592ffb21SWarner Losh 			goto done;
339*592ffb21SWarner Losh 		}
340*592ffb21SWarner Losh 
341*592ffb21SWarner Losh 		if (dev->driver->set_version)
342*592ffb21SWarner Losh 			dev->driver->set_version(dev, sv);
343*592ffb21SWarner Losh 	}
344*592ffb21SWarner Losh 
345*592ffb21SWarner Losh done:
346*592ffb21SWarner Losh 	sv->drm_di_major = DRM_IF_MAJOR;
347*592ffb21SWarner Losh 	sv->drm_di_minor = DRM_IF_MINOR;
348*592ffb21SWarner Losh 	sv->drm_dd_major = dev->driver->major;
349*592ffb21SWarner Losh 	sv->drm_dd_minor = dev->driver->minor;
350*592ffb21SWarner Losh 
351*592ffb21SWarner Losh 	return retcode;
352*592ffb21SWarner Losh }
353*592ffb21SWarner Losh 
354*592ffb21SWarner Losh /** No-op ioctl. */
355*592ffb21SWarner Losh int drm_noop(struct drm_device *dev, void *data,
356*592ffb21SWarner Losh 	     struct drm_file *file_priv)
357*592ffb21SWarner Losh {
358*592ffb21SWarner Losh 	DRM_DEBUG("\n");
359*592ffb21SWarner Losh 	return 0;
360*592ffb21SWarner Losh }
361*592ffb21SWarner Losh EXPORT_SYMBOL(drm_noop);
362