diff options
author | Kristian Høgsberg <krh@bitplanet.net> | 2009-11-17 11:14:54 -0500 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2009-11-17 11:15:06 -0500 |
commit | 4f57abfe66091281c9f59c14e6ea27b524b55d5b (patch) | |
tree | f00d1022cf208b381b93aa5c96858164e6a3f602 /libdrm/xf86drm.c | |
parent | 9dd3613073aa2491cef440725fdfa0cf1e8f1a42 (diff) |
Move libdrm/ up one level
Diffstat (limited to 'libdrm/xf86drm.c')
-rw-r--r-- | libdrm/xf86drm.c | 2512 |
1 files changed, 0 insertions, 2512 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c deleted file mode 100644 index 26dd8129..00000000 --- a/libdrm/xf86drm.c +++ /dev/null @@ -1,2512 +0,0 @@ -/** - * \file xf86drm.c - * User-level interface to DRM device - * - * \author Rickard E. (Rik) Faith <faith@valinux.com> - * \author Kevin E. Martin <martin@valinux.com> - */ - -/* - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <strings.h> -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> -#define stat_t struct stat -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <stdarg.h> - -/* Not all systems have MAP_FAILED defined */ -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -#include "xf86drm.h" - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#define DRM_MAJOR 145 -#endif - -#ifdef __NetBSD__ -#define DRM_MAJOR 34 -#endif - -# ifdef __OpenBSD__ -# define DRM_MAJOR 81 -# endif - -#ifndef DRM_MAJOR -#define DRM_MAJOR 226 /* Linux */ -#endif - -#ifndef DRM_MAX_MINOR -#define DRM_MAX_MINOR 16 -#endif - -/* - * This definition needs to be changed on some systems if dev_t is a structure. - * If there is a header file we can get it from, there would be best. - */ -#ifndef makedev -#define makedev(x,y) ((dev_t)(((x) << 8) | (y))) -#endif - -#define DRM_MSG_VERBOSITY 3 - -#define DRM_NODE_CONTROL 0 -#define DRM_NODE_RENDER 1 - -static drmServerInfoPtr drm_server_info; - -void drmSetServerInfo(drmServerInfoPtr info) -{ - drm_server_info = info; -} - -/** - * Output a message to stderr. - * - * \param format printf() like format string. - * - * \internal - * This function is a wrapper around vfprintf(). - */ - -static int drmDebugPrint(const char *format, va_list ap) -{ - return vfprintf(stderr, format, ap); -} - -static int (*drm_debug_print)(const char *format, va_list ap) = drmDebugPrint; - -void -drmMsg(const char *format, ...) -{ - va_list ap; - const char *env; - if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || drm_server_info) - { - va_start(ap, format); - if (drm_server_info) { - drm_server_info->debug_print(format,ap); - } else { - drm_debug_print(format, ap); - } - va_end(ap); - } -} - -void -drmSetDebugMsgFunction(int (*debug_msg_ptr)(const char *format, va_list ap)) -{ - drm_debug_print = debug_msg_ptr; -} - -static void *drmHashTable = NULL; /* Context switch callbacks */ - -void *drmGetHashTable(void) -{ - return drmHashTable; -} - -void *drmMalloc(int size) -{ - void *pt; - if ((pt = malloc(size))) - memset(pt, 0, size); - return pt; -} - -void drmFree(void *pt) -{ - if (pt) - free(pt); -} - -/* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */ -static char *drmStrdup(const char *s) -{ - char *retval; - - if (!s) - return NULL; - - retval = malloc(strlen(s)+1); - if (!retval) - return NULL; - - strcpy(retval, s); - - return retval; -} - -/** - * Call ioctl, restarting if it is interupted - */ -int -drmIoctl(int fd, unsigned long request, void *arg) -{ - int ret; - - do { - ret = ioctl(fd, request, arg); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); - return ret; -} - -static unsigned long drmGetKeyFromFd(int fd) -{ - stat_t st; - - st.st_rdev = 0; - fstat(fd, &st); - return st.st_rdev; -} - -drmHashEntry *drmGetEntry(int fd) -{ - unsigned long key = drmGetKeyFromFd(fd); - void *value; - drmHashEntry *entry; - - if (!drmHashTable) - drmHashTable = drmHashCreate(); - - if (drmHashLookup(drmHashTable, key, &value)) { - entry = drmMalloc(sizeof(*entry)); - entry->fd = fd; - entry->f = NULL; - entry->tagTable = drmHashCreate(); - drmHashInsert(drmHashTable, key, entry); - } else { - entry = value; - } - return entry; -} - -/** - * Compare two busid strings - * - * \param first - * \param second - * - * \return 1 if matched. - * - * \internal - * This function compares two bus ID strings. It understands the older - * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is - * domain, b is bus, d is device, f is function. - */ -static int drmMatchBusID(const char *id1, const char *id2) -{ - /* First, check if the IDs are exactly the same */ - if (strcasecmp(id1, id2) == 0) - return 1; - - /* Try to match old/new-style PCI bus IDs. */ - if (strncasecmp(id1, "pci", 3) == 0) { - unsigned int o1, b1, d1, f1; - unsigned int o2, b2, d2, f2; - int ret; - - ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); - if (ret != 4) { - o1 = 0; - ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); - if (ret != 3) - return 0; - } - - ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); - if (ret != 4) { - o2 = 0; - ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); - if (ret != 3) - return 0; - } - - if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) - return 0; - else - return 1; - } - return 0; -} - -/** - * Handles error checking for chown call. - * - * \param path to file. - * \param id of the new owner. - * \param id of the new group. - * - * \return zero if success or -1 if failure. - * - * \internal - * Checks for failure. If failure was caused by signal call chown again. - * If any other failure happened then it will output error mesage using - * drmMsg() call. - */ -static int chown_check_return(const char *path, uid_t owner, gid_t group) -{ - int rv; - - do { - rv = chown(path, owner, group); - } while (rv != 0 && errno == EINTR); - - if (rv == 0) - return 0; - - drmMsg("Failed to change owner or group for file %s! %d: %s\n", - path, errno, strerror(errno)); - return -1; -} - -/** - * Open the DRM device, creating it if necessary. - * - * \param dev major and minor numbers of the device. - * \param minor minor number of the device. - * - * \return a file descriptor on success, or a negative value on error. - * - * \internal - * Assembles the device name from \p minor and opens it, creating the device - * special file node with the major and minor numbers specified by \p dev and - * parent directory if necessary and was called by root. - */ -static int drmOpenDevice(long dev, int minor, int type) -{ - stat_t st; - char buf[64]; - int fd; - mode_t devmode = DRM_DEV_MODE, serv_mode; - int isroot = !geteuid(); - uid_t user = DRM_DEV_UID; - gid_t group = DRM_DEV_GID, serv_group; - - sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor); - drmMsg("drmOpenDevice: node name is %s\n", buf); - - if (drm_server_info) { - drm_server_info->get_perms(&serv_group, &serv_mode); - devmode = serv_mode ? serv_mode : DRM_DEV_MODE; - devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); - group = (serv_group >= 0) ? serv_group : DRM_DEV_GID; - } - -#if !defined(UDEV) - if (stat(DRM_DIR_NAME, &st)) { - if (!isroot) - return DRM_ERR_NOT_ROOT; - mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); - chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ - chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); - } - - /* Check if the device node exists and create it if necessary. */ - if (stat(buf, &st)) { - if (!isroot) - return DRM_ERR_NOT_ROOT; - remove(buf); - mknod(buf, S_IFCHR | devmode, dev); - } - - if (drm_server_info) { - chown_check_return(buf, user, group); - chmod(buf, devmode); - } -#else - /* if we modprobed then wait for udev */ - { - int udev_count = 0; -wait_for_udev: - if (stat(DRM_DIR_NAME, &st)) { - usleep(20); - udev_count++; - - if (udev_count == 50) - return -1; - goto wait_for_udev; - } - - if (stat(buf, &st)) { - usleep(20); - udev_count++; - - if (udev_count == 50) - return -1; - goto wait_for_udev; - } - } -#endif - - fd = open(buf, O_RDWR, 0); - drmMsg("drmOpenDevice: open result is %d, (%s)\n", - fd, fd < 0 ? strerror(errno) : "OK"); - if (fd >= 0) - return fd; - - /* Check if the device node is not what we expect it to be, and recreate it - * and try again if so. - */ - if (st.st_rdev != dev) { - if (!isroot) - return DRM_ERR_NOT_ROOT; - remove(buf); - mknod(buf, S_IFCHR | devmode, dev); - if (drm_server_info) { - chown_check_return(buf, user, group); - chmod(buf, devmode); - } - } - fd = open(buf, O_RDWR, 0); - drmMsg("drmOpenDevice: open result is %d, (%s)\n", - fd, fd < 0 ? strerror(errno) : "OK"); - if (fd >= 0) - return fd; - - drmMsg("drmOpenDevice: Open failed\n"); - remove(buf); - return -errno; -} - - -/** - * Open the DRM device - * - * \param minor device minor number. - * \param create allow to create the device if set. - * - * \return a file descriptor on success, or a negative value on error. - * - * \internal - * Calls drmOpenDevice() if \p create is set, otherwise assembles the device - * name from \p minor and opens it. - */ -static int drmOpenMinor(int minor, int create, int type) -{ - int fd; - char buf[64]; - - if (create) - return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); - - sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor); - if ((fd = open(buf, O_RDWR, 0)) >= 0) - return fd; - return -errno; -} - - -/** - * Determine whether the DRM kernel driver has been loaded. - * - * \return 1 if the DRM driver is loaded, 0 otherwise. - * - * \internal - * Determine the presence of the kernel driver by attempting to open the 0 - * minor and get version information. For backward compatibility with older - * Linux implementations, /proc/dri is also checked. - */ -int drmAvailable(void) -{ - drmVersionPtr version; - int retval = 0; - int fd; - - if ((fd = drmOpenMinor(0, 1, DRM_NODE_RENDER)) < 0) { -#ifdef __linux__ - /* Try proc for backward Linux compatibility */ - if (!access("/proc/dri/0", R_OK)) - return 1; -#endif - return 0; - } - - if ((version = drmGetVersion(fd))) { - retval = 1; - drmFreeVersion(version); - } - close(fd); - - return retval; -} - - -/** - * Open the device by bus ID. - * - * \param busid bus ID. - * - * \return a file descriptor on success, or a negative value on error. - * - * \internal - * This function attempts to open every possible minor (up to DRM_MAX_MINOR), - * comparing the device bus ID with the one supplied. - * - * \sa drmOpenMinor() and drmGetBusid(). - */ -static int drmOpenByBusid(const char *busid) -{ - int i; - int fd; - const char *buf; - drmSetVersion sv; - - drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); - for (i = 0; i < DRM_MAX_MINOR; i++) { - fd = drmOpenMinor(i, 1, DRM_NODE_RENDER); - drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); - if (fd >= 0) { - sv.drm_di_major = 1; - sv.drm_di_minor = 1; - sv.drm_dd_major = -1; /* Don't care */ - sv.drm_dd_minor = -1; /* Don't care */ - drmSetInterfaceVersion(fd, &sv); - buf = drmGetBusid(fd); - drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); - if (buf && drmMatchBusID(buf, busid)) { - drmFreeBusid(buf); - return fd; - } - if (buf) - drmFreeBusid(buf); - close(fd); - } - } - return -1; -} - - -/** - * Open the device by name. - * - * \param name driver name. - * - * \return a file descriptor on success, or a negative value on error. - * - * \internal - * This function opens the first minor number that matches the driver name and - * isn't already in use. If it's in use it then it will already have a bus ID - * assigned. - * - * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). - */ -static int drmOpenByName(const char *name) -{ - int i; - int fd; - drmVersionPtr version; - char * id; - - if (!drmAvailable()) { - if (!drm_server_info) { - return -1; - } - else { - /* try to load the kernel module now */ - if (!drm_server_info->load_module(name)) { - drmMsg("[drm] failed to load kernel module \"%s\"\n", name); - return -1; - } - } - } - - /* - * Open the first minor number that matches the driver name and isn't - * already in use. If it's in use it will have a busid assigned already. - */ - for (i = 0; i < DRM_MAX_MINOR; i++) { - if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) { - if ((version = drmGetVersion(fd))) { - if (!strcmp(version->name, name)) { - drmFreeVersion(version); - id = drmGetBusid(fd); - drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); - if (!id || !*id) { - if (id) - drmFreeBusid(id); - return fd; - } else { - drmFreeBusid(id); - } - } else { - drmFreeVersion(version); - } - } - close(fd); - } - } - -#ifdef __linux__ - /* Backward-compatibility /proc support */ - for (i = 0; i < 8; i++) { - char proc_name[64], buf[512]; - char *driver, *pt, *devstring; - int retcode; - - sprintf(proc_name, "/proc/dri/%d/name", i); - if ((fd = open(proc_name, 0, 0)) >= 0) { - retcode = read(fd, buf, sizeof(buf)-1); - close(fd); - if (retcode) { - buf[retcode-1] = '\0'; - for (driver = pt = buf; *pt && *pt != ' '; ++pt) - ; - if (*pt) { /* Device is next */ - *pt = '\0'; - if (!strcmp(driver, name)) { /* Match */ - for (devstring = ++pt; *pt && *pt != ' '; ++pt) - ; - if (*pt) { /* Found busid */ - return drmOpenByBusid(++pt); - } else { /* No busid */ - return drmOpenDevice(strtol(devstring, NULL, 0),i, DRM_NODE_RENDER); - } - } - } - } - } - } -#endif - - return -1; -} - - -/** - * Open the DRM device. - * - * Looks up the specified name and bus ID, and opens the device found. The - * entry in /dev/dri is created if necessary and if called by root. - * - * \param name driver name. Not referenced if bus ID is supplied. - * \param busid bus ID. Zero if not known. - * - * \return a file descriptor on success, or a negative value on error. - * - * \internal - * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() - * otherwise. - */ -int drmOpen(const char *name, const char *busid) -{ - if (!drmAvailable() && name != NULL && drm_server_info) { - /* try to load the kernel */ - if (!drm_server_info->load_module(name)) { - drmMsg("[drm] failed to load kernel module \"%s\"\n", name); - return -1; - } - } - - if (busid) { - int fd = drmOpenByBusid(busid); - if (fd >= 0) - return fd; - } - - if (name) - return drmOpenByName(name); - - return -1; -} - -int drmOpenControl(int minor) -{ - return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); -} - -/** - * Free the version information returned by drmGetVersion(). - * - * \param v pointer to the version information. - * - * \internal - * It frees the memory pointed by \p %v as well as all the non-null strings - * pointers in it. - */ -void drmFreeVersion(drmVersionPtr v) -{ - if (!v) - return; - drmFree(v->name); - drmFree(v->date); - drmFree(v->desc); - drmFree(v); -} - - -/** - * Free the non-public version information returned by the kernel. - * - * \param v pointer to the version information. - * - * \internal - * Used by drmGetVersion() to free the memory pointed by \p %v as well as all - * the non-null strings pointers in it. - */ -static void drmFreeKernelVersion(drm_version_t *v) -{ - if (!v) - return; - drmFree(v->name); - drmFree(v->date); - drmFree(v->desc); - drmFree(v); -} - - -/** - * Copy version information. - * - * \param d destination pointer. - * \param s source pointer. - * - * \internal - * Used by drmGetVersion() to translate the information returned by the ioctl - * interface in a private structure into the public structure counterpart. - */ -static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) -{ - d->version_major = s->version_major; - d->version_minor = s->version_minor; - d->version_patchlevel = s->version_patchlevel; - d->name_len = s->name_len; - d->name = drmStrdup(s->name); - d->date_len = s->date_len; - d->date = drmStrdup(s->date); - d->desc_len = s->desc_len; - d->desc = drmStrdup(s->desc); -} - - -/** - * Query the driver version information. - * - * \param fd file descriptor. - * - * \return pointer to a drmVersion structure which should be freed with - * drmFreeVersion(). - * - * \note Similar information is available via /proc/dri. - * - * \internal - * It gets the version information via successive DRM_IOCTL_VERSION ioctls, - * first with zeros to get the string lengths, and then the actually strings. - * It also null-terminates them since they might not be already. - */ -drmVersionPtr drmGetVersion(int fd) -{ - drmVersionPtr retval; - drm_version_t *version = drmMalloc(sizeof(*version)); - - version->name_len = 0; - version->name = NULL; - version->date_len = 0; - version->date = NULL; - version->desc_len = 0; - version->desc = NULL; - - if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { - drmFreeKernelVersion(version); - return NULL; - } - - if (version->name_len) - version->name = drmMalloc(version->name_len + 1); - if (version->date_len) - version->date = drmMalloc(version->date_len + 1); - if (version->desc_len) - version->desc = drmMalloc(version->desc_len + 1); - - if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { - drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); - drmFreeKernelVersion(version); - return NULL; - } - - /* The results might not be null-terminated strings, so terminate them. */ - if (version->name_len) version->name[version->name_len] = '\0'; - if (version->date_len) version->date[version->date_len] = '\0'; - if (version->desc_len) version->desc[version->desc_len] = '\0'; - - retval = drmMalloc(sizeof(*retval)); - drmCopyVersion(retval, version); - drmFreeKernelVersion(version); - return retval; -} - - -/** - * Get version information for the DRM user space library. - * - * This version number is driver independent. - * - * \param fd file descriptor. - * - * \return version information. - * - * \internal - * This function allocates and fills a drm_version structure with a hard coded - * version number. - */ -drmVersionPtr drmGetLibVersion(int fd) -{ - drm_version_t *version = drmMalloc(sizeof(*version)); - - /* Version history: - * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it - * revision 1.0.x = original DRM interface with no drmGetLibVersion - * entry point and many drm<Device> extensions - * revision 1.1.x = added drmCommand entry points for device extensions - * added drmGetLibVersion to identify libdrm.a version - * revision 1.2.x = added drmSetInterfaceVersion - * modified drmOpen to handle both busid and name - * revision 1.3.x = added server + memory manager - */ - version->version_major = 1; - version->version_minor = 3; - version->version_patchlevel = 0; - - return (drmVersionPtr)version; -} - - -/** - * Free the bus ID information. - * - * \param busid bus ID information string as given by drmGetBusid(). - * - * \internal - * This function is just frees the memory pointed by \p busid. - */ -void drmFreeBusid(const char *busid) -{ - drmFree((void *)busid); -} - - -/** - * Get the bus ID of the device. - * - * \param fd file descriptor. - * - * \return bus ID string. - * - * \internal - * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to - * get the string length and data, passing the arguments in a drm_unique - * structure. - */ -char *drmGetBusid(int fd) -{ - drm_unique_t u; - - u.unique_len = 0; - u.unique = NULL; - - if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) - return NULL; - u.unique = drmMalloc(u.unique_len + 1); - if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) - return NULL; - u.unique[u.unique_len] = '\0'; - - return u.unique; -} - - -/** - * Set the bus ID of the device. - * - * \param fd file descriptor. - * \param busid bus ID string. - * - * \return zero on success, negative on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing - * the arguments in a drm_unique structure. - */ -int drmSetBusid(int fd, const char *busid) -{ - drm_unique_t u; - - u.unique = (char *)busid; - u.unique_len = strlen(busid); - - if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { - return -errno; - } - return 0; -} - -int drmGetMagic(int fd, drm_magic_t * magic) -{ - drm_auth_t auth; - - *magic = 0; - if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) - return -errno; - *magic = auth.magic; - return 0; -} - -int drmAuthMagic(int fd, drm_magic_t magic) -{ - drm_auth_t auth; - - auth.magic = magic; - if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) - return -errno; - return 0; -} - -/** - * Specifies a range of memory that is available for mapping by a - * non-root process. - * - * \param fd file descriptor. - * \param offset usually the physical address. The actual meaning depends of - * the \p type parameter. See below. - * \param size of the memory in bytes. - * \param type type of the memory to be mapped. - * \param flags combination of several flags to modify the function actions. - * \param handle will be set to a value that may be used as the offset - * parameter for mmap(). - * - * \return zero on success or a negative value on error. - * - * \par Mapping the frame buffer - * For the frame buffer - * - \p offset will be the physical address of the start of the frame buffer, - * - \p size will be the size of the frame buffer in bytes, and - * - \p type will be DRM_FRAME_BUFFER. - * - * \par - * The area mapped will be uncached. If MTRR support is available in the - * kernel, the frame buffer area will be set to write combining. - * - * \par Mapping the MMIO register area - * For the MMIO register area, - * - \p offset will be the physical address of the start of the register area, - * - \p size will be the size of the register area bytes, and - * - \p type will be DRM_REGISTERS. - * \par - * The area mapped will be uncached. - * - * \par Mapping the SAREA - * For the SAREA, - * - \p offset will be ignored and should be set to zero, - * - \p size will be the desired size of the SAREA in bytes, - * - \p type will be DRM_SHM. - * - * \par - * A shared memory area of the requested size will be created and locked in - * kernel memory. This area may be mapped into client-space by using the handle - * returned. - * - * \note May only be called by root. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing - * the arguments in a drm_map structure. - */ -int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, - drmMapFlags flags, drm_handle_t *handle) -{ - drm_map_t map; - - map.offset = offset; - map.size = size; - map.handle = 0; - map.type = type; - map.flags = flags; - if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) - return -errno; - if (handle) - *handle = (drm_handle_t)map.handle; - return 0; -} - -int drmRmMap(int fd, drm_handle_t handle) -{ - drm_map_t map; - - map.handle = (void *)handle; - - if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) - return -errno; - return 0; -} - -/** - * Make buffers available for DMA transfers. - * - * \param fd file descriptor. - * \param count number of buffers. - * \param size size of each buffer. - * \param flags buffer allocation flags. - * \param agp_offset offset in the AGP aperture - * - * \return number of buffers allocated, negative on error. - * - * \internal - * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. - * - * \sa drm_buf_desc. - */ -int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, - int agp_offset) -{ - drm_buf_desc_t request; - - request.count = count; - request.size = size; - request.low_mark = 0; - request.high_mark = 0; - request.flags = flags; - request.agp_start = agp_offset; - - if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) - return -errno; - return request.count; -} - -int drmMarkBufs(int fd, double low, double high) -{ - drm_buf_info_t info; - int i; - - info.count = 0; - info.list = NULL; - - if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) - return -EINVAL; - - if (!info.count) - return -EINVAL; - - if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) - return -ENOMEM; - - if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { - int retval = -errno; - drmFree(info.list); - return retval; - } - - for (i = 0; i < info.count; i++) { - info.list[i].low_mark = low * info.list[i].count; - info.list[i].high_mark = high * info.list[i].count; - if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { - int retval = -errno; - drmFree(info.list); - return retval; - } - } - drmFree(info.list); - - return 0; -} - -/** - * Free buffers. - * - * \param fd file descriptor. - * \param count number of buffers to free. - * \param list list of buffers to be freed. - * - * \return zero on success, or a negative value on failure. - * - * \note This function is primarily used for debugging. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing - * the arguments in a drm_buf_free structure. - */ -int drmFreeBufs(int fd, int count, int *list) -{ - drm_buf_free_t request; - - request.count = count; - request.list = list; - if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) - return -errno; - return 0; -} - - -/** - * Close the device. - * - * \param fd file descriptor. - * - * \internal - * This function closes the file descriptor. - */ -int drmClose(int fd) -{ - unsigned long key = drmGetKeyFromFd(fd); - drmHashEntry *entry = drmGetEntry(fd); - - drmHashDestroy(entry->tagTable); - entry->fd = 0; - entry->f = NULL; - entry->tagTable = NULL; - - drmHashDelete(drmHashTable, key); - drmFree(entry); - - return close(fd); -} - - -/** - * Map a region of memory. - * - * \param fd file descriptor. - * \param handle handle returned by drmAddMap(). - * \param size size in bytes. Must match the size used by drmAddMap(). - * \param address will contain the user-space virtual address where the mapping - * begins. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper for mmap(). - */ -int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address) -{ - static unsigned long pagesize_mask = 0; - - if (fd < 0) - return -EINVAL; - - if (!pagesize_mask) - pagesize_mask = getpagesize() - 1; - - size = (size + pagesize_mask) & ~pagesize_mask; - - *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); - if (*address == MAP_FAILED) - return -errno; - return 0; -} - - -/** - * Unmap mappings obtained with drmMap(). - * - * \param address address as given by drmMap(). - * \param size size in bytes. Must match the size used by drmMap(). - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper for munmap(). - */ -int drmUnmap(drmAddress address, drmSize size) -{ - return munmap(address, size); -} - -drmBufInfoPtr drmGetBufInfo(int fd) -{ - drm_buf_info_t info; - drmBufInfoPtr retval; - int i; - - info.count = 0; - info.list = NULL; - - if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) - return NULL; - - if (info.count) { - if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) - return NULL; - - if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { - drmFree(info.list); - return NULL; - } - - retval = drmMalloc(sizeof(*retval)); - retval->count = info.count; - retval->list = drmMalloc(info.count * sizeof(*retval->list)); - for (i = 0; i < info.count; i++) { - retval->list[i].count = info.list[i].count; - retval->list[i].size = info.list[i].size; - retval->list[i].low_mark = info.list[i].low_mark; - retval->list[i].high_mark = info.list[i].high_mark; - } - drmFree(info.list); - return retval; - } - return NULL; -} - -/** - * Map all DMA buffers into client-virtual space. - * - * \param fd file descriptor. - * - * \return a pointer to a ::drmBufMap structure. - * - * \note The client may not use these buffers until obtaining buffer indices - * with drmDMA(). - * - * \internal - * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned - * information about the buffers in a drm_buf_map structure into the - * client-visible data structures. - */ -drmBufMapPtr drmMapBufs(int fd) -{ - drm_buf_map_t bufs; - drmBufMapPtr retval; - int i; - - bufs.count = 0; - bufs.list = NULL; - bufs.virtual = NULL; - if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) - return NULL; - - if (!bufs.count) - return NULL; - - if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) - return NULL; - - if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { - drmFree(bufs.list); - return NULL; - } - - retval = drmMalloc(sizeof(*retval)); - retval->count = bufs.count; - retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); - for (i = 0; i < bufs.count; i++) { - retval->list[i].idx = bufs.list[i].idx; - retval->list[i].total = bufs.list[i].total; - retval->list[i].used = 0; - retval->list[i].address = bufs.list[i].address; - } - - drmFree(bufs.list); - - return retval; -} - - -/** - * Unmap buffers allocated with drmMapBufs(). - * - * \return zero on success, or negative value on failure. - * - * \internal - * Calls munmap() for every buffer stored in \p bufs and frees the - * memory allocated by drmMapBufs(). - */ -int drmUnmapBufs(drmBufMapPtr bufs) -{ - int i; - - for (i = 0; i < bufs->count; i++) { - munmap(bufs->list[i].address, bufs->list[i].total); - } - - drmFree(bufs->list); - drmFree(bufs); - - return 0; -} - - -#define DRM_DMA_RETRY 16 - -/** - * Reserve DMA buffers. - * - * \param fd file descriptor. - * \param request - * - * \return zero on success, or a negative value on failure. - * - * \internal - * Assemble the arguments into a drm_dma structure and keeps issuing the - * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. - */ -int drmDMA(int fd, drmDMAReqPtr request) -{ - drm_dma_t dma; - int ret, i = 0; - - dma.context = request->context; - dma.send_count = request->send_count; - dma.send_indices = request->send_list; - dma.send_sizes = request->send_sizes; - dma.flags = request->flags; - dma.request_count = request->request_count; - dma.request_size = request->request_size; - dma.request_indices = request->request_list; - dma.request_sizes = request->request_sizes; - dma.granted_count = 0; - - do { - ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); - } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); - - if ( ret == 0 ) { - request->granted_count = dma.granted_count; - return 0; - } else { - return -errno; - } -} - - -/** - * Obtain heavyweight hardware lock. - * - * \param fd file descriptor. - * \param context context. - * \param flags flags that determine the sate of the hardware when the function - * returns. - * - * \return always zero. - * - * \internal - * This function translates the arguments into a drm_lock structure and issue - * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. - */ -int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) -{ - drm_lock_t lock; - - lock.context = context; - lock.flags = 0; - if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; - if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; - if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; - if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; - if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; - if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; - - while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) - ; - return 0; -} - -/** - * Release the hardware lock. - * - * \param fd file descriptor. - * \param context context. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the - * argument in a drm_lock structure. - */ -int drmUnlock(int fd, drm_context_t context) -{ - drm_lock_t lock; - - lock.context = context; - lock.flags = 0; - return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); -} - -drm_context_t *drmGetReservedContextList(int fd, int *count) -{ - drm_ctx_res_t res; - drm_ctx_t *list; - drm_context_t * retval; - int i; - - res.count = 0; - res.contexts = NULL; - if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) - return NULL; - - if (!res.count) - return NULL; - - if (!(list = drmMalloc(res.count * sizeof(*list)))) - return NULL; - if (!(retval = drmMalloc(res.count * sizeof(*retval)))) { - drmFree(list); - return NULL; - } - - res.contexts = list; - if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) - return NULL; - - for (i = 0; i < res.count; i++) - retval[i] = list[i].handle; - drmFree(list); - - *count = res.count; - return retval; -} - -void drmFreeReservedContextList(drm_context_t *pt) -{ - drmFree(pt); -} - -/** - * Create context. - * - * Used by the X server during GLXContext initialization. This causes - * per-context kernel-level resources to be allocated. - * - * \param fd file descriptor. - * \param handle is set on success. To be used by the client when requesting DMA - * dispatch with drmDMA(). - * - * \return zero on success, or a negative value on failure. - * - * \note May only be called by root. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the - * argument in a drm_ctx structure. - */ -int drmCreateContext(int fd, drm_context_t *handle) -{ - drm_ctx_t ctx; - - ctx.flags = 0; /* Modified with functions below */ - if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) - return -errno; - *handle = ctx.handle; - return 0; -} - -int drmSwitchToContext(int fd, drm_context_t context) -{ - drm_ctx_t ctx; - - ctx.handle = context; - if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) - return -errno; - return 0; -} - -int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags) -{ - drm_ctx_t ctx; - - /* - * Context preserving means that no context switches are done between DMA - * buffers from one context and the next. This is suitable for use in the - * X server (which promises to maintain hardware context), or in the - * client-side library when buffers are swapped on behalf of two threads. - */ - ctx.handle = context; - ctx.flags = 0; - if (flags & DRM_CONTEXT_PRESERVED) - ctx.flags |= _DRM_CONTEXT_PRESERVED; - if (flags & DRM_CONTEXT_2DONLY) - ctx.flags |= _DRM_CONTEXT_2DONLY; - if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) - return -errno; - return 0; -} - -int drmGetContextFlags(int fd, drm_context_t context, - drm_context_tFlagsPtr flags) -{ - drm_ctx_t ctx; - - ctx.handle = context; - if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) - return -errno; - *flags = 0; - if (ctx.flags & _DRM_CONTEXT_PRESERVED) - *flags |= DRM_CONTEXT_PRESERVED; - if (ctx.flags & _DRM_CONTEXT_2DONLY) - *flags |= DRM_CONTEXT_2DONLY; - return 0; -} - -/** - * Destroy context. - * - * Free any kernel-level resources allocated with drmCreateContext() associated - * with the context. - * - * \param fd file descriptor. - * \param handle handle given by drmCreateContext(). - * - * \return zero on success, or a negative value on failure. - * - * \note May only be called by root. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the - * argument in a drm_ctx structure. - */ -int drmDestroyContext(int fd, drm_context_t handle) -{ - drm_ctx_t ctx; - ctx.handle = handle; - if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) - return -errno; - return 0; -} - -int drmCreateDrawable(int fd, drm_drawable_t *handle) -{ - drm_draw_t draw; - if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) - return -errno; - *handle = draw.handle; - return 0; -} - -int drmDestroyDrawable(int fd, drm_drawable_t handle) -{ - drm_draw_t draw; - draw.handle = handle; - if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) - return -errno; - return 0; -} - -int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, - drm_drawable_info_type_t type, unsigned int num, - void *data) -{ - drm_update_draw_t update; - - update.handle = handle; - update.type = type; - update.num = num; - update.data = (unsigned long long)(unsigned long)data; - - if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) - return -errno; - - return 0; -} - -/** - * Acquire the AGP device. - * - * Must be called before any of the other AGP related calls. - * - * \param fd file descriptor. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. - */ -int drmAgpAcquire(int fd) -{ - if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) - return -errno; - return 0; -} - - -/** - * Release the AGP device. - * - * \param fd file descriptor. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. - */ -int drmAgpRelease(int fd) -{ - if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) - return -errno; - return 0; -} - - -/** - * Set the AGP mode. - * - * \param fd file descriptor. - * \param mode AGP mode. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the - * argument in a drm_agp_mode structure. - */ -int drmAgpEnable(int fd, unsigned long mode) -{ - drm_agp_mode_t m; - - m.mode = mode; - if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) - return -errno; - return 0; -} - - -/** - * Allocate a chunk of AGP memory. - * - * \param fd file descriptor. - * \param size requested memory size in bytes. Will be rounded to page boundary. - * \param type type of memory to allocate. - * \param address if not zero, will be set to the physical address of the - * allocated memory. - * \param handle on success will be set to a handle of the allocated memory. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the - * arguments in a drm_agp_buffer structure. - */ -int drmAgpAlloc(int fd, unsigned long size, unsigned long type, - unsigned long *address, drm_handle_t *handle) -{ - drm_agp_buffer_t b; - - *handle = DRM_AGP_NO_HANDLE; - b.size = size; - b.handle = 0; - b.type = type; - if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) - return -errno; - if (address != 0UL) - *address = b.physical; - *handle = b.handle; - return 0; -} - - -/** - * Free a chunk of AGP memory. - * - * \param fd file descriptor. - * \param handle handle to the allocated memory, as given by drmAgpAllocate(). - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the - * argument in a drm_agp_buffer structure. - */ -int drmAgpFree(int fd, drm_handle_t handle) -{ - drm_agp_buffer_t b; - - b.size = 0; - b.handle = handle; - if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) - return -errno; - return 0; -} - - -/** - * Bind a chunk of AGP memory. - * - * \param fd file descriptor. - * \param handle handle to the allocated memory, as given by drmAgpAllocate(). - * \param offset offset in bytes. It will round to page boundary. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the - * argument in a drm_agp_binding structure. - */ -int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) -{ - drm_agp_binding_t b; - - b.handle = handle; - b.offset = offset; - if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) - return -errno; - return 0; -} - - -/** - * Unbind a chunk of AGP memory. - * - * \param fd file descriptor. - * \param handle handle to the allocated memory, as given by drmAgpAllocate(). - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing - * the argument in a drm_agp_binding structure. - */ -int drmAgpUnbind(int fd, drm_handle_t handle) -{ - drm_agp_binding_t b; - - b.handle = handle; - b.offset = 0; - if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) - return -errno; - return 0; -} - - -/** - * Get AGP driver major version number. - * - * \param fd file descriptor. - * - * \return major version number on success, or a negative value on failure.. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -int drmAgpVersionMajor(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return -errno; - return i.agp_version_major; -} - - -/** - * Get AGP driver minor version number. - * - * \param fd file descriptor. - * - * \return minor version number on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -int drmAgpVersionMinor(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return -errno; - return i.agp_version_minor; -} - - -/** - * Get AGP mode. - * - * \param fd file descriptor. - * - * \return mode on success, or zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned long drmAgpGetMode(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.mode; -} - - -/** - * Get AGP aperture base. - * - * \param fd file descriptor. - * - * \return aperture base on success, zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned long drmAgpBase(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.aperture_base; -} - - -/** - * Get AGP aperture size. - * - * \param fd file descriptor. - * - * \return aperture size on success, zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned long drmAgpSize(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.aperture_size; -} - - -/** - * Get used AGP memory. - * - * \param fd file descriptor. - * - * \return memory used on success, or zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned long drmAgpMemoryUsed(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.memory_used; -} - - -/** - * Get available AGP memory. - * - * \param fd file descriptor. - * - * \return memory available on success, or zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned long drmAgpMemoryAvail(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.memory_allowed; -} - - -/** - * Get hardware vendor ID. - * - * \param fd file descriptor. - * - * \return vendor ID on success, or zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned int drmAgpVendorId(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.id_vendor; -} - - -/** - * Get hardware device ID. - * - * \param fd file descriptor. - * - * \return zero on success, or zero on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the - * necessary information in a drm_agp_info structure. - */ -unsigned int drmAgpDeviceId(int fd) -{ - drm_agp_info_t i; - - if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) - return 0; - return i.id_device; -} - -int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle) -{ - drm_scatter_gather_t sg; - - *handle = 0; - sg.size = size; - sg.handle = 0; - if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) - return -errno; - *handle = sg.handle; - return 0; -} - -int drmScatterGatherFree(int fd, drm_handle_t handle) -{ - drm_scatter_gather_t sg; - - sg.size = 0; - sg.handle = handle; - if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) - return -errno; - return 0; -} - -/** - * Wait for VBLANK. - * - * \param fd file descriptor. - * \param vbl pointer to a drmVBlank structure. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. - */ -int drmWaitVBlank(int fd, drmVBlankPtr vbl) -{ - struct timespec timeout, cur; - int ret; - - ret = clock_gettime(CLOCK_MONOTONIC, &timeout); - if (ret < 0) { - fprintf(stderr, "clock_gettime failed: %s\n", strerror(ret)); - goto out; - } - timeout.tv_sec++; - - do { - ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); - vbl->request.type &= ~DRM_VBLANK_RELATIVE; - if (ret && errno == EINTR) { - clock_gettime(CLOCK_MONOTONIC, &cur); - /* Timeout after 1s */ - if (cur.tv_sec > timeout.tv_sec + 1 || - (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= - timeout.tv_nsec)) { - errno = EBUSY; - ret = -1; - break; - } - } - } while (ret && errno == EINTR); - -out: - return ret; -} - -int drmError(int err, const char *label) -{ - switch (err) { - case DRM_ERR_NO_DEVICE: - fprintf(stderr, "%s: no device\n", label); - break; - case DRM_ERR_NO_ACCESS: - fprintf(stderr, "%s: no access\n", label); - break; - case DRM_ERR_NOT_ROOT: - fprintf(stderr, "%s: not root\n", label); - break; - case DRM_ERR_INVALID: - fprintf(stderr, "%s: invalid args\n", label); - break; - default: - if (err < 0) - err = -err; - fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); - break; - } - - return 1; -} - -/** - * Install IRQ handler. - * - * \param fd file descriptor. - * \param irq IRQ number. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the - * argument in a drm_control structure. - */ -int drmCtlInstHandler(int fd, int irq) -{ - drm_control_t ctl; - - ctl.func = DRM_INST_HANDLER; - ctl.irq = irq; - if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) - return -errno; - return 0; -} - - -/** - * Uninstall IRQ handler. - * - * \param fd file descriptor. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the - * argument in a drm_control structure. - */ -int drmCtlUninstHandler(int fd) -{ - drm_control_t ctl; - - ctl.func = DRM_UNINST_HANDLER; - ctl.irq = 0; - if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) - return -errno; - return 0; -} - -int drmFinish(int fd, int context, drmLockFlags flags) -{ - drm_lock_t lock; - - lock.context = context; - lock.flags = 0; - if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; - if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; - if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; - if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; - if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; - if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; - if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) - return -errno; - return 0; -} - -/** - * Get IRQ from bus ID. - * - * \param fd file descriptor. - * \param busnum bus number. - * \param devnum device number. - * \param funcnum function number. - * - * \return IRQ number on success, or a negative value on failure. - * - * \internal - * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the - * arguments in a drm_irq_busid structure. - */ -int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum) -{ - drm_irq_busid_t p; - - p.busnum = busnum; - p.devnum = devnum; - p.funcnum = funcnum; - if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) - return -errno; - return p.irq; -} - -int drmAddContextTag(int fd, drm_context_t context, void *tag) -{ - drmHashEntry *entry = drmGetEntry(fd); - - if (drmHashInsert(entry->tagTable, context, tag)) { - drmHashDelete(entry->tagTable, context); - drmHashInsert(entry->tagTable, context, tag); - } - return 0; -} - -int drmDelContextTag(int fd, drm_context_t context) -{ - drmHashEntry *entry = drmGetEntry(fd); - - return drmHashDelete(entry->tagTable, context); -} - -void *drmGetContextTag(int fd, drm_context_t context) -{ - drmHashEntry *entry = drmGetEntry(fd); - void *value; - - if (drmHashLookup(entry->tagTable, context, &value)) - return NULL; - - return value; -} - -int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, - drm_handle_t handle) -{ - drm_ctx_priv_map_t map; - - map.ctx_id = ctx_id; - map.handle = (void *)handle; - - if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) - return -errno; - return 0; -} - -int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, - drm_handle_t *handle) -{ - drm_ctx_priv_map_t map; - - map.ctx_id = ctx_id; - - if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) - return -errno; - if (handle) - *handle = (drm_handle_t)map.handle; - - return 0; -} - -int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, - drmMapType *type, drmMapFlags *flags, drm_handle_t *handle, - int *mtrr) -{ - drm_map_t map; - - map.offset = idx; - if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) - return -errno; - *offset = map.offset; - *size = map.size; - *type = map.type; - *flags = map.flags; - *handle = (unsigned long)map.handle; - *mtrr = map.mtrr; - return 0; -} - -int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, - unsigned long *magic, unsigned long *iocs) -{ - drm_client_t client; - - client.idx = idx; - if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) - return -errno; - *auth = client.auth; - *pid = client.pid; - *uid = client.uid; - *magic = client.magic; - *iocs = client.iocs; - return 0; -} - -int drmGetStats(int fd, drmStatsT *stats) -{ - drm_stats_t s; - int i; - - if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) - return -errno; - - stats->count = 0; - memset(stats, 0, sizeof(*stats)); - if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) - return -1; - -#define SET_VALUE \ - stats->data[i].long_format = "%-20.20s"; \ - stats->data[i].rate_format = "%8.8s"; \ - stats->data[i].isvalue = 1; \ - stats->data[i].verbose = 0 - -#define SET_COUNT \ - stats->data[i].long_format = "%-20.20s"; \ - stats->data[i].rate_format = "%5.5s"; \ - stats->data[i].isvalue = 0; \ - stats->data[i].mult_names = "kgm"; \ - stats->data[i].mult = 1000; \ - stats->data[i].verbose = 0 - -#define SET_BYTE \ - stats->data[i].long_format = "%-20.20s"; \ - stats->data[i].rate_format = "%5.5s"; \ - stats->data[i].isvalue = 0; \ - stats->data[i].mult_names = "KGM"; \ - stats->data[i].mult = 1024; \ - stats->data[i].verbose = 0 - - - stats->count = s.count; - for (i = 0; i < s.count; i++) { - stats->data[i].value = s.data[i].value; - switch (s.data[i].type) { - case _DRM_STAT_LOCK: - stats->data[i].long_name = "Lock"; - stats->data[i].rate_name = "Lock"; - SET_VALUE; - break; - case _DRM_STAT_OPENS: - stats->data[i].long_name = "Opens"; - stats->data[i].rate_name = "O"; - SET_COUNT; - stats->data[i].verbose = 1; - break; - case _DRM_STAT_CLOSES: - stats->data[i].long_name = "Closes"; - stats->data[i].rate_name = "Lock"; - SET_COUNT; - stats->data[i].verbose = 1; - break; - case _DRM_STAT_IOCTLS: - stats->data[i].long_name = "Ioctls"; - stats->data[i].rate_name = "Ioc/s"; - SET_COUNT; - break; - case _DRM_STAT_LOCKS: - stats->data[i].long_name = "Locks"; - stats->data[i].rate_name = "Lck/s"; - SET_COUNT; - break; - case _DRM_STAT_UNLOCKS: - stats->data[i].long_name = "Unlocks"; - stats->data[i].rate_name = "Unl/s"; - SET_COUNT; - break; - case _DRM_STAT_IRQ: - stats->data[i].long_name = "IRQs"; - stats->data[i].rate_name = "IRQ/s"; - SET_COUNT; - break; - case _DRM_STAT_PRIMARY: - stats->data[i].long_name = "Primary Bytes"; - stats->data[i].rate_name = "PB/s"; - SET_BYTE; - break; - case _DRM_STAT_SECONDARY: - stats->data[i].long_name = "Secondary Bytes"; - stats->data[i].rate_name = "SB/s"; - SET_BYTE; - break; - case _DRM_STAT_DMA: - stats->data[i].long_name = "DMA"; - stats->data[i].rate_name = "DMA/s"; - SET_COUNT; - break; - case _DRM_STAT_SPECIAL: - stats->data[i].long_name = "Special DMA"; - stats->data[i].rate_name = "dma/s"; - SET_COUNT; - break; - case _DRM_STAT_MISSED: - stats->data[i].long_name = "Miss"; - stats->data[i].rate_name = "Ms/s"; - SET_COUNT; - break; - case _DRM_STAT_VALUE: - stats->data[i].long_name = "Value"; - stats->data[i].rate_name = "Value"; - SET_VALUE; - break; - case _DRM_STAT_BYTE: - stats->data[i].long_name = "Bytes"; - stats->data[i].rate_name = "B/s"; - SET_BYTE; - break; - case _DRM_STAT_COUNT: - default: - stats->data[i].long_name = "Count"; - stats->data[i].rate_name = "Cnt/s"; - SET_COUNT; - break; - } - } - return 0; -} - -/** - * Issue a set-version ioctl. - * - * \param fd file descriptor. - * \param drmCommandIndex command index - * \param data source pointer of the data to be read and written. - * \param size size of the data to be read and written. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * It issues a read-write ioctl given by - * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. - */ -int drmSetInterfaceVersion(int fd, drmSetVersion *version) -{ - int retcode = 0; - drm_set_version_t sv; - - sv.drm_di_major = version->drm_di_major; - sv.drm_di_minor = version->drm_di_minor; - sv.drm_dd_major = version->drm_dd_major; - sv.drm_dd_minor = version->drm_dd_minor; - - if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { - retcode = -errno; - } - - version->drm_di_major = sv.drm_di_major; - version->drm_di_minor = sv.drm_di_minor; - version->drm_dd_major = sv.drm_dd_major; - version->drm_dd_minor = sv.drm_dd_minor; - - return retcode; -} - -/** - * Send a device-specific command. - * - * \param fd file descriptor. - * \param drmCommandIndex command index - * - * \return zero on success, or a negative value on failure. - * - * \internal - * It issues a ioctl given by - * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. - */ -int drmCommandNone(int fd, unsigned long drmCommandIndex) -{ - void *data = NULL; /* dummy */ - unsigned long request; - - request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); - - if (drmIoctl(fd, request, data)) { - return -errno; - } - return 0; -} - - -/** - * Send a device-specific read command. - * - * \param fd file descriptor. - * \param drmCommandIndex command index - * \param data destination pointer of the data to be read. - * \param size size of the data to be read. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * It issues a read ioctl given by - * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. - */ -int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data, - unsigned long size) -{ - unsigned long request; - - request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, - DRM_COMMAND_BASE + drmCommandIndex, size); - - if (drmIoctl(fd, request, data)) { - return -errno; - } - return 0; -} - - -/** - * Send a device-specific write command. - * - * \param fd file descriptor. - * \param drmCommandIndex command index - * \param data source pointer of the data to be written. - * \param size size of the data to be written. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * It issues a write ioctl given by - * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. - */ -int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data, - unsigned long size) -{ - unsigned long request; - - request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, - DRM_COMMAND_BASE + drmCommandIndex, size); - - if (drmIoctl(fd, request, data)) { - return -errno; - } - return 0; -} - - -/** - * Send a device-specific read-write command. - * - * \param fd file descriptor. - * \param drmCommandIndex command index - * \param data source pointer of the data to be read and written. - * \param size size of the data to be read and written. - * - * \return zero on success, or a negative value on failure. - * - * \internal - * It issues a read-write ioctl given by - * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. - */ -int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, - unsigned long size) -{ - unsigned long request; - - request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, - DRM_COMMAND_BASE + drmCommandIndex, size); - - if (drmIoctl(fd, request, data)) - return -errno; - return 0; -} - -#define DRM_MAX_FDS 16 -static struct { - char *BusID; - int fd; - int refcount; -} connection[DRM_MAX_FDS]; - -static int nr_fds = 0; - -int drmOpenOnce(void *unused, - const char *BusID, - int *newlyopened) -{ - int i; - int fd; - - for (i = 0; i < nr_fds; i++) - if (strcmp(BusID, connection[i].BusID) == 0) { - connection[i].refcount++; - *newlyopened = 0; - return connection[i].fd; - } - - fd = drmOpen(unused, BusID); - if (fd <= 0 || nr_fds == DRM_MAX_FDS) - return fd; - - connection[nr_fds].BusID = strdup(BusID); - connection[nr_fds].fd = fd; - connection[nr_fds].refcount = 1; - *newlyopened = 1; - - if (0) - fprintf(stderr, "saved connection %d for %s %d\n", - nr_fds, connection[nr_fds].BusID, - strcmp(BusID, connection[nr_fds].BusID)); - - nr_fds++; - - return fd; -} - -void drmCloseOnce(int fd) -{ - int i; - - for (i = 0; i < nr_fds; i++) { - if (fd == connection[i].fd) { - if (--connection[i].refcount == 0) { - drmClose(connection[i].fd); - free(connection[i].BusID); - - if (i < --nr_fds) - connection[i] = connection[nr_fds]; - - return; - } - } - } -} - -int drmSetMaster(int fd) -{ - int ret; - - fprintf(stderr,"Setting master \n"); - ret = ioctl(fd, DRM_IOCTL_SET_MASTER, 0); - return ret; -} - -int drmDropMaster(int fd) -{ - int ret; - fprintf(stderr,"Dropping master \n"); - ret = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); - return ret; -} |