[bus,driver] Move attach_fdo into driver module
authorShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Sat, 11 Dec 2010 17:50:34 +0000 (12:50 -0500)
committerShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Sat, 11 Dec 2010 18:44:49 +0000 (13:44 -0500)
attach_fdo is really a _driver_ thing, rather than a
_bus_ thing, so we move it into the driver module as
driver__attach_fdo_().

This allows us to remove bus module initialization,
meaning the bus module should be purely library now.

Our driver's AddDevice routine (driver__attach_fdo_) is
hard-coded to only attach a maximum of one FDO, which
will be the main WinVBlock bus.  This could change later.

src/winvblock/bus/bus.c
src/winvblock/driver.c

index 1f9ee1b..f113cf8 100644 (file)
 #include "bus_dev_ctl.h"
 #include "debug.h"
 
-/* Globals. */
-static LIST_ENTRY bus__list_;
-static KSPIN_LOCK bus__list_lock_;
-winvblock__bool bus__module_up_ = FALSE;
-
 /* Forward declarations. */
 static device__free_func bus__free_;
 static device__create_pdo_func bus__create_pdo_;
 
-/**
- * Tear down the global, bus-common environment.
- */
-void bus__module_shutdown(void) {
-
-    DBG("Entry\n");
-    bus__module_up_ = FALSE;
-    DBG("Exit\n");
-    return;
-  }
-
 /**
  * Add a child node to the bus.
  *
@@ -75,10 +59,6 @@ winvblock__lib_func winvblock__bool STDCALL bus__add_child(
     device__type_ptr walker;
 
     DBG("Entry\n");
-    if (!bus__module_up_) {
-        DBG("Bus module not initialized.\n");
-        return FALSE;
-      }
     if ((bus_ptr == NULL) || (dev_ptr == NULL)) {
         DBG("No bus or no device!\n");
         return FALSE;
@@ -204,95 +184,6 @@ NTSTATUS STDCALL bus__get_dev_capabilities(
     return status;
   }
 
-static NTSTATUS STDCALL attach_fdo(
-    IN PDRIVER_OBJECT DriverObject,
-    IN PDEVICE_OBJECT PhysicalDeviceObject
-  ) {
-    PLIST_ENTRY walker;
-    struct bus__type * bus_ptr;
-    NTSTATUS status;
-    PUNICODE_STRING dev_name = NULL;
-    PDEVICE_OBJECT fdo = NULL;
-    device__type_ptr dev_ptr;
-
-    DBG("Entry\n");
-    /* Search for the associated bus. */
-    walker = bus__list_.Flink;
-    while (walker != &bus__list_) {
-        bus_ptr = CONTAINING_RECORD(walker, struct bus__type, tracking);
-        if (bus_ptr->PhysicalDeviceObject == PhysicalDeviceObject)
-          break;
-        walker = walker->Flink;
-      }
-    /* If we get back to the list head, we need to create a bus. */
-    if (walker == &bus__list_) {
-        DBG("No bus->PDO association.  Creating a new bus\n");
-        bus_ptr = bus__create();
-        if (bus_ptr == NULL) {
-            return Error(
-                "Could not create a bus!\n",
-                STATUS_INSUFFICIENT_RESOURCES
-              );
-          }
-      }
-    /* This bus might have an associated name. */
-    if (bus_ptr->named)
-      dev_name = &bus_ptr->dev_name;
-    /* Create the bus FDO. */
-    status = IoCreateDevice(
-        DriverObject,
-        sizeof (driver__dev_ext),
-        dev_name,
-        FILE_DEVICE_CONTROLLER,
-        FILE_DEVICE_SECURE_OPEN,
-        FALSE,
-        &fdo
-      );
-    if (!NT_SUCCESS(status)) {
-        device__free(bus_ptr->device);
-        return Error("IoCreateDevice", status);
-      }
-    /* DosDevice symlink. */
-    if (bus_ptr->named) {
-        status = IoCreateSymbolicLink(
-            &bus_ptr->dos_dev_name,
-            &bus_ptr->dev_name
-          );
-      }
-    if (!NT_SUCCESS(status)) {
-        IoDeleteDevice(fdo);
-        device__free(bus_ptr->device);
-        return Error("IoCreateSymbolicLink", status);
-      }
-
-    /* Set associations for the bus, device, FDO, PDO. */
-    dev_ptr = bus_ptr->device;
-    device__set(fdo, dev_ptr);
-    dev_ptr->Self = fdo;
-
-    bus_ptr->PhysicalDeviceObject = PhysicalDeviceObject;
-    fdo->Flags |= DO_DIRECT_IO;         /* FIXME? */
-    fdo->Flags |= DO_POWER_INRUSH;      /* FIXME? */
-    /* Add the bus to the device tree. */
-    if (PhysicalDeviceObject != NULL) {
-        bus_ptr->LowerDeviceObject = IoAttachDeviceToDeviceStack(
-            fdo,
-            PhysicalDeviceObject
-          );
-        if (bus_ptr->LowerDeviceObject == NULL) {
-            IoDeleteDevice(fdo);
-            device__free(bus_ptr->device);
-            return Error("IoAttachDeviceToDeviceStack", STATUS_NO_SUCH_DEVICE);
-          }
-      }
-    fdo->Flags &= ~DO_DEVICE_INITIALIZING;
-    #ifdef RIS
-    dev_ptr->State = Started;
-    #endif
-    DBG("Exit\n");
-    return STATUS_SUCCESS;
-  }
-
 /* Bus dispatch routine. */
 static NTSTATUS STDCALL bus_dispatch(
     IN PDEVICE_OBJECT dev,
@@ -367,10 +258,6 @@ winvblock__lib_func struct bus__type * bus__create(void) {
     device__type_ptr dev_ptr;
     struct bus__type * bus_ptr;
 
-    if (!bus__module_up_) {
-        DBG("Bus module not initialized.\n");
-        return NULL;
-      }
     /* Try to create a device. */
     dev_ptr = device__create();
     if (dev_ptr == NULL)
@@ -382,12 +269,6 @@ winvblock__lib_func struct bus__type * bus__create(void) {
     bus_ptr = wv_mallocz(sizeof *bus_ptr);
     if (bus_ptr == NULL)
       goto err_nobus;
-    /* Track the new bus in our global list. */
-    ExInterlockedInsertTailList(
-        &bus__list_,
-        &bus_ptr->tracking,
-        &bus__list_lock_
-      );
     /* Populate non-zero device defaults. */
     bus_ptr->device = dev_ptr;
     bus_ptr->prev_free = dev_ptr->ops.free;
@@ -476,24 +357,6 @@ static PDEVICE_OBJECT STDCALL bus__create_pdo_(IN device__type_ptr dev) {
     return NULL;
   }
 
-/**
- * Initialize the global, bus-common environment.
- *
- * @ret ntstatus        STATUS_SUCCESS or the NTSTATUS for a failure.
- */
-NTSTATUS bus__module_init(void) {
-    struct bus__type * boot_bus_ptr;
-
-    /* Initialize the global list of devices. */
-    InitializeListHead(&bus__list_);
-    KeInitializeSpinLock(&bus__list_lock_);
-    /* We handle AddDevice call-backs for the driver. */
-    driver__obj_ptr->DriverExtension->AddDevice = attach_fdo;
-    bus__module_up_ = TRUE;
-
-    return STATUS_SUCCESS;
-  }
-
 /**
  * Default bus deletion operation.
  *
@@ -503,12 +366,6 @@ static void STDCALL bus__free_(IN device__type_ptr dev_ptr) {
     struct bus__type * bus_ptr = bus__get(dev_ptr);
     /* Free the "inherited class". */
     bus_ptr->prev_free(dev_ptr);
-    /*
-     * Track the bus deletion in our global list.  Unfortunately,
-     * for now we have faith that a bus won't be deleted twice and
-     * result in a race condition.  Something to keep in mind...
-     */
-    ExInterlockedRemoveHeadList(bus_ptr->tracking.Blink, &bus__list_lock_);
 
     wv_free(bus_ptr);
   }
index 51ce83c..d998342 100644 (file)
@@ -50,6 +50,7 @@ PDRIVER_OBJECT driver__obj_ptr = NULL;
 static void * driver__state_handle_;
 static winvblock__bool driver__started_ = FALSE;
 static PDEVICE_OBJECT driver__bus_fdo_ = NULL;
+static KSPIN_LOCK driver__bus_fdo_lock_;
 /* Contains TXTSETUP.SIF/BOOT.INI-style OsLoadOptions parameters. */
 static LPWSTR driver__os_load_opts_ = NULL;
 
@@ -113,12 +114,26 @@ static LPWSTR STDCALL get_opt(IN LPWSTR opt_name) {
     return the_opt;
   }
 
-/* Create the root-enumerated, main bus device. */
-NTSTATUS STDCALL driver__create_bus_(void) {
-    struct bus__type * bus;
+static NTSTATUS STDCALL driver__attach_fdo_(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDEVICE_OBJECT PhysicalDeviceObject
+  ) {
+    KIRQL irql;
     NTSTATUS status;
-    PDEVICE_OBJECT bus_pdo = NULL;
+    PLIST_ENTRY walker;
+    struct bus__type * bus;
+    PUNICODE_STRING dev_name = NULL;
+    PDEVICE_OBJECT fdo = NULL;
+    device__type_ptr dev_ptr;
 
+    DBG("Entry\n");
+    /* Do we alreay have our main bus? */
+    if (driver__bus_fdo_) {
+        DBG("Already have the main bus.  Refusing.\n");
+        status = STATUS_NOT_SUPPORTED;
+        goto err_already_established;
+      }
+    /* Create the bus. */
     bus = bus__create();
     if (!bus) {
         DBG("bus__create() failed for the main bus.\n");
@@ -135,6 +150,87 @@ NTSTATUS STDCALL driver__create_bus_(void) {
         L"\\DosDevices\\" winvblock__literal_w
       );
     bus->named = TRUE;
+    /* Create the bus FDO. */
+    status = IoCreateDevice(
+        DriverObject,
+        sizeof (driver__dev_ext),
+        &bus->dev_name,
+        FILE_DEVICE_CONTROLLER,
+        FILE_DEVICE_SECURE_OPEN,
+        FALSE,
+        &fdo
+      );
+    if (!NT_SUCCESS(status)) {
+        DBG("IoCreateDevice() failed!\n");
+        goto err_fdo;
+      }
+    /* DosDevice symlink. */
+    status = IoCreateSymbolicLink(
+        &bus->dos_dev_name,
+        &bus->dev_name
+      );
+    if (!NT_SUCCESS(status)) {
+        DBG("IoCreateSymbolicLink() failed!\n");
+        goto err_dos_symlink;
+      }
+    /* Set associations for the bus, device, FDO, PDO. */
+    device__set(fdo, bus->device);
+    bus->device->Self = fdo;
+    bus->PhysicalDeviceObject = PhysicalDeviceObject;
+    fdo->Flags |= DO_DIRECT_IO;         /* FIXME? */
+    fdo->Flags |= DO_POWER_INRUSH;      /* FIXME? */
+    /* Attach the FDO to the PDO. */
+    bus->LowerDeviceObject = IoAttachDeviceToDeviceStack(
+        fdo,
+        PhysicalDeviceObject
+      );
+    if (bus->LowerDeviceObject == NULL) {
+        status = STATUS_NO_SUCH_DEVICE;
+        DBG("IoAttachDeviceToDeviceStack() failed!\n");
+        goto err_attach;
+      }
+    /* Ok! */
+    KeAcquireSpinLock(&driver__bus_fdo_lock_, &irql);
+    if (driver__bus_fdo_) {
+        KeReleaseSpinLock(&driver__bus_fdo_lock_, irql);
+        DBG("Beaten to it!\n");
+        status = STATUS_NOT_SUPPORTED;
+        goto err_race_failed;
+      }
+    fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+    #ifdef RIS
+    bus->device->State = Started;
+    #endif
+    driver__bus_fdo_ = fdo;
+    KeReleaseSpinLock(&driver__bus_fdo_lock_, irql);
+    DBG("Exit\n");
+    return STATUS_SUCCESS;
+
+    err_race_failed:
+
+    err_attach:
+
+    IoDeleteSymbolicLink(&bus->dos_dev_name);
+    err_dos_symlink:
+
+    IoDeleteDevice(fdo);
+    err_fdo:
+
+    device__free(bus->device);
+    err_bus:
+
+    err_already_established:
+
+    DBG("Exit with failure\n");
+    return status;
+  }
+
+/* Create the root-enumerated, main bus device. */
+NTSTATUS STDCALL driver__create_bus_(void) {
+    struct bus__type * bus;
+    NTSTATUS status;
+    PDEVICE_OBJECT bus_pdo = NULL;
+
     /* Create the PDO. */
     IoReportDetectedDevice(
         driver__obj_ptr,
@@ -151,26 +247,13 @@ NTSTATUS STDCALL driver__create_bus_(void) {
         status = STATUS_UNSUCCESSFUL;
         goto err_driver_bus;
       }
-    /* We have a PDO.  Note it.  We need this in order to attach the FDO. */
-    bus->PhysicalDeviceObject = bus_pdo;
-    /*
-     * Attach FDO to PDO. *sigh*  Note that we do not own the PDO,
-     * so we must associate the bus structure with the FDO, instead.
-     * Consider that the AddDevice()/attach_fdo() routine takes two parameters,
-     * neither of which are guaranteed to be owned by a caller in this driver.
-     * Since attach_fdo() associates a bus device, it is forced to walk our
-     * global list of bus devices.  Otherwise, it would be easy to pass it here
-     */
-    status = driver__obj_ptr->DriverExtension->AddDevice(
-        driver__obj_ptr,
-        bus_pdo
-      );
+    /* Attach FDO to PDO. */
+    status = driver__attach_fdo_(driver__obj_ptr, bus_pdo);
     if (!NT_SUCCESS(status)) {
-        DBG("attach_fdo() went wrong!\n");
+        DBG("driver__attach_fdo_() went wrong!\n");
         goto err_add_dev;
       }
-    /* Bus created, PDO created, FDO attached.  All done. */
-    driver__bus_fdo_ = bus->device->Self;
+    /* PDO created, FDO attached.  All done. */
     return STATUS_SUCCESS;
 
     err_add_dev:
@@ -178,9 +261,6 @@ NTSTATUS STDCALL driver__create_bus_(void) {
     IoDeleteDevice(bus_pdo);
     err_driver_bus:
 
-    device__free(bus->device);
-    err_bus:
-
     return status;
   }
 
@@ -209,6 +289,7 @@ NTSTATUS STDCALL DriverEntry(
       return Error("registry__note_driver__os_load_opts", status);
 
     driver__state_handle_ = NULL;
+    KeInitializeSpinLock(&driver__bus_fdo_lock_);
 
     if ((driver__state_handle_ = PoRegisterSystemState(
         NULL,
@@ -231,9 +312,10 @@ NTSTATUS STDCALL DriverEntry(
     DriverObject->MajorFunction[IRP_MJ_SCSI] = driver__dispatch_;
     /* Set the driver Unload callback. */
     DriverObject->DriverUnload = driver__unload_;
+    /* Set the driver AddDevice callback. */
+    DriverObject->DriverExtension->AddDevice = driver__attach_fdo_;
     /* Initialize various modules. */
     device__init();             /* TODO: Check for error. */
-    bus__module_init();         /* TODO: Check for error. */
     disk__init();               /* TODO: Check for error. */
     filedisk__init();           /* TODO: Check for error. */
     ramdisk__init();            /* TODO: Check for error. */
@@ -396,7 +478,6 @@ static void STDCALL driver__unload_(IN PDRIVER_OBJECT DriverObject) {
       );
     IoDeleteSymbolicLink(&DosDeviceName);
     driver__bus_fdo_ = NULL;
-    bus__module_shutdown();
     wv_free(driver__os_load_opts_);
     driver__started_ = FALSE;
     DBG("Done\n");