xref: /titanic_50/usr/src/uts/common/io/drm/drm_ioctl.c (revision 14ea4bb737263733ad80a36b4f73f681c30a6b45)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*-
8  * Created: Fri Jan  8 09:01:26 1999 by faith@valinux.com
9  */
10 /*
11  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
12  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13  * All Rights Reserved.
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the "Software"),
17  * to deal in the Software without restriction, including without limitation
18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19  * and/or sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the next
23  * paragraph) shall be included in all copies or substantial portions of the
24  * Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
29  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32  * OTHER DEALINGS IN THE SOFTWARE.
33  *
34  * Authors:
35  *    Rickard E. (Rik) Faith <faith@valinux.com>
36  *    Gareth Hughes <gareth@valinux.com>
37  *
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "drmP.h"
43 
44 /*
45  * Beginning in revision 1.1 of the DRM interface, getunique will return
46  * a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
47  * before setunique has been called.  The format for the bus-specific part of
48  * the unique is not defined for any other bus.
49  */
50 /*ARGSUSED*/
51 int
52 drm_getunique(DRM_IOCTL_ARGS)
53 {
54 	DRM_DEVICE;
55 	drm_unique_t	 u1;
56 
57 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
58 		drm_unique32_t u32;
59 
60 		DRM_COPY_FROM_USER_IOCTL(u32,
61 			(drm_unique32_t *)data,
62 			sizeof (drm_unique32_t));
63 		u1.unique_len = u32.unique_len;
64 		u1.unique = (char __user *)(uintptr_t)u32.unique;
65 	} else
66 		DRM_COPY_FROM_USER_IOCTL(
67 			u1, (drm_unique_t *)data, sizeof (u1));
68 
69 	if (u1.unique_len >= dev->unique_len) {
70 		if (dev->unique_len == 0) {
71 			DRM_ERROR("drm_getunique: dev->unique_len = 0");
72 			return (DRM_ERR(EFAULT));
73 		}
74 		if (DRM_COPY_TO_USER(u1.unique, dev->unique, dev->unique_len))
75 			return (DRM_ERR(EFAULT));
76 	}
77 	u1.unique_len = dev->unique_len;
78 
79 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
80 		drm_unique32_t u32;
81 
82 		u32.unique_len = u1.unique_len;
83 		u32.unique = (caddr32_t)(uintptr_t)u1.unique;
84 		DRM_COPY_TO_USER_IOCTL((drm_unique32_t *)data, u32,
85 			sizeof (drm_unique32_t));
86 	} else
87 		DRM_COPY_TO_USER_IOCTL((drm_unique_t *)data, u1, sizeof (u1));
88 
89 	return (0);
90 }
91 
92 /*
93  * Deprecated in DRM version 1.1, and will return EBUSY when setversion has
94  * requested version 1.1 or greater.
95  */
96 /*ARGSUSED*/
97 int
98 drm_setunique(DRM_IOCTL_ARGS)
99 {
100 	return (DRM_ERR(EINVAL));
101 }
102 
103 
104 static int
105 drm_set_busid(drm_device_t *dev)
106 {
107 	DRM_LOCK();
108 
109 	if (dev->unique != NULL) {
110 		DRM_UNLOCK();
111 		return (DRM_ERR(EBUSY));
112 	}
113 
114 	dev->unique_len = 20;
115 	dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
116 	if (dev->unique == NULL) {
117 		DRM_UNLOCK();
118 		return (DRM_ERR(ENOMEM));
119 	}
120 
121 	(void) snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
122 	    dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
123 
124 	DRM_UNLOCK();
125 
126 	return (0);
127 }
128 
129 /*ARGSUSED*/
130 int
131 drm_getmap(DRM_IOCTL_ARGS)
132 {
133 	DRM_DEVICE;
134 	drm_map_t	map;
135 	drm_local_map_t    *mapinlist;
136 	int		idx;
137 	int		i = 0;
138 
139 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
140 		drm_map32_t map32;
141 
142 		DRM_COPY_FROM_USER_IOCTL(map32,
143 			(drm_map32_t *)data,
144 			sizeof (drm_map32_t));
145 		map.offset = map32.offset;
146 		map.size = map32.size;
147 		map.type = map32.type;
148 		map.flags = map32.flags;
149 		map.handle = map32.handle;
150 		map.mtrr = map32.mtrr;
151 	} else
152 		DRM_COPY_FROM_USER_IOCTL(map, (drm_map_t *)data, sizeof (map));
153 
154 	idx = map.offset;
155 
156 	DRM_LOCK();
157 	if (idx < 0) {
158 		DRM_UNLOCK();
159 		return (DRM_ERR(EINVAL));
160 	}
161 
162 	TAILQ_FOREACH(mapinlist, &dev->maplist, link) {
163 		if (i == idx) {
164 			map.offset = mapinlist->offset.off;
165 			map.size   = mapinlist->size;
166 			map.type   = mapinlist->type;
167 			map.flags  = mapinlist->flags;
168 			map.handle = (unsigned long long)(uintptr_t)
169 						mapinlist->handle;
170 			map.mtrr   = mapinlist->mtrr;
171 			break;
172 		}
173 		i++;
174 	}
175 
176 	DRM_UNLOCK();
177 
178 	if (mapinlist == NULL)
179 		return (DRM_ERR(EINVAL));
180 
181 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
182 		drm_map32_t map32;
183 
184 		map32.offset = map.offset;
185 		map32.size = map.size;
186 		map32.type = map.type;
187 		map32.flags = map.flags;
188 		map32.handle = map.handle;
189 		map32.mtrr = map.mtrr;
190 		DRM_COPY_TO_USER_IOCTL((drm_map32_t *)data, map32,
191 			sizeof (drm_map32_t));
192 	} else
193 		DRM_COPY_TO_USER_IOCTL((drm_map_t *)data, map, sizeof (map));
194 
195 	return (0);
196 }
197 
198 /*ARGSUSED*/
199 int
200 drm_getclient(DRM_IOCTL_ARGS)
201 {
202 	DRM_DEVICE;
203 	drm_client_t	client;
204 	drm_file_t	*pt;
205 	int		idx;
206 	int		i = 0;
207 
208 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
209 		drm_client32_t client32;
210 
211 		DRM_COPY_FROM_USER_IOCTL(client32,
212 			(drm_client32_t *)data,
213 			sizeof (drm_client32_t));
214 		client.idx = client32.idx;
215 		client.auth = client32.auth;
216 		client.pid = client32.pid;
217 		client.uid = client32.uid;
218 		client.magic = client32.magic;
219 		client.iocs = client32.iocs;
220 	} else
221 		DRM_COPY_FROM_USER_IOCTL(
222 			client, (drm_client_t *)data, sizeof (client));
223 
224 	idx = client.idx;
225 	DRM_LOCK();
226 	TAILQ_FOREACH(pt, &dev->files, link) {
227 		if (i == idx) {
228 			client.auth  = pt->authenticated;
229 			client.pid   = pt->pid;
230 			client.uid   = pt->uid;
231 			client.magic = pt->magic;
232 			client.iocs  = pt->ioctl_count;
233 			DRM_UNLOCK();
234 
235 
236 			if (ddi_model_convert_from(mode & FMODELS) ==
237 				DDI_MODEL_ILP32) {
238 
239 				drm_client32_t client32;
240 
241 				client32.idx = client.idx;
242 				client32.auth = client.auth;
243 				client32.pid = client.pid;
244 				client32.uid = client.uid;
245 				client32.magic = client.magic;
246 				client32.iocs = client.iocs;
247 
248 				DRM_COPY_TO_USER_IOCTL((drm_client32_t *)data,
249 					client32,
250 					sizeof (drm_client32_t));
251 			} else
252 				DRM_COPY_TO_USER_IOCTL((drm_client_t *)data,
253 					client, sizeof (client));
254 
255 			return (0);
256 		}
257 		i++;
258 	}
259 	DRM_UNLOCK();
260 	return (DRM_ERR(EINVAL));
261 }
262 
263 /*ARGSUSED*/
264 int
265 drm_getstats(DRM_IOCTL_ARGS)
266 {
267 	DRM_DEVICE;
268 	drm_stats_t	stats;
269 	int		i;
270 
271 	bzero(&stats, sizeof (stats));
272 
273 	DRM_LOCK();
274 
275 	for (i = 0; i < dev->counters; i++) {
276 		if (dev->types[i] == _DRM_STAT_LOCK) {
277 			stats.data[i].value
278 				= (dev->lock.hw_lock
279 				    ? dev->lock.hw_lock->lock : 0);
280 		} else
281 			stats.data[i].value = atomic_read(&dev->counts[i]);
282 		stats.data[i].type  = dev->types[i];
283 	}
284 
285 	stats.count = dev->counters;
286 
287 	DRM_UNLOCK();
288 
289 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
290 		drm_stats32_t stats32;
291 		stats32.count = stats.count;
292 		for (i = 0; i < 15; i++) {
293 			stats32.data[i].value = stats.data[i].value;
294 			stats32.data[i].type = stats.data[i].type;
295 		}
296 		DRM_COPY_TO_USER_IOCTL((drm_stats32_t *)data, stats32,
297 			sizeof (drm_stats32_t));
298 	} else
299 		DRM_COPY_TO_USER_IOCTL(
300 			(drm_stats_t *)data, stats, sizeof (stats));
301 
302 	return (0);
303 }
304 
305 #define	DRM_IF_MAJOR	1
306 #define	DRM_IF_MINOR	2
307 
308 /*ARGSUSED*/
309 int
310 drm_setversion(DRM_IOCTL_ARGS)
311 {
312 	DRM_DEVICE;
313 	drm_set_version_t sv;
314 	drm_set_version_t retv;
315 	int if_version;
316 
317 	DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof (sv));
318 
319 	retv.drm_di_major = DRM_IF_MAJOR;
320 	retv.drm_di_minor = DRM_IF_MINOR;
321 	retv.drm_dd_major = dev->driver_major;
322 	retv.drm_dd_minor = dev->driver_minor;
323 
324 	DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof (sv));
325 
326 	if (sv.drm_di_major != -1) {
327 		if (sv.drm_di_major != DRM_IF_MAJOR ||
328 		    sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
329 			return (DRM_ERR(EINVAL));
330 		if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
331 		dev->if_version = DRM_MAX(if_version, dev->if_version);
332 		if (sv.drm_di_minor >= 1) {
333 			/*
334 			 * Version 1.1 includes tying of DRM to specific device
335 			 */
336 			(void) drm_set_busid(dev);
337 		}
338 	}
339 
340 	if (sv.drm_dd_major != -1) {
341 		if (sv.drm_dd_major != dev->driver_major ||
342 		    sv.drm_dd_minor < 0 || sv.drm_dd_minor > dev->driver_minor)
343 			return (DRM_ERR(EINVAL));
344 	}
345 	return (0);
346 }
347 
348 
349 /*ARGSUSED*/
350 int
351 drm_noop(DRM_IOCTL_ARGS)
352 {
353 	DRM_DEBUG("drm_noop\n");
354 	return (0);
355 }
356 
357 /*ARGSUSED*/
358 int
359 drm_version(DRM_IOCTL_ARGS)
360 {
361 	DRM_DEVICE;
362 	drm_version_t version;
363 	int len;
364 
365 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
366 		drm_version32_t version32;
367 
368 		DRM_COPY_FROM_USER_IOCTL(version32,
369 			(drm_version32_t *)data,
370 			sizeof (drm_version32_t));
371 		version.version_major = version32.version_major;
372 		version.version_minor = version32.version_minor;
373 		version.version_patchlevel = version32.version_patchlevel;
374 		version.name_len = version32.name_len;
375 		version.name = (char __user *)(uintptr_t)version32.name;
376 		version.date_len = version32.date_len;
377 		version.date = (char __user *)(uintptr_t)version32.date;
378 		version.desc_len = version32.desc_len;
379 		version.desc = (char __user *)(uintptr_t)version32.desc;
380 	} else
381 		DRM_COPY_FROM_USER_IOCTL(
382 			version, (drm_version_t *)data, sizeof (version));
383 
384 #define	DRM_COPY(name, value)                                         \
385 	len = strlen(value);                                          \
386 	if (len > name##_len) len = name##_len;                       \
387 	name##_len = strlen(value);                                   \
388 	if (len && name) {                                            \
389 		if (DRM_COPY_TO_USER(name, value, len))             \
390 			return (DRM_ERR(EFAULT));                         \
391 	}
392 
393 	version.version_major = dev->driver_major;
394 	version.version_minor = dev->driver_minor;
395 	version.version_patchlevel = dev->driver_patchlevel;
396 
397 	DRM_COPY(version.name, dev->driver_name);
398 	DRM_COPY(version.date, dev->driver_date);
399 	DRM_COPY(version.desc, dev->driver_desc);
400 
401 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
402 		drm_version32_t version32;
403 
404 		version32.version_major = version.version_major;
405 		version32.version_minor = version.version_minor;
406 		version32.version_patchlevel = version.version_patchlevel;
407 		version32.name_len = version.name_len;
408 		version32.name = (caddr32_t)(uintptr_t)version.name;
409 		version32.date_len = version.date_len;
410 		version32.date = (caddr32_t)(uintptr_t)version.date;
411 		version32.desc_len = version.desc_len;
412 		version32.desc = (caddr32_t)(uintptr_t)version.desc;
413 		DRM_COPY_TO_USER_IOCTL((drm_version32_t *)data, version32,
414 			sizeof (drm_version32_t));
415 	} else
416 		DRM_COPY_TO_USER_IOCTL(
417 			(drm_version_t *)data, version, sizeof (version));
418 
419 	return (0);
420 }
421