summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/sys/include/io/pci/pci.h14
-rw-r--r--src/sys/io/pci/pci.c80
2 files changed, 94 insertions, 0 deletions
diff --git a/src/sys/include/io/pci/pci.h b/src/sys/include/io/pci/pci.h
index bc39647..cff5f0a 100644
--- a/src/sys/include/io/pci/pci.h
+++ b/src/sys/include/io/pci/pci.h
@@ -58,6 +58,20 @@ struct pci_device {
TAILQ_ENTRY(pci_device) link;
};
+typedef enum {
+ PCI_LU_VENDEV, /* Vendor / device */
+ PCI_LU_CLASSREV, /* Class / subclass */
+} lookup_type_t;
+
+/*
+ * Lookup a device on the PCI(e) bus by using the pci_descriptor
+ * as a lookup key.
+ *
+ * @lookup: Lookup descriptor that must match a device
+ * @type: Lookup type
+ */
+int pci_bus_lookup(struct pci_device *lookup, lookup_type_t type);
+
/*
* Read from a specific register on a specific PCI
* enabled device.
diff --git a/src/sys/io/pci/pci.c b/src/sys/io/pci/pci.c
index 6385c6e..bce6108 100644
--- a/src/sys/io/pci/pci.c
+++ b/src/sys/io/pci/pci.c
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/errno.h>
#include <sys/cdefs.h>
#include <sys/queue.h>
#include <sys/panic.h>
@@ -51,6 +52,52 @@ static TAILQ_HEAD(, pci_device) devlist;
static struct cam_hook cam;
/*
+ * Lookup hook for matching vendor and device IDs
+ *
+ * @vda: Vendor device (A)
+ * @vdb: Vendor device (B)
+ *
+ * Returns zero on match
+ */
+static int
+pci_vd_match(struct pci_device *vda, struct pci_device *vdb)
+{
+ if (vda == NULL || vdb == NULL)
+ return -EINVAL;
+
+ /* The actual match */
+ if (vda->device != vdb->device)
+ return -1;
+ if (vda->vendor != vdb->vendor);
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Lookup hook for matching class and subclass IDs
+ *
+ * @csa: Class / subclass (A)
+ * @csb: Class / subclass (B)
+ *
+ * Returns zero on match
+ */
+static int
+pci_cs_match(struct pci_device *csa, struct pci_device *csb)
+{
+ if (csa == NULL || csb == NULL)
+ return -EINVAL;
+
+ /* Do the actual match */
+ if (csa->class != csb->class)
+ return -1;
+ if (csa->subclass != csb->subclass)
+ return -1;
+
+ return 0;
+}
+
+/*
* Attempt to register a PCI device and bail
* if it doesn't exist on the bus.
*/
@@ -156,6 +203,39 @@ pci_enum_bus(uint16_t bus)
}
/*
+ * Lookup devices on the PCI bus
+ */
+int
+pci_bus_lookup(struct pci_device *lookup, lookup_type_t type)
+{
+ struct pci_device *dp;
+ int cmp = -1;
+
+ if (lookup == NULL) {
+ return -EINVAL;
+ }
+
+ TAILQ_FOREACH(dp, &devlist, link) {
+ switch (type) {
+ case PCI_LU_CLASSREV:
+ cmp = pci_cs_match(lookup, dp);
+ break;
+ case PCI_LU_VENDEV:
+ cmp = pci_vd_match(lookup, dp);
+ break;
+ }
+
+ /* Does it match? */
+ if (cmp == 0) {
+ *lookup = *dp;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+/*
* Read from a specific register
*/
pcireg_t