blob: 8d3a20d117a2f81e21797033254ce8c33e242f94 [file] [log] [blame]
Daryll Straussb3a57661999-12-05 01:19:48 +00001/* xf86drm.c -- User-level interface to DRM device
2 * Created: Tue Jan 5 08:16:21 1999 by faith@precisioninsight.com
Daryll Straussb3a57661999-12-05 01:19:48 +00003 *
Brian Paul569da5a2000-06-08 14:38:22 +00004 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
Daryll Straussb3a57661999-12-05 01:19:48 +00006 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
Gareth Hughes36047532001-02-15 08:12:14 +000014 *
Daryll Straussb3a57661999-12-05 01:19:48 +000015 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
Gareth Hughes36047532001-02-15 08:12:14 +000018 *
Daryll Straussb3a57661999-12-05 01:19:48 +000019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
Gareth Hughes36047532001-02-15 08:12:14 +000026 *
Brian Paul569da5a2000-06-08 14:38:22 +000027 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
28 * Kevin E. Martin <martin@valinux.com>
29 *
David Dawes44aa4d62002-01-27 20:05:42 +000030 * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.25 2001/08/27 17:40:59 dawes Exp $
Gareth Hughes36047532001-02-15 08:12:14 +000031 *
Daryll Straussb3a57661999-12-05 01:19:48 +000032 */
33
34#ifdef XFree86Server
35# include "xf86.h"
36# include "xf86_OSproc.h"
37# include "xf86_ansic.h"
Daryll Straussb3a57661999-12-05 01:19:48 +000038# define _DRM_MALLOC xalloc
39# define _DRM_FREE xfree
40# ifndef XFree86LOADER
Daryll Straussb3a57661999-12-05 01:19:48 +000041# include <sys/mman.h>
42# endif
43#else
44# include <stdio.h>
45# include <stdlib.h>
46# include <unistd.h>
47# include <string.h>
48# include <ctype.h>
49# include <fcntl.h>
50# include <errno.h>
51# include <signal.h>
52# include <sys/types.h>
53# include <sys/stat.h>
David Dawesfcc21062001-03-30 17:16:20 +000054# define stat_t struct stat
Daryll Straussb3a57661999-12-05 01:19:48 +000055# include <sys/ioctl.h>
56# include <sys/mman.h>
57# include <sys/time.h>
David Dawes56bd9c22001-07-30 19:59:39 +000058# include <stdarg.h>
Daryll Straussb3a57661999-12-05 01:19:48 +000059# ifdef DRM_USE_MALLOC
60# define _DRM_MALLOC malloc
61# define _DRM_FREE free
Daryll Strausse1dba5c1999-12-07 03:37:16 +000062extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *);
Daryll Straussb3a57661999-12-05 01:19:48 +000063extern int xf86RemoveSIGIOHandler(int fd);
64# else
David Dawes9e69d0d2001-08-25 03:13:04 +000065# include <X11/Xlibint.h>
Daryll Straussb3a57661999-12-05 01:19:48 +000066# define _DRM_MALLOC Xmalloc
67# define _DRM_FREE Xfree
68# endif
69#endif
70
Alan Hourihane08137602001-05-04 14:05:13 +000071/* No longer needed with CVS kernel modules on alpha
David Dawes2ea12222001-05-01 21:39:35 +000072#if defined(__alpha__) && defined(__linux__)
73extern unsigned long _bus_base(void);
74#define BUS_BASE _bus_base()
75#endif
Alan Hourihane08137602001-05-04 14:05:13 +000076*/
David Dawes2ea12222001-05-01 21:39:35 +000077
Daryll Straussb3a57661999-12-05 01:19:48 +000078/* Not all systems have MAP_FAILED defined */
79#ifndef MAP_FAILED
80#define MAP_FAILED ((void *)-1)
81#endif
82
Daryll Straussb3a57661999-12-05 01:19:48 +000083#include "xf86drm.h"
84#include "drm.h"
85
Rik Faith88dbee52001-02-28 09:27:44 +000086#ifndef DRM_MAJOR
87#define DRM_MAJOR 226 /* Linux */
88#endif
89
90#ifndef __linux__
91#undef DRM_MAJOR
92#define DRM_MAJOR 145 /* Should set in drm.h for *BSD */
93#endif
94
95#ifndef DRM_MAX_MINOR
96#define DRM_MAX_MINOR 16
97#endif
Brian Paul569da5a2000-06-08 14:38:22 +000098
99#ifdef __linux__
100#include <sys/sysmacros.h> /* for makedev() */
101#endif
102
103#ifndef makedev
104 /* This definition needs to be changed on
105 some systems if dev_t is a structure.
106 If there is a header file we can get it
107 from, there would be best. */
108#define makedev(x,y) ((dev_t)(((x) << 8) | (y)))
109#endif
110
David Dawes56bd9c22001-07-30 19:59:39 +0000111#define DRM_MSG_VERBOSITY 3
112
113static void
114drmMsg(const char *format, ...)
115{
116 va_list ap;
117
118#ifndef XFree86Server
119 const char *env;
120 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose"))
121#endif
122 {
123 va_start(ap, format);
124#ifdef XFree86Server
125 xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap);
126#else
127 vfprintf(stderr, format, ap);
128#endif
129 va_end(ap);
130 }
131}
132
Daryll Straussb3a57661999-12-05 01:19:48 +0000133static void *drmHashTable = NULL; /* Context switch callbacks */
134
135typedef struct drmHashEntry {
136 int fd;
137 void (*f)(int, void *, void *);
138 void *tagTable;
139} drmHashEntry;
140
141void *drmMalloc(int size)
142{
143 void *pt;
144 if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size);
145 return pt;
146}
147
148void drmFree(void *pt)
149{
150 if (pt) _DRM_FREE(pt);
151}
152
Brian Paul569da5a2000-06-08 14:38:22 +0000153/* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */
Daryll Straussb3a57661999-12-05 01:19:48 +0000154static char *drmStrdup(const char *s)
155{
Brian Paul569da5a2000-06-08 14:38:22 +0000156 char *retval = NULL;
Gareth Hughes36047532001-02-15 08:12:14 +0000157
Brian Paul569da5a2000-06-08 14:38:22 +0000158 if (s) {
159 retval = _DRM_MALLOC(strlen(s)+1);
160 strcpy(retval, s);
161 }
162 return retval;
Daryll Straussb3a57661999-12-05 01:19:48 +0000163}
164
165
Daryll Straussb3a57661999-12-05 01:19:48 +0000166static unsigned long drmGetKeyFromFd(int fd)
167{
David Dawesfcc21062001-03-30 17:16:20 +0000168 stat_t st;
Daryll Straussb3a57661999-12-05 01:19:48 +0000169
170 st.st_rdev = 0;
171 fstat(fd, &st);
172 return st.st_rdev;
173}
174
175static drmHashEntry *drmGetEntry(int fd)
176{
177 unsigned long key = drmGetKeyFromFd(fd);
178 void *value;
179 drmHashEntry *entry;
180
181 if (!drmHashTable) drmHashTable = drmHashCreate();
182
183 if (drmHashLookup(drmHashTable, key, &value)) {
184 entry = drmMalloc(sizeof(*entry));
185 entry->fd = fd;
186 entry->f = NULL;
187 entry->tagTable = drmHashCreate();
188 drmHashInsert(drmHashTable, key, entry);
189 } else {
190 entry = value;
191 }
192 return entry;
193}
194
Rik Faith88dbee52001-02-28 09:27:44 +0000195static int drmOpenDevice(long dev, int minor)
Daryll Straussb3a57661999-12-05 01:19:48 +0000196{
David Dawes9c775d02001-05-14 14:49:58 +0000197 stat_t st;
Rik Faith88dbee52001-02-28 09:27:44 +0000198 char buf[64];
199 int fd;
200 mode_t dirmode = DRM_DEV_DIRMODE;
201 mode_t devmode = DRM_DEV_MODE;
202 int isroot = !geteuid();
203#if defined(XFree86Server)
204 uid_t user = DRM_DEV_UID;
205 gid_t group = DRM_DEV_GID;
206#endif
Daryll Straussb3a57661999-12-05 01:19:48 +0000207
David Dawes56bd9c22001-07-30 19:59:39 +0000208 drmMsg("drmOpenDevice: minor is %d\n", minor);
209
Rik Faith88dbee52001-02-28 09:27:44 +0000210#if defined(XFree86Server)
211 devmode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE;
212 dirmode = (devmode & S_IRUSR) ? S_IXUSR : 0;
213 dirmode |= (devmode & S_IRGRP) ? S_IXGRP : 0;
214 dirmode |= (devmode & S_IROTH) ? S_IXOTH : 0;
215 dirmode |= devmode;
216 devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
217 group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID;
218#endif
Brian Paul569da5a2000-06-08 14:38:22 +0000219
Rik Faith88dbee52001-02-28 09:27:44 +0000220 if (stat(DRM_DIR_NAME, &st)) {
221 if (!isroot) return DRM_ERR_NOT_ROOT;
222 remove(DRM_DIR_NAME);
223 mkdir(DRM_DIR_NAME, dirmode);
Brian Paul569da5a2000-06-08 14:38:22 +0000224 }
Rik Faith88dbee52001-02-28 09:27:44 +0000225#if defined(XFree86Server)
226 chown(DRM_DIR_NAME, user, group);
227 chmod(DRM_DIR_NAME, dirmode);
228#endif
Daryll Straussb3a57661999-12-05 01:19:48 +0000229
Rik Faith88dbee52001-02-28 09:27:44 +0000230 sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
David Dawes56bd9c22001-07-30 19:59:39 +0000231 drmMsg("drmOpenDevice: node name is %s\n", buf);
Eric Anholtd2f2b422002-08-08 21:23:46 +0000232 if (stat(buf, &st)) {
Rik Faith88dbee52001-02-28 09:27:44 +0000233 if (!isroot) return DRM_ERR_NOT_ROOT;
234 remove(buf);
235 mknod(buf, S_IFCHR | devmode, dev);
Daryll Straussb3a57661999-12-05 01:19:48 +0000236 }
Rik Faith88dbee52001-02-28 09:27:44 +0000237#if defined(XFree86Server)
238 chown(buf, user, group);
239 chmod(buf, devmode);
240#endif
241
David Dawes56bd9c22001-07-30 19:59:39 +0000242 fd = open(buf, O_RDWR, 0);
243 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
244 fd, fd < 0 ? strerror(errno) : "OK");
245 if (fd >= 0) return fd;
Eric Anholtd2f2b422002-08-08 21:23:46 +0000246
247 if (st.st_rdev != dev) {
248 if (!isroot) return DRM_ERR_NOT_ROOT;
249 remove(buf);
250 mknod(buf, S_IFCHR | devmode, dev);
251 }
252 fd = open(buf, O_RDWR, 0);
253 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
254 fd, fd < 0 ? strerror(errno) : "OK");
255
David Dawes56bd9c22001-07-30 19:59:39 +0000256 drmMsg("drmOpenDevice: Open failed\n");
Rik Faith88dbee52001-02-28 09:27:44 +0000257 remove(buf);
258 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +0000259}
260
David Dawesfcc21062001-03-30 17:16:20 +0000261static int drmOpenMinor(int minor, int create)
Rik Faith88dbee52001-02-28 09:27:44 +0000262{
263 int fd;
264 char buf[64];
265
266 if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
267
268 sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
269 if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
270 return -errno;
271}
272
273/* drmAvailable looks for (DRM_MAJOR, 0) and returns 1 if it returns
274 information for DRM_IOCTL_VERSION. For backward compatibility with
275 older Linux implementations, /proc/dri is also checked. */
Brian Paul569da5a2000-06-08 14:38:22 +0000276
277int drmAvailable(void)
278{
Brian Paul569da5a2000-06-08 14:38:22 +0000279 drmVersionPtr version;
280 int retval = 0;
281 int fd;
Gareth Hughes36047532001-02-15 08:12:14 +0000282
Rik Faith88dbee52001-02-28 09:27:44 +0000283 if ((fd = drmOpenMinor(0, 1)) < 0) {
284 /* Try proc for backward Linux compatibility */
285 if (!access("/proc/dri/0", R_OK)) return 1;
286 return 0;
Brian Paul569da5a2000-06-08 14:38:22 +0000287 }
Rik Faith88dbee52001-02-28 09:27:44 +0000288
289 if ((version = drmGetVersion(fd))) {
290 retval = 1;
291 drmFreeVersion(version);
292 }
293 close(fd);
Brian Paul569da5a2000-06-08 14:38:22 +0000294
295 return retval;
296}
297
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000298static int drmOpenByBusid(const char *busid)
299{
Rik Faith88dbee52001-02-28 09:27:44 +0000300 int i;
301 int fd;
302 const char *buf;
303
David Dawes56bd9c22001-07-30 19:59:39 +0000304 drmMsg("drmOpenByBusid: busid is %s\n", busid);
Rik Faith88dbee52001-02-28 09:27:44 +0000305 for (i = 0; i < DRM_MAX_MINOR; i++) {
David Dawes56bd9c22001-07-30 19:59:39 +0000306 fd = drmOpenMinor(i, 1);
307 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
308 if (fd >= 0) {
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000309 buf = drmGetBusid(fd);
David Dawes56bd9c22001-07-30 19:59:39 +0000310 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000311 if (buf && !strcmp(buf, busid)) {
Rik Faith88dbee52001-02-28 09:27:44 +0000312 drmFreeBusid(buf);
313 return fd;
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000314 }
315 if (buf) drmFreeBusid(buf);
316 close(fd);
317 }
318 }
319 return -1;
320}
321
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000322static int drmOpenByName(const char *name)
Daryll Straussb3a57661999-12-05 01:19:48 +0000323{
Rik Faith88dbee52001-02-28 09:27:44 +0000324 int i;
325 int fd;
326 drmVersionPtr version;
David Dawes56bd9c22001-07-30 19:59:39 +0000327 char * id;
Rik Faith88dbee52001-02-28 09:27:44 +0000328
Brian Paul01836822000-04-20 16:36:40 +0000329 if (!drmAvailable()) {
Rik Faith88dbee52001-02-28 09:27:44 +0000330#if !defined(XFree86Server)
331 return -1;
332#else
Brian Paul01836822000-04-20 16:36:40 +0000333 /* try to load the kernel module now */
Jeff Hartmannae5b4ef2001-07-20 20:31:30 +0000334 if (!xf86LoadKernelModule(name)) {
Brian Paul01836822000-04-20 16:36:40 +0000335 ErrorF("[drm] failed to load kernel module \"%s\"\n",
336 name);
337 return -1;
338 }
Brian Paul01836822000-04-20 16:36:40 +0000339#endif
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000340 }
341
David Dawes56bd9c22001-07-30 19:59:39 +0000342 /*
343 * Open the first minor number that matches the driver name and isn't
344 * already in use. If it's in use it will have a busid assigned already.
345 */
Rik Faith88dbee52001-02-28 09:27:44 +0000346 for (i = 0; i < DRM_MAX_MINOR; i++) {
347 if ((fd = drmOpenMinor(i, 1)) >= 0) {
348 if ((version = drmGetVersion(fd))) {
349 if (!strcmp(version->name, name)) {
350 drmFreeVersion(version);
David Dawes56bd9c22001-07-30 19:59:39 +0000351 id = drmGetBusid(fd);
352 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
353 if (!id || !*id) {
354 if (id) {
355 drmFreeBusid(id);
356 }
357 return fd;
358 } else {
359 drmFreeBusid(id);
360 }
361 } else {
362 drmFreeVersion(version);
Rik Faith88dbee52001-02-28 09:27:44 +0000363 }
Rik Faith88dbee52001-02-28 09:27:44 +0000364 }
David Dawes56bd9c22001-07-30 19:59:39 +0000365 close(fd);
Rik Faith88dbee52001-02-28 09:27:44 +0000366 }
367 }
368
369#ifdef __linux__
370 /* Backward-compatibility /proc support */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000371 for (i = 0; i < 8; i++) {
Rik Faith88dbee52001-02-28 09:27:44 +0000372 char proc_name[64], buf[512];
373 char *driver, *pt, *devstring;
374 int retcode;
375
Daryll Strauss0371c291999-12-18 18:34:59 +0000376 sprintf(proc_name, "/proc/dri/%d/name", i);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000377 if ((fd = open(proc_name, 0, 0)) >= 0) {
378 retcode = read(fd, buf, sizeof(buf)-1);
379 close(fd);
380 if (retcode) {
381 buf[retcode-1] = '\0';
382 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
383 ;
384 if (*pt) { /* Device is next */
385 *pt = '\0';
386 if (!strcmp(driver, name)) { /* Match */
387 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
388 ;
389 if (*pt) { /* Found busid */
Rik Faith88dbee52001-02-28 09:27:44 +0000390 return drmOpenByBusid(++pt);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000391 } else { /* No busid */
Rik Faith88dbee52001-02-28 09:27:44 +0000392 return drmOpenDevice(strtol(devstring, NULL, 0),i);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000393 }
394 }
395 }
396 }
Brian Paul569da5a2000-06-08 14:38:22 +0000397 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000398 }
Rik Faith88dbee52001-02-28 09:27:44 +0000399#endif
400
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000401 return -1;
402}
403
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000404/* drmOpen looks up the specified name and busid, and opens the device
Daryll Strauss0371c291999-12-18 18:34:59 +0000405 found. The entry in /dev/dri is created if necessary (and if root).
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000406 A file descriptor is returned. On error, the return value is
407 negative. */
408
409int drmOpen(const char *name, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000410{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000411
412 if (busid) return drmOpenByBusid(busid);
413 return drmOpenByName(name);
Daryll Straussb3a57661999-12-05 01:19:48 +0000414}
415
416void drmFreeVersion(drmVersionPtr v)
417{
418 if (!v) return;
419 if (v->name) drmFree(v->name);
420 if (v->date) drmFree(v->date);
421 if (v->desc) drmFree(v->desc);
422 drmFree(v);
423}
424
425static void drmFreeKernelVersion(drm_version_t *v)
426{
427 if (!v) return;
428 if (v->name) drmFree(v->name);
429 if (v->date) drmFree(v->date);
430 if (v->desc) drmFree(v->desc);
431 drmFree(v);
432}
433
Brian Paul569da5a2000-06-08 14:38:22 +0000434static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
Daryll Straussb3a57661999-12-05 01:19:48 +0000435{
436 d->version_major = s->version_major;
437 d->version_minor = s->version_minor;
438 d->version_patchlevel = s->version_patchlevel;
439 d->name_len = s->name_len;
440 d->name = drmStrdup(s->name);
441 d->date_len = s->date_len;
442 d->date = drmStrdup(s->date);
443 d->desc_len = s->desc_len;
444 d->desc = drmStrdup(s->desc);
445}
446
Jens Owen3903e5a2002-04-09 21:54:56 +0000447/* drmGet Version obtains the driver version information via an ioctl. Similar
Brian Paul569da5a2000-06-08 14:38:22 +0000448 * information is available via /proc/dri. */
Daryll Straussb3a57661999-12-05 01:19:48 +0000449
450drmVersionPtr drmGetVersion(int fd)
451{
452 drmVersionPtr retval;
453 drm_version_t *version = drmMalloc(sizeof(*version));
454
455 /* First, get the lengths */
456 version->name_len = 0;
457 version->name = NULL;
458 version->date_len = 0;
459 version->date = NULL;
460 version->desc_len = 0;
461 version->desc = NULL;
Gareth Hughes36047532001-02-15 08:12:14 +0000462
Daryll Straussb3a57661999-12-05 01:19:48 +0000463 if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
464 drmFreeKernelVersion(version);
465 return NULL;
466 }
467
468 /* Now, allocate space and get the data */
469 if (version->name_len)
470 version->name = drmMalloc(version->name_len + 1);
471 if (version->date_len)
472 version->date = drmMalloc(version->date_len + 1);
473 if (version->desc_len)
474 version->desc = drmMalloc(version->desc_len + 1);
Gareth Hughes36047532001-02-15 08:12:14 +0000475
Daryll Straussb3a57661999-12-05 01:19:48 +0000476 if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
477 drmFreeKernelVersion(version);
478 return NULL;
479 }
480
481 /* The results might not be null-terminated
482 strings, so terminate them. */
483
484 if (version->name_len) version->name[version->name_len] = '\0';
485 if (version->date_len) version->date[version->date_len] = '\0';
486 if (version->desc_len) version->desc[version->desc_len] = '\0';
487
488 /* Now, copy it all back into the
489 client-visible data structure... */
490 retval = drmMalloc(sizeof(*retval));
491 drmCopyVersion(retval, version);
492 drmFreeKernelVersion(version);
493 return retval;
494}
495
Jens Owen3903e5a2002-04-09 21:54:56 +0000496/* drmGetLibVersion set version information for the drm user space library.
497 * this version number is driver indepedent */
498
499drmVersionPtr drmGetLibVersion(int fd)
500{
501 drm_version_t *version = drmMalloc(sizeof(*version));
502
503 /* Version history:
504 * revision 1.0.x = original DRM interface with no drmGetLibVersion
505 * entry point and many drm<Device> extensions
506 * revision 1.1.x = added drmCommand entry points for device extensions
507 * added drmGetLibVersion to identify libdrm.a version
508 */
509 version->version_major = 1;
510 version->version_minor = 1;
511 version->version_patchlevel = 0;
512
513 return (drmVersionPtr)version;
514}
515
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000516void drmFreeBusid(const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000517{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000518 drmFree((void *)busid);
Daryll Straussb3a57661999-12-05 01:19:48 +0000519}
520
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000521char *drmGetBusid(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000522{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000523 drm_unique_t u;
524
525 u.unique_len = 0;
526 u.unique = NULL;
527
528 if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
529 u.unique = drmMalloc(u.unique_len + 1);
530 if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
531 u.unique[u.unique_len] = '\0';
532 return u.unique;
Daryll Straussb3a57661999-12-05 01:19:48 +0000533}
534
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000535int drmSetBusid(int fd, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000536{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000537 drm_unique_t u;
Daryll Straussb3a57661999-12-05 01:19:48 +0000538
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000539 u.unique = (char *)busid;
540 u.unique_len = strlen(busid);
Daryll Straussb3a57661999-12-05 01:19:48 +0000541
David Dawes56bd9c22001-07-30 19:59:39 +0000542 if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
543 return -errno;
544 }
Daryll Straussb3a57661999-12-05 01:19:48 +0000545 return 0;
546}
547
548int drmGetMagic(int fd, drmMagicPtr magic)
549{
550 drm_auth_t auth;
551
552 *magic = 0;
553 if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) return -errno;
554 *magic = auth.magic;
555 return 0;
556}
557
558int drmAuthMagic(int fd, drmMagic magic)
559{
560 drm_auth_t auth;
561
562 auth.magic = magic;
563 if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) return -errno;
564 return 0;
565}
566
567int drmAddMap(int fd,
568 drmHandle offset,
569 drmSize size,
570 drmMapType type,
571 drmMapFlags flags,
572 drmHandlePtr handle)
573{
574 drm_map_t map;
575
576 map.offset = offset;
Alan Hourihane08137602001-05-04 14:05:13 +0000577/* No longer needed with CVS kernel modules on alpha
David Dawes2ea12222001-05-01 21:39:35 +0000578#ifdef __alpha__
David Dawes2ea12222001-05-01 21:39:35 +0000579 if (type != DRM_SHM)
580 map.offset += BUS_BASE;
581#endif
Alan Hourihane08137602001-05-04 14:05:13 +0000582*/
Daryll Straussb3a57661999-12-05 01:19:48 +0000583 map.size = size;
584 map.handle = 0;
585 map.type = type;
586 map.flags = flags;
587 if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno;
588 if (handle) *handle = (drmHandle)map.handle;
589 return 0;
590}
591
Kevin E Martin74e19a42001-03-14 22:22:50 +0000592int drmRmMap(int fd, drmHandle handle)
593{
594 drm_map_t map;
595
596 map.handle = (void *)handle;
597
598 if(ioctl(fd, DRM_IOCTL_RM_MAP, &map)) return -errno;
599 return 0;
600}
601
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +0000602int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
603 int agp_offset)
Daryll Straussb3a57661999-12-05 01:19:48 +0000604{
605 drm_buf_desc_t request;
Gareth Hughes36047532001-02-15 08:12:14 +0000606
Daryll Straussb3a57661999-12-05 01:19:48 +0000607 request.count = count;
608 request.size = size;
609 request.low_mark = 0;
610 request.high_mark = 0;
611 request.flags = flags;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +0000612 request.agp_start = agp_offset;
Gareth Hughes36047532001-02-15 08:12:14 +0000613
Daryll Straussb3a57661999-12-05 01:19:48 +0000614 if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno;
615 return request.count;
616}
617
618int drmMarkBufs(int fd, double low, double high)
619{
620 drm_buf_info_t info;
621 int i;
622
623 info.count = 0;
624 info.list = NULL;
625
626 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL;
627
628 if (!info.count) return -EINVAL;
Gareth Hughes36047532001-02-15 08:12:14 +0000629
Daryll Straussb3a57661999-12-05 01:19:48 +0000630 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
631 return -ENOMEM;
Gareth Hughes36047532001-02-15 08:12:14 +0000632
Daryll Straussb3a57661999-12-05 01:19:48 +0000633 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
634 int retval = -errno;
635 drmFree(info.list);
636 return retval;
637 }
Gareth Hughes36047532001-02-15 08:12:14 +0000638
Daryll Straussb3a57661999-12-05 01:19:48 +0000639 for (i = 0; i < info.count; i++) {
640 info.list[i].low_mark = low * info.list[i].count;
641 info.list[i].high_mark = high * info.list[i].count;
642 if (ioctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
643 int retval = -errno;
644 drmFree(info.list);
645 return retval;
646 }
647 }
648 drmFree(info.list);
Gareth Hughes36047532001-02-15 08:12:14 +0000649
Daryll Straussb3a57661999-12-05 01:19:48 +0000650 return 0;
651}
652
653int drmFreeBufs(int fd, int count, int *list)
654{
655 drm_buf_free_t request;
656
657 request.count = count;
658 request.list = list;
659 if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno;
660 return 0;
661}
662
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000663int drmClose(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000664{
665 unsigned long key = drmGetKeyFromFd(fd);
666 drmHashEntry *entry = drmGetEntry(fd);
667
668 drmHashDestroy(entry->tagTable);
669 entry->fd = 0;
670 entry->f = NULL;
671 entry->tagTable = NULL;
672
673 drmHashDelete(drmHashTable, key);
674 drmFree(entry);
675
676 return close(fd);
677}
678
679int drmMap(int fd,
680 drmHandle handle,
681 drmSize size,
682 drmAddressPtr address)
683{
Alan Hourihanec7558d82000-09-24 09:34:10 +0000684 static unsigned long pagesize_mask = 0;
685
Daryll Straussb3a57661999-12-05 01:19:48 +0000686 if (fd < 0) return -EINVAL;
Alan Hourihanec7558d82000-09-24 09:34:10 +0000687
688 if (!pagesize_mask)
689 pagesize_mask = getpagesize() - 1;
690
691 size = (size + pagesize_mask) & ~pagesize_mask;
692
Daryll Straussb3a57661999-12-05 01:19:48 +0000693 *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
694 if (*address == MAP_FAILED) return -errno;
695 return 0;
696}
697
698int drmUnmap(drmAddress address, drmSize size)
699{
700 return munmap(address, size);
701}
702
703drmBufInfoPtr drmGetBufInfo(int fd)
704{
705 drm_buf_info_t info;
706 drmBufInfoPtr retval;
707 int i;
708
709 info.count = 0;
710 info.list = NULL;
711
712 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return NULL;
713
714 if (info.count) {
715 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
716 return NULL;
Gareth Hughes36047532001-02-15 08:12:14 +0000717
Daryll Straussb3a57661999-12-05 01:19:48 +0000718 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
719 drmFree(info.list);
720 return NULL;
721 }
722 /* Now, copy it all back into the
723 client-visible data structure... */
724 retval = drmMalloc(sizeof(*retval));
725 retval->count = info.count;
726 retval->list = drmMalloc(info.count * sizeof(*retval->list));
727 for (i = 0; i < info.count; i++) {
728 retval->list[i].count = info.list[i].count;
729 retval->list[i].size = info.list[i].size;
730 retval->list[i].low_mark = info.list[i].low_mark;
731 retval->list[i].high_mark = info.list[i].high_mark;
732 }
733 drmFree(info.list);
734 return retval;
735 }
736 return NULL;
737}
738
739drmBufMapPtr drmMapBufs(int fd)
740{
741 drm_buf_map_t bufs;
742 drmBufMapPtr retval;
743 int i;
Gareth Hughes36047532001-02-15 08:12:14 +0000744
Daryll Straussb3a57661999-12-05 01:19:48 +0000745 bufs.count = 0;
746 bufs.list = NULL;
747 if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL;
748
749 if (bufs.count) {
750 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
751 return NULL;
752
753 if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
754 drmFree(bufs.list);
755 return NULL;
756 }
757 /* Now, copy it all back into the
758 client-visible data structure... */
759 retval = drmMalloc(sizeof(*retval));
760 retval->count = bufs.count;
761 retval->list = drmMalloc(bufs.count * sizeof(*retval->list));
762 for (i = 0; i < bufs.count; i++) {
763 retval->list[i].idx = bufs.list[i].idx;
764 retval->list[i].total = bufs.list[i].total;
765 retval->list[i].used = 0;
766 retval->list[i].address = bufs.list[i].address;
767 }
768 return retval;
769 }
770 return NULL;
771}
772
773int drmUnmapBufs(drmBufMapPtr bufs)
774{
775 int i;
Gareth Hughes36047532001-02-15 08:12:14 +0000776
Daryll Straussb3a57661999-12-05 01:19:48 +0000777 for (i = 0; i < bufs->count; i++) {
778 munmap(bufs->list[i].address, bufs->list[i].total);
779 }
780 return 0;
781}
782
Gareth Hughes36047532001-02-15 08:12:14 +0000783#define DRM_DMA_RETRY 16
784
Daryll Straussb3a57661999-12-05 01:19:48 +0000785int drmDMA(int fd, drmDMAReqPtr request)
786{
787 drm_dma_t dma;
Gareth Hughes36047532001-02-15 08:12:14 +0000788 int ret, i = 0;
Daryll Straussb3a57661999-12-05 01:19:48 +0000789
790 /* Copy to hidden structure */
791 dma.context = request->context;
792 dma.send_count = request->send_count;
793 dma.send_indices = request->send_list;
794 dma.send_sizes = request->send_sizes;
795 dma.flags = request->flags;
796 dma.request_count = request->request_count;
797 dma.request_size = request->request_size;
798 dma.request_indices = request->request_list;
799 dma.request_sizes = request->request_sizes;
Gareth Hughes36047532001-02-15 08:12:14 +0000800
801 do {
802 ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
803 } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
804
805 if ( ret == 0 ) {
806 request->granted_count = dma.granted_count;
807 return 0;
808 } else {
809 return -errno;
810 }
Daryll Straussb3a57661999-12-05 01:19:48 +0000811}
812
813int drmGetLock(int fd, drmContext context, drmLockFlags flags)
814{
815 drm_lock_t lock;
816
817 lock.context = context;
818 lock.flags = 0;
819 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
820 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
821 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
822 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
823 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
824 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
Gareth Hughes36047532001-02-15 08:12:14 +0000825
Daryll Straussb3a57661999-12-05 01:19:48 +0000826 while (ioctl(fd, DRM_IOCTL_LOCK, &lock))
827 ;
828 return 0;
829}
830
831int drmUnlock(int fd, drmContext context)
832{
833 drm_lock_t lock;
834
835 lock.context = context;
836 lock.flags = 0;
837 return ioctl(fd, DRM_IOCTL_UNLOCK, &lock);
838}
839
840drmContextPtr drmGetReservedContextList(int fd, int *count)
841{
842 drm_ctx_res_t res;
843 drm_ctx_t *list;
844 drmContextPtr retval;
845 int i;
846
847 res.count = 0;
848 res.contexts = NULL;
849 if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
850
851 if (!res.count) return NULL;
852
853 if (!(list = drmMalloc(res.count * sizeof(*list)))) return NULL;
854 if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
855 drmFree(list);
856 return NULL;
857 }
858
859 res.contexts = list;
860 if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
861
862 for (i = 0; i < res.count; i++) retval[i] = list[i].handle;
863 drmFree(list);
864
865 *count = res.count;
866 return retval;
867}
868
869void drmFreeReservedContextList(drmContextPtr pt)
870{
871 drmFree(pt);
872}
873
874int drmCreateContext(int fd, drmContextPtr handle)
875{
876 drm_ctx_t ctx;
877
878 ctx.flags = 0; /* Modified with functions below */
879 if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno;
880 *handle = ctx.handle;
881 return 0;
882}
883
884int drmSwitchToContext(int fd, drmContext context)
885{
886 drm_ctx_t ctx;
887
888 ctx.handle = context;
889 if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) return -errno;
890 return 0;
891}
892
893int drmSetContextFlags(int fd, drmContext context, drmContextFlags flags)
894{
895 drm_ctx_t ctx;
896
897 /* Context preserving means that no context
898 switched are done between DMA buffers
899 from one context and the next. This is
900 suitable for use in the X server (which
901 promises to maintain hardware context,
902 or in the client-side library when
903 buffers are swapped on behalf of two
904 threads. */
905 ctx.handle = context;
906 ctx.flags = 0;
907 if (flags & DRM_CONTEXT_PRESERVED) ctx.flags |= _DRM_CONTEXT_PRESERVED;
908 if (flags & DRM_CONTEXT_2DONLY) ctx.flags |= _DRM_CONTEXT_2DONLY;
909 if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) return -errno;
910 return 0;
911}
912
913int drmGetContextFlags(int fd, drmContext context, drmContextFlagsPtr flags)
914{
915 drm_ctx_t ctx;
916
917 ctx.handle = context;
918 if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx)) return -errno;
919 *flags = 0;
920 if (ctx.flags & _DRM_CONTEXT_PRESERVED) *flags |= DRM_CONTEXT_PRESERVED;
921 if (ctx.flags & _DRM_CONTEXT_2DONLY) *flags |= DRM_CONTEXT_2DONLY;
922 return 0;
923}
Gareth Hughes36047532001-02-15 08:12:14 +0000924
Daryll Straussb3a57661999-12-05 01:19:48 +0000925int drmDestroyContext(int fd, drmContext handle)
926{
927 drm_ctx_t ctx;
928 ctx.handle = handle;
929 if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno;
930 return 0;
931}
932
933int drmCreateDrawable(int fd, drmDrawablePtr handle)
934{
935 drm_draw_t draw;
936 if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) return -errno;
937 *handle = draw.handle;
938 return 0;
939}
940
941int drmDestroyDrawable(int fd, drmDrawable handle)
942{
943 drm_draw_t draw;
944 draw.handle = handle;
945 if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw)) return -errno;
946 return 0;
947}
948
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +0000949int drmAgpAcquire(int fd)
950{
951 if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno;
952 return 0;
953}
954
955int drmAgpRelease(int fd)
956{
957 if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno;
958 return 0;
959}
960
961int drmAgpEnable(int fd, unsigned long mode)
962{
963 drm_agp_mode_t m;
964
965 m.mode = mode;
966 if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno;
967 return 0;
968}
969
970int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
971 unsigned long *address, unsigned long *handle)
972{
973 drm_agp_buffer_t b;
974 *handle = 0;
975 b.size = size;
976 b.handle = 0;
977 b.type = type;
978 if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno;
979 if (address != 0UL) *address = b.physical;
980 *handle = b.handle;
981 return 0;
982}
983
984int drmAgpFree(int fd, unsigned long handle)
985{
986 drm_agp_buffer_t b;
987
988 b.size = 0;
989 b.handle = handle;
990 if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno;
991 return 0;
992}
993
994int drmAgpBind(int fd, unsigned long handle, unsigned long offset)
995{
996 drm_agp_binding_t b;
997
998 b.handle = handle;
999 b.offset = offset;
1000 if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno;
1001 return 0;
1002}
1003
1004int drmAgpUnbind(int fd, unsigned long handle)
1005{
1006 drm_agp_binding_t b;
1007
1008 b.handle = handle;
1009 b.offset = 0;
1010 if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno;
1011 return 0;
1012}
1013
1014int drmAgpVersionMajor(int fd)
1015{
1016 drm_agp_info_t i;
1017
1018 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
1019 return i.agp_version_major;
1020}
1021
1022int drmAgpVersionMinor(int fd)
1023{
1024 drm_agp_info_t i;
1025
1026 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
1027 return i.agp_version_minor;
1028}
1029
1030unsigned long drmAgpGetMode(int fd)
1031{
1032 drm_agp_info_t i;
1033
1034 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1035 return i.mode;
1036}
1037
1038unsigned long drmAgpBase(int fd)
1039{
1040 drm_agp_info_t i;
1041
1042 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1043 return i.aperture_base;
1044}
1045
1046unsigned long drmAgpSize(int fd)
1047{
1048 drm_agp_info_t i;
1049
1050 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1051 return i.aperture_size;
1052}
1053
1054unsigned long drmAgpMemoryUsed(int fd)
1055{
1056 drm_agp_info_t i;
1057
1058 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1059 return i.memory_used;
1060}
1061
1062unsigned long drmAgpMemoryAvail(int fd)
1063{
1064 drm_agp_info_t i;
1065
1066 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1067 return i.memory_allowed;
1068}
1069
1070unsigned int drmAgpVendorId(int fd)
1071{
1072 drm_agp_info_t i;
1073
1074 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1075 return i.id_vendor;
1076}
1077
1078unsigned int drmAgpDeviceId(int fd)
1079{
1080 drm_agp_info_t i;
1081
1082 if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
1083 return i.id_device;
1084}
1085
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00001086int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle)
1087{
1088 drm_scatter_gather_t sg;
1089
1090 *handle = 0;
1091 sg.size = size;
1092 sg.handle = 0;
1093 if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno;
1094 *handle = sg.handle;
1095 return 0;
1096}
1097
1098int drmScatterGatherFree(int fd, unsigned long handle)
1099{
1100 drm_scatter_gather_t sg;
1101
1102 sg.size = 0;
1103 sg.handle = handle;
1104 if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno;
1105 return 0;
1106}
1107
Michel Daenzer55acd0d2002-09-25 17:18:19 +00001108int drmWaitVBlank(int fd, drmVBlankPtr vbl)
1109{
1110 int ret;
1111
1112 do {
1113 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
1114 } while (ret && errno == EINTR);
1115
1116 return ret;
1117}
1118
Daryll Straussb3a57661999-12-05 01:19:48 +00001119int drmError(int err, const char *label)
1120{
1121 switch (err) {
1122 case DRM_ERR_NO_DEVICE: fprintf(stderr, "%s: no device\n", label); break;
1123 case DRM_ERR_NO_ACCESS: fprintf(stderr, "%s: no access\n", label); break;
1124 case DRM_ERR_NOT_ROOT: fprintf(stderr, "%s: not root\n", label); break;
1125 case DRM_ERR_INVALID: fprintf(stderr, "%s: invalid args\n", label);break;
1126 default:
1127 if (err < 0) err = -err;
1128 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
1129 break;
1130 }
1131
1132 return 1;
1133}
1134
Daryll Straussb3a57661999-12-05 01:19:48 +00001135int drmCtlInstHandler(int fd, int irq)
1136{
1137 drm_control_t ctl;
1138
1139 ctl.func = DRM_INST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +00001140 ctl.irq = irq;
Daryll Straussb3a57661999-12-05 01:19:48 +00001141 if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
1142 return 0;
1143}
1144
1145int drmCtlUninstHandler(int fd)
1146{
1147 drm_control_t ctl;
1148
1149 ctl.func = DRM_UNINST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +00001150 ctl.irq = 0;
Daryll Straussb3a57661999-12-05 01:19:48 +00001151 if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
1152 return 0;
1153}
1154
1155int drmFinish(int fd, int context, drmLockFlags flags)
1156{
1157 drm_lock_t lock;
1158
1159 lock.context = context;
1160 lock.flags = 0;
1161 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
1162 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
1163 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
1164 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
1165 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
1166 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
1167 if (ioctl(fd, DRM_IOCTL_FINISH, &lock)) return -errno;
1168 return 0;
1169}
1170
1171int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
1172{
1173 drm_irq_busid_t p;
1174
1175 p.busnum = busnum;
1176 p.devnum = devnum;
1177 p.funcnum = funcnum;
1178 if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno;
1179 return p.irq;
1180}
1181
1182int drmAddContextTag(int fd, drmContext context, void *tag)
1183{
1184 drmHashEntry *entry = drmGetEntry(fd);
1185
1186 if (drmHashInsert(entry->tagTable, context, tag)) {
1187 drmHashDelete(entry->tagTable, context);
1188 drmHashInsert(entry->tagTable, context, tag);
1189 }
1190 return 0;
1191}
1192
1193int drmDelContextTag(int fd, drmContext context)
1194{
1195 drmHashEntry *entry = drmGetEntry(fd);
1196
1197 return drmHashDelete(entry->tagTable, context);
1198}
1199
1200void *drmGetContextTag(int fd, drmContext context)
1201{
1202 drmHashEntry *entry = drmGetEntry(fd);
1203 void *value;
Gareth Hughes36047532001-02-15 08:12:14 +00001204
Daryll Straussb3a57661999-12-05 01:19:48 +00001205 if (drmHashLookup(entry->tagTable, context, &value)) return NULL;
1206
1207 return value;
1208}
1209
Kevin E Martin74e19a42001-03-14 22:22:50 +00001210int drmAddContextPrivateMapping(int fd, drmContext ctx_id, drmHandle handle)
1211{
1212 drm_ctx_priv_map_t map;
1213
1214 map.ctx_id = ctx_id;
1215 map.handle = (void *)handle;
1216
1217 if (ioctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) return -errno;
1218 return 0;
1219}
1220
1221int drmGetContextPrivateMapping(int fd, drmContext ctx_id, drmHandlePtr handle)
1222{
1223 drm_ctx_priv_map_t map;
1224
1225 map.ctx_id = ctx_id;
1226
1227 if (ioctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) return -errno;
1228 if (handle) *handle = (drmHandle)map.handle;
1229
1230 return 0;
1231}
1232
Rik Faith88dbee52001-02-28 09:27:44 +00001233int drmGetMap(int fd, int idx, drmHandle *offset, drmSize *size,
1234 drmMapType *type, drmMapFlags *flags, drmHandle *handle,
1235 int *mtrr)
1236{
1237 drm_map_t map;
1238
1239 map.offset = idx;
1240 if (ioctl(fd, DRM_IOCTL_GET_MAP, &map)) return -errno;
1241 *offset = map.offset;
1242 *size = map.size;
1243 *type = map.type;
1244 *flags = map.flags;
1245 *handle = (unsigned long)map.handle;
1246 *mtrr = map.mtrr;
1247 return 0;
1248}
1249
1250int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
1251 unsigned long *magic, unsigned long *iocs)
1252{
1253 drm_client_t client;
1254
1255 client.idx = idx;
1256 if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client)) return -errno;
1257 *auth = client.auth;
1258 *pid = client.pid;
1259 *uid = client.uid;
1260 *magic = client.magic;
1261 *iocs = client.iocs;
1262 return 0;
1263}
1264
1265int drmGetStats(int fd, drmStatsT *stats)
1266{
1267 drm_stats_t s;
1268 int i;
1269
1270 if (ioctl(fd, DRM_IOCTL_GET_STATS, &s)) return -errno;
1271
1272 stats->count = 0;
1273 memset(stats, 0, sizeof(*stats));
1274 if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
1275 return -1;
1276
1277#define SET_VALUE \
1278 stats->data[i].long_format = "%-20.20s"; \
1279 stats->data[i].rate_format = "%8.8s"; \
1280 stats->data[i].isvalue = 1; \
1281 stats->data[i].verbose = 0
1282
1283#define SET_COUNT \
1284 stats->data[i].long_format = "%-20.20s"; \
1285 stats->data[i].rate_format = "%5.5s"; \
1286 stats->data[i].isvalue = 0; \
1287 stats->data[i].mult_names = "kgm"; \
1288 stats->data[i].mult = 1000; \
1289 stats->data[i].verbose = 0
1290
1291#define SET_BYTE \
1292 stats->data[i].long_format = "%-20.20s"; \
1293 stats->data[i].rate_format = "%5.5s"; \
1294 stats->data[i].isvalue = 0; \
1295 stats->data[i].mult_names = "KGM"; \
1296 stats->data[i].mult = 1024; \
1297 stats->data[i].verbose = 0
1298
1299
1300 stats->count = s.count;
1301 for (i = 0; i < s.count; i++) {
1302 stats->data[i].value = s.data[i].value;
1303 switch (s.data[i].type) {
1304 case _DRM_STAT_LOCK:
1305 stats->data[i].long_name = "Lock";
1306 stats->data[i].rate_name = "Lock";
1307 SET_VALUE;
1308 break;
1309 case _DRM_STAT_OPENS:
1310 stats->data[i].long_name = "Opens";
1311 stats->data[i].rate_name = "O";
1312 SET_COUNT;
1313 stats->data[i].verbose = 1;
1314 break;
1315 case _DRM_STAT_CLOSES:
1316 stats->data[i].long_name = "Closes";
1317 stats->data[i].rate_name = "Lock";
1318 SET_COUNT;
1319 stats->data[i].verbose = 1;
1320 break;
1321 case _DRM_STAT_IOCTLS:
1322 stats->data[i].long_name = "Ioctls";
1323 stats->data[i].rate_name = "Ioc/s";
1324 SET_COUNT;
1325 break;
1326 case _DRM_STAT_LOCKS:
1327 stats->data[i].long_name = "Locks";
1328 stats->data[i].rate_name = "Lck/s";
1329 SET_COUNT;
1330 break;
1331 case _DRM_STAT_UNLOCKS:
1332 stats->data[i].long_name = "Unlocks";
1333 stats->data[i].rate_name = "Unl/s";
1334 SET_COUNT;
1335 break;
1336 case _DRM_STAT_IRQ:
1337 stats->data[i].long_name = "IRQs";
1338 stats->data[i].rate_name = "IRQ/s";
1339 SET_COUNT;
1340 break;
1341 case _DRM_STAT_PRIMARY:
1342 stats->data[i].long_name = "Primary Bytes";
1343 stats->data[i].rate_name = "PB/s";
1344 SET_BYTE;
1345 break;
1346 case _DRM_STAT_SECONDARY:
1347 stats->data[i].long_name = "Secondary Bytes";
1348 stats->data[i].rate_name = "SB/s";
1349 SET_BYTE;
1350 break;
1351 case _DRM_STAT_DMA:
1352 stats->data[i].long_name = "DMA";
1353 stats->data[i].rate_name = "DMA/s";
1354 SET_COUNT;
1355 break;
1356 case _DRM_STAT_SPECIAL:
1357 stats->data[i].long_name = "Special DMA";
1358 stats->data[i].rate_name = "dma/s";
1359 SET_COUNT;
1360 break;
1361 case _DRM_STAT_MISSED:
1362 stats->data[i].long_name = "Miss";
1363 stats->data[i].rate_name = "Ms/s";
1364 SET_COUNT;
1365 break;
1366 case _DRM_STAT_VALUE:
1367 stats->data[i].long_name = "Value";
1368 stats->data[i].rate_name = "Value";
1369 SET_VALUE;
1370 break;
1371 case _DRM_STAT_BYTE:
1372 stats->data[i].long_name = "Bytes";
1373 stats->data[i].rate_name = "B/s";
1374 SET_BYTE;
1375 break;
1376 case _DRM_STAT_COUNT:
1377 default:
1378 stats->data[i].long_name = "Count";
1379 stats->data[i].rate_name = "Cnt/s";
1380 SET_COUNT;
1381 break;
1382 }
1383 }
1384 return 0;
1385}
1386
Jens Owen3903e5a2002-04-09 21:54:56 +00001387int drmCommandNone(int fd, unsigned long drmCommandIndex)
1388{
1389 void *data = NULL; /* dummy */
1390 unsigned long request;
1391
1392 request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
1393
1394 if (ioctl(fd, request, data)) {
1395 return -errno;
1396 }
1397 return 0;
1398}
1399
1400int drmCommandRead(int fd, unsigned long drmCommandIndex,
1401 void *data, unsigned long size )
1402{
1403 unsigned long request;
1404
Alan Hourihane74ef13f2002-07-05 08:31:11 +00001405 request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
1406 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00001407
1408 if (ioctl(fd, request, data)) {
1409 return -errno;
1410 }
1411 return 0;
1412}
1413
1414int drmCommandWrite(int fd, unsigned long drmCommandIndex,
1415 void *data, unsigned long size )
1416{
1417 unsigned long request;
1418
Alan Hourihane74ef13f2002-07-05 08:31:11 +00001419 request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
1420 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00001421
1422 if (ioctl(fd, request, data)) {
1423 return -errno;
1424 }
1425 return 0;
1426}
1427
1428int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
1429 void *data, unsigned long size )
1430{
1431 unsigned long request;
1432
Alan Hourihane74ef13f2002-07-05 08:31:11 +00001433 request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
1434 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00001435
1436 if (ioctl(fd, request, data)) {
1437 return -errno;
1438 }
1439 return 0;
1440}
1441
Daryll Straussb3a57661999-12-05 01:19:48 +00001442#if defined(XFree86Server) || defined(DRM_USE_MALLOC)
Daryll Strausse1dba5c1999-12-07 03:37:16 +00001443static void drmSIGIOHandler(int interrupt, void *closure)
Daryll Straussb3a57661999-12-05 01:19:48 +00001444{
1445 unsigned long key;
1446 void *value;
1447 ssize_t count;
1448 drm_ctx_t ctx;
1449 typedef void (*_drmCallback)(int, void *, void *);
1450 char buf[256];
1451 drmContext old;
1452 drmContext new;
1453 void *oldctx;
1454 void *newctx;
1455 char *pt;
1456 drmHashEntry *entry;
1457
1458 if (!drmHashTable) return;
1459 if (drmHashFirst(drmHashTable, &key, &value)) {
1460 entry = value;
1461 do {
1462#if 0
1463 fprintf(stderr, "Trying %d\n", entry->fd);
1464#endif
1465 if ((count = read(entry->fd, buf, sizeof(buf)))) {
1466 buf[count] = '\0';
1467#if 0
1468 fprintf(stderr, "Got %s\n", buf);
1469#endif
Gareth Hughes36047532001-02-15 08:12:14 +00001470
Daryll Straussb3a57661999-12-05 01:19:48 +00001471 for (pt = buf; *pt != ' '; ++pt); /* Find first space */
1472 ++pt;
1473 old = strtol(pt, &pt, 0);
1474 new = strtol(pt, NULL, 0);
1475 oldctx = drmGetContextTag(entry->fd, old);
1476 newctx = drmGetContextTag(entry->fd, new);
1477#if 0
1478 fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx);
1479#endif
1480 ((_drmCallback)entry->f)(entry->fd, oldctx, newctx);
1481 ctx.handle = new;
1482 ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx);
1483 }
1484 } while (drmHashNext(drmHashTable, &key, &value));
1485 }
1486}
1487
1488int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *))
1489{
1490 drmHashEntry *entry;
1491
1492 entry = drmGetEntry(fd);
1493 entry->f = f;
1494
Daryll Strausse1dba5c1999-12-07 03:37:16 +00001495 return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0);
Daryll Straussb3a57661999-12-05 01:19:48 +00001496}
1497
1498int drmRemoveSIGIOHandler(int fd)
1499{
1500 drmHashEntry *entry = drmGetEntry(fd);
1501
1502 entry->f = NULL;
Gareth Hughes36047532001-02-15 08:12:14 +00001503
Daryll Straussb3a57661999-12-05 01:19:48 +00001504 return xf86RemoveSIGIOHandler(fd);
1505}
1506#endif