73a083e38bd5d1fb6b674a05f0929a8b2e474faa
[profile/ivi/libdrm.git] / libdrm / xf86drm.c
1 /* xf86drm.c -- User-level interface to DRM device
2  * Created: Tue Jan  5 08:16:21 1999 by faith@precisioninsight.com
3  *
4  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6  * 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:
14  *
15  * 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.
18  *
19  * 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.
26  *
27  * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
28  *          Kevin E. Martin <martin@valinux.com>
29  *
30  * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.17 2000/09/24 13:51:32 alanh Exp $
31  *
32  */
33
34 #ifdef XFree86Server
35 # include "xf86.h"
36 # include "xf86_OSproc.h"
37 # include "xf86_ansic.h"
38 # include "xf86Priv.h"
39 # define _DRM_MALLOC xalloc
40 # define _DRM_FREE   xfree
41 # ifndef XFree86LOADER
42 #  include <sys/stat.h>
43 #  include <sys/mman.h>
44 # endif
45 #else
46 # include <stdio.h>
47 # include <stdlib.h>
48 # include <unistd.h>
49 # include <string.h>
50 # include <ctype.h>
51 # include <fcntl.h>
52 # include <errno.h>
53 # include <signal.h>
54 # include <sys/types.h>
55 # include <sys/stat.h>
56 # include <sys/ioctl.h>
57 # include <sys/mman.h>
58 # include <sys/time.h>
59 # ifdef DRM_USE_MALLOC
60 #  define _DRM_MALLOC malloc
61 #  define _DRM_FREE   free
62 extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *);
63 extern int xf86RemoveSIGIOHandler(int fd);
64 # else
65 #  include <Xlibint.h>
66 #  define _DRM_MALLOC Xmalloc
67 #  define _DRM_FREE   Xfree
68 # endif
69 #endif
70
71 #ifdef __alpha__
72 extern unsigned long _bus_base(void);
73 #define BUS_BASE _bus_base()
74 #endif
75
76 /* Not all systems have MAP_FAILED defined */
77 #ifndef MAP_FAILED
78 #define MAP_FAILED ((void *)-1)
79 #endif
80
81 #include "xf86drm.h"
82 #include "drm.h"
83
84 #ifndef DRM_MAJOR
85 #define DRM_MAJOR 226           /* Linux */
86 #endif
87
88 #ifndef __linux__
89 #undef  DRM_MAJOR
90 #define DRM_MAJOR 145           /* Should set in drm.h for *BSD */
91 #endif
92
93 #ifndef DRM_MAX_MINOR
94 #define DRM_MAX_MINOR 16
95 #endif
96
97 #ifdef __linux__
98 #include <sys/sysmacros.h>      /* for makedev() */
99 #endif
100
101 #ifndef makedev
102                                 /* This definition needs to be changed on
103                                    some systems if dev_t is a structure.
104                                    If there is a header file we can get it
105                                    from, there would be best. */
106 #define makedev(x,y)    ((dev_t)(((x) << 8) | (y)))
107 #endif
108
109 static void *drmHashTable = NULL; /* Context switch callbacks */
110
111 typedef struct drmHashEntry {
112     int      fd;
113     void     (*f)(int, void *, void *);
114     void     *tagTable;
115 } drmHashEntry;
116
117 void *drmMalloc(int size)
118 {
119     void *pt;
120     if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size);
121     return pt;
122 }
123
124 void drmFree(void *pt)
125 {
126     if (pt) _DRM_FREE(pt);
127 }
128
129 /* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */
130 static char *drmStrdup(const char *s)
131 {
132     char *retval = NULL;
133
134     if (s) {
135         retval = _DRM_MALLOC(strlen(s)+1);
136         strcpy(retval, s);
137     }
138     return retval;
139 }
140
141
142 static unsigned long drmGetKeyFromFd(int fd)
143 {
144 #ifdef XFree86LOADER
145     struct xf86stat st;
146 #else
147     struct stat     st;
148 #endif
149
150     st.st_rdev = 0;
151     fstat(fd, &st);
152     return st.st_rdev;
153 }
154
155 static drmHashEntry *drmGetEntry(int fd)
156 {
157     unsigned long key = drmGetKeyFromFd(fd);
158     void          *value;
159     drmHashEntry  *entry;
160
161     if (!drmHashTable) drmHashTable = drmHashCreate();
162
163     if (drmHashLookup(drmHashTable, key, &value)) {
164         entry           = drmMalloc(sizeof(*entry));
165         entry->fd       = fd;
166         entry->f        = NULL;
167         entry->tagTable = drmHashCreate();
168         drmHashInsert(drmHashTable, key, entry);
169     } else {
170         entry = value;
171     }
172     return entry;
173 }
174
175 static int drmOpenDevice(long dev, int minor)
176 {
177 #ifdef XFree86LOADER
178     struct xf86stat st;
179 #else
180     struct stat     st;
181 #endif
182     char            buf[64];
183     int             fd;
184     mode_t          dirmode = DRM_DEV_DIRMODE;
185     mode_t          devmode = DRM_DEV_MODE;
186     int             isroot  = !geteuid();
187 #if defined(XFree86Server)
188     uid_t           user    = DRM_DEV_UID;
189     gid_t           group   = DRM_DEV_GID;
190 #endif
191
192 #if defined(XFree86Server)
193     devmode  = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE;
194     dirmode  = (devmode & S_IRUSR) ? S_IXUSR : 0;
195     dirmode |= (devmode & S_IRGRP) ? S_IXGRP : 0;
196     dirmode |= (devmode & S_IROTH) ? S_IXOTH : 0;
197     dirmode |= devmode;
198     devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
199     group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID;
200 #endif
201
202     if (stat(DRM_DIR_NAME, &st)) {
203         if (!isroot) return DRM_ERR_NOT_ROOT;
204         remove(DRM_DIR_NAME);
205         mkdir(DRM_DIR_NAME, dirmode);
206     }
207 #if defined(XFree86Server)
208     chown(DRM_DIR_NAME, user, group);
209     chmod(DRM_DIR_NAME, dirmode);
210 #endif
211
212     sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
213     if (stat(buf, &st) || st.st_rdev != dev) {
214         if (!isroot) return DRM_ERR_NOT_ROOT;
215         remove(buf);
216         mknod(buf, S_IFCHR | devmode, dev);
217     }
218 #if defined(XFree86Server)
219     chown(buf, user, group);
220     chmod(buf, devmode);
221 #endif
222
223     if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
224     remove(buf);
225     return -errno;
226 }
227
228 int drmOpenMinor(int minor, int create)
229 {
230     int  fd;
231     char buf[64];
232     
233     if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
234     
235     sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
236     if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
237     return -errno;
238 }
239
240 /* drmAvailable looks for (DRM_MAJOR, 0) and returns 1 if it returns
241    information for DRM_IOCTL_VERSION.  For backward compatibility with
242    older Linux implementations, /proc/dri is also checked. */
243
244 int drmAvailable(void)
245 {
246     drmVersionPtr version;
247     int           retval = 0;
248     int           fd;
249
250     if ((fd = drmOpenMinor(0, 1)) < 0) {
251                                 /* Try proc for backward Linux compatibility */
252         if (!access("/proc/dri/0", R_OK)) return 1;
253         return 0;
254     }
255     
256     if ((version = drmGetVersion(fd))) {
257         retval = 1;
258         drmFreeVersion(version);
259     }
260     close(fd);
261
262     return retval;
263 }
264
265 static int drmOpenByBusid(const char *busid)
266 {
267     int        i;
268     int        fd;
269     const char *buf;
270     
271     for (i = 0; i < DRM_MAX_MINOR; i++) {
272         if ((fd = drmOpenMinor(i, 0)) >= 0) {
273             buf = drmGetBusid(fd);
274             if (buf && !strcmp(buf, busid)) {
275                 drmFreeBusid(buf);
276                 return fd;
277             }
278             if (buf) drmFreeBusid(buf);
279             close(fd);
280         }
281     }
282     return -1;
283 }
284
285 static int drmOpenByName(const char *name)
286 {
287     int           i;
288     int           fd;
289     drmVersionPtr version;
290     
291     if (!drmAvailable()) {
292 #if !defined(XFree86Server)
293         return -1;
294 #else
295         /* try to load the kernel module now */
296         if (!xf86LoadKernelModule(name)) {
297             ErrorF("[drm] failed to load kernel module \"%s\"\n",
298                    name);
299             return -1;
300         }
301 #endif
302     }
303
304     for (i = 0; i < DRM_MAX_MINOR; i++) {
305         if ((fd = drmOpenMinor(i, 1)) >= 0) {
306             if ((version = drmGetVersion(fd))) {
307                 if (!strcmp(version->name, name)) {
308                     drmFreeVersion(version);
309                     return fd;
310                 }
311                 drmFreeVersion(version);
312             }
313         }
314     }
315
316 #ifdef __linux__
317                                 /* Backward-compatibility /proc support */
318     for (i = 0; i < 8; i++) {
319         char proc_name[64], buf[512];
320         char *driver, *pt, *devstring;
321         int  retcode;
322         
323         sprintf(proc_name, "/proc/dri/%d/name", i);
324         if ((fd = open(proc_name, 0, 0)) >= 0) {
325             retcode = read(fd, buf, sizeof(buf)-1);
326             close(fd);
327             if (retcode) {
328                 buf[retcode-1] = '\0';
329                 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
330                     ;
331                 if (*pt) {      /* Device is next */
332                     *pt = '\0';
333                     if (!strcmp(driver, name)) { /* Match */
334                         for (devstring = ++pt; *pt && *pt != ' '; ++pt)
335                             ;
336                         if (*pt) { /* Found busid */
337                             return drmOpenByBusid(++pt);
338                         } else {        /* No busid */
339                             return drmOpenDevice(strtol(devstring, NULL, 0),i);
340                         }
341                     }
342                 }
343             }
344         }
345     }
346 #endif
347
348     return -1;
349 }
350
351 /* drmOpen looks up the specified name and busid, and opens the device
352    found.  The entry in /dev/dri is created if necessary (and if root).
353    A file descriptor is returned.  On error, the return value is
354    negative. */
355
356 int drmOpen(const char *name, const char *busid)
357 {
358
359     if (busid) return drmOpenByBusid(busid);
360     return drmOpenByName(name);
361 }
362
363 void drmFreeVersion(drmVersionPtr v)
364 {
365     if (!v) return;
366     if (v->name) drmFree(v->name);
367     if (v->date) drmFree(v->date);
368     if (v->desc) drmFree(v->desc);
369     drmFree(v);
370 }
371
372 static void drmFreeKernelVersion(drm_version_t *v)
373 {
374     if (!v) return;
375     if (v->name) drmFree(v->name);
376     if (v->date) drmFree(v->date);
377     if (v->desc) drmFree(v->desc);
378     drmFree(v);
379 }
380
381 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
382 {
383     d->version_major      = s->version_major;
384     d->version_minor      = s->version_minor;
385     d->version_patchlevel = s->version_patchlevel;
386     d->name_len           = s->name_len;
387     d->name               = drmStrdup(s->name);
388     d->date_len           = s->date_len;
389     d->date               = drmStrdup(s->date);
390     d->desc_len           = s->desc_len;
391     d->desc               = drmStrdup(s->desc);
392 }
393
394 /* drmVersion obtains the version information via an ioctl.  Similar
395  * information is available via /proc/dri. */
396
397 drmVersionPtr drmGetVersion(int fd)
398 {
399     drmVersionPtr retval;
400     drm_version_t *version = drmMalloc(sizeof(*version));
401
402                                 /* First, get the lengths */
403     version->name_len    = 0;
404     version->name        = NULL;
405     version->date_len    = 0;
406     version->date        = NULL;
407     version->desc_len    = 0;
408     version->desc        = NULL;
409
410     if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
411         drmFreeKernelVersion(version);
412         return NULL;
413     }
414
415                                 /* Now, allocate space and get the data */
416     if (version->name_len)
417         version->name    = drmMalloc(version->name_len + 1);
418     if (version->date_len)
419         version->date    = drmMalloc(version->date_len + 1);
420     if (version->desc_len)
421         version->desc    = drmMalloc(version->desc_len + 1);
422
423     if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
424         drmFreeKernelVersion(version);
425         return NULL;
426     }
427
428                                 /* The results might not be null-terminated
429                                    strings, so terminate them. */
430
431     if (version->name_len) version->name[version->name_len] = '\0';
432     if (version->date_len) version->date[version->date_len] = '\0';
433     if (version->desc_len) version->desc[version->desc_len] = '\0';
434
435                                 /* Now, copy it all back into the
436                                    client-visible data structure... */
437     retval = drmMalloc(sizeof(*retval));
438     drmCopyVersion(retval, version);
439     drmFreeKernelVersion(version);
440     return retval;
441 }
442
443 void drmFreeBusid(const char *busid)
444 {
445     drmFree((void *)busid);
446 }
447
448 char *drmGetBusid(int fd)
449 {
450     drm_unique_t u;
451
452     u.unique_len = 0;
453     u.unique     = NULL;
454
455     if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
456     u.unique = drmMalloc(u.unique_len + 1);
457     if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
458     u.unique[u.unique_len] = '\0';
459     return u.unique;
460 }
461
462 int drmSetBusid(int fd, const char *busid)
463 {
464     drm_unique_t u;
465
466     u.unique     = (char *)busid;
467     u.unique_len = strlen(busid);
468
469     if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) return -errno;
470     return 0;
471 }
472
473 int drmGetMagic(int fd, drmMagicPtr magic)
474 {
475     drm_auth_t auth;
476
477     *magic = 0;
478     if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) return -errno;
479     *magic = auth.magic;
480     return 0;
481 }
482
483 int drmAuthMagic(int fd, drmMagic magic)
484 {
485     drm_auth_t auth;
486
487     auth.magic = magic;
488     if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) return -errno;
489     return 0;
490 }
491
492 int drmAddMap(int fd,
493               drmHandle offset,
494               drmSize size,
495               drmMapType type,
496               drmMapFlags flags,
497               drmHandlePtr handle)
498 {
499     drm_map_t map;
500
501     map.offset  = offset;
502 #ifdef __alpha__
503     /* Make sure we add the bus_base to all but shm */
504     if (type != DRM_SHM)
505         map.offset += BUS_BASE;
506 #endif
507     map.size    = size;
508     map.handle  = 0;
509     map.type    = type;
510     map.flags   = flags;
511     if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno;
512     if (handle) *handle = (drmHandle)map.handle;
513     return 0;
514 }
515
516 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
517                int agp_offset)
518 {
519     drm_buf_desc_t request;
520
521     request.count     = count;
522     request.size      = size;
523     request.low_mark  = 0;
524     request.high_mark = 0;
525     request.flags     = flags;
526     request.agp_start = agp_offset;
527
528     if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno;
529     return request.count;
530 }
531
532 int drmMarkBufs(int fd, double low, double high)
533 {
534     drm_buf_info_t info;
535     int            i;
536
537     info.count = 0;
538     info.list  = NULL;
539
540     if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL;
541
542     if (!info.count) return -EINVAL;
543
544     if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
545         return -ENOMEM;
546
547     if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
548         int retval = -errno;
549         drmFree(info.list);
550         return retval;
551     }
552
553     for (i = 0; i < info.count; i++) {
554         info.list[i].low_mark  = low  * info.list[i].count;
555         info.list[i].high_mark = high * info.list[i].count;
556         if (ioctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
557             int retval = -errno;
558             drmFree(info.list);
559             return retval;
560         }
561     }
562     drmFree(info.list);
563
564     return 0;
565 }
566
567 int drmFreeBufs(int fd, int count, int *list)
568 {
569     drm_buf_free_t request;
570
571     request.count = count;
572     request.list  = list;
573     if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno;
574     return 0;
575 }
576
577 int drmClose(int fd)
578 {
579     unsigned long key    = drmGetKeyFromFd(fd);
580     drmHashEntry  *entry = drmGetEntry(fd);
581
582     drmHashDestroy(entry->tagTable);
583     entry->fd       = 0;
584     entry->f        = NULL;
585     entry->tagTable = NULL;
586
587     drmHashDelete(drmHashTable, key);
588     drmFree(entry);
589
590     return close(fd);
591 }
592
593 int drmMap(int fd,
594            drmHandle handle,
595            drmSize size,
596            drmAddressPtr address)
597 {
598     static unsigned long pagesize_mask = 0;
599
600     if (fd < 0) return -EINVAL;
601
602     if (!pagesize_mask)
603         pagesize_mask = getpagesize() - 1;
604
605     size = (size + pagesize_mask) & ~pagesize_mask;
606
607     *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
608     if (*address == MAP_FAILED) return -errno;
609     return 0;
610 }
611
612 int drmUnmap(drmAddress address, drmSize size)
613 {
614     return munmap(address, size);
615 }
616
617 drmBufInfoPtr drmGetBufInfo(int fd)
618 {
619     drm_buf_info_t info;
620     drmBufInfoPtr  retval;
621     int            i;
622
623     info.count = 0;
624     info.list  = NULL;
625
626     if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return NULL;
627
628     if (info.count) {
629         if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
630             return NULL;
631
632         if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
633             drmFree(info.list);
634             return NULL;
635         }
636                                 /* Now, copy it all back into the
637                                    client-visible data structure... */
638         retval = drmMalloc(sizeof(*retval));
639         retval->count = info.count;
640         retval->list  = drmMalloc(info.count * sizeof(*retval->list));
641         for (i = 0; i < info.count; i++) {
642             retval->list[i].count     = info.list[i].count;
643             retval->list[i].size      = info.list[i].size;
644             retval->list[i].low_mark  = info.list[i].low_mark;
645             retval->list[i].high_mark = info.list[i].high_mark;
646         }
647         drmFree(info.list);
648         return retval;
649     }
650     return NULL;
651 }
652
653 drmBufMapPtr drmMapBufs(int fd)
654 {
655     drm_buf_map_t bufs;
656     drmBufMapPtr  retval;
657     int           i;
658
659     bufs.count = 0;
660     bufs.list  = NULL;
661     if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL;
662
663     if (bufs.count) {
664         if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
665             return NULL;
666
667         if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
668             drmFree(bufs.list);
669             return NULL;
670         }
671                                 /* Now, copy it all back into the
672                                    client-visible data structure... */
673         retval = drmMalloc(sizeof(*retval));
674         retval->count = bufs.count;
675         retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
676         for (i = 0; i < bufs.count; i++) {
677             retval->list[i].idx     = bufs.list[i].idx;
678             retval->list[i].total   = bufs.list[i].total;
679             retval->list[i].used    = 0;
680             retval->list[i].address = bufs.list[i].address;
681         }
682         return retval;
683     }
684     return NULL;
685 }
686
687 int drmUnmapBufs(drmBufMapPtr bufs)
688 {
689     int i;
690
691     for (i = 0; i < bufs->count; i++) {
692         munmap(bufs->list[i].address, bufs->list[i].total);
693     }
694     return 0;
695 }
696
697 #define DRM_DMA_RETRY           16
698
699 int drmDMA(int fd, drmDMAReqPtr request)
700 {
701     drm_dma_t dma;
702     int ret, i = 0;
703
704                                 /* Copy to hidden structure */
705     dma.context         = request->context;
706     dma.send_count      = request->send_count;
707     dma.send_indices    = request->send_list;
708     dma.send_sizes      = request->send_sizes;
709     dma.flags           = request->flags;
710     dma.request_count   = request->request_count;
711     dma.request_size    = request->request_size;
712     dma.request_indices = request->request_list;
713     dma.request_sizes   = request->request_sizes;
714
715     do {
716         ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
717     } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
718
719     if ( ret == 0 ) {
720         request->granted_count = dma.granted_count;
721         return 0;
722     } else {
723         return -errno;
724     }
725 }
726
727 int drmGetLock(int fd, drmContext context, drmLockFlags flags)
728 {
729     drm_lock_t lock;
730
731     lock.context = context;
732     lock.flags   = 0;
733     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
734     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
735     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
736     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
737     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
738     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
739
740     while (ioctl(fd, DRM_IOCTL_LOCK, &lock))
741         ;
742     return 0;
743 }
744
745 int drmUnlock(int fd, drmContext context)
746 {
747     drm_lock_t lock;
748
749     lock.context = context;
750     lock.flags   = 0;
751     return ioctl(fd, DRM_IOCTL_UNLOCK, &lock);
752 }
753
754 drmContextPtr drmGetReservedContextList(int fd, int *count)
755 {
756     drm_ctx_res_t res;
757     drm_ctx_t     *list;
758     drmContextPtr retval;
759     int           i;
760
761     res.count    = 0;
762     res.contexts = NULL;
763     if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
764
765     if (!res.count) return NULL;
766
767     if (!(list   = drmMalloc(res.count * sizeof(*list)))) return NULL;
768     if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
769         drmFree(list);
770         return NULL;
771     }
772
773     res.contexts = list;
774     if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
775
776     for (i = 0; i < res.count; i++) retval[i] = list[i].handle;
777     drmFree(list);
778
779     *count = res.count;
780     return retval;
781 }
782
783 void drmFreeReservedContextList(drmContextPtr pt)
784 {
785     drmFree(pt);
786 }
787
788 int drmCreateContext(int fd, drmContextPtr handle)
789 {
790     drm_ctx_t ctx;
791
792     ctx.flags = 0;      /* Modified with functions below */
793     if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno;
794     *handle = ctx.handle;
795     return 0;
796 }
797
798 int drmSwitchToContext(int fd, drmContext context)
799 {
800     drm_ctx_t ctx;
801
802     ctx.handle = context;
803     if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) return -errno;
804     return 0;
805 }
806
807 int drmSetContextFlags(int fd, drmContext context, drmContextFlags flags)
808 {
809     drm_ctx_t ctx;
810
811                                 /* Context preserving means that no context
812                                    switched are done between DMA buffers
813                                    from one context and the next.  This is
814                                    suitable for use in the X server (which
815                                    promises to maintain hardware context,
816                                    or in the client-side library when
817                                    buffers are swapped on behalf of two
818                                    threads. */
819     ctx.handle = context;
820     ctx.flags  = 0;
821     if (flags & DRM_CONTEXT_PRESERVED) ctx.flags |= _DRM_CONTEXT_PRESERVED;
822     if (flags & DRM_CONTEXT_2DONLY)    ctx.flags |= _DRM_CONTEXT_2DONLY;
823     if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) return -errno;
824     return 0;
825 }
826
827 int drmGetContextFlags(int fd, drmContext context, drmContextFlagsPtr flags)
828 {
829     drm_ctx_t ctx;
830
831     ctx.handle = context;
832     if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx)) return -errno;
833     *flags = 0;
834     if (ctx.flags & _DRM_CONTEXT_PRESERVED) *flags |= DRM_CONTEXT_PRESERVED;
835     if (ctx.flags & _DRM_CONTEXT_2DONLY)    *flags |= DRM_CONTEXT_2DONLY;
836     return 0;
837 }
838
839 int drmDestroyContext(int fd, drmContext handle)
840 {
841     drm_ctx_t ctx;
842     ctx.handle = handle;
843     if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno;
844     return 0;
845 }
846
847 int drmCreateDrawable(int fd, drmDrawablePtr handle)
848 {
849     drm_draw_t draw;
850     if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) return -errno;
851     *handle = draw.handle;
852     return 0;
853 }
854
855 int drmDestroyDrawable(int fd, drmDrawable handle)
856 {
857     drm_draw_t draw;
858     draw.handle = handle;
859     if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw)) return -errno;
860     return 0;
861 }
862
863 int drmAgpAcquire(int fd)
864 {
865     if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno;
866     return 0;
867 }
868
869 int drmAgpRelease(int fd)
870 {
871     if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno;
872     return 0;
873 }
874
875 int drmAgpEnable(int fd, unsigned long mode)
876 {
877     drm_agp_mode_t m;
878
879     m.mode = mode;
880     if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno;
881     return 0;
882 }
883
884 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
885                 unsigned long *address, unsigned long *handle)
886 {
887     drm_agp_buffer_t b;
888     *handle = 0;
889     b.size   = size;
890     b.handle = 0;
891     b.type   = type;
892     if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno;
893     if (address != 0UL) *address = b.physical;
894     *handle = b.handle;
895     return 0;
896 }
897
898 int drmAgpFree(int fd, unsigned long handle)
899 {
900     drm_agp_buffer_t b;
901
902     b.size   = 0;
903     b.handle = handle;
904     if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno;
905     return 0;
906 }
907
908 int drmAgpBind(int fd, unsigned long handle, unsigned long offset)
909 {
910     drm_agp_binding_t b;
911
912     b.handle = handle;
913     b.offset = offset;
914     if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno;
915     return 0;
916 }
917
918 int drmAgpUnbind(int fd, unsigned long handle)
919 {
920     drm_agp_binding_t b;
921
922     b.handle = handle;
923     b.offset = 0;
924     if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno;
925     return 0;
926 }
927
928 int drmAgpVersionMajor(int fd)
929 {
930     drm_agp_info_t i;
931
932     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
933     return i.agp_version_major;
934 }
935
936 int drmAgpVersionMinor(int fd)
937 {
938     drm_agp_info_t i;
939
940     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
941     return i.agp_version_minor;
942 }
943
944 unsigned long drmAgpGetMode(int fd)
945 {
946     drm_agp_info_t i;
947
948     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
949     return i.mode;
950 }
951
952 unsigned long drmAgpBase(int fd)
953 {
954     drm_agp_info_t i;
955
956     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
957     return i.aperture_base;
958 }
959
960 unsigned long drmAgpSize(int fd)
961 {
962     drm_agp_info_t i;
963
964     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
965     return i.aperture_size;
966 }
967
968 unsigned long drmAgpMemoryUsed(int fd)
969 {
970     drm_agp_info_t i;
971
972     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
973     return i.memory_used;
974 }
975
976 unsigned long drmAgpMemoryAvail(int fd)
977 {
978     drm_agp_info_t i;
979
980     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
981     return i.memory_allowed;
982 }
983
984 unsigned int drmAgpVendorId(int fd)
985 {
986     drm_agp_info_t i;
987
988     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
989     return i.id_vendor;
990 }
991
992 unsigned int drmAgpDeviceId(int fd)
993 {
994     drm_agp_info_t i;
995
996     if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
997     return i.id_device;
998 }
999
1000 int drmError(int err, const char *label)
1001 {
1002     switch (err) {
1003     case DRM_ERR_NO_DEVICE: fprintf(stderr, "%s: no device\n", label);   break;
1004     case DRM_ERR_NO_ACCESS: fprintf(stderr, "%s: no access\n", label);   break;
1005     case DRM_ERR_NOT_ROOT:  fprintf(stderr, "%s: not root\n", label);    break;
1006     case DRM_ERR_INVALID:   fprintf(stderr, "%s: invalid args\n", label);break;
1007     default:
1008         if (err < 0) err = -err;
1009         fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
1010         break;
1011     }
1012
1013     return 1;
1014 }
1015
1016 int drmCtlInstHandler(int fd, int irq)
1017 {
1018     drm_control_t ctl;
1019
1020     ctl.func  = DRM_INST_HANDLER;
1021     ctl.irq   = irq;
1022     if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
1023     return 0;
1024 }
1025
1026 int drmCtlUninstHandler(int fd)
1027 {
1028     drm_control_t ctl;
1029
1030     ctl.func  = DRM_UNINST_HANDLER;
1031     ctl.irq   = 0;
1032     if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
1033     return 0;
1034 }
1035
1036 int drmFinish(int fd, int context, drmLockFlags flags)
1037 {
1038     drm_lock_t lock;
1039
1040     lock.context = context;
1041     lock.flags   = 0;
1042     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
1043     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
1044     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
1045     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
1046     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
1047     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
1048     if (ioctl(fd, DRM_IOCTL_FINISH, &lock)) return -errno;
1049     return 0;
1050 }
1051
1052 int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
1053 {
1054     drm_irq_busid_t p;
1055
1056     p.busnum  = busnum;
1057     p.devnum  = devnum;
1058     p.funcnum = funcnum;
1059     if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno;
1060     return p.irq;
1061 }
1062
1063 int drmAddContextTag(int fd, drmContext context, void *tag)
1064 {
1065     drmHashEntry  *entry = drmGetEntry(fd);
1066
1067     if (drmHashInsert(entry->tagTable, context, tag)) {
1068         drmHashDelete(entry->tagTable, context);
1069         drmHashInsert(entry->tagTable, context, tag);
1070     }
1071     return 0;
1072 }
1073
1074 int drmDelContextTag(int fd, drmContext context)
1075 {
1076     drmHashEntry  *entry = drmGetEntry(fd);
1077
1078     return drmHashDelete(entry->tagTable, context);
1079 }
1080
1081 void *drmGetContextTag(int fd, drmContext context)
1082 {
1083     drmHashEntry  *entry = drmGetEntry(fd);
1084     void          *value;
1085
1086     if (drmHashLookup(entry->tagTable, context, &value)) return NULL;
1087
1088     return value;
1089 }
1090
1091 int drmGetMap(int fd, int idx, drmHandle *offset, drmSize *size,
1092               drmMapType *type, drmMapFlags *flags, drmHandle *handle,
1093               int *mtrr)
1094 {
1095     drm_map_t map;
1096
1097     map.offset = idx;
1098     if (ioctl(fd, DRM_IOCTL_GET_MAP, &map)) return -errno;
1099     *offset = map.offset;
1100     *size   = map.size;
1101     *type   = map.type;
1102     *flags  = map.flags;
1103     *handle = (unsigned long)map.handle;
1104     *mtrr   = map.mtrr;
1105     return 0;
1106 }
1107
1108 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
1109                  unsigned long *magic, unsigned long *iocs)
1110 {
1111     drm_client_t client;
1112
1113     client.idx = idx;
1114     if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client)) return -errno;
1115     *auth      = client.auth;
1116     *pid       = client.pid;
1117     *uid       = client.uid;
1118     *magic     = client.magic;
1119     *iocs      = client.iocs;
1120     return 0;
1121 }
1122
1123 int drmGetStats(int fd, drmStatsT *stats)
1124 {
1125     drm_stats_t s;
1126     int         i;
1127
1128     if (ioctl(fd, DRM_IOCTL_GET_STATS, &s)) return -errno;
1129
1130     stats->count = 0;
1131     memset(stats, 0, sizeof(*stats));
1132     if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
1133         return -1;
1134
1135 #define SET_VALUE                              \
1136     stats->data[i].long_format = "%-20.20s";   \
1137     stats->data[i].rate_format = "%8.8s";      \
1138     stats->data[i].isvalue     = 1;            \
1139     stats->data[i].verbose     = 0
1140
1141 #define SET_COUNT                              \
1142     stats->data[i].long_format = "%-20.20s";   \
1143     stats->data[i].rate_format = "%5.5s";      \
1144     stats->data[i].isvalue     = 0;            \
1145     stats->data[i].mult_names  = "kgm";        \
1146     stats->data[i].mult        = 1000;         \
1147     stats->data[i].verbose     = 0
1148
1149 #define SET_BYTE                               \
1150     stats->data[i].long_format = "%-20.20s";   \
1151     stats->data[i].rate_format = "%5.5s";      \
1152     stats->data[i].isvalue     = 0;            \
1153     stats->data[i].mult_names  = "KGM";        \
1154     stats->data[i].mult        = 1024;         \
1155     stats->data[i].verbose     = 0
1156
1157
1158     stats->count = s.count;
1159     for (i = 0; i < s.count; i++) {
1160         stats->data[i].value = s.data[i].value;
1161         switch (s.data[i].type) {
1162         case _DRM_STAT_LOCK:
1163             stats->data[i].long_name = "Lock";
1164             stats->data[i].rate_name = "Lock";
1165             SET_VALUE;
1166             break;
1167         case _DRM_STAT_OPENS:
1168             stats->data[i].long_name = "Opens";
1169             stats->data[i].rate_name = "O";
1170             SET_COUNT;
1171             stats->data[i].verbose   = 1;
1172             break;
1173         case _DRM_STAT_CLOSES:
1174             stats->data[i].long_name = "Closes";
1175             stats->data[i].rate_name = "Lock";
1176             SET_COUNT;
1177             stats->data[i].verbose   = 1;
1178             break;
1179         case _DRM_STAT_IOCTLS:
1180             stats->data[i].long_name = "Ioctls";
1181             stats->data[i].rate_name = "Ioc/s";
1182             SET_COUNT;
1183             break;
1184         case _DRM_STAT_LOCKS:
1185             stats->data[i].long_name = "Locks";
1186             stats->data[i].rate_name = "Lck/s";
1187             SET_COUNT;
1188             break;
1189         case _DRM_STAT_UNLOCKS:
1190             stats->data[i].long_name = "Unlocks";
1191             stats->data[i].rate_name = "Unl/s";
1192             SET_COUNT;
1193             break;
1194         case _DRM_STAT_IRQ:
1195             stats->data[i].long_name = "IRQs";
1196             stats->data[i].rate_name = "IRQ/s";
1197             SET_COUNT;
1198             break;
1199         case _DRM_STAT_PRIMARY:
1200             stats->data[i].long_name = "Primary Bytes";
1201             stats->data[i].rate_name = "PB/s";
1202             SET_BYTE;
1203             break;
1204         case _DRM_STAT_SECONDARY:
1205             stats->data[i].long_name = "Secondary Bytes";
1206             stats->data[i].rate_name = "SB/s";
1207             SET_BYTE;
1208             break;
1209         case _DRM_STAT_DMA:
1210             stats->data[i].long_name = "DMA";
1211             stats->data[i].rate_name = "DMA/s";
1212             SET_COUNT;
1213             break;
1214         case _DRM_STAT_SPECIAL:
1215             stats->data[i].long_name = "Special DMA";
1216             stats->data[i].rate_name = "dma/s";
1217             SET_COUNT;
1218             break;
1219         case _DRM_STAT_MISSED:
1220             stats->data[i].long_name = "Miss";
1221             stats->data[i].rate_name = "Ms/s";
1222             SET_COUNT;
1223             break;
1224         case _DRM_STAT_VALUE:
1225             stats->data[i].long_name = "Value";
1226             stats->data[i].rate_name = "Value";
1227             SET_VALUE;
1228             break;
1229         case _DRM_STAT_BYTE:
1230             stats->data[i].long_name = "Bytes";
1231             stats->data[i].rate_name = "B/s";
1232             SET_BYTE;
1233             break;
1234         case _DRM_STAT_COUNT:
1235         default:
1236             stats->data[i].long_name = "Count";
1237             stats->data[i].rate_name = "Cnt/s";
1238             SET_COUNT;
1239             break;
1240         }
1241     }
1242     return 0;
1243 }
1244
1245 #if defined(XFree86Server) || defined(DRM_USE_MALLOC)
1246 static void drmSIGIOHandler(int interrupt, void *closure)
1247 {
1248     unsigned long key;
1249     void          *value;
1250     ssize_t       count;
1251     drm_ctx_t     ctx;
1252     typedef void  (*_drmCallback)(int, void *, void *);
1253     char          buf[256];
1254     drmContext    old;
1255     drmContext    new;
1256     void          *oldctx;
1257     void          *newctx;
1258     char          *pt;
1259     drmHashEntry  *entry;
1260
1261     if (!drmHashTable) return;
1262     if (drmHashFirst(drmHashTable, &key, &value)) {
1263         entry = value;
1264         do {
1265 #if 0
1266             fprintf(stderr, "Trying %d\n", entry->fd);
1267 #endif
1268             if ((count = read(entry->fd, buf, sizeof(buf)))) {
1269                 buf[count] = '\0';
1270 #if 0
1271                 fprintf(stderr, "Got %s\n", buf);
1272 #endif
1273
1274                 for (pt = buf; *pt != ' '; ++pt); /* Find first space */
1275                 ++pt;
1276                 old    = strtol(pt, &pt, 0);
1277                 new    = strtol(pt, NULL, 0);
1278                 oldctx = drmGetContextTag(entry->fd, old);
1279                 newctx = drmGetContextTag(entry->fd, new);
1280 #if 0
1281                 fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx);
1282 #endif
1283                 ((_drmCallback)entry->f)(entry->fd, oldctx, newctx);
1284                 ctx.handle = new;
1285                 ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx);
1286             }
1287         } while (drmHashNext(drmHashTable, &key, &value));
1288     }
1289 }
1290
1291 int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *))
1292 {
1293     drmHashEntry     *entry;
1294
1295     entry     = drmGetEntry(fd);
1296     entry->f  = f;
1297
1298     return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0);
1299 }
1300
1301 int drmRemoveSIGIOHandler(int fd)
1302 {
1303     drmHashEntry     *entry = drmGetEntry(fd);
1304
1305     entry->f = NULL;
1306
1307     return xf86RemoveSIGIOHandler(fd);
1308 }
1309 #endif