$NetBSD: patch-ab,v 1.8 2015/08/14 17:12:35 wiz Exp $

Code for OpenBSD adapted for NetBSD.  Assumes NetBSD kernel has been
patched to use drm ioctl number 0x0f.

Patches from FreeBSD ports libdrm 2.4.75.

Patches from https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=214580
and code from libdevq 0.0.4.

Tries to account for DragonFly major number not well defined.

Tries to account for FreeBSD device control64D to be ignored.

Many debugging messages added for use with LIBGL_DEBUG=verbose.

Added code to deduce node type from a device name such as dri/card0
for FreeBSD, DragonFly, and NetBSD, OSes that support devname().
Moved static drmGetNodeType() for drmGetNodeTypeFromFd().

--- xf86drm.c.orig	2017-01-28 01:15:16.000000000 +0000
+++ xf86drm.c
@@ -31,6 +31,36 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+/* Port for FreeBSD and DragonFly uses code from libdevq 0.0.4
+ *     https://github.com/freebsd/libdevq
+ * with copyright notice:
+ *
+ * Copyright (c) 2014 Jean-Sebastien Pedron <dumbbell@FreeBSD.org>
+ * Copyright (c) 2016 Koop Mast <kwm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
@@ -72,6 +102,10 @@
 
 #include "util_math.h"
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <sys/sysctl.h>
+#endif
+
 #ifdef __OpenBSD__
 #define DRM_PRIMARY_MINOR_NAME  "drm"
 #define DRM_CONTROL_MINOR_NAME  "drmC"
@@ -82,12 +116,22 @@
 #define DRM_RENDER_MINOR_NAME   "renderD"
 #endif
 
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-#define DRM_MAJOR 145
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#define DRM_MAJOR 0 
+#endif
+
+#if defined(__DragonFly__)
+/* DragonFly's devfs dynamically allocates major numbers.
+ * Sometimes the majors do not match,
+ * so keep track of the first major seen.
+ */
+#define DRM_MAJOR 64
+static int maj_firstseen = -1;
 #endif
 
 #ifdef __NetBSD__
-#define DRM_MAJOR 34
+#undef DRM_MAJOR
+#define DRM_MAJOR 180
 #endif
 
 #ifdef __OpenBSD__
@@ -102,7 +146,7 @@
 #define DRM_MAJOR 226 /* Linux */
 #endif
 
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__NetBSD__)
 struct drm_pciinfo {
 	uint16_t	domain;
 	uint8_t		bus;
@@ -114,8 +158,12 @@ struct drm_pciinfo {
 	uint16_t	subdevice_id;
 	uint8_t		revision_id;
 };
+#endif
 
+#if defined(__OpenBSD__)
 #define DRM_IOCTL_GET_PCIINFO	DRM_IOR(0x15, struct drm_pciinfo)
+#elif defined(__NetBSD__)
+#define DRM_IOCTL_GET_PCIINFO   DRM_IOR(0x0f, struct drm_pciinfo)
 #endif
 
 #define DRM_MSG_VERBOSITY 3
@@ -189,7 +237,14 @@ drmIoctl(int fd, unsigned long request,
 
     do {
         ret = ioctl(fd, request, arg);
+#if defined(__FreeBSD__)
+/*
+ * FreeBSD Bug 204174: error code 512 (ERESTARTSYS) leaked from kernel space.
+ */
+    } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == 512));
+#else
     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+#endif
     return ret;
 }
 
@@ -548,6 +603,7 @@ static int drmGetMinorType(int minor)
     }
 }
 
+#if !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__NetBSD__)
 static const char *drmGetMinorName(int type)
 {
     switch (type) {
@@ -561,6 +617,7 @@ static const char *drmGetMinorName(int t
         return NULL;
     }
 }
+#endif
 
 /**
  * Open the device by bus ID.
@@ -2723,11 +2780,35 @@ char *drmGetDeviceNameFromFd(int fd)
     return strdup(name);
 }
 
+static int drmGetNodeType(const char *name)
+{
+    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
+        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
+        return DRM_NODE_PRIMARY;
+
+    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
+        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
+        return DRM_NODE_CONTROL;
+
+    if (strncmp(name, DRM_RENDER_MINOR_NAME,
+        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
+        return DRM_NODE_RENDER;
+
+    return -EINVAL;
+}
+
 int drmGetNodeTypeFromFd(int fd)
 {
     struct stat sbuf;
     int maj, min, type;
 
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+    char name[64];
+    char base_name[64];
+#endif
+
+    drmMsg("libdrm, file xf86drm.c, drmGetNodeTypeFromFd(): fd (%d)\n", fd);
+
     if (fstat(fd, &sbuf))
         return -1;
 
@@ -2735,11 +2816,42 @@ int drmGetNodeTypeFromFd(int fd)
     min = minor(sbuf.st_rdev);
 
     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
+#if defined(__DragonFly__)
+        if ((maj_firstseen < 0) && (maj >= 0) && S_ISCHR(sbuf.st_mode)) {
+            maj_firstseen = maj;
+            drmMsg("First seen maj (%d) != DRM_MAJOR (%d)\n", maj, DRM_MAJOR);
+        }
+        else if (maj == maj_firstseen) {
+            drmMsg("maj == maj_firstseen (%d)\n", maj_firstseen);
+        }
+        else {
+            errno = EINVAL;
+            return -1;
+        }
+#else
         errno = EINVAL;
         return -1;
+#endif
     }
 
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+    snprintf(name, sizeof(name), "%s",
+             devname(sbuf.st_rdev, S_IFCHR));
+
+    drmMsg("Name of device file (%s)\n", name);
+
+    memset(base_name, 0, sizeof(base_name));
+    sscanf(name, "dri/%s", base_name);
+
+    drmMsg("Basename of device file (%s)\n", base_name);
+
+    type = drmGetNodeType(base_name);
+#else
     type = drmGetMinorType(min);
+#endif
+
+    drmMsg("Deduced fd node_type (%d)\n", type);
+
     if (type == -1)
         errno = ENODEV;
     return type;
@@ -2833,6 +2945,15 @@ static char *drmGetMinorNameForFD(int fd
 
 out_close_dir:
     closedir(sysdir);
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+    struct stat buf;
+    char name[64];
+
+    fstat(fd, &buf);
+    snprintf(name, sizeof(name), "/dev/%s",
+             devname(buf.st_rdev, S_IFCHR));
+
+    return strdup(name);
 #else
     struct stat sbuf;
     char buf[PATH_MAX + 1];
@@ -2962,6 +3083,12 @@ static int drmParseSubsystemType(int maj
     return -EINVAL;
 #elif defined(__OpenBSD__)
     return DRM_BUS_PCI;
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+    /* XXX: Don't know how to get the subsystem type, hardcode for now.
+     * The code following the call to this function needs depends on
+     * information provided by the /pci subsystem on linux. No replacement
+     * found yet for FreeBSD. */
+    return DRM_BUS_PCI;
 #else
 #warning "Missing implementation of drmParseSubsystemType"
     return -EINVAL;
@@ -2993,18 +3120,27 @@ static int drmParsePciBusInfo(int maj, i
     info->func = func;
 
     return 0;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__NetBSD__)
     struct drm_pciinfo pinfo;
     int fd, type;
 
+    drmMsg("drmParsePciBusInfo()\n");
+    drmMsg("Before drmGetMinorType: min (%d)\n", min);
+
     type = drmGetMinorType(min);
     if (type == -1)
         return -ENODEV;
 
+    drmMsg("Before drmOpenMinor: type (%d), DRM_NODE_PRIMARY (%d)\n",
+        type, DRM_NODE_PRIMARY);
+
     fd = drmOpenMinor(min, 0, type);
     if (fd < 0)
         return -errno;
 
+    drmMsg("Before drmIoctl: ioctl (0x%02x) using fd (%d)\n",
+        DRM_IOCTL_GET_PCIINFO, fd);
+
     if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
         close(fd);
         return -errno;
@@ -3017,6 +3153,58 @@ static int drmParsePciBusInfo(int maj, i
     info->func = pinfo.func;
 
     return 0;
+#elif (defined(__FreeBSD__) || defined(__DragonFly__))
+/*
+ * Read the hw.dri.$min.busid sysctl
+ * Adapted from function devq_device_get_pcibusaddr(),
+ * project devq version 0.0.4, file src/freebsd/device.c
+ */
+    char sysctl_name[32], sysctl_value[128];
+    const char *busid_format;
+    size_t sysctl_value_len;
+    int domain, bus, dev, func;
+    int ret;
+    snprintf(sysctl_name, 31, "hw.dri.%d.busid", min);
+
+    drmMsg("Reading sysctl_name (%s)\n", sysctl_name);
+
+    busid_format = "pci:%d:%d:%d.%d";
+    sysctl_value_len = sizeof(sysctl_value);
+    memset(sysctl_value, 0, sysctl_value_len);
+    ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len,
+        NULL, 0);
+    if (ret != 0) {
+        /*
+         * If hw.dri.$n.busid isn't available, fallback on
+         * hw.dri.$n.name.
+         */
+         busid_format = "%*s %*s pci:%d:%d:%d.%d";
+         sysctl_value_len = sizeof(sysctl_value);
+         memset(sysctl_value, 0, sysctl_value_len);
+         snprintf(sysctl_name, 31, "hw.dri.%d.name", min);
+
+         drmMsg("Reading sysctl_name (%s)\n", sysctl_name);
+
+         ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len,
+             NULL, 0);
+    }
+
+    if (ret != 0)
+        return (-EINVAL);
+
+    drmMsg("Scanning sysctl_value (%s) using busid_format (%s)\n",
+        sysctl_value, busid_format);
+
+    if (sscanf(sysctl_value, busid_format,
+               &domain, &bus, &dev, &func) != 4)
+        return -EINVAL;
+    
+    info->domain = domain;
+    info->bus = bus;
+    info->dev = dev;
+    info->func = func;
+
+    return 0;
 #else
 #warning "Missing implementation of drmParsePciBusInfo"
     return -EINVAL;
@@ -3051,23 +3239,6 @@ static int drmCompareBusInfo(drmDevicePt
     return -1;
 }
 
-static int drmGetNodeType(const char *name)
-{
-    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
-        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
-        return DRM_NODE_PRIMARY;
-
-    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
-        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
-        return DRM_NODE_CONTROL;
-
-    if (strncmp(name, DRM_RENDER_MINOR_NAME,
-        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
-        return DRM_NODE_RENDER;
-
-    return -EINVAL;
-}
-
 static int drmGetMaxNodeName(void)
 {
     return sizeof(DRM_DIR_NAME) +
@@ -3145,9 +3316,89 @@ static int parse_config_sysfs_file(int m
 }
 #endif
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+/* Uses function of name prefixed by devq_
+ * from libdevq 0.0.4, file src/freebsd/device.c
+ */
+static int
+compare_vgapci_busaddr(int i, int *domain, int *bus, int *slot,
+    int *function)
+{
+    int ret;
+    char sysctl_name[32], sysctl_value[128];
+    size_t sysctl_value_len;
+
+    snprintf(sysctl_name, 31, "dev.vgapci.%d.%%location", i);
+
+    drmMsg("Reading sysctl_name (%s)\n", sysctl_name);
+
+    sysctl_value_len = sizeof(sysctl_value);
+    memset(sysctl_value, 0, sysctl_value_len);
+    ret = sysctlbyname(sysctl_name, sysctl_value,
+        &sysctl_value_len, NULL, 0);
+    if (ret != 0)
+        return (-1);
+
+    drmMsg("Read sysctl_value (%s)\n", sysctl_value);
+
+    /*
+     * dev.vgapci.$m.%location can have two formats:
+     *     o  "pci0:2:0:0 handle=\_SB_.PCI0.PEG3.MXM3" (FreeBSD 11+)
+     *     o  "slot=1 function=0" (DragonFly or up-to FreeBSD 10)
+     */
+
+    ret = sscanf(sysctl_value, "pci%d:%d:%d:%d %*s",
+        domain, bus, slot, function);
+
+    if (ret == 4)
+        drmMsg("compare_vgapci_busaddr(): domain (%d), bus (%d), slot (%d), function (%d)\n",
+            *domain, *bus, *slot, *function);
+
+    if (ret == 4)
+        return (0);
+
+    ret = sscanf(sysctl_value, "slot=%d function=%d %*s",
+        slot, function);
+    if (ret != 2)
+        return (-1);
+
+    snprintf(sysctl_name, 31, "dev.vgapci.%d.%%parent", i);
+
+    drmMsg("Reading sysctl_name (%s)\n", sysctl_name);
+
+    sysctl_value_len = sizeof(sysctl_value);
+    memset(sysctl_value, 0, sysctl_value_len);
+    ret = sysctlbyname(sysctl_name, sysctl_value,
+        &sysctl_value_len, NULL, 0);
+    if (ret != 0)
+        return (-1);
+    
+    drmMsg("Read sysctl_value (%s)\n", sysctl_value);
+
+    ret = sscanf(sysctl_value, "pci%d", bus);
+    if (ret != 1)
+        return (-1);
+
+    /* FIXME: What domain to assume? */
+    *domain = 0;
+
+    drmMsg("compare_vgapci_busaddr(): domain (%d), bus (%d), slot (%d), function (%d)\n",
+        *domain, *bus, *slot, *function);
+
+    return (0);
+}
+#endif
+
+#if !defined(__FreeBSD__) && !defined(__DragonFly__)
 static int drmParsePciDeviceInfo(int maj, int min,
                                  drmPciDeviceInfoPtr device,
                                  uint32_t flags)
+#else
+static int drmParsePciDeviceInfoBSD(int maj, int min,
+                                 drmPciDeviceInfoPtr device,
+                                 drmPciBusInfoPtr info,
+                                 uint32_t flags)
+#endif
 {
 #ifdef __linux__
     if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
@@ -3157,18 +3408,27 @@ static int drmParsePciDeviceInfo(int maj
         return parse_config_sysfs_file(maj, min, device);
 
     return 0;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__NetBSD__)
     struct drm_pciinfo pinfo;
     int fd, type;
 
+    drmMsg("drmParsePciDeviceInfo()\n");
+    drmMsg("Before drmGetMinorType: min (%d)\n", min);
+
     type = drmGetMinorType(min);
     if (type == -1)
         return -ENODEV;
 
+    drmMsg("Before drmOpenMinor: type (%d), DRM_NODE_PRIMARY (%d)\n",
+        type, DRM_NODE_PRIMARY);
+
     fd = drmOpenMinor(min, 0, type);
     if (fd < 0)
         return -errno;
 
+    drmMsg("Before drmIoctl: ioctl (0x%02x) using fd (%d)\n",
+        DRM_IOCTL_GET_PCIINFO, fd);
+
     if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
         close(fd);
         return -errno;
@@ -3182,6 +3442,88 @@ static int drmParsePciDeviceInfo(int maj
     device->subdevice_id = pinfo.subdevice_id;
 
     return 0;
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+/*
+ * Adapted from function devq_device_get_pciid_full_from_fd(),
+ * from libdevq 0.0.4, file src/freebsd/device.c,
+ */
+    unsigned int vendor_id = 0, device_id = 0, subvendor_id = 0, 
+        subdevice_id = 0, revision_id = 0;
+    int i, ret;
+    char sysctl_name[32], sysctl_value[128];
+    size_t sysctl_value_len;
+
+/*
+ * Now, look at all dev.vgapci.$m trees until we find the
+ * correct device. We specifically look at:
+ *     o  dev.vgapci.$m.%location
+ *     o  dev.vgapci.$m.%parent
+ */
+    for (i = 0; i < DRM_MAX_FDS; ++i) {
+        int tmp_domain, tmp_bus, tmp_slot, tmp_function;
+
+        ret = compare_vgapci_busaddr(i, &tmp_domain, &tmp_bus,
+            &tmp_slot, &tmp_function);
+
+        if (ret == 0 &&
+            tmp_domain == info->domain &&
+            tmp_bus == info->bus &&
+            tmp_slot == info->dev &&
+            tmp_function == info->func)
+            break;
+    }
+
+    if (i == DRM_MAX_FDS) {
+        drmMsg("All DRM_MAX_FDS (%d) vgapci tried!\n", DRM_MAX_FDS);
+        errno = ENOENT;
+        return (-1);
+    }
+
+/*
+ * Ok, we have the right tree. Let's read dev.vgapci.$m.%pnpinfo
+ * to gather the PCI ID.
+ */
+    snprintf(sysctl_name, 31, "dev.vgapci.%d.%%pnpinfo", i);
+
+    drmMsg("Reading sysctl_name (%s)\n", sysctl_name);
+
+    sysctl_value_len = sizeof(sysctl_value);
+    memset(sysctl_value, 0, sysctl_value_len);
+    ret = sysctlbyname(sysctl_name, sysctl_value,
+        &sysctl_value_len, NULL, 0);
+    if (ret != 0)
+        return (-1);
+    
+    drmMsg("Read sysctl_value (%s)\n", sysctl_value);
+
+#if defined(__DragonFly__)
+/* DragonFly has a device class field following the subdevice field */
+    ret = sscanf(sysctl_value,
+        "vendor=0x%04x device=0x%04x subvendor=0x%04x subdevice=0x%04x %*s",
+        &vendor_id, &device_id, &subvendor_id, &subdevice_id);
+#else /* FreeBSD */
+    ret = sscanf(sysctl_value,
+        "vendor=0x%04x device=0x%04x subvendor=0x%04x subdevice=0x%04x",
+        &vendor_id, &device_id, &subvendor_id, &subdevice_id);
+    if (ret != 4) {
+        ret = sscanf(sysctl_value,
+            "vendor=0x%04x device=0x%04x subvendor=0x%04x subdevice=0x%04x %*s",
+            &vendor_id, &device_id, &subvendor_id, &subdevice_id);
+    }
+#endif
+    if (ret != 4) {
+        errno = EINVAL;
+        return (-1);
+    }
+
+    device->vendor_id = (uint16_t) vendor_id;
+    device->device_id = (uint16_t) device_id;
+    device->subvendor_id = (uint16_t) subvendor_id;
+    device->subdevice_id = (uint16_t) subdevice_id;
+    /* XXX: add code to find out revision id */
+    device->revision_id = (uint8_t) revision_id;
+
+    return 0;
 #else
 #warning "Missing implementation of drmParsePciDeviceInfo"
     return -EINVAL;
@@ -3299,6 +3641,9 @@ static int drmProcessPciDevice(drmDevice
     char *addr;
     int ret;
 
+    drmMsg("libdrm, file xf86drm.c, drmProcessPciDevice() called\n");
+    drmMsg("    node (%s), node_type (%d)\n", node, node_type);
+
     dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
                          sizeof(drmPciDeviceInfo), &addr);
     if (!dev)
@@ -3308,18 +3653,39 @@ static int drmProcessPciDevice(drmDevice
 
     dev->businfo.pci = (drmPciBusInfoPtr)addr;
 
+    drmMsg("Before drmParsePciBusInfo(): maj (%d), min (%d)\n", maj, min);
     ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
+    drmMsg("After  drmParsePciBusInfo(): return value (%d)\n", ret);
+
     if (ret)
         goto free_device;
 
+    drmMsg("d domain == %04x\n", dev->businfo.pci->domain);
+    drmMsg("d bus    == %02x\n", dev->businfo.pci->bus);
+    drmMsg("d dev    == %02x\n", dev->businfo.pci->dev);
+    drmMsg("d func   == %1u\n",  dev->businfo.pci->func);
+
     // Fetch the device info if the user has requested it
     if (fetch_deviceinfo) {
         addr += sizeof(drmPciBusInfo);
         dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
 
+        drmMsg("Before drmParsePciDeviceInfo(): maj (%d), min (%d), flags (%d)\n",
+            maj, min, flags);
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+        ret = drmParsePciDeviceInfoBSD(maj, min, dev->deviceinfo.pci, dev->businfo.pci, flags);
+#else
         ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
+#endif
         if (ret)
             goto free_device;
+
+            drmMsg("d vendor_id    == %04x\n", dev->deviceinfo.pci->vendor_id);
+            drmMsg("d device_id    == %04x\n", dev->deviceinfo.pci->device_id);
+            drmMsg("d subvendor_id == %04x\n", dev->deviceinfo.pci->subvendor_id);
+            drmMsg("d subdevice_id == %04x\n", dev->deviceinfo.pci->subdevice_id);
+            drmMsg("d revision_id  == %02x\n", dev->deviceinfo.pci->revision_id);
     }
 
     *device = dev;
@@ -3681,6 +4047,35 @@ drm_device_validate_flags(uint32_t flags
         return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
 }
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+/*
+ * XXX temporary workaround, because FreeBSD doesn't provide 
+ * pcibus device sysctl trees for renderD and controlD nodes (yet)
+ * Finds the corresponding /dev/dri/cardn device and also
+ * returns the number n.
+ */
+static int 
+drmBSDDeviceNameHack(const char *path, char *hacked_path, int length,
+                     int node_type)
+{
+    int start, number, base;
+    const char *errstr;
+
+    base = drmGetMinorBase(node_type);
+    if (node_type == DRM_NODE_RENDER) {
+        start = sizeof(DRM_RENDER_MINOR_NAME) - 1;
+    } else if (node_type == DRM_NODE_CONTROL) {
+        start = sizeof(DRM_CONTROL_MINOR_NAME) - 1;
+    } else {
+        start = sizeof(DRM_PRIMARY_MINOR_NAME) - 1;
+    }
+    number = strtonum(&(path[start]), 0, 256, &errstr) - base;
+    snprintf(hacked_path, length, "card%i", number);
+
+    return number;
+}
+#endif
+
 /**
  * Get information about the opened drm device
  *
@@ -3773,6 +4168,15 @@ int drmGetDevice2(int fd, uint32_t flags
     int max_count = 16;
     dev_t find_rdev;
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+    char hacked_path[128];
+#endif
+
+    drmMsg("libdrm, file xf86drm.c, drmGetDevice2(): fd (%d)\n", fd);
+
+    drmMsg("Before drm_device_validate_flags: flags (%d), DRM_DEVICE_GET_PCI_REVISION (%d)\n",
+        flags, DRM_DEVICE_GET_PCI_REVISION);
+
     if (drm_device_validate_flags(flags))
         return -EINVAL;
 
@@ -3786,15 +4190,35 @@ int drmGetDevice2(int fd, uint32_t flags
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
+    drmMsg("DRM_MAJOR (%d), fd maj (%d), min (%d)\n", DRM_MAJOR, maj, min);
+
     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+#if defined(__DragonFly__)
+    {
+        if ((maj_firstseen < 0) && (maj >= 0) && S_ISCHR(sbuf.st_mode)) {
+            maj_firstseen = maj;
+            drmMsg("First seen maj (%d) != DRM_MAJOR (%d)\n", maj, DRM_MAJOR);
+        }
+        else if (maj == maj_firstseen) {
+            drmMsg("maj == maj_firstseen (%d)\n", maj_firstseen);
+        }
+        else {
+            return -EINVAL;
+        }
+    }
+#else
         return -EINVAL;
+#endif
 
     subsystem_type = drmParseSubsystemType(maj, min);
+    drmMsg("fd subsystem_type (%d)\n", subsystem_type);
 
     local_devices = calloc(max_count, sizeof(drmDevicePtr));
     if (local_devices == NULL)
         return -ENOMEM;
 
+    drmMsg("Opening DRM_DIR_NAME (%s)\n", DRM_DIR_NAME);
+
     sysdir = opendir(DRM_DIR_NAME);
     if (!sysdir) {
         ret = -errno;
@@ -3803,26 +4227,65 @@ int drmGetDevice2(int fd, uint32_t flags
 
     i = 0;
     while ((dent = readdir(sysdir))) {
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+        int number;
+#endif
+
+        drmMsg("Examining dent->d_name (%s)\n", dent->d_name);
+
         node_type = drmGetNodeType(dent->d_name);
+
+        drmMsg("Examining node_type (%d)\n", node_type);
+
         if (node_type < 0)
             continue;
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+        number = drmBSDDeviceNameHack(dent->d_name, hacked_path, 127,
+                                          node_type);
+
+        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, hacked_path);
+#else
         snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
+#endif
         if (stat(node, &sbuf))
             continue;
 
         maj = major(sbuf.st_rdev);
         min = minor(sbuf.st_rdev);
 
+        drmMsg("Device node (%s) has maj (%d), min (%d)\n", node, maj, min);
+
+#if defined(__DragonFly__)
+        if (((maj != DRM_MAJOR) && (maj != maj_firstseen)) || (maj < 0) || !S_ISCHR(sbuf.st_mode))
+#else
         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+#endif
             continue;
 
+        drmMsg("    and subsystem_type (%d) compared to DRM_BUS_PCI (%d)\n",
+            drmParseSubsystemType(maj, min), DRM_BUS_PCI);
+
         if (drmParseSubsystemType(maj, min) != subsystem_type)
             continue;
 
         switch (subsystem_type) {
         case DRM_BUS_PCI:
+
+#if defined (__FreeBSD__) || defined(__DragonFly__)
+            drmMsg("Before drmProcessPciDevice(): number (%d), node_type (%d)\n",
+                number, node_type);
+
+            ret = drmProcessPciDevice(&d, node, node_type, maj, number, true, flags);
+#else
+            drmMsg("Before drmProcessPciDevice(): min (%d), node_type (%d)\n",
+                min, node_type);
+
             ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
+#endif
+            drmMsg("After drmProcessPciDevice():  return value (%d)\n", ret);
+
             if (ret)
                 continue;
 
@@ -3938,6 +4401,15 @@ int drmGetDevices2(uint32_t flags, drmDe
     int ret, i, node_count, device_count;
     int max_count = 16;
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+    char hacked_path[128];
+#endif
+
+    drmMsg("libdrm, file xf86drm.c, drmGetDevices2(): max_devices (%d)\n", max_devices);
+
+    drmMsg("Before drm_device_validate_flags: flags (%d), DRM_DEVICE_GET_PCI_REVISION (%d)\n",
+        flags, DRM_DEVICE_GET_PCI_REVISION);
+
     if (drm_device_validate_flags(flags))
         return -EINVAL;
 
@@ -3953,11 +4425,23 @@ int drmGetDevices2(uint32_t flags, drmDe
 
     i = 0;
     while ((dent = readdir(sysdir))) {
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+        int number;
+#endif
+
         node_type = drmGetNodeType(dent->d_name);
         if (node_type < 0)
             continue;
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+        number = drmBSDDeviceNameHack(dent->d_name, hacked_path, 127,
+                                          node_type);
+
+        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, hacked_path);
+#else
         snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
+#endif
         if (stat(node, &sbuf))
             continue;
 
@@ -3965,7 +4449,22 @@ int drmGetDevices2(uint32_t flags, drmDe
         min = minor(sbuf.st_rdev);
 
         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+#if defined(__DragonFly__)
+        {
+            if ((maj_firstseen < 0) && (maj >= 0) && S_ISCHR(sbuf.st_mode)) {
+                maj_firstseen = maj;
+                drmMsg("First seen maj (%d) != DRM_MAJOR (%d)\n", maj, DRM_MAJOR);
+            }
+            else if (maj == maj_firstseen) {
+                drmMsg("maj == maj_firstseen (%d)\n", maj_firstseen);
+            }
+            else {
+                continue;
+            }
+        }
+#else
             continue;
+#endif
 
         subsystem_type = drmParseSubsystemType(maj, min);
 
@@ -3974,8 +4473,13 @@ int drmGetDevices2(uint32_t flags, drmDe
 
         switch (subsystem_type) {
         case DRM_BUS_PCI:
+#if defined (__FreeBSD__) || defined(__DragonFly__)
+            ret = drmProcessPciDevice(&device, node, node_type,
+                                      maj, number, devices != NULL, flags);
+#else
             ret = drmProcessPciDevice(&device, node, node_type,
                                       maj, min, devices != NULL, flags);
+#endif
             if (ret)
                 continue;
 
@@ -4095,6 +4599,21 @@ char *drmGetDeviceNameFromFd2(int fd)
     free(value);
 
     return strdup(path);
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+    struct stat sbuf;
+    char path[64];
+
+    drmMsg("libdrm, file xf86drm.c, drmGetDeviceFromFd2(): fd (%d)\n", fd);
+
+    if (fstat(fd, &sbuf))
+        return NULL;
+
+    snprintf(path, sizeof(path), "/dev/%s",
+             devname(sbuf.st_rdev, S_IFCHR));
+
+    drmMsg("path from devname (%s)\n", path);
+
+    return strdup(path);
 #else
     struct stat      sbuf;
     char             node[PATH_MAX + 1];
