xf86drm.c revision 88dbee54ed400a3fd5594fab506518c171167805
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 62extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *); 63extern 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__ 72extern 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 109static void *drmHashTable = NULL; /* Context switch callbacks */ 110 111typedef struct drmHashEntry { 112 int fd; 113 void (*f)(int, void *, void *); 114 void *tagTable; 115} drmHashEntry; 116 117void *drmMalloc(int size) 118{ 119 void *pt; 120 if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size); 121 return pt; 122} 123 124void 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... */ 130static 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 142static 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 155static 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 175static 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 228int 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 244int 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 265static 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 285static 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 356int drmOpen(const char *name, const char *busid) 357{ 358 359 if (busid) return drmOpenByBusid(busid); 360 return drmOpenByName(name); 361} 362 363void 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 372static 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 381static 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 397drmVersionPtr 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 443void drmFreeBusid(const char *busid) 444{ 445 drmFree((void *)busid); 446} 447 448char *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 462int 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 473int 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 483int 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 492int 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 516int 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 532int 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 567int 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 577int 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 593int 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 612int drmUnmap(drmAddress address, drmSize size) 613{ 614 return munmap(address, size); 615} 616 617drmBufInfoPtr 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 653drmBufMapPtr 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 687int 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 699int 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 727int 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 745int 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 754drmContextPtr 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 783void drmFreeReservedContextList(drmContextPtr pt) 784{ 785 drmFree(pt); 786} 787 788int 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 798int 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 807int 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 827int 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 839int 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 847int 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 855int 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 863int drmAgpAcquire(int fd) 864{ 865 if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno; 866 return 0; 867} 868 869int drmAgpRelease(int fd) 870{ 871 if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno; 872 return 0; 873} 874 875int 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 884int 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 898int 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 908int 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 918int 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 928int 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 936int 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 944unsigned 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 952unsigned 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 960unsigned 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 968unsigned 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 976unsigned 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 984unsigned 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 992unsigned 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 1000int 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 1016int 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 1026int 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 1036int 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 1052int 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 1063int 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 1074int drmDelContextTag(int fd, drmContext context) 1075{ 1076 drmHashEntry *entry = drmGetEntry(fd); 1077 1078 return drmHashDelete(entry->tagTable, context); 1079} 1080 1081void *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 1091int 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 1108int 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 1123int 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) 1246static 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 1291int 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 1301int drmRemoveSIGIOHandler(int fd) 1302{ 1303 drmHashEntry *entry = drmGetEntry(fd); 1304 1305 entry->f = NULL; 1306 1307 return xf86RemoveSIGIOHandler(fd); 1308} 1309#endif 1310