Add pci_device_drivers, IDE driver
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 1552d82..436339a 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -8,12 +8,12 @@
                 "${workspaceFolder}/include/kernel",
                 "${workspaceFolder}/src/kernel"
             ],
-            "defines": [],
+            "defines": [
+                "TEST_PCI"
+            ],
             "compilerPath": "/usr/bin/gcc",
             "cStandard": "c11",
-            // "cppStandard": "c++14",
             "intelliSenseMode": "linux-gcc-x86",
-            // "compileCommands": "${workspaceFolder}/compile_commands.json",
             "compilerArgs": [
                 "-nostdinc -nostdlib -O2 -m32 -g"
             ]
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 36e5778..a79fd77 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
 {
-    "restructuredtext.confPath": "${workspaceFolder}/doc"
+    "restructuredtext.confPath": "${workspaceFolder}/doc",
+    "restructuredtext.languageServer.disabled": true
 }
\ No newline at end of file
diff --git a/src/kernel/alloc.h b/include/kernel/alloc.h
similarity index 100%
rename from src/kernel/alloc.h
rename to include/kernel/alloc.h
diff --git a/include/kernel/dri/ide/ide.h b/include/kernel/dri/ide/ide.h
new file mode 100644
index 0000000..0283999
--- /dev/null
+++ b/include/kernel/dri/ide/ide.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <dri/pci/pci.h>
+
+void ide_register();
diff --git a/include/kernel/dri/pci/pci.h b/include/kernel/dri/pci/pci.h
index 5791674..b4c21f1 100644
--- a/include/kernel/dri/pci/pci.h
+++ b/include/kernel/dri/pci/pci.h
@@ -17,7 +17,23 @@
 	bool valid;
 };
 
+struct pci_device_driver
+{
+	bool (* supports)(struct pci_device *dev);
+	void (* init)(struct pci_device dev, uchar bus, uchar slot, uchar func);
+	char *generic_name;
+	uint loaded; // reserved
+	struct pci_device dev; // reserved
+};
+
+// Call this first
+void pci_init();
+// Call this after registering drivers to load them
+void pci_load();
+
 // offset is in dwords
 uint pci_config_readd(uchar bus, uchar slot, uchar func, uchar offset);
 struct pci_device pci_check_device(uchar bus, uchar slot, uchar func);
 void pci_print_devices();
+void pci_register_device_driver(struct pci_device_driver driver);
+void pci_print_drivers();
diff --git a/src/kernel/task.h b/include/kernel/task.h
similarity index 100%
rename from src/kernel/task.h
rename to include/kernel/task.h
diff --git a/src/kernel/Jmk b/src/kernel/Jmk
index ddbc343..3759fd6 100644
--- a/src/kernel/Jmk
+++ b/src/kernel/Jmk
@@ -13,6 +13,7 @@
 depends(initrd, $(ROOT)/boot/initrd, initrd.img)
 depends(ata_pio, dri/ata_pio, ata_pio.a)
 depends(pci, dri/pci, pci.a)
+depends(ide, dri/ide, ide.a)
 # AHCI not yet implemented
 # depends(ahci, dri/ahci, ahci.a)
 
@@ -49,7 +50,8 @@
 			task_api.o \
 			faults.o \
 			lib(ata_pio) \
-			lib(pci)
+			lib(pci) \
+			lib(ide)
 
 type(custom_link)
 
diff --git a/src/kernel/dri/ide/Jmk b/src/kernel/dri/ide/Jmk
new file mode 100644
index 0000000..675af5a
--- /dev/null
+++ b/src/kernel/dri/ide/Jmk
@@ -0,0 +1,17 @@
+init(ide, ide.a)
+
+preset(freestanding)
+preset(optimize)
+preset(debug)
+preset(32)
+preset(warn)
+
+archetype(c)
+
+CFLAGS += -I$(ROOT)/include/kernel
+
+OBJECTS = ide.o
+
+type(static_lib)
+
+finish
diff --git a/src/kernel/dri/ide/ide.c b/src/kernel/dri/ide/ide.c
new file mode 100644
index 0000000..c5a5241
--- /dev/null
+++ b/src/kernel/dri/ide/ide.c
@@ -0,0 +1,42 @@
+#include <dri/ide/ide.h>
+#include <task.h>
+#include <alloc.h>
+
+struct ide_thread_data
+{
+    struct pci_device dev;
+    uchar bus, slot, func;
+};
+
+bool ide_supports(struct pci_device *dev)
+{
+    return dev->class == 1 && dev->subclass == 1;
+}
+
+void ide_thread(struct ide_thread_data *data)
+{
+    kprintf("IDE driver thread starting: device=0x%x\n", data->dev.device_id);
+}
+
+void ide_init(struct pci_device dev, uchar bus, uchar slot, uchar func)
+{
+    struct ide_thread_data *data = malloc(sizeof(struct ide_thread_data));
+    data->dev = dev;
+    data->bus = bus;
+    data->slot = slot;
+    data->func = func;
+
+    spawn_thread(ide_thread, data);
+}
+
+void ide_register()
+{
+    struct pci_device_driver dri =
+    {
+        .supports = ide_supports,
+        .init = ide_init,
+        .generic_name = "IDE Controller",
+    };
+
+    pci_register_device_driver(dri);
+}
diff --git a/src/kernel/dri/pci/pci.c b/src/kernel/dri/pci/pci.c
index a5416b6..6d35edc 100644
--- a/src/kernel/dri/pci/pci.c
+++ b/src/kernel/dri/pci/pci.c
@@ -2,40 +2,51 @@
 #include <dri/pci/vendors.h>
 #include <io.h>
 #include <log.h>
+#include <alloc.h>
+
+static uint num_drivers, size_drivers;
+static struct pci_device_driver *drivers;
 
 uint pci_config_readd(uchar bus, uchar slot, uchar func, uchar offset)
 {
-	uint address = (bus << 16) | (slot << 11) | (func << 8) | (offset << 2) | 0x80000000;
+	uint address =
+		(bus << 16) | (slot << 11) | (func << 8) | (offset << 2) | 0x80000000;
 
 	outl(PCI_CONFIG_ADDRESS, address);
 
 	return inl(PCI_CONFIG_DATA);
 }
 
-struct pci_vendor *pci_check_vendor(uchar bus, uchar slot, uchar func, ushort *v, ushort *d)
+struct pci_device pci_check_device(uchar bus, uchar slot, uchar func)
 {
 	uint vendor_device = pci_config_readd(bus, slot, func, 0);
 	ushort vendor = vendor_device & 0xffff;
 
-	if (v)
-		*v = vendor;
+	struct pci_device device;
+	device.valid = false;
 
 	if (vendor != 0xffff)
 	{
-		if (d)
-			*d = vendor_device >> 16;
+		device.valid = true;
 
-		return pci_vendor_by_id(vendor);
+		device.device_id = vendor_device >> 16;
+		device.vendor = pci_vendor_by_id(vendor);
+
+		// 3rd dword
+		uint class_subclass = pci_config_readd(bus, slot, func, 2);
+		device.class = class_subclass >> 24;
+		device.subclass = (class_subclass >> 16) & 0xff;
+		device.prog_if = (class_subclass >> 8) & 0xff;
 	}
-	return NULL;
+
+	return device;
 }
 
 struct pci_vendor *pci_vendor_by_id(ushort id)
 {
 	// Find vendor using binary search
 
-	uint start = 0, 
-		max = pci_num_vendors;
+	uint start = 0, max = pci_num_vendors;
 
 	while (true)
 	{
@@ -63,15 +74,73 @@
 		{
 			for (int func = 0; func < 8; func++)
 			{
-				ushort vendor, device;
+				struct pci_device dev = pci_check_device(bus, slot, func);
 
-				struct pci_vendor *v = pci_check_vendor(bus, slot, func, &vendor, &device);
-
-				if (v)
+				if (dev.valid)
 				{
-					kprintf("%d %d %d --- v:0x%x d:0x%x --- %s\n", bus, slot, func, vendor, device, v->name);
+					kprintf("%d %d %d --- d:0x%x --- %d:%d:%d --- %s\n", bus,
+							slot, func, dev.device_id, dev.class, dev.subclass,
+							dev.prog_if, dev.vendor->name);
 				}
 			}
 		}
 	}
 }
+
+void pci_register_device_driver(struct pci_device_driver driver)
+{
+	if (num_drivers == size_drivers)
+	{
+		size_drivers += 8;
+		drivers = realloc(drivers, sizeof(struct pci_device_driver) * size_drivers);
+	}
+
+	driver.loaded = 0;
+	drivers[num_drivers++] = driver;
+}
+
+void pci_init()
+{
+	num_drivers = 0;
+	size_drivers = 4;
+	drivers = malloc(sizeof(struct pci_device_driver) * size_drivers);
+}
+
+void pci_load()
+{
+	for (int bus = 0; bus < 0xff; bus++)
+	{
+		for (int slot = 0; slot < 32; slot++)
+		{
+			for (int func = 0; func < 8; func++)
+			{
+				struct pci_device dev = pci_check_device(bus, slot, func);
+
+				// Do any drivers support this?
+
+				for (int i = 0; i < num_drivers; i++)
+				{
+					if (drivers[i].supports(&dev))
+					{
+						drivers[i].loaded++;
+						drivers[i].dev = dev;
+						drivers[i].init(dev, bus, slot, func);
+					}
+				}
+			}
+		}
+	}
+}
+
+void pci_print_drivers()
+{
+	kprintf("Enumerating PCI device drivers:\n");
+	for (int i = 0; i < num_drivers; i++)
+	{
+		for (int j = 0; j < drivers[i].loaded; j++)
+		{
+			struct pci_device_driver d = drivers[i];
+			kprintf("Driver: %s, vendor: %s\n", d.generic_name, d.dev.vendor->name);
+		}
+	}
+}
diff --git a/src/kernel/main.c b/src/kernel/main.c
index bc40ff8..b973b41 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -12,6 +12,7 @@
 #include "vga.h"
 #include <dri/ata_pio/ata_pio.h>
 #include <dri/pci/pci.h>
+#include <dri/ide/ide.h>
 
 void greet()
 {
@@ -80,6 +81,13 @@
 	init_tasks();
 	kprintf("\ndone initializing tasks\n");
 
+	pci_init();
+
+	// Register PCI drivers
+	ide_register();
+
+	pci_load();
+
 #ifdef TEST_THREADS
 	spawn_thread(other_thread, NULL);
 
@@ -92,6 +100,7 @@
 
 #ifdef TEST_PCI
 	pci_print_devices();
+	pci_print_drivers();
 #endif
 
 	while (true)