summaryrefslogtreecommitdiff
path: root/libdrm/xf86drm.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdrm/xf86drm.c')
-rw-r--r--libdrm/xf86drm.c108
1 files changed, 90 insertions, 18 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index 2e3c9b43..1174a0fa 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -1,7 +1,8 @@
/* xf86drm.c -- User-level interface to DRM device
* Created: Tue Jan 5 08:16:21 1999 by faith@precisioninsight.com
*
- * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * 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
@@ -23,8 +24,9 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
- * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com>
- *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Kevin E. Martin <martin@valinux.com>
+ *
* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.10 2000/02/23 04:47:23 martin Exp $
*
*/
@@ -71,10 +73,23 @@ extern int xf86RemoveSIGIOHandler(int fd);
#define MAP_FAILED ((void *)-1)
#endif
-#include <sys/sysmacros.h> /* for makedev() */
#include "xf86drm.h"
#include "drm.h"
+#define DRM_FIXED_DEVICE_MAJOR 145
+
+#ifdef __linux__
+#include <sys/sysmacros.h> /* for makedev() */
+#endif
+
+#ifndef makedev
+ /* 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. */
+#define makedev(x,y) ((dev_t)(((x) << 8) | (y)))
+#endif
+
static void *drmHashTable = NULL; /* Context switch callbacks */
typedef struct drmHashEntry {
@@ -95,9 +110,16 @@ void drmFree(void *pt)
if (pt) _DRM_FREE(pt);
}
+/* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */
static char *drmStrdup(const char *s)
{
- return s ? strdup(s) : NULL;
+ char *retval = NULL;
+
+ if (s) {
+ retval = _DRM_MALLOC(strlen(s)+1);
+ strcpy(retval, s);
+ }
+ return retval;
}
@@ -134,7 +156,7 @@ static drmHashEntry *drmGetEntry(int fd)
return entry;
}
-/* drm_open is used to open the /dev/drm device */
+/* drm_open is used to open the /dev/dri device */
static int drm_open(const char *file)
{
@@ -144,14 +166,6 @@ static int drm_open(const char *file)
return -errno;
}
-/* drmAvailable looks for /proc/dri, and returns 1 if it is present. */
-
-int drmAvailable(void)
-{
- if (!access("/proc/dri/0", R_OK)) return 1;
- return 0;
-}
-
static int drmOpenDevice(const char *path, long dev,
mode_t mode, uid_t user, gid_t group)
{
@@ -161,7 +175,16 @@ static int drmOpenDevice(const char *path, long dev,
struct stat st;
#endif
- if (!stat(path, &st) && st.st_rdev == dev) return drm_open(path);
+ /* Fiddle mode to remove execute bits */
+ mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
+
+ if (!stat(path, &st) && st.st_rdev == dev) {
+ if (!geteuid()) {
+ chown(path, user, group);
+ chmod(path, mode);
+ }
+ return drm_open(path);
+ }
if (geteuid()) return DRM_ERR_NOT_ROOT;
remove(path);
@@ -174,6 +197,38 @@ static int drmOpenDevice(const char *path, long dev,
return drm_open(path);
}
+/* drmAvailable looks for /proc/dri, and returns 1 if it is present. On
+ OSs that do not have a Linux-like /proc, this information will not be
+ available, and we'll have to create a device and check if the driver is
+ loaded that way. */
+
+int drmAvailable(void)
+{
+ char dev_name[64];
+ drmVersionPtr version;
+ int retval = 0;
+ int fd;
+
+ if (!access("/proc/dri/0", R_OK)) return 1;
+
+ sprintf(dev_name, "/dev/dri-temp-%d", getpid());
+
+ remove(dev_name);
+ if ((fd = drmOpenDevice(dev_name, makedev(DRM_FIXED_DEVICE_MAJOR, 0),
+ S_IRUSR, geteuid(), getegid())) >= 0) {
+ /* Read version to make sure this is
+ actually a DRI device. */
+ if ((version = drmGetVersion(fd))) {
+ retval = 1;
+ drmFreeVersion(version);
+ }
+ close(fd);
+ }
+ remove(dev_name);
+
+ return retval;
+}
+
static int drmOpenByBusid(const char *busid)
{
int i;
@@ -268,7 +323,24 @@ static int drmOpenByName(const char *name)
}
}
}
- } else remove(dev_name);
+ } else {
+ drmVersionPtr version;
+ /* /proc/dri not available, possibly
+ because we aren't on a Linux system.
+ So, try to create the next device and
+ see if it's active. */
+ dev = makedev(DRM_FIXED_DEVICE_MAJOR, i);
+ if ((fd = drmOpenDevice(dev_name, dev, mode, user, group))) {
+ if ((version = drmGetVersion(fd))) {
+ if (!strcmp(version->name, name)) {
+ drmFreeVersion(version);
+ return fd;
+ }
+ drmFreeVersion(version);
+ }
+ }
+ remove(dev_name);
+ }
}
return -1;
}
@@ -303,7 +375,7 @@ static void drmFreeKernelVersion(drm_version_t *v)
drmFree(v);
}
-static void drmCopyVersion(drmVersionPtr d, drm_version_t *s)
+static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
{
d->version_major = s->version_major;
d->version_minor = s->version_minor;
@@ -317,7 +389,7 @@ static void drmCopyVersion(drmVersionPtr d, drm_version_t *s)
}
/* drmVersion obtains the version information via an ioctl. Similar
- * information is available via /proc/drm. */
+ * information is available via /proc/dri. */
drmVersionPtr drmGetVersion(int fd)
{