blob: 0d3b90a86da3f43383c80d1d06e27b97201b09cf [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 Strausse1dba5c1999-12-07 03:37:16 +00003 * Revised: Mon Dec 6 11:34:13 1999 by faith@precisioninsight.com
Daryll Straussb3a57661999-12-05 01:19:48 +00004 *
5 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
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 *
Daryll Straussb6a28bf1999-12-05 23:10:37 +000027 * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.43 1999/08/04 18:14:43 faith Exp $
Daryll Strausse1dba5c1999-12-07 03:37:16 +000028 * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.5 1999/10/13 22:33:07 dawes Exp $
Daryll Straussb3a57661999-12-05 01:19:48 +000029 *
30 */
31
32#ifdef XFree86Server
33# include "xf86.h"
34# include "xf86_OSproc.h"
35# include "xf86_ansic.h"
36# include "xf86Priv.h"
37# define _DRM_MALLOC xalloc
38# define _DRM_FREE xfree
39# ifndef XFree86LOADER
40# include <sys/stat.h>
41# 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>
54# include <sys/ioctl.h>
55# include <sys/mman.h>
56# include <sys/time.h>
57# ifdef DRM_USE_MALLOC
58# define _DRM_MALLOC malloc
59# define _DRM_FREE free
Daryll Strausse1dba5c1999-12-07 03:37:16 +000060extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *);
Daryll Straussb3a57661999-12-05 01:19:48 +000061extern int xf86RemoveSIGIOHandler(int fd);
62# else
63# include <Xlibint.h>
64# define _DRM_MALLOC Xmalloc
65# define _DRM_FREE Xfree
66# endif
67#endif
68
69/* Not all systems have MAP_FAILED defined */
70#ifndef MAP_FAILED
71#define MAP_FAILED ((void *)-1)
72#endif
73
74#include <sys/sysmacros.h> /* for makedev() */
75#include "xf86drm.h"
76#include "drm.h"
77
78static void *drmHashTable = NULL; /* Context switch callbacks */
79
80typedef struct drmHashEntry {
81 int fd;
82 void (*f)(int, void *, void *);
83 void *tagTable;
84} drmHashEntry;
85
86void *drmMalloc(int size)
87{
88 void *pt;
89 if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size);
90 return pt;
91}
92
93void drmFree(void *pt)
94{
95 if (pt) _DRM_FREE(pt);
96}
97
98static char *drmStrdup(const char *s)
99{
100 return s ? strdup(s) : NULL;
101}
102
103
Daryll Straussb3a57661999-12-05 01:19:48 +0000104static unsigned long drmGetKeyFromFd(int fd)
105{
106#ifdef XFree86LOADER
107 struct xf86stat st;
108#else
109 struct stat st;
110#endif
111
112 st.st_rdev = 0;
113 fstat(fd, &st);
114 return st.st_rdev;
115}
116
117static drmHashEntry *drmGetEntry(int fd)
118{
119 unsigned long key = drmGetKeyFromFd(fd);
120 void *value;
121 drmHashEntry *entry;
122
123 if (!drmHashTable) drmHashTable = drmHashCreate();
124
125 if (drmHashLookup(drmHashTable, key, &value)) {
126 entry = drmMalloc(sizeof(*entry));
127 entry->fd = fd;
128 entry->f = NULL;
129 entry->tagTable = drmHashCreate();
130 drmHashInsert(drmHashTable, key, entry);
131 } else {
132 entry = value;
133 }
134 return entry;
135}
136
137/* drm_open is used to open the /dev/drm device */
138
139static int drm_open(const char *file)
140{
141 int fd = open(file, O_RDWR, 0);
142
143 if (fd >= 0) return fd;
144 return -errno;
145}
146
147/* drmAvailable looks for /proc/drm, and returns 1 if it is present. */
148
149int drmAvailable(void)
150{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000151 if (!access("/proc/graphics/0", R_OK)) return 1;
Daryll Straussb3a57661999-12-05 01:19:48 +0000152 return 0;
153}
154
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000155static int drmOpenDevice(const char *path, long dev,
156 mode_t mode, uid_t user, gid_t group)
Daryll Straussb3a57661999-12-05 01:19:48 +0000157{
158#ifdef XFree86LOADER
159 struct xf86stat st;
160#else
161 struct stat st;
162#endif
Daryll Straussb3a57661999-12-05 01:19:48 +0000163
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000164 if (!stat(path, &st) && st.st_rdev == dev) return drm_open(path);
Daryll Straussb3a57661999-12-05 01:19:48 +0000165
Daryll Straussb3a57661999-12-05 01:19:48 +0000166 if (geteuid()) return DRM_ERR_NOT_ROOT;
167 remove(path);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000168 if (mknod(path, S_IFCHR, dev)) {
Daryll Straussb3a57661999-12-05 01:19:48 +0000169 remove(path);
170 return DRM_ERR_NOT_ROOT;
171 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000172 chown(path, user, group);
173 chmod(path, mode);
Daryll Straussb3a57661999-12-05 01:19:48 +0000174 return drm_open(path);
175}
176
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000177static int drmOpenByBusid(const char *busid)
178{
179 int i;
180 char dev_name[64];
181 char *buf;
182 int fd;
183
184 for (i = 0; i < 8; i++) {
185 sprintf(dev_name, "/dev/graphics/card%d", i);
186 if ((fd = drm_open(dev_name)) >= 0) {
187 buf = drmGetBusid(fd);
188 if (buf && !strcmp(buf, busid)) {
189 drmFreeBusid(buf);
190 return fd;
191 }
192 if (buf) drmFreeBusid(buf);
193 close(fd);
194 }
195 }
196 return -1;
197}
198
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000199static int drmOpenByName(const char *name)
Daryll Straussb3a57661999-12-05 01:19:48 +0000200{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000201 int i;
202 char proc_name[64];
203 char dev_name[64];
204 char buf[512];
205 mode_t mode = DRM_DEV_MODE;
206 mode_t dirmode;
207 gid_t group = DRM_DEV_GID;
208 uid_t user = DRM_DEV_UID;
209 int fd;
210 char *pt;
211 char *driver = NULL;
212 char *devstring;
213 long dev = 0;
214 int retcode;
215
216#if defined(XFree86Server)
217 mode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE;
218 group = xf86ConfigDRI.group ? xf86ConfigDRI.group : DRM_DEV_GID;
219#endif
220
221 if (!geteuid()) {
222 dirmode = mode;
223 if (dirmode & S_IRUSR) dirmode |= S_IXUSR;
224 if (dirmode & S_IRGRP) dirmode |= S_IXGRP;
225 if (dirmode & S_IROTH) dirmode |= S_IXOTH;
226 dirmode &= ~(S_IWGRP | S_IWOTH);
227 mkdir("/dev/graphics", 0);
228 chown("/dev/graphics", user, group);
229 chmod("/dev/graphics", dirmode);
230 }
231
232 for (i = 0; i < 8; i++) {
233 sprintf(proc_name, "/proc/graphics/%d/name", i);
234 sprintf(dev_name, "/dev/graphics/card%d", i);
235 if ((fd = open(proc_name, 0, 0)) >= 0) {
236 retcode = read(fd, buf, sizeof(buf)-1);
237 close(fd);
238 if (retcode) {
239 buf[retcode-1] = '\0';
240 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
241 ;
242 if (*pt) { /* Device is next */
243 *pt = '\0';
244 if (!strcmp(driver, name)) { /* Match */
245 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
246 ;
247 if (*pt) { /* Found busid */
248 return drmOpenByBusid(++pt);
249 } else { /* No busid */
250 dev = strtol(devstring, NULL, 0);
251 return drmOpenDevice(dev_name, dev,
252 mode, user, group);
253 }
254 }
255 }
256 }
257 } else remove(dev_name);
258 }
259 return -1;
260}
261
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000262/* drmOpen looks up the specified name and busid, and opens the device
263 found. The entry in /dev/graphics is created if necessary (and if root).
264 A file descriptor is returned. On error, the return value is
265 negative. */
266
267int drmOpen(const char *name, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000268{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000269
270 if (busid) return drmOpenByBusid(busid);
271 return drmOpenByName(name);
Daryll Straussb3a57661999-12-05 01:19:48 +0000272}
273
274void drmFreeVersion(drmVersionPtr v)
275{
276 if (!v) return;
277 if (v->name) drmFree(v->name);
278 if (v->date) drmFree(v->date);
279 if (v->desc) drmFree(v->desc);
280 drmFree(v);
281}
282
283static void drmFreeKernelVersion(drm_version_t *v)
284{
285 if (!v) return;
286 if (v->name) drmFree(v->name);
287 if (v->date) drmFree(v->date);
288 if (v->desc) drmFree(v->desc);
289 drmFree(v);
290}
291
292static void drmCopyVersion(drmVersionPtr d, drm_version_t *s)
293{
294 d->version_major = s->version_major;
295 d->version_minor = s->version_minor;
296 d->version_patchlevel = s->version_patchlevel;
297 d->name_len = s->name_len;
298 d->name = drmStrdup(s->name);
299 d->date_len = s->date_len;
300 d->date = drmStrdup(s->date);
301 d->desc_len = s->desc_len;
302 d->desc = drmStrdup(s->desc);
303}
304
305/* drmVersion obtains the version information via an ioctl. Similar
306 * information is available via /proc/drm. */
307
308drmVersionPtr drmGetVersion(int fd)
309{
310 drmVersionPtr retval;
311 drm_version_t *version = drmMalloc(sizeof(*version));
312
313 /* First, get the lengths */
314 version->name_len = 0;
315 version->name = NULL;
316 version->date_len = 0;
317 version->date = NULL;
318 version->desc_len = 0;
319 version->desc = NULL;
320
321 if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
322 drmFreeKernelVersion(version);
323 return NULL;
324 }
325
326 /* Now, allocate space and get the data */
327 if (version->name_len)
328 version->name = drmMalloc(version->name_len + 1);
329 if (version->date_len)
330 version->date = drmMalloc(version->date_len + 1);
331 if (version->desc_len)
332 version->desc = drmMalloc(version->desc_len + 1);
333
334 if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
335 drmFreeKernelVersion(version);
336 return NULL;
337 }
338
339 /* The results might not be null-terminated
340 strings, so terminate them. */
341
342 if (version->name_len) version->name[version->name_len] = '\0';
343 if (version->date_len) version->date[version->date_len] = '\0';
344 if (version->desc_len) version->desc[version->desc_len] = '\0';
345
346 /* Now, copy it all back into the
347 client-visible data structure... */
348 retval = drmMalloc(sizeof(*retval));
349 drmCopyVersion(retval, version);
350 drmFreeKernelVersion(version);
351 return retval;
352}
353
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000354void drmFreeBusid(const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000355{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000356 drmFree((void *)busid);
Daryll Straussb3a57661999-12-05 01:19:48 +0000357}
358
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000359char *drmGetBusid(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000360{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000361 drm_unique_t u;
362
363 u.unique_len = 0;
364 u.unique = NULL;
365
366 if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
367 u.unique = drmMalloc(u.unique_len + 1);
368 if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
369 u.unique[u.unique_len] = '\0';
370 return u.unique;
Daryll Straussb3a57661999-12-05 01:19:48 +0000371}
372
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000373int drmSetBusid(int fd, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000374{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000375 drm_unique_t u;
Daryll Straussb3a57661999-12-05 01:19:48 +0000376
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000377 u.unique = (char *)busid;
378 u.unique_len = strlen(busid);
Daryll Straussb3a57661999-12-05 01:19:48 +0000379
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000380 if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +0000381 return 0;
382}
383
384int drmGetMagic(int fd, drmMagicPtr magic)
385{
386 drm_auth_t auth;
387
388 *magic = 0;
389 if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) return -errno;
390 *magic = auth.magic;
391 return 0;
392}
393
394int drmAuthMagic(int fd, drmMagic magic)
395{
396 drm_auth_t auth;
397
398 auth.magic = magic;
399 if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) return -errno;
400 return 0;
401}
402
403int drmAddMap(int fd,
404 drmHandle offset,
405 drmSize size,
406 drmMapType type,
407 drmMapFlags flags,
408 drmHandlePtr handle)
409{
410 drm_map_t map;
411
412 map.offset = offset;
413 map.size = size;
414 map.handle = 0;
415 map.type = type;
416 map.flags = flags;
417 if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno;
418 if (handle) *handle = (drmHandle)map.handle;
419 return 0;
420}
421
422int drmAddBufs(int fd, int count, int size, int flags)
423{
424 drm_buf_desc_t request;
425
426 request.count = count;
427 request.size = size;
428 request.low_mark = 0;
429 request.high_mark = 0;
430 request.flags = flags;
431 if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno;
432 return request.count;
433}
434
435int drmMarkBufs(int fd, double low, double high)
436{
437 drm_buf_info_t info;
438 int i;
439
440 info.count = 0;
441 info.list = NULL;
442
443 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL;
444
445 if (!info.count) return -EINVAL;
446
447 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
448 return -ENOMEM;
449
450 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
451 int retval = -errno;
452 drmFree(info.list);
453 return retval;
454 }
455
456 for (i = 0; i < info.count; i++) {
457 info.list[i].low_mark = low * info.list[i].count;
458 info.list[i].high_mark = high * info.list[i].count;
459 if (ioctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
460 int retval = -errno;
461 drmFree(info.list);
462 return retval;
463 }
464 }
465 drmFree(info.list);
466
467 return 0;
468}
469
470int drmFreeBufs(int fd, int count, int *list)
471{
472 drm_buf_free_t request;
473
474 request.count = count;
475 request.list = list;
476 if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno;
477 return 0;
478}
479
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000480int drmClose(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000481{
482 unsigned long key = drmGetKeyFromFd(fd);
483 drmHashEntry *entry = drmGetEntry(fd);
484
485 drmHashDestroy(entry->tagTable);
486 entry->fd = 0;
487 entry->f = NULL;
488 entry->tagTable = NULL;
489
490 drmHashDelete(drmHashTable, key);
491 drmFree(entry);
492
493 return close(fd);
494}
495
496int drmMap(int fd,
497 drmHandle handle,
498 drmSize size,
499 drmAddressPtr address)
500{
501 if (fd < 0) return -EINVAL;
502 *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
503 if (*address == MAP_FAILED) return -errno;
504 return 0;
505}
506
507int drmUnmap(drmAddress address, drmSize size)
508{
509 return munmap(address, size);
510}
511
512drmBufInfoPtr drmGetBufInfo(int fd)
513{
514 drm_buf_info_t info;
515 drmBufInfoPtr retval;
516 int i;
517
518 info.count = 0;
519 info.list = NULL;
520
521 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return NULL;
522
523 if (info.count) {
524 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
525 return NULL;
526
527 if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
528 drmFree(info.list);
529 return NULL;
530 }
531 /* Now, copy it all back into the
532 client-visible data structure... */
533 retval = drmMalloc(sizeof(*retval));
534 retval->count = info.count;
535 retval->list = drmMalloc(info.count * sizeof(*retval->list));
536 for (i = 0; i < info.count; i++) {
537 retval->list[i].count = info.list[i].count;
538 retval->list[i].size = info.list[i].size;
539 retval->list[i].low_mark = info.list[i].low_mark;
540 retval->list[i].high_mark = info.list[i].high_mark;
541 }
542 drmFree(info.list);
543 return retval;
544 }
545 return NULL;
546}
547
548drmBufMapPtr drmMapBufs(int fd)
549{
550 drm_buf_map_t bufs;
551 drmBufMapPtr retval;
552 int i;
553
554 bufs.count = 0;
555 bufs.list = NULL;
556 if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL;
557
558 if (bufs.count) {
559 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
560 return NULL;
561
562 if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
563 drmFree(bufs.list);
564 return NULL;
565 }
566 /* Now, copy it all back into the
567 client-visible data structure... */
568 retval = drmMalloc(sizeof(*retval));
569 retval->count = bufs.count;
570 retval->list = drmMalloc(bufs.count * sizeof(*retval->list));
571 for (i = 0; i < bufs.count; i++) {
572 retval->list[i].idx = bufs.list[i].idx;
573 retval->list[i].total = bufs.list[i].total;
574 retval->list[i].used = 0;
575 retval->list[i].address = bufs.list[i].address;
576 }
577 return retval;
578 }
579 return NULL;
580}
581
582int drmUnmapBufs(drmBufMapPtr bufs)
583{
584 int i;
585
586 for (i = 0; i < bufs->count; i++) {
587 munmap(bufs->list[i].address, bufs->list[i].total);
588 }
589 return 0;
590}
591
592int drmDMA(int fd, drmDMAReqPtr request)
593{
594 drm_dma_t dma;
595
596 /* Copy to hidden structure */
597 dma.context = request->context;
598 dma.send_count = request->send_count;
599 dma.send_indices = request->send_list;
600 dma.send_sizes = request->send_sizes;
601 dma.flags = request->flags;
602 dma.request_count = request->request_count;
603 dma.request_size = request->request_size;
604 dma.request_indices = request->request_list;
605 dma.request_sizes = request->request_sizes;
606 if (ioctl(fd, DRM_IOCTL_DMA, &dma)) return -errno;
607 request->granted_count = dma.granted_count;
608
609 return 0;
610}
611
612int drmGetLock(int fd, drmContext context, drmLockFlags flags)
613{
614 drm_lock_t lock;
615
616 lock.context = context;
617 lock.flags = 0;
618 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
619 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
620 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
621 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
622 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
623 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
624
625 while (ioctl(fd, DRM_IOCTL_LOCK, &lock))
626 ;
627 return 0;
628}
629
630int drmUnlock(int fd, drmContext context)
631{
632 drm_lock_t lock;
633
634 lock.context = context;
635 lock.flags = 0;
636 return ioctl(fd, DRM_IOCTL_UNLOCK, &lock);
637}
638
639drmContextPtr drmGetReservedContextList(int fd, int *count)
640{
641 drm_ctx_res_t res;
642 drm_ctx_t *list;
643 drmContextPtr retval;
644 int i;
645
646 res.count = 0;
647 res.contexts = NULL;
648 if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
649
650 if (!res.count) return NULL;
651
652 if (!(list = drmMalloc(res.count * sizeof(*list)))) return NULL;
653 if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
654 drmFree(list);
655 return NULL;
656 }
657
658 res.contexts = list;
659 if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
660
661 for (i = 0; i < res.count; i++) retval[i] = list[i].handle;
662 drmFree(list);
663
664 *count = res.count;
665 return retval;
666}
667
668void drmFreeReservedContextList(drmContextPtr pt)
669{
670 drmFree(pt);
671}
672
673int drmCreateContext(int fd, drmContextPtr handle)
674{
675 drm_ctx_t ctx;
676
677 ctx.flags = 0; /* Modified with functions below */
678 if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno;
679 *handle = ctx.handle;
680 return 0;
681}
682
683int drmSwitchToContext(int fd, drmContext context)
684{
685 drm_ctx_t ctx;
686
687 ctx.handle = context;
688 if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) return -errno;
689 return 0;
690}
691
692int drmSetContextFlags(int fd, drmContext context, drmContextFlags flags)
693{
694 drm_ctx_t ctx;
695
696 /* Context preserving means that no context
697 switched are done between DMA buffers
698 from one context and the next. This is
699 suitable for use in the X server (which
700 promises to maintain hardware context,
701 or in the client-side library when
702 buffers are swapped on behalf of two
703 threads. */
704 ctx.handle = context;
705 ctx.flags = 0;
706 if (flags & DRM_CONTEXT_PRESERVED) ctx.flags |= _DRM_CONTEXT_PRESERVED;
707 if (flags & DRM_CONTEXT_2DONLY) ctx.flags |= _DRM_CONTEXT_2DONLY;
708 if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) return -errno;
709 return 0;
710}
711
712int drmGetContextFlags(int fd, drmContext context, drmContextFlagsPtr flags)
713{
714 drm_ctx_t ctx;
715
716 ctx.handle = context;
717 if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx)) return -errno;
718 *flags = 0;
719 if (ctx.flags & _DRM_CONTEXT_PRESERVED) *flags |= DRM_CONTEXT_PRESERVED;
720 if (ctx.flags & _DRM_CONTEXT_2DONLY) *flags |= DRM_CONTEXT_2DONLY;
721 return 0;
722}
723
724int drmDestroyContext(int fd, drmContext handle)
725{
726 drm_ctx_t ctx;
727 ctx.handle = handle;
728 if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno;
729 return 0;
730}
731
732int drmCreateDrawable(int fd, drmDrawablePtr handle)
733{
734 drm_draw_t draw;
735 if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) return -errno;
736 *handle = draw.handle;
737 return 0;
738}
739
740int drmDestroyDrawable(int fd, drmDrawable handle)
741{
742 drm_draw_t draw;
743 draw.handle = handle;
744 if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw)) return -errno;
745 return 0;
746}
747
748int drmError(int err, const char *label)
749{
750 switch (err) {
751 case DRM_ERR_NO_DEVICE: fprintf(stderr, "%s: no device\n", label); break;
752 case DRM_ERR_NO_ACCESS: fprintf(stderr, "%s: no access\n", label); break;
753 case DRM_ERR_NOT_ROOT: fprintf(stderr, "%s: not root\n", label); break;
754 case DRM_ERR_INVALID: fprintf(stderr, "%s: invalid args\n", label);break;
755 default:
756 if (err < 0) err = -err;
757 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
758 break;
759 }
760
761 return 1;
762}
763
Daryll Straussb3a57661999-12-05 01:19:48 +0000764int drmCtlInstHandler(int fd, int irq)
765{
766 drm_control_t ctl;
767
768 ctl.func = DRM_INST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +0000769 ctl.irq = irq;
Daryll Straussb3a57661999-12-05 01:19:48 +0000770 if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
771 return 0;
772}
773
774int drmCtlUninstHandler(int fd)
775{
776 drm_control_t ctl;
777
778 ctl.func = DRM_UNINST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +0000779 ctl.irq = 0;
Daryll Straussb3a57661999-12-05 01:19:48 +0000780 if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
781 return 0;
782}
783
784int drmFinish(int fd, int context, drmLockFlags flags)
785{
786 drm_lock_t lock;
787
788 lock.context = context;
789 lock.flags = 0;
790 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
791 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
792 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
793 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
794 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
795 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
796 if (ioctl(fd, DRM_IOCTL_FINISH, &lock)) return -errno;
797 return 0;
798}
799
800int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
801{
802 drm_irq_busid_t p;
803
804 p.busnum = busnum;
805 p.devnum = devnum;
806 p.funcnum = funcnum;
807 if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno;
808 return p.irq;
809}
810
811int drmAddContextTag(int fd, drmContext context, void *tag)
812{
813 drmHashEntry *entry = drmGetEntry(fd);
814
815 if (drmHashInsert(entry->tagTable, context, tag)) {
816 drmHashDelete(entry->tagTable, context);
817 drmHashInsert(entry->tagTable, context, tag);
818 }
819 return 0;
820}
821
822int drmDelContextTag(int fd, drmContext context)
823{
824 drmHashEntry *entry = drmGetEntry(fd);
825
826 return drmHashDelete(entry->tagTable, context);
827}
828
829void *drmGetContextTag(int fd, drmContext context)
830{
831 drmHashEntry *entry = drmGetEntry(fd);
832 void *value;
833
834 if (drmHashLookup(entry->tagTable, context, &value)) return NULL;
835
836 return value;
837}
838
839#if defined(XFree86Server) || defined(DRM_USE_MALLOC)
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000840static void drmSIGIOHandler(int interrupt, void *closure)
Daryll Straussb3a57661999-12-05 01:19:48 +0000841{
842 unsigned long key;
843 void *value;
844 ssize_t count;
845 drm_ctx_t ctx;
846 typedef void (*_drmCallback)(int, void *, void *);
847 char buf[256];
848 drmContext old;
849 drmContext new;
850 void *oldctx;
851 void *newctx;
852 char *pt;
853 drmHashEntry *entry;
854
855 if (!drmHashTable) return;
856 if (drmHashFirst(drmHashTable, &key, &value)) {
857 entry = value;
858 do {
859#if 0
860 fprintf(stderr, "Trying %d\n", entry->fd);
861#endif
862 if ((count = read(entry->fd, buf, sizeof(buf)))) {
863 buf[count] = '\0';
864#if 0
865 fprintf(stderr, "Got %s\n", buf);
866#endif
867
868 for (pt = buf; *pt != ' '; ++pt); /* Find first space */
869 ++pt;
870 old = strtol(pt, &pt, 0);
871 new = strtol(pt, NULL, 0);
872 oldctx = drmGetContextTag(entry->fd, old);
873 newctx = drmGetContextTag(entry->fd, new);
874#if 0
875 fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx);
876#endif
877 ((_drmCallback)entry->f)(entry->fd, oldctx, newctx);
878 ctx.handle = new;
879 ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx);
880 }
881 } while (drmHashNext(drmHashTable, &key, &value));
882 }
883}
884
885int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *))
886{
887 drmHashEntry *entry;
888
889 entry = drmGetEntry(fd);
890 entry->f = f;
891
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000892 return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0);
Daryll Straussb3a57661999-12-05 01:19:48 +0000893}
894
895int drmRemoveSIGIOHandler(int fd)
896{
897 drmHashEntry *entry = drmGetEntry(fd);
898
899 entry->f = NULL;
900
901 return xf86RemoveSIGIOHandler(fd);
902}
903#endif