summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <gordon.w.ross@gmail.com>2016-11-05 22:21:12 -0400
committerGordon Ross <gordon.w.ross@gmail.com>2016-11-23 00:27:10 -0500
commitc627a2c3758eb647b4b0d1def0f986d7cea01497 (patch)
tree9d57d14267be969fb52b918b715486b715d45914
parent652f7de48d84d3676be26d15e484640c5d6665c0 (diff)
downloadillumos-gfx-drm-c627a2c3758eb647b4b0d1def0f986d7cea01497.tar.gz
Add proper implementations of drmGetMinorNameForFD etc.
These use (new) OS-specific interfaces in libdrm. Tests for these interfaces are in getsundev, and indirectly in getclient, getversion etc. Fix drmdevice test failure in drmParsePciDeviceInfo The path arg to drmParsePciDeviceinfo can be relative to /dev/dri Fix drmGetDeviceNameFromFd() by dropping clone minor bits.
-rw-r--r--usr/src/cmd/drm-tests/misc2/Makefile.com6
-rw-r--r--usr/src/cmd/drm-tests/misc2/common/drmtest_sun.c100
-rw-r--r--usr/src/cmd/drm-tests/misc2/common/getsundev.c131
-rw-r--r--usr/src/common/libdrm/patches/xf86drm-c.patch170
-rw-r--r--usr/src/common/libdrm/patches/xf86drm-h.patch18
-rw-r--r--usr/src/lib/libdrm/Makefile.com12
-rw-r--r--usr/src/lib/libdrm/common/sun_devinfo.c291
-rw-r--r--usr/src/lib/libdrm/common/sun_xf86drm.c176
-rw-r--r--usr/src/pkg/manifests/system-test-libdrm.mf2
9 files changed, 856 insertions, 50 deletions
diff --git a/usr/src/cmd/drm-tests/misc2/Makefile.com b/usr/src/cmd/drm-tests/misc2/Makefile.com
index dd2862b..a6a24dd 100644
--- a/usr/src/cmd/drm-tests/misc2/Makefile.com
+++ b/usr/src/cmd/drm-tests/misc2/Makefile.com
@@ -20,7 +20,8 @@ PROG= \
getstats \
setversion \
updatedraw \
- name_from_fd
+ name_from_fd \
+ getsundev
# All programs here require this devinfo object.
DEVOBJ=drmtest_sun.o
@@ -53,6 +54,9 @@ clean:
%.o : ../common/%.c
$(COMPILE.c) -o $@ -c $<
+getsundev : getsundev.o
+ $(LINK.c) -o $@ $@.o $(DEVOBJ) $(LDLIBS)
+
.KEEP_STATE:
include ../../../Makefile.targ
diff --git a/usr/src/cmd/drm-tests/misc2/common/drmtest_sun.c b/usr/src/cmd/drm-tests/misc2/common/drmtest_sun.c
index 6328803..caf5d31 100644
--- a/usr/src/cmd/drm-tests/misc2/common/drmtest_sun.c
+++ b/usr/src/cmd/drm-tests/misc2/common/drmtest_sun.c
@@ -25,6 +25,29 @@
*
*/
+/*
+ * Copyright 2016 Gordon W. Ross
+ */
+
+/*
+ * Helper functions for libdrm/tests. See:
+ * drm_open_any()
+ * getclient.c
+ * getstats.c
+ * getversion.c
+ * openclose.c
+ * drm_open_any_master()
+ * setversion.c
+ * updatedraw.c
+ *
+ * This module replaces libdrm/tests/drmtest.c
+ * which needs the linux "udev" interfaces.
+ * Here we use libdevinfo.h instead via these
+ * private interfaces in libdrm:
+ * _sun_drm_find_device()
+ * _sun_drm_get_pci_info()
+ */
+
#include <string.h>
#include <fcntl.h>
#include <fnmatch.h>
@@ -53,48 +76,45 @@ static int is_master(int fd)
return 1;
}
-/** Open the first DRM device matching the criteria */
+/*
+ * Open the first DRM device matching the criteria
+ */
int drm_open_matching(const char *pci_glob, int flags)
{
- di_node_t udev;
-// struct udev_enumerate *e;
-// struct udev_device *device, *parent;
-// struct udev_list_entry *entry;
- const char *pci_id, *path;
- const char *usub, *dnode;
- uint_t di_flags;
- int fd;
-
- /* Get everything? */
- di_flags = DINFOSUBTREE | DINFOPROP | DINFOMINOR | DINFOPATH | DINFOLYR;
- udev = di_init("/", di_flags);
- if (udev == DI_NODE_NIL) {
- fprintf(stderr, "failed to initialize devinfo context\n");
- exit (1);
- }
-
- fd = -1;
-#if 0 // Todo
- e = udev_enumerate_new(udev);
- udev_enumerate_add_match_subsystem(e, "drm");
- udev_enumerate_scan_devices(e);
- udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
- path = udev_list_entry_get_name(entry);
- device = udev_device_new_from_syspath(udev, path);
- parent = udev_device_get_parent(device);
- usub = udev_device_get_subsystem(parent);
- /* Filter out KMS output devices. */
- if (!usub || (strcmp(usub, "pci") != 0))
- continue;
- pci_id = udev_device_get_property_value(parent, "PCI_ID");
- if (fnmatch(pci_glob, pci_id, 0) != 0)
- continue;
- dnode = udev_device_get_devnode(device);
- if (strstr(dnode, "control"))
+ char *path = NULL;
+ int i, ret;
+ int fd = -1;
+
+ /*
+ * If our glob patter matches all, let's skip
+ * getting the PCI info etc.
+ */
+ if (strcmp(pci_glob, "*:*") == 0)
+ pci_glob = NULL;
+
+ /* Could also start at the offset for some device type. */
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ free(path);
+ ret = _sun_drm_find_device(i, &path);
+ if (ret != 0)
continue;
- fd = open(dnode, O_RDWR);
+
+ if (pci_glob != NULL) {
+ drmPciDeviceInfo pcii;
+ char pci_str[32];
+ ret = _sun_drm_get_pci_info(path, &pcii);
+ if (ret != 0)
+ continue;
+ snprintf(pci_str, sizeof (pci_str),
+ "%x:%x", pcii.vendor_id, pcii.device_id);
+ if (fnmatch(pci_glob, pci_str, 0) != 0)
+ continue;
+ }
+
+ fd = open(path, O_RDWR);
if (fd < 0)
continue;
+
if ((flags & DRM_TEST_MASTER) && !is_master(fd)) {
close(fd);
fd = -1;
@@ -103,12 +123,8 @@ int drm_open_matching(const char *pci_glob, int flags)
break;
}
- udev_enumerate_unref(e);
-#else
- exit (1);
-#endif
- di_fini(udev);
+ free(path);
return fd;
}
diff --git a/usr/src/cmd/drm-tests/misc2/common/getsundev.c b/usr/src/cmd/drm-tests/misc2/common/getsundev.c
new file mode 100644
index 0000000..12be92f
--- /dev/null
+++ b/usr/src/cmd/drm-tests/misc2/common/getsundev.c
@@ -0,0 +1,131 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2016 Gordon W. Ross
+ */
+
+/*
+ * Tests for the OS-dependent functions over in:
+ * libdevinfo/common/sun_devinfo.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <fnmatch.h>
+#include <libdevinfo.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mkdev.h>
+
+#include "xf86drm.h"
+
+int main(int argc, char **argv)
+{
+ drmPciBusInfo pci_bus;
+ drmPciDeviceInfo pci_dev;
+ char *path;
+ char *path2;
+ int failures = 0;
+ int min = 0;
+ int maj;
+ int fd, ret;
+
+ if (argc > 1)
+ min = atoi(argv[1]);
+
+ maj = _sun_drm_get_major();
+ printf("drm major: %d\n", maj);
+
+ ret = _sun_drm_find_device(min, &path);
+ if (ret) {
+ printf("FAIL: _sun_drm_find_device(%d, &) -> %d\n", min, ret);
+ failures++;
+ } else {
+ printf("Found device: %s\n", path);
+ }
+
+ ret = _sun_drmParseSubsystemType(maj, min);
+ if (ret != DRM_BUS_PCI) {
+ printf("FAIL: _sun_drmParseSubsystemType(%d, %d) -> %d\n",
+ maj, min, ret);
+ failures++;
+ }
+
+ ret = _sun_drmParsePciBusInfo(maj, min, &pci_bus);
+ if (ret) {
+ printf("FAIL: _sun_drmParsePciBusInfo(%d, %d, &) -> %d\n",
+ maj, min, ret);
+ failures++;
+ } else {
+ printf("PCI bus info: dom=%d bus=%d dev=%d func=%d\n",
+ pci_bus.domain,
+ pci_bus.bus,
+ pci_bus.dev,
+ pci_bus.func);
+ }
+
+ ret = _sun_drmParsePciDeviceInfo(path, &pci_dev);
+ if (ret) {
+ printf("FAIL: _sun_drmParsePciDeviceInfo(\"%s\", &) -> %d\n",
+ path, ret);
+ failures++;
+ } else {
+ printf("PCI device info: ven=%x dev=%x "
+ "subven=%x subdev=%x rev=%x\n",
+ pci_dev.vendor_id,
+ pci_dev.device_id,
+ pci_dev.subvendor_id,
+ pci_dev.subdevice_id,
+ pci_dev.revision_id);
+ }
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ ret = errno;
+ printf("FAIL: open(%s) -> %d\n", path, ret);
+ return (1);
+ }
+
+ path2 = _sun_drmGetMinorNameForFD(fd, 0);
+ if (path2 == NULL) {
+ ret = errno;
+ printf("FAIL: open(%s) -> %d\n", path, ret);
+ failures++;
+ } else {
+ printf("Path from fd: %s\n", path2);
+ if (strcmp(path2, path) != 0) {
+ printf("FAIL\n");
+ failures++;
+ }
+ }
+
+ close(fd);
+ free(path2);
+ free(path);
+
+ return (failures ? 1 : 0);
+}
diff --git a/usr/src/common/libdrm/patches/xf86drm-c.patch b/usr/src/common/libdrm/patches/xf86drm-c.patch
index 7c6064b..19a6b25 100644
--- a/usr/src/common/libdrm/patches/xf86drm-c.patch
+++ b/usr/src/common/libdrm/patches/xf86drm-c.patch
@@ -1,7 +1,83 @@
-diff ... b/xf86drm.c
---- a/xf86drm.c Fri Mar 20 07:05:48 2015
-+++ b/xf86drm.c Fri Mar 20 07:06:10 2015
-@@ -1108,7 +1108,7 @@
+diff ... libdrm-2.4.71/xf86drm.c
+--- libdrm-2.4.71-ref/xf86drm.c Wed Jul 20 19:42:21 2016
++++ libdrm-2.4.71/xf86drm.c Sun Nov 20 11:16:08 2016
+@@ -98,6 +98,11 @@
+ #endif
+ #endif /* __OpenBSD__ */
+
++#if defined(__sun)
++/* Device majors are dynamic. */
++#define DRM_MAJOR (_sun_drm_get_major())
++#endif /* __sun */
++
+ #ifndef DRM_MAJOR
+ #define DRM_MAJOR 226 /* Linux */
+ #endif
+@@ -349,9 +354,14 @@
+ if (stat(DRM_DIR_NAME, &st)) {
+ if (!isroot)
+ return DRM_ERR_NOT_ROOT;
++#if defined(__sun)
++ /* Let the system do this. */
++ return DRM_ERR_NO_DEVICE;
++#else
+ mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+ chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
+ chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
++#endif
+ }
+
+ /* Check if the device node exists and create it if necessary. */
+@@ -358,8 +368,13 @@
+ if (stat(buf, &st)) {
+ if (!isroot)
+ return DRM_ERR_NOT_ROOT;
++#if defined(__sun)
++ /* Let the system do this. */
++ return DRM_ERR_NO_DEVICE;
++#else
+ remove(buf);
+ mknod(buf, S_IFCHR | devmode, dev);
++#endif
+ }
+
+ if (drm_server_info && drm_server_info->get_perms) {
+@@ -405,6 +420,10 @@
+ if (st.st_rdev != dev) {
+ if (!isroot)
+ return DRM_ERR_NOT_ROOT;
++#if defined(__sun)
++ /* Let the system do this. */
++ return DRM_ERR_NO_DEVICE;
++#else
+ remove(buf);
+ mknod(buf, S_IFCHR | devmode, dev);
+ if (drm_server_info && drm_server_info->get_perms) {
+@@ -411,6 +430,7 @@
+ chown_check_return(buf, user, group);
+ chmod(buf, devmode);
+ }
++#endif
+ }
+ fd = open(buf, O_RDWR, 0);
+ drmMsg("drmOpenDevice: open result is %d, (%s)\n",
+@@ -532,6 +552,7 @@
+ }
+ }
+
++#ifndef __sun /* Avoid "static unused" warning */
+ static const char *drmGetMinorName(int type)
+ {
+ switch (type) {
+@@ -545,6 +566,7 @@
+ return NULL;
+ }
+ }
++#endif /* __sun */
+
+ /**
+ * Open the device by bus ID.
+@@ -1108,7 +1130,7 @@
drm_map_t map;
memclear(map);
@@ -10,3 +86,89 @@ diff ... b/xf86drm.c
if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
return -errno;
+@@ -2696,6 +2718,15 @@
+ fstat(fd, &sbuf);
+ d = sbuf.st_rdev;
+
++#if defined(__sun)
++ /*
++ * Get rid of clone-open bits in the minor number.
++ * See: the drm driver drm_sun_open()
++ * Don't have DRM_CLONEID_NBITS here.
++ */
++ d &= ~0x3fe00;
++#endif
++
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
+ if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
+@@ -2761,6 +2792,10 @@
+ return 0;
+ }
+
++#ifdef __sun /* OS-dependent */
++#define drmGetMinorNameForFD(fd, t) \
++ _sun_drmGetMinorNameForFD(fd, t)
++#else /* __sun */
+ static char *drmGetMinorNameForFD(int fd, int type)
+ {
+ #ifdef __linux__
+@@ -2822,6 +2857,7 @@
+ #endif
+ return NULL;
+ }
++#endif /* __sun */
+
+ char *drmGetPrimaryDeviceNameFromFd(int fd)
+ {
+@@ -2833,6 +2869,10 @@
+ return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
+ }
+
++#ifdef __sun /* OS-dependent */
++#define drmParseSubsystemType(ma, mi) \
++ _sun_drmParseSubsystemType(ma, mi)
++#else /* __sun */
+ static int drmParseSubsystemType(int maj, int min)
+ {
+ #ifdef __linux__
+@@ -2859,7 +2899,12 @@
+ return -EINVAL;
+ #endif
+ }
++#endif /* __sun */
+
++#ifdef __sun /* OS-dependent */
++#define drmParsePciBusInfo(ma, mi, inf) \
++ _sun_drmParsePciBusInfo(ma, mi, inf)
++#else /* __sun */
+ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
+ {
+ #ifdef __linux__
+@@ -2901,6 +2946,7 @@
+ return -EINVAL;
+ #endif
+ }
++#endif /* __sun */
+
+ static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
+ {
+@@ -2946,6 +2992,10 @@
+ 3 /* length of the node number */;
+ }
+
++#ifdef __sun /* OS-dependent */
++#define drmParsePciDeviceInfo(name, dip) \
++ _sun_drmParsePciDeviceInfo(name, dip)
++#else /* __sun */
+ static int drmParsePciDeviceInfo(const char *d_name,
+ drmPciDeviceInfoPtr device)
+ {
+@@ -2976,6 +3026,7 @@
+ return -EINVAL;
+ #endif
+ }
++#endif /* __sun */
+
+ void drmFreeDevice(drmDevicePtr *device)
+ {
diff --git a/usr/src/common/libdrm/patches/xf86drm-h.patch b/usr/src/common/libdrm/patches/xf86drm-h.patch
index 6b00073..1dd0f7e 100644
--- a/usr/src/common/libdrm/patches/xf86drm-h.patch
+++ b/usr/src/common/libdrm/patches/xf86drm-h.patch
@@ -47,3 +47,21 @@ index 76eb94e..6a14120 100644
#ifndef DRM_CAS
#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */
#endif
+@@ -796,6 +807,17 @@
+ extern int drmGetDevices(drmDevicePtr devices[], int max_devices);
+ extern void drmFreeDevices(drmDevicePtr devices[], int count);
+
++#ifdef __sun
++extern int _sun_drm_get_major(void);
++extern char * _sun_drmGetMinorNameForFD(int fd, int type);
++extern int _sun_drmParseSubsystemType(int maj, int min);
++extern int _sun_drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info);
++extern int _sun_drmParsePciDeviceInfo(const char *d_name,
++ drmPciDeviceInfoPtr device);
++extern int _sun_drm_find_device(int min, char **pathp);
++extern int _sun_drm_get_pci_info(char *path, drmPciDeviceInfo *pcii);
++#endif /* __sun */
++
+ #if defined(__cplusplus)
+ }
+ #endif
diff --git a/usr/src/lib/libdrm/Makefile.com b/usr/src/lib/libdrm/Makefile.com
index 8dd6a3d..c8aa409 100644
--- a/usr/src/lib/libdrm/Makefile.com
+++ b/usr/src/lib/libdrm/Makefile.com
@@ -30,8 +30,8 @@ VERS= .2
# See common/libdrm/libdrm-*/Makefile.in am__objects
OBJECTS= xf86drm.o xf86drmHash.o \
- xf86drmRandom.o xf86drmSL.o \
- xf86drmMode.o
+ xf86drmRandom.o xf86drmSL.o xf86drmMode.o \
+ sun_xf86drm.o sun_devinfo.o
include ../../Makefile.lib
include $(SRC)/common/libdrm/Makefile.drm
@@ -43,8 +43,10 @@ MAPFILES=
SRCDIR = $(LIBDRM_CMN_DIR)
SRCS = $(OBJECTS:%.o=$(SRCDIR)/%.c)
+CPPFLAGS += -I$(LIBDRM_CMN_DIR)
+
# CFLAGS += $(CCVERBOSE)
-LDLIBS += -lm -lc
+LDLIBS += -lm -ldevinfo -lc
all : $(LIBS) $(PCS)
@@ -53,4 +55,8 @@ lint :
include ../Makefile.pc
include ../../Makefile.targ
+objs/%.o pics/%.o: ../common/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
.KEEP_STATE:
diff --git a/usr/src/lib/libdrm/common/sun_devinfo.c b/usr/src/lib/libdrm/common/sun_devinfo.c
new file mode 100644
index 0000000..d7d5669
--- /dev/null
+++ b/usr/src/lib/libdrm/common/sun_devinfo.c
@@ -0,0 +1,291 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2016 Gordon W. Ross
+ */
+
+/*
+ * Helper functions for sun_xf86drm.c to find DRM device nodes
+ * given a pair of device major/minor numbers.
+ *
+ * Some of this code was cribbed from the "prtconf" command.
+ */
+
+/*
+ * Device major numbers on illumos and Solaris are dynamic.
+ *
+ * Device node naming is also different. See:
+ * uts/common/io/drm/drm_stub.c drm_get_minor()
+ * uts/common/io/drm/drm_sysfs.c drm_sysfs_device_add()
+ *
+ * Device "types" (encoded in some of the minor bits)
+ * Typical device setup with intel graphics:
+ *
+ * DRM_MINOR_LEGACY /devices/pci@0,0/display@2:drm0
+ * DRM_MINOR_CONTROL /devices/pci@0,0/display@2:controlD0
+ * DRM_MINOR_RENDER /devices/pci@0,0/display@2:renderD0
+ * DRM_MINOR_VGATEXT /devices/pci@0,0/display@2:gfx0
+ * DRM_MINOR_AGPMASTER /devices/pci@0,0/display@2:agpmaster0
+ *
+ * The "devlinks" system also makes links under /dev
+ * which normally look something like this:
+ *
+ * /dev/fbs/gfx0 -> .../display@2:gfx0
+ * /dev/fb -> .../display@2:gfx0
+ * /dev/fb0 -> fbs/text-0
+ * /dev/fb1 -> fbs/gfx0
+ * /dev/agp/agpmaster0 -> .../display@2:agpmaster0
+ * /dev/dri/card1 -> .../display@2:controlD0
+ *
+ * (i916 driver) /devices/pci@0,0/pci1179,1@0:agptarget
+ * /dev/agp/agptarget0 -> /devices/pci@0,0/pci1179,1@0:agptarget
+ *
+ * (agpgart driver) /devices/agpgart:agpgart
+ * /dev/agpgart -> /devices/agpgart:agpgart
+ */
+
+#include <string.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <libdevinfo.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mkdev.h>
+
+#include "xf86drm.h"
+
+struct search_args {
+ char *s_path;
+ int s_minor;
+};
+
+static int find_dev(di_node_t, void *);
+static int find_minor(di_node_t, di_minor_t, struct search_args *);
+
+static int _sun_drm_major; /* cache */
+
+int _sun_drm_get_major(void)
+{
+ struct stat sbuf;
+ dev_t dev = 0;
+ char *path;
+ int i, ret;
+
+ if (_sun_drm_major != 0)
+ return (_sun_drm_major);
+
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ ret = _sun_drm_find_device(i, &path);
+ if (ret != 0)
+ continue;
+ ret = stat(path, &sbuf);
+ free(path);
+ if (ret != 0)
+ continue;
+ if (!S_ISCHR(sbuf.st_mode))
+ continue;
+ dev = major(sbuf.st_rdev);
+ if (dev != 0) {
+ _sun_drm_major = dev;
+ return (dev);
+ }
+ }
+
+ /*
+ * No devices found? No way to return errors here,
+ * so just return an impossible value, and let
+ * later calls like open fail.
+ */
+ return (MAXMAJ32);
+}
+
+int
+_sun_drm_find_device(int min, char **pathp)
+{
+ struct search_args sargs;
+ di_node_t root_node;
+
+ root_node = di_init("/", DINFOCPYALL);
+ if (root_node == DI_NODE_NIL)
+ return (-errno);
+
+ memset(&sargs, 0, sizeof (sargs));
+
+ di_walk_node(root_node, DI_WALK_CLDFIRST, &sargs, find_dev);
+ di_fini(root_node);
+
+ if (sargs.s_path == NULL)
+ return (-ENOENT);
+
+ if (pathp != NULL)
+ *pathp = sargs.s_path;
+ else
+ free(sargs.s_path);
+
+ return (0);
+}
+
+/*
+ * Call back function for di_walk_node, called for every device node.
+ */
+static int
+find_dev(di_node_t node, void *vargs)
+{
+ struct search_args *sargs = vargs;
+ const char *node_name;
+ di_minor_t minor_node;
+
+ node_name = di_node_name(node);
+
+ if (strcmp(node_name, "pseudo") == 0)
+ return (DI_WALK_PRUNECHILD);
+
+ /*
+ * Had: udev_enumerate_add_match_subsystem(e, "drm");
+ * so skip anything outside "drm".
+ * For illumos or Solaris, I think we want to skip
+ * anything that's not named "display".
+ */
+ if (strcmp(node_name, "display") != 0)
+ return (DI_WALK_CONTINUE);
+
+ /*
+ * Walk the minor node paths searching...
+ */
+ minor_node = DI_MINOR_NIL;
+ while ((minor_node = di_minor_next(node, minor_node)) != DI_MINOR_NIL) {
+ if (find_minor(node, minor_node, sargs)) {
+ /* Found it! */
+ return (DI_WALK_TERMINATE);
+ }
+ }
+
+ return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Search function called for each minor node under some device
+ * that was found to be of likely interest above.
+ * Return non-zero if match found.
+ */
+static int
+find_minor(di_node_t node, di_minor_t minor, struct search_args *sargs)
+{
+ char *path;
+ dev_t devt;
+ int ret;
+
+ devt = di_minor_devt(minor);
+
+ /* Does the caller want a specific minor number? */
+ if (sargs->s_minor >= 0 &&
+ sargs->s_minor != minor(devt))
+ return (0);
+
+ /*
+ * get device minor node path
+ * Note: allocates path
+ */
+ if ((path = di_devfs_minor_path(minor)) == NULL)
+ return (0);
+ ret = asprintf(&sargs->s_path, "/devices%s", path);
+ di_devfs_path_free(path);
+
+ if (ret < 0) {
+ free(sargs->s_path);
+ return (0);
+ }
+
+ return (1);
+}
+
+/*
+ * Get PCI data for the give device path.
+ *
+ * Note path given is a full minor under /devices i.e.
+ * /devices/pci@0,0/display@2:drm
+ * and libdevinfo wants just:
+ * /pci@0,0/display@2
+ */
+int
+_sun_drm_get_pci_info(char *path, drmPciDeviceInfo *pcii)
+{
+ char pathbuf[MAXPATHLEN];
+ di_node_t node;
+ char *s;
+ char *propstr = NULL;
+ int *propval = NULL;
+ int ret = -EINVAL;
+
+ /* Skip the /devices prefix, if present. */
+ if (strncmp(path, "/devices/", 9) == 0)
+ path += 8; /* the next slash */
+ strlcpy(pathbuf, path, sizeof (pathbuf));
+
+ /* Strip :drm0 or whatever */
+ if ((s = strrchr(pathbuf, ':')) != NULL)
+ *s = '\0';
+
+ /*
+ * Ask libdevinfo about this device
+ */
+ node = di_init(pathbuf, DINFOCPYALL);
+ if (node == DI_NODE_NIL)
+ return -EINVAL;
+
+ /*
+ * Get the various PCI properties.
+ * Only the first two are required.
+ */
+ memset(pcii, 0, sizeof(*pcii));
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "vendor-id", &propval) > 0)
+ pcii->vendor_id = (uint16_t)*propval;
+ else
+ goto out;
+
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "device-id", &propval) > 0)
+ pcii->device_id = (uint16_t)*propval;
+ else
+ goto out;
+
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "subsystem-vendor-id", &propval) > 0)
+ pcii->subvendor_id = (uint16_t)*propval;
+
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "subsystem-id", &propval) > 0)
+ pcii->subdevice_id = (uint16_t)*propval;
+
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "revision-id", &propval) > 0)
+ pcii->revision_id = (uint16_t)*propval;
+
+ ret = 0;
+out:
+ di_fini(node);
+ return (ret);
+}
diff --git a/usr/src/lib/libdrm/common/sun_xf86drm.c b/usr/src/lib/libdrm/common/sun_xf86drm.c
new file mode 100644
index 0000000..5387bce
--- /dev/null
+++ b/usr/src/lib/libdrm/common/sun_xf86drm.c
@@ -0,0 +1,176 @@
+/**
+ * \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.
+ */
+
+/*
+ * OS-dependent versions of several functions found in:
+ * libdrm/xf86drm.c (mostly where those need "udev")
+ * Here we use libdevinfo.h instead via these
+ * private interfaces in libdrm:
+ * _sun_drm_find_device()
+ * _sun_drm_get_pci_info()
+ *
+ * See sun_devinfo.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mkdev.h>
+
+#include "xf86drm.h"
+
+/* Device majors are dynamic. */
+#define DRM_MAJOR (_sun_drm_get_major())
+
+char *_sun_drmGetMinorNameForFD(int fd, int type)
+{
+ char *path = NULL;
+ struct stat sbuf;
+ int err, maj, min;
+
+ if (fstat(fd, &sbuf))
+ return NULL;
+
+ maj = major(sbuf.st_rdev);
+ min = minor(sbuf.st_rdev);
+
+ if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ return NULL;
+
+ /* Walk devices looking for this minor */
+ err = _sun_drm_find_device(min, &path);
+ if (err != 0)
+ return (NULL);
+
+ return (path);
+}
+
+int _sun_drmParseSubsystemType(int maj, int min)
+{
+ char *path = NULL;
+ char *p;
+ int ret;
+
+ if (maj != DRM_MAJOR)
+ return -EINVAL;
+
+ ret = _sun_drm_find_device(min, &path);
+ if (ret != 0)
+ return (ret);
+
+ p = path;
+ if (strncmp(p, "/devices", 8) == 0)
+ p += 8;
+
+ if (strncmp(p, "/pci@", 5) == 0)
+ ret = DRM_BUS_PCI;
+ else
+ ret = -EINVAL;
+ free(path);
+
+ return (ret);
+}
+
+int _sun_drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
+{
+ char *path = NULL;
+ int bus, slot, unit;
+ int n, ret;
+
+ if (maj != DRM_MAJOR)
+ return -EINVAL;
+
+ ret = _sun_drm_find_device(min, &path);
+ if (ret != 0)
+ return (ret);
+
+ n = sscanf(path, "/devices/pci@%d,%d/display@%d:",
+ &bus, &slot, &unit);
+ free(path);
+ if (n != 3)
+ return -EINVAL;
+
+ info->domain = 0;
+ info->bus = bus;
+ info->dev = slot;
+ info->func = unit;
+
+ return 0;
+}
+
+/*
+ * Given d_name as some name under /dev,
+ * find the /devices path and then get the
+ * PCI properties for that device.
+ */
+int _sun_drmParsePciDeviceInfo(const char *d_name,
+ drmPciDeviceInfo *pcii)
+{
+ struct stat sbuf;
+ int err, maj, min;
+ char dev_path[256];
+ char *path = NULL;
+
+ if (d_name[0] == '/')
+ strlcpy(dev_path, d_name, sizeof (dev_path));
+ else
+ snprintf(dev_path, sizeof (dev_path),
+ DRM_DIR_NAME "/%s", d_name);
+ if (stat(dev_path, &sbuf))
+ return -errno;
+
+ maj = major(sbuf.st_rdev);
+ min = minor(sbuf.st_rdev);
+ if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ return -EINVAL;
+
+ /* Get the /devices path */
+ err = _sun_drm_find_device(min, &path);
+ if (err != 0)
+ return err;
+
+ err = _sun_drm_get_pci_info(path, pcii);
+ free(path);
+
+ return err;
+}
+
+/*
+ * XXX: todo - int drmCheckModesettingSupported()
+ */
diff --git a/usr/src/pkg/manifests/system-test-libdrm.mf b/usr/src/pkg/manifests/system-test-libdrm.mf
index 4c3558f..b8df185 100644
--- a/usr/src/pkg/manifests/system-test-libdrm.mf
+++ b/usr/src/pkg/manifests/system-test-libdrm.mf
@@ -30,6 +30,7 @@ file path=opt/drm-tests/$(ARCH64)/exynos_fimg2d_perf
file path=opt/drm-tests/$(ARCH64)/exynos_fimg2d_test
file path=opt/drm-tests/$(ARCH64)/getclient
file path=opt/drm-tests/$(ARCH64)/getstats
+file path=opt/drm-tests/$(ARCH64)/getsundev
file path=opt/drm-tests/$(ARCH64)/getversion
file path=opt/drm-tests/$(ARCH64)/hash
file path=opt/drm-tests/$(ARCH64)/kms-steal-crtc
@@ -55,6 +56,7 @@ file path=opt/drm-tests/exynos_fimg2d_perf
file path=opt/drm-tests/exynos_fimg2d_test
file path=opt/drm-tests/getclient
file path=opt/drm-tests/getstats
+file path=opt/drm-tests/getsundev
file path=opt/drm-tests/getversion
file path=opt/drm-tests/hash
file path=opt/drm-tests/kms-steal-crtc