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