1145132Sanholt/*-
2145132Sanholt * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
3145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4145132Sanholt * All Rights Reserved.
5145132Sanholt *
6145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
7145132Sanholt * copy of this software and associated documentation files (the "Software"),
8145132Sanholt * to deal in the Software without restriction, including without limitation
9145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the
11145132Sanholt * Software is furnished to do so, subject to the following conditions:
12145132Sanholt *
13145132Sanholt * The above copyright notice and this permission notice (including the next
14145132Sanholt * paragraph) shall be included in all copies or substantial portions of the
15145132Sanholt * Software.
16145132Sanholt *
17145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20145132Sanholt * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23145132Sanholt * OTHER DEALINGS IN THE SOFTWARE.
24145132Sanholt *
25145132Sanholt * Authors:
26145132Sanholt *    Rickard E. (Rik) Faith <faith@valinux.com>
27145132Sanholt *    Gareth Hughes <gareth@valinux.com>
28145132Sanholt *
29145132Sanholt */
30145132Sanholt
31152909Sanholt#include <sys/cdefs.h>
32152909Sanholt__FBSDID("$FreeBSD$");
33152909Sanholt
34182080Srnoland/** @file drm_ioctl.c
35182080Srnoland * Varios minor DRM ioctls not applicable to other files, such as versioning
36182080Srnoland * information and reporting DRM information to userland.
37182080Srnoland */
38182080Srnoland
39145132Sanholt#include "dev/drm/drmP.h"
40145132Sanholt
41145132Sanholt/*
42145132Sanholt * Beginning in revision 1.1 of the DRM interface, getunique will return
43145132Sanholt * a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
44145132Sanholt * before setunique has been called.  The format for the bus-specific part of
45145132Sanholt * the unique is not defined for any other bus.
46145132Sanholt */
47182080Srnolandint drm_getunique(struct drm_device *dev, void *data,
48182080Srnoland		  struct drm_file *file_priv)
49145132Sanholt{
50183573Srnoland	struct drm_unique *u = data;
51145132Sanholt
52182080Srnoland	if (u->unique_len >= dev->unique_len) {
53182080Srnoland		if (DRM_COPY_TO_USER(u->unique, dev->unique, dev->unique_len))
54182080Srnoland			return EFAULT;
55145132Sanholt	}
56182080Srnoland	u->unique_len = dev->unique_len;
57145132Sanholt
58145132Sanholt	return 0;
59145132Sanholt}
60145132Sanholt
61145132Sanholt/* Deprecated in DRM version 1.1, and will return EBUSY when setversion has
62145132Sanholt * requested version 1.1 or greater.
63145132Sanholt */
64182080Srnolandint drm_setunique(struct drm_device *dev, void *data,
65182080Srnoland		  struct drm_file *file_priv)
66145132Sanholt{
67183573Srnoland	struct drm_unique *u = data;
68145132Sanholt	int domain, bus, slot, func, ret;
69145132Sanholt	char *busid;
70145132Sanholt
71145132Sanholt	/* Check and copy in the submitted Bus ID */
72182080Srnoland	if (!u->unique_len || u->unique_len > 1024)
73182080Srnoland		return EINVAL;
74145132Sanholt
75183833Srnoland	busid = malloc(u->unique_len + 1, DRM_MEM_DRIVER, M_WAITOK);
76145132Sanholt	if (busid == NULL)
77182080Srnoland		return ENOMEM;
78145132Sanholt
79182080Srnoland	if (DRM_COPY_FROM_USER(busid, u->unique, u->unique_len)) {
80183833Srnoland		free(busid, DRM_MEM_DRIVER);
81182080Srnoland		return EFAULT;
82145132Sanholt	}
83182080Srnoland	busid[u->unique_len] = '\0';
84145132Sanholt
85145132Sanholt	/* Return error if the busid submitted doesn't match the device's actual
86145132Sanholt	 * busid.
87145132Sanholt	 */
88145132Sanholt	ret = sscanf(busid, "PCI:%d:%d:%d", &bus, &slot, &func);
89145132Sanholt	if (ret != 3) {
90183833Srnoland		free(busid, DRM_MEM_DRIVER);
91182080Srnoland		return EINVAL;
92145132Sanholt	}
93145132Sanholt	domain = bus >> 8;
94145132Sanholt	bus &= 0xff;
95145132Sanholt
96145132Sanholt	if ((domain != dev->pci_domain) ||
97145132Sanholt	    (bus != dev->pci_bus) ||
98145132Sanholt	    (slot != dev->pci_slot) ||
99145132Sanholt	    (func != dev->pci_func)) {
100183833Srnoland		free(busid, DRM_MEM_DRIVER);
101182080Srnoland		return EINVAL;
102145132Sanholt	}
103145132Sanholt
104145132Sanholt	/* Actually set the device's busid now. */
105145132Sanholt	DRM_LOCK();
106145132Sanholt	if (dev->unique_len || dev->unique) {
107145132Sanholt		DRM_UNLOCK();
108182080Srnoland		return EBUSY;
109145132Sanholt	}
110145132Sanholt
111182080Srnoland	dev->unique_len = u->unique_len;
112145132Sanholt	dev->unique = busid;
113145132Sanholt	DRM_UNLOCK();
114145132Sanholt
115145132Sanholt	return 0;
116145132Sanholt}
117145132Sanholt
118145132Sanholt
119145132Sanholtstatic int
120182080Srnolanddrm_set_busid(struct drm_device *dev)
121145132Sanholt{
122145132Sanholt
123145132Sanholt	DRM_LOCK();
124145132Sanholt
125145132Sanholt	if (dev->unique != NULL) {
126145132Sanholt		DRM_UNLOCK();
127145132Sanholt		return EBUSY;
128145132Sanholt	}
129145132Sanholt
130145132Sanholt	dev->unique_len = 20;
131183833Srnoland	dev->unique = malloc(dev->unique_len + 1, DRM_MEM_DRIVER, M_NOWAIT);
132145132Sanholt	if (dev->unique == NULL) {
133145132Sanholt		DRM_UNLOCK();
134145132Sanholt		return ENOMEM;
135145132Sanholt	}
136145132Sanholt
137145132Sanholt	snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
138145132Sanholt	    dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
139145132Sanholt
140145132Sanholt	DRM_UNLOCK();
141145132Sanholt
142145132Sanholt	return 0;
143145132Sanholt}
144145132Sanholt
145182080Srnolandint drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
146145132Sanholt{
147183573Srnoland	struct drm_map     *map = data;
148145132Sanholt	drm_local_map_t    *mapinlist;
149145132Sanholt	int          idx;
150145132Sanholt	int	     i = 0;
151145132Sanholt
152182080Srnoland	idx = map->offset;
153145132Sanholt
154145132Sanholt	DRM_LOCK();
155145132Sanholt	if (idx < 0) {
156145132Sanholt		DRM_UNLOCK();
157182080Srnoland		return EINVAL;
158145132Sanholt	}
159145132Sanholt
160145132Sanholt	TAILQ_FOREACH(mapinlist, &dev->maplist, link) {
161183573Srnoland		if (i == idx) {
162182080Srnoland			map->offset = mapinlist->offset;
163182080Srnoland			map->size   = mapinlist->size;
164182080Srnoland			map->type   = mapinlist->type;
165182080Srnoland			map->flags  = mapinlist->flags;
166182080Srnoland			map->handle = mapinlist->handle;
167182080Srnoland			map->mtrr   = mapinlist->mtrr;
168145132Sanholt			break;
169145132Sanholt		}
170145132Sanholt		i++;
171145132Sanholt	}
172145132Sanholt
173145132Sanholt	DRM_UNLOCK();
174145132Sanholt
175145132Sanholt 	if (mapinlist == NULL)
176145132Sanholt		return EINVAL;
177145132Sanholt
178145132Sanholt	return 0;
179145132Sanholt}
180145132Sanholt
181182080Srnolandint drm_getclient(struct drm_device *dev, void *data,
182182080Srnoland		  struct drm_file *file_priv)
183145132Sanholt{
184183573Srnoland	struct drm_client *client = data;
185183573Srnoland	struct drm_file *pt;
186183573Srnoland	int idx;
187183573Srnoland	int i = 0;
188145132Sanholt
189182080Srnoland	idx = client->idx;
190145132Sanholt	DRM_LOCK();
191145132Sanholt	TAILQ_FOREACH(pt, &dev->files, link) {
192183573Srnoland		if (i == idx) {
193182080Srnoland			client->auth  = pt->authenticated;
194182080Srnoland			client->pid   = pt->pid;
195182080Srnoland			client->uid   = pt->uid;
196182080Srnoland			client->magic = pt->magic;
197182080Srnoland			client->iocs  = pt->ioctl_count;
198145132Sanholt			DRM_UNLOCK();
199145132Sanholt			return 0;
200145132Sanholt		}
201145132Sanholt		i++;
202145132Sanholt	}
203145132Sanholt	DRM_UNLOCK();
204145132Sanholt
205182080Srnoland	return EINVAL;
206145132Sanholt}
207145132Sanholt
208182080Srnolandint drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv)
209145132Sanholt{
210183573Srnoland	struct drm_stats *stats = data;
211145132Sanholt	int          i;
212145132Sanholt
213183573Srnoland	memset(stats, 0, sizeof(struct drm_stats));
214145132Sanholt
215145132Sanholt	DRM_LOCK();
216145132Sanholt
217145132Sanholt	for (i = 0; i < dev->counters; i++) {
218145132Sanholt		if (dev->types[i] == _DRM_STAT_LOCK)
219183573Srnoland			stats->data[i].value =
220183573Srnoland			    (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
221145132Sanholt		else
222182080Srnoland			stats->data[i].value = atomic_read(&dev->counts[i]);
223183573Srnoland		stats->data[i].type = dev->types[i];
224145132Sanholt	}
225145132Sanholt
226182080Srnoland	stats->count = dev->counters;
227145132Sanholt
228145132Sanholt	DRM_UNLOCK();
229145132Sanholt
230145132Sanholt	return 0;
231145132Sanholt}
232145132Sanholt
233145132Sanholt#define DRM_IF_MAJOR	1
234145132Sanholt#define DRM_IF_MINOR	2
235145132Sanholt
236182080Srnolandint drm_setversion(struct drm_device *dev, void *data,
237182080Srnoland		   struct drm_file *file_priv)
238145132Sanholt{
239183573Srnoland	struct drm_set_version *sv = data;
240183573Srnoland	struct drm_set_version ver;
241145132Sanholt	int if_version;
242145132Sanholt
243182080Srnoland	/* Save the incoming data, and set the response before continuing
244182080Srnoland	 * any further.
245182080Srnoland	 */
246182080Srnoland	ver = *sv;
247182080Srnoland	sv->drm_di_major = DRM_IF_MAJOR;
248182080Srnoland	sv->drm_di_minor = DRM_IF_MINOR;
249183573Srnoland	sv->drm_dd_major = dev->driver->major;
250183573Srnoland	sv->drm_dd_minor = dev->driver->minor;
251145132Sanholt
252182080Srnoland	if (ver.drm_di_major != -1) {
253182080Srnoland		if (ver.drm_di_major != DRM_IF_MAJOR ||
254182080Srnoland		    ver.drm_di_minor < 0 || ver.drm_di_minor > DRM_IF_MINOR) {
255145132Sanholt			return EINVAL;
256182080Srnoland		}
257182080Srnoland		if_version = DRM_IF_VERSION(ver.drm_di_major,
258182080Srnoland		    ver.drm_dd_minor);
259145132Sanholt		dev->if_version = DRM_MAX(if_version, dev->if_version);
260182080Srnoland		if (ver.drm_di_minor >= 1) {
261145132Sanholt			/*
262145132Sanholt			 * Version 1.1 includes tying of DRM to specific device
263145132Sanholt			 */
264145132Sanholt			drm_set_busid(dev);
265145132Sanholt		}
266145132Sanholt	}
267145132Sanholt
268182080Srnoland	if (ver.drm_dd_major != -1) {
269183573Srnoland		if (ver.drm_dd_major != dev->driver->major ||
270182080Srnoland		    ver.drm_dd_minor < 0 ||
271183573Srnoland		    ver.drm_dd_minor > dev->driver->minor)
272182080Srnoland		{
273145132Sanholt			return EINVAL;
274182080Srnoland		}
275145132Sanholt	}
276182080Srnoland
277145132Sanholt	return 0;
278145132Sanholt}
279145132Sanholt
280145132Sanholt
281182080Srnolandint drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv)
282145132Sanholt{
283145132Sanholt	DRM_DEBUG("\n");
284145132Sanholt	return 0;
285145132Sanholt}
286