$NetBSD: patch-xf86drm.c,v 1.7 2022/03/13 15:20:01 tnn Exp $

Implement drmParseSubsystemType, drmParsePciBusInfo for NetBSD

--- xf86drm.c.orig	2021-07-02 12:49:05.459105300 +0000
+++ xf86drm.c
@@ -86,7 +86,10 @@
 #endif
 
 #ifdef __NetBSD__
-#define DRM_MAJOR 34
+#define DRM_MAJOR 180
+#include <sys/param.h>
+#include <dev/pci/pcireg.h>
+#include <pci.h>
 #endif
 
 #ifdef __OpenBSD__
@@ -3499,6 +3502,65 @@ static int drmParseSubsystemType(int maj
             return DRM_BUS_VIRTIO;
      }
     return subsystem_type;
+#elif defined(__NetBSD__)
+    int type, fd;
+    drmSetVersion sv;
+    char *buf;
+    unsigned domain, bus, dev;
+    int func;
+    int ret;
+
+    /* Get the type of device we're looking for to pick the right pathname.  */
+    type = drmGetMinorType(maj, min);
+    if (type == -1)
+	return -ENODEV;
+
+    /* Open the device.  Don't try to create it if it's not there.  */
+    fd = drmOpenMinor(min, 0, type);
+    if (fd < 0)
+	return -errno;
+
+    /*
+     * Set the interface version to 1.4 or 1.1, which has the effect of
+     * populating the bus id for us.
+     */
+    sv.drm_di_major = 1;
+    sv.drm_di_minor = 4;
+    sv.drm_dd_major = -1;
+    sv.drm_dd_minor = -1;
+    if (drmSetInterfaceVersion(fd, &sv)) {
+	sv.drm_di_major = 1;
+	sv.drm_di_minor = 1;
+	sv.drm_dd_major = -1;
+	sv.drm_dd_minor = -1;
+	if (drmSetInterfaceVersion(fd, &sv)) {
+	    /*
+	     * We're probably not the master.  Hope the master already
+	     * set the version to >=1.1 so that we can get the busid.
+	     */
+	}
+    }
+
+    /* Get the bus id.  */
+    buf = drmGetBusid(fd);
+
+    /* We're done with the device now.  */
+    (void)close(fd);
+
+    /* If there is no bus id, fail.  */
+    if (buf == NULL)
+	return -ENODEV;
+
+    /* Find a string we know about; otherwise -EINVAL.  */
+    ret = -EINVAL;
+    if (strncmp(buf, "pci:", 4) == 0)
+	ret = DRM_BUS_PCI;
+
+    /* We're done with the bus id.  */
+    free(buf);
+
+    /* Success or not, we're done.  */
+    return ret;
 #elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__)
     return DRM_BUS_PCI;
 #else
@@ -3610,6 +3672,73 @@ static int drmParsePciBusInfo(int maj, i
     info->func = func;
 
     return 0;
+#elif defined(__NetBSD__)
+    int type, fd;
+    drmSetVersion sv;
+    char *buf;
+    unsigned domain, bus, dev;
+    int func;
+    int ret;
+
+    /* Get the type of device we're looking for to pick the right pathname.  */
+    type = drmGetMinorType(maj, min);
+    if (type == -1)
+	return -ENODEV;
+
+    /* Open the device.  Don't try to create it if it's not there.  */
+    fd = drmOpenMinor(min, 0, type);
+    if (fd < 0)
+	return -errno;
+
+    /*
+     * Set the interface version to 1.4 or 1.1, which has the effect of
+     * populating the bus id for us.
+     */
+    sv.drm_di_major = 1;
+    sv.drm_di_minor = 4;
+    sv.drm_dd_major = -1;
+    sv.drm_dd_minor = -1;
+    if (drmSetInterfaceVersion(fd, &sv)) {
+	sv.drm_di_major = 1;
+	sv.drm_di_minor = 1;
+	sv.drm_dd_major = -1;
+	sv.drm_dd_minor = -1;
+	if (drmSetInterfaceVersion(fd, &sv)) {
+            /*
+	     * We're probably not the master.  Hope the master already
+	     * set the version to >=1.1 so that we can get the busid.
+	     */
+	}
+    }
+
+    /* Get the bus id.  */
+    buf = drmGetBusid(fd);
+
+    /* We're done with the device now.  */
+    (void)close(fd);
+
+    /* If there is no bus id, fail.  */
+    if (buf == NULL)
+	return -ENODEV;
+
+    /* Parse the bus id.  */
+    ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
+
+    /* We're done with the bus id.  */
+    free(buf);
+
+    /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail.  */
+    if (ret != 4)
+	return -ENODEV;
+
+    /* Populate the results.  */
+    info->domain = domain;
+    info->bus = bus;
+    info->dev = dev;
+    info->func = func;
+
+    /* Success!  */
+    return 0;
 #elif defined(__OpenBSD__) || defined(__DragonFly__)
     struct drm_pciinfo pinfo;
     int fd, type;
@@ -3778,6 +3907,48 @@ static int drmParsePciDeviceInfo(int maj
         return parse_config_sysfs_file(maj, min, device);
 
     return 0;
+#elif defined(__NetBSD__)
+    drmPciBusInfo businfo;
+    char fname[PATH_MAX];
+    int pcifd;
+    pcireg_t id, class, subsys;
+    int ret;
+
+    /* Find where on the bus the device lives.  */
+    ret = drmParsePciBusInfo(maj, min, &businfo);
+    if (ret)
+	return ret;
+
+    /* Open the pciN device node to get at its config registers.  */
+    if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain)
+	>= sizeof fname)
+	return -ENODEV;
+    if ((pcifd = open(fname, O_RDONLY)) == -1)
+	return -errno;
+
+    ret = -1;
+    /* Read the id and class pci config registers.  */
+    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
+	    PCI_ID_REG, &id) == -1)
+	goto out;
+    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
+	    PCI_CLASS_REG, &class) == -1)
+	goto out;
+    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
+	    PCI_SUBSYS_ID_REG, &subsys) == -1)
+	goto out;
+
+    ret = 0;
+    device->vendor_id = PCI_VENDOR(id);
+    device->device_id = PCI_PRODUCT(id);
+    device->subvendor_id = PCI_SUBSYS_VENDOR(subsys);
+    device->subdevice_id = PCI_SUBSYS_ID(subsys);
+    device->revision_id = PCI_REVISION(class);
+out:
+    if (ret == -1)
+	ret = -errno;
+    close(pcifd);
+    return ret;
 #elif defined(__OpenBSD__) || defined(__DragonFly__)
     struct drm_pciinfo pinfo;
     int fd, type;
