[driver,dummy] Move dummy device feature into dummy.[c,h]
authorShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Sun, 2 Jan 2011 20:57:50 +0000 (15:57 -0500)
committerShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Sun, 2 Jan 2011 21:41:22 +0000 (16:41 -0500)
WinVBlock.dev
src/aoe/bus.c
src/aoe/driver.c
src/include/driver.h
src/include/dummy.h [new file with mode: 0644]
src/winvblock/driver.c
src/winvblock/dummy.c [new file with mode: 0644]
src/winvblock/makedriver.bat

index 9480573..4f54346 100644 (file)
@@ -1,7 +1,7 @@
 [Project]\r
 FileName=WinVBlock.dev\r
 Name=WinVBlock\r
-UnitCount=63\r
+UnitCount=65\r
 PchHead=-1\r
 PchSource=-1\r
 Ver=3\r
@@ -612,7 +612,7 @@ OverrideBuildCmd=0
 BuildCmd=\r
 \r
 [Unit64]\r
-FileName=src\include\aoe_bus.h\r
+FileName=src\include\dummy.h\r
 CompileCpp=1\r
 Folder=Include\r
 Compile=1\r
@@ -622,9 +622,9 @@ OverrideBuildCmd=0
 BuildCmd=\r
 \r
 [Unit65]\r
-FileName=src\aoe\bus.c\r
+FileName=src\winvblock\dummy.c\r
 CompileCpp=1\r
-Folder=AoE\r
+Folder=WinVBlock\r
 Compile=1\r
 Link=1\r
 Priority=1000\r
index 4bc1acc..972a1b9 100644 (file)
@@ -30,9 +30,9 @@
 #include "winvblock.h"
 #include "wv_stdlib.h"
 #include "irp.h"
-#include "driver.h"
 #include "bus.h"
 #include "device.h"
+#include "dummy.h"
 #include "aoe.h"
 #include "mount.h"
 #include "debug.h"
@@ -63,7 +63,7 @@ static UNICODE_STRING AoeBusDosname_ = {
     sizeof AOE_M_BUS_DOSNAME_ - sizeof (WCHAR),
     AOE_M_BUS_DOSNAME_
   };
-const WV_S_DRIVER_DUMMY_IDS * AoeBusDummyIds;
+const WV_S_DUMMY_IDS * AoeBusDummyIds;
 
 static NTSTATUS STDCALL AoeBusDevCtlDetach_(IN PIRP irp) {
     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
@@ -142,7 +142,7 @@ NTSTATUS STDCALL AoeBusDevCtl(
   X_(Y_, Instance, L"0"                 ) \
   X_(Y_, Hardware, WVL_M_WLIT L"\\AoE\0") \
   X_(Y_, Compat,   WVL_M_WLIT L"\\AoE\0")
-WV_M_DRIVER_DUMMY_ID_GEN(AoeBusDummyIds_, AOE_M_BUS_IDS);
+WV_M_DUMMY_ID_GEN(AoeBusDummyIds_, AOE_M_BUS_IDS);
 
 /* Destroy the AoE bus. */
 VOID AoeBusFree(void) {
index 9ac9828..432fea6 100644 (file)
@@ -34,9 +34,9 @@
 #include "wv_stdlib.h"
 #include "wv_string.h"
 #include "irp.h"
-#include "driver.h"
 #include "bus.h"
 #include "device.h"
+#include "dummy.h"
 #include "disk.h"
 #include "mount.h"
 #include "aoe.h"
@@ -61,7 +61,7 @@ extern NTSTATUS STDCALL AoeBusAttachFdo(
     IN PDRIVER_OBJECT,
     IN PDEVICE_OBJECT
   );
-extern const WV_S_DRIVER_DUMMY_IDS * AoeBusDummyIds;
+extern const WV_S_DUMMY_IDS * AoeBusDummyIds;
 extern BOOLEAN STDCALL AoeBusAddDev(IN OUT WV_SP_DEV_T);
 /* From aoe/registry.c */
 extern BOOLEAN STDCALL AoeRegSetup(OUT PNTSTATUS);
@@ -1332,7 +1332,7 @@ static VOID STDCALL AoeThread_(IN PVOID StartContext)
     DBG ( "Entry\n" );
 
     /* Create the PDO for the sub-bus on the WinVBlock bus. */
-    status = WvDriverAddDummy(
+    status = WvDummyAdd(
         AoeBusDummyIds,
         FILE_DEVICE_CONTROLLER,
         FILE_DEVICE_SECURE_OPEN
index 10cbfbb..4279cc4 100644 (file)
@@ -46,77 +46,6 @@ typedef struct WV_DEV_EXT {
     struct WV_DEV_T * device;
   } WV_S_DEV_EXT, * WV_SP_DEV_EXT;
 
-/* PnP IDs for a dummy device. */
-typedef struct WV_DRIVER_DUMMY_IDS {
-    UINT32 DevOffset;
-    UINT32 DevLen;
-    UINT32 InstanceOffset;
-    UINT32 InstanceLen;
-    UINT32 HardwareOffset;
-    UINT32 HardwareLen;
-    UINT32 CompatOffset;
-    UINT32 CompatLen;
-    UINT32 Len;
-    const WCHAR * Ids;
-    WCHAR Text[1];
-  } WV_S_DRIVER_DUMMY_IDS, * WV_SP_DRIVER_DUMMY_IDS;
-
-/* Macro support for dummy ID generation. */
-#define WV_M_DRIVER_DUMMY_IDS_X_ENUM(prefix_, name_, literal_)    \
-  prefix_ ## name_ ## Offset_,                                    \
-  prefix_ ## name_ ## Len_ = sizeof (literal_) / sizeof (WCHAR),  \
-  prefix_ ## name_ ## End_ =                                      \
-    prefix_ ## name_ ## Offset_ + prefix_ ## name_ ## Len_ - 1,
-
-#define WV_M_DRIVER_DUMMY_IDS_X_LITERALS(prefix_, name_, literal_) \
-  literal_ L"\0"
-
-#define WV_M_DRIVER_DUMMY_IDS_X_FILL(prefix_, name_, literal_)  \
-  prefix_ ## name_ ## Offset_,                                  \
-  prefix_ ## name_ ## Len_,
-
-/**
- * Generate a static const WV_S_DRIVER_DUMMY_IDS object.
- *
- * @v DummyIds          The name of the desired object.  Also used as prefix.
- * @v XMacro            The x-macro with the ID text.
- *
- * This macro will produce the following:
- *   enum values:
- *     [DummyIds]DevOffset_
- *     [DummyIds]DevLen_
- *     [DummyIds]DevEnd_
- *     [DummyIds]InstanceOffset_
- *     [DummyIds]InstanceLen_
- *     [DummyIds]InstanceEnd_
- *     [DummyIds]HardwareOffset_
- *     [DummyIds]HardwareLen_
- *     [DummyIds]HardwareEnd_
- *     [DummyIds]CompatOffset_
- *     [DummyIds]CompatLen_
- *     [DummyIds]CompatEnd_
- *     [DummyIds]Len_
- *   WCHAR[]:
- *     [DummyIds]String_
- *   static const WV_S_DRIVER_DUMMY_IDS:
- *     [DummyIds]
- */
-#define WV_M_DRIVER_DUMMY_ID_GEN(DummyIds, XMacro)    \
-                                                      \
-enum {                                                \
-    XMacro(WV_M_DRIVER_DUMMY_IDS_X_ENUM, DummyIds)    \
-    DummyIds ## Len_                                  \
-  };                                                  \
-                                                      \
-static const WCHAR DummyIds ## String_[] =            \
-  XMacro(WV_M_DRIVER_DUMMY_IDS_X_LITERALS, DummyIds); \
-                                                      \
-static const WV_S_DRIVER_DUMMY_IDS DummyIds = {       \
-    XMacro(WV_M_DRIVER_DUMMY_IDS_X_FILL, DummyIds)    \
-    DummyIds ## Len_,                                 \
-    DummyIds ## String_                               \
-  }
-
 extern WVL_M_LIB BOOLEAN STDCALL WvDriverBusAddDev(
     IN WV_SP_DEV_T
   );
@@ -124,14 +53,5 @@ extern NTSTATUS STDCALL WvDriverGetDevCapabilities(
     IN PDEVICE_OBJECT,
     IN PDEVICE_CAPABILITIES
   );
-extern WVL_M_LIB NTSTATUS STDCALL WvDriverAddDummy(
-    IN const WV_S_DRIVER_DUMMY_IDS *,
-    IN DEVICE_TYPE,
-    IN ULONG
-  );
-extern WVL_M_LIB NTSTATUS STDCALL WvDriverDummyIds(
-    IN PIRP,
-    IN WV_SP_DRIVER_DUMMY_IDS
-  );
 
 #endif /* WV_M_DRIVER_H_ */
diff --git a/src/include/dummy.h b/src/include/dummy.h
new file mode 100644 (file)
index 0000000..f675723
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2010-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
+ *
+ * This file is part of WinVBlock, originally derived from WinAoE.
+ *
+ * WinVBlock is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * WinVBlock is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef WV_M_DUMMY_H_
+#  define WV_M_DUMMY_H_
+
+/**
+ * @file
+ *
+ * Dummy device specifics.
+ */
+
+/* PnP IDs for a dummy device. */
+typedef struct WV_DUMMY_IDS {
+    UINT32 DevOffset;
+    UINT32 DevLen;
+    UINT32 InstanceOffset;
+    UINT32 InstanceLen;
+    UINT32 HardwareOffset;
+    UINT32 HardwareLen;
+    UINT32 CompatOffset;
+    UINT32 CompatLen;
+    UINT32 Len;
+    const WCHAR * Ids;
+    WCHAR Text[1];
+  } WV_S_DUMMY_IDS, * WV_SP_DUMMY_IDS;
+
+/* Macro support for dummy ID generation. */
+#define WV_M_DUMMY_IDS_X_ENUM(prefix_, name_, literal_)           \
+  prefix_ ## name_ ## Offset_,                                    \
+  prefix_ ## name_ ## Len_ = sizeof (literal_) / sizeof (WCHAR),  \
+  prefix_ ## name_ ## End_ =                                      \
+    prefix_ ## name_ ## Offset_ + prefix_ ## name_ ## Len_ - 1,
+
+#define WV_M_DUMMY_IDS_X_LITERALS(prefix_, name_, literal_) \
+  literal_ L"\0"
+
+#define WV_M_DUMMY_IDS_X_FILL(prefix_, name_, literal_) \
+  prefix_ ## name_ ## Offset_,                          \
+  prefix_ ## name_ ## Len_,
+
+/**
+ * Generate a static const WV_S_DUMMY_IDS object.
+ *
+ * @v DummyIds          The name of the desired object.  Also used as prefix.
+ * @v XMacro            The x-macro with the ID text.
+ *
+ * This macro will produce the following:
+ *   enum values:
+ *     [DummyIds]DevOffset_
+ *     [DummyIds]DevLen_
+ *     [DummyIds]DevEnd_
+ *     [DummyIds]InstanceOffset_
+ *     [DummyIds]InstanceLen_
+ *     [DummyIds]InstanceEnd_
+ *     [DummyIds]HardwareOffset_
+ *     [DummyIds]HardwareLen_
+ *     [DummyIds]HardwareEnd_
+ *     [DummyIds]CompatOffset_
+ *     [DummyIds]CompatLen_
+ *     [DummyIds]CompatEnd_
+ *     [DummyIds]Len_
+ *   WCHAR[]:
+ *     [DummyIds]String_
+ *   static const WV_S_DUMMY_IDS:
+ *     [DummyIds]
+ */
+#define WV_M_DUMMY_ID_GEN(DummyIds, XMacro)     \
+                                                \
+enum {                                          \
+    XMacro(WV_M_DUMMY_IDS_X_ENUM, DummyIds)     \
+    DummyIds ## Len_                            \
+  };                                            \
+                                                \
+static const WCHAR DummyIds ## String_[] =      \
+  XMacro(WV_M_DUMMY_IDS_X_LITERALS, DummyIds);  \
+                                                \
+static const WV_S_DUMMY_IDS DummyIds = {        \
+    XMacro(WV_M_DUMMY_IDS_X_FILL, DummyIds)     \
+    DummyIds ## Len_,                           \
+    DummyIds ## String_                         \
+  }
+
+extern WVL_M_LIB NTSTATUS STDCALL WvDummyAdd(
+    IN const WV_S_DUMMY_IDS *,
+    IN DEVICE_TYPE,
+    IN ULONG
+  );
+
+#endif /* WV_M_DUMMY_H_ */
index ea1f705..631a3e7 100644 (file)
@@ -67,7 +67,7 @@ static UNICODE_STRING WvBusDosname = {
     WV_M_BUS_DOSNAME
   };
 /* The main bus. */
-static WVL_S_BUS_T WvBus = {0};
+WVL_S_BUS_T WvBus = {0};
 static WV_S_DEV_T WvBusDev = {0};
 static PETHREAD WvBusThread = NULL;
 /* Contains TXTSETUP.SIF/BOOT.INI-style OsLoadOptions parameters. */
@@ -825,239 +825,3 @@ static NTSTATUS STDCALL WvBusPnpQueryDevText(
 
     return WvlIrpComplete(irp, irp->IoStatus.Information, status);
   }
-
-/**
- * Dummy device feature.
- */
-
-/* Prototype safety. */
-WV_F_DEV_PNP WvDummyPnp;
-
-/* Dummy PnP IRP handler. */
-static NTSTATUS STDCALL WvDummyPnp(
-    IN WV_SP_DEV_T dev,
-    IN PIRP irp,
-    IN UCHAR code
-  ) {
-    if (code != IRP_MN_QUERY_ID)
-      return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED);
-
-    /* The WV_S_DEV_T extension points to the dummy IDs. */
-    return WvDriverDummyIds(irp, dev->ext);
-  }
-
-typedef struct WV_ADD_DUMMY {
-    const WV_S_DRIVER_DUMMY_IDS * DummyIds;
-    DEVICE_TYPE DevType;
-    ULONG DevCharacteristics;
-    PKEVENT Event;
-    NTSTATUS Status;
-  } WV_S_ADD_DUMMY, * WV_SP_ADD_DUMMY;
-
-/* Prototype safety. */
-static WVL_F_BUS_WORK_ITEM WvAddDummy_;
-
-/**
- * Add a dummy PDO child node in the context of the bus' thread.  Internal.
- *
- * @v context           Points to the WV_S_ADD_DUMMY to process.
- */
-static VOID STDCALL WvAddDummy_(PVOID context) {
-    WV_SP_ADD_DUMMY dummy_context = context;
-    NTSTATUS status;
-    PDEVICE_OBJECT pdo = NULL;
-    WV_SP_DEV_T dev;
-    wv_size_t dummy_ids_size;
-    WV_SP_DRIVER_DUMMY_IDS dummy_ids;
-    static WV_S_DEV_IRP_MJ irp_mj = {
-        (WV_FP_DEV_DISPATCH) 0,
-        (WV_FP_DEV_DISPATCH) 0,
-        (WV_FP_DEV_CTL) 0,
-        (WV_FP_DEV_SCSI) 0,
-        WvDummyPnp,
-      };
-
-    status = IoCreateDevice(
-        WvDriverObj,
-        sizeof (WV_S_DEV_EXT),
-        NULL,
-        dummy_context->DevType,
-        dummy_context->DevCharacteristics,
-        FALSE,
-        &pdo
-      );
-    if (!NT_SUCCESS(status) || !pdo) {
-        DBG("Couldn't create dummy device.\n");
-        dummy_context->Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto err_create_pdo;
-      }
-
-    dev = wv_malloc(sizeof *dev);
-    if (!dev) {
-        DBG("Couldn't allocate dummy device.\n");
-        dummy_context->Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto err_dev;
-      }
-
-    dummy_ids_size =
-      sizeof *dummy_ids +
-      dummy_context->DummyIds->Len * sizeof dummy_ids->Text[0] -
-      sizeof dummy_ids->Text[0];        /* The struct hack uses a WCHAR[1]. */
-    dummy_ids = wv_malloc(dummy_ids_size);
-    if (!dummy_ids) {
-        DBG("Couldn't allocate dummy IDs.\n");
-        dummy_context->Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto err_dummy_ids;
-      }
-    /* Copy the IDs offsets and lengths. */
-    RtlCopyMemory(dummy_ids, dummy_context->DummyIds, sizeof *dummy_ids);
-    /* Copy the text of the IDs. */
-    RtlCopyMemory(
-        &dummy_ids->Text,
-        dummy_context->DummyIds->Ids,
-        dummy_context->DummyIds->Len * sizeof dummy_ids->Text[0]
-      );
-    /* Point to the copy of the text. */
-    dummy_ids->Ids = dummy_ids->Text;
-
-    /* Ok! */
-    WvDevInit(dev);
-    dev->IrpMj = &irp_mj;
-    dev->ext = dummy_ids;       /* TODO: Implement a dummy free.  Leaking. */
-    dev->Self = pdo;
-    WvDevForDevObj(pdo, dev);
-    WvlBusInitNode(&dev->BusNode, pdo);
-    /* Associate the parent bus. */
-    dev->Parent = WvBus.Fdo;
-    /* Add the new PDO device to the bus' list of children. */
-    WvlBusAddNode(&WvBus, &dev->BusNode);
-    dev->DevNum = WvlBusGetNodeNum(&dev->BusNode);
-    pdo->Flags &= ~DO_DEVICE_INITIALIZING;
-
-    dummy_context->Status = STATUS_SUCCESS;
-    KeSetEvent(dummy_context->Event, 0, FALSE);
-    return;
-
-    wv_free(dummy_ids);
-    err_dummy_ids:
-
-    wv_free(dev);
-    err_dev:
-
-    IoDeleteDevice(pdo);
-    err_create_pdo:
-
-    KeSetEvent(dummy_context->Event, 0, FALSE);
-    return;
-  }
-
-/**
- * Produce a dummy PDO node on the main bus.
- *
- * @v DummyIds                  The PnP IDs for the dummy.
- * @v DevType                   The type for the dummy device.
- * @v DevCharacteristics        The dummy device characteristics.
- * @ret NTSTATUS                The status of the operation.
- */
-WVL_M_LIB NTSTATUS STDCALL WvDriverAddDummy(
-    IN const WV_S_DRIVER_DUMMY_IDS * DummyIds,
-    IN DEVICE_TYPE DevType,
-    IN ULONG DevCharacteristics
-  ) {
-    KEVENT event;
-    WV_S_ADD_DUMMY context = {
-        DummyIds,
-        DevType,
-        DevCharacteristics,
-        &event,
-        STATUS_UNSUCCESSFUL
-      };
-    WVL_S_BUS_CUSTOM_WORK_ITEM work_item = {
-        WvAddDummy_,
-        &context
-      };
-    NTSTATUS status;
-
-    if (!DummyIds)
-      return STATUS_INVALID_PARAMETER;
-
-    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
-
-    status = WvlBusEnqueueCustomWorkItem(&WvBus, &work_item);
-    if (!NT_SUCCESS(status))
-      return status;
-
-    /* Wait for WvAddDummy_() to complete. */
-    KeWaitForSingleObject(
-        &event,
-        Executive,
-        KernelMode,
-        FALSE,
-        NULL
-      );
-
-    return context.Status;
-  }
-
-/**
- * Handle a PnP ID query with a WV_S_DRIVER_DUMMY_IDS object.
- *
- * @v Irp               The PnP ID query IRP to handle.
- * @v DummyIds          The object containing the IDs to respond with.
- * @ret NTSTATUS        The status of the operation.
- */
-WVL_M_LIB NTSTATUS STDCALL WvDriverDummyIds(
-    IN PIRP Irp,
-    IN WV_SP_DRIVER_DUMMY_IDS DummyIds
-  ) {
-    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp);
-    BUS_QUERY_ID_TYPE query_type = io_stack_loc->Parameters.QueryId.IdType;
-    const WCHAR * ids;
-    UINT32 len;
-    NTSTATUS status;
-
-    switch (query_type) {
-        case BusQueryDeviceID:
-          ids = DummyIds->Ids + DummyIds->DevOffset;
-          len = DummyIds->DevLen;
-          break;
-
-        case BusQueryInstanceID:
-          ids = DummyIds->Ids + DummyIds->InstanceOffset;
-          len = DummyIds->InstanceLen;
-          break;
-
-        case BusQueryHardwareIDs:
-          ids = DummyIds->Ids + DummyIds->HardwareOffset;
-          len = DummyIds->HardwareLen;
-          break;
-
-        case BusQueryCompatibleIDs:
-          ids = DummyIds->Ids + DummyIds->CompatOffset;
-          len = DummyIds->CompatLen;
-          break;
-
-        default:
-          return WvlIrpComplete(Irp, 0, STATUS_NOT_SUPPORTED);
-      }
-
-    /* Allocate the return buffer. */
-    Irp->IoStatus.Information = (ULONG_PTR) wv_palloc(len * sizeof *ids);
-    if (Irp->IoStatus.Information == 0) {
-        DBG("wv_palloc failed.\n");
-        status = STATUS_INSUFFICIENT_RESOURCES;
-        goto alloc_info;
-      }
-    /* Copy the working buffer to the return buffer. */
-    RtlCopyMemory(
-        (PVOID) Irp->IoStatus.Information,
-        ids,
-        len * sizeof *ids
-      );
-    status = STATUS_SUCCESS;
-
-    /* irp->IoStatus.Information not freed. */
-    alloc_info:
-
-    return WvlIrpComplete(Irp, Irp->IoStatus.Information, status);
-  }
diff --git a/src/winvblock/dummy.c b/src/winvblock/dummy.c
new file mode 100644 (file)
index 0000000..2270b43
--- /dev/null
@@ -0,0 +1,270 @@
+/**
+ * Copyright (C) 2010-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
+ *
+ * This file is part of WinVBlock, originally derived from WinAoE.
+ *
+ * WinVBlock is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * WinVBlock is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file
+ *
+ * Dummy device specifics.
+ */
+
+#include <ntddk.h>
+
+#include "portable.h"
+#include "winvblock.h"
+#include "wv_stdlib.h"
+#include "irp.h"
+#include "driver.h"
+#include "bus.h"
+#include "device.h"
+#include "dummy.h"
+#include "debug.h"
+
+/* From driver.c */
+extern WVL_S_BUS_T WvBus;
+
+/* Forward declarations. */
+static NTSTATUS STDCALL WvDummyIds(IN PIRP, IN WV_SP_DUMMY_IDS);
+static WV_F_DEV_PNP WvDummyPnp;
+static WVL_F_BUS_WORK_ITEM WvDummyAdd_;
+
+/* Dummy PnP IRP handler. */
+static NTSTATUS STDCALL WvDummyPnp(
+    IN WV_SP_DEV_T dev,
+    IN PIRP irp,
+    IN UCHAR code
+  ) {
+    if (code != IRP_MN_QUERY_ID)
+      return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED);
+
+    /* The WV_S_DEV_T extension points to the dummy IDs. */
+    return WvDummyIds(irp, dev->ext);
+  }
+
+typedef struct WV_ADD_DUMMY {
+    const WV_S_DUMMY_IDS * DummyIds;
+    DEVICE_TYPE DevType;
+    ULONG DevCharacteristics;
+    PKEVENT Event;
+    NTSTATUS Status;
+  } WV_S_ADD_DUMMY, * WV_SP_ADD_DUMMY;
+
+/**
+ * Add a dummy PDO child node in the context of the bus' thread.  Internal.
+ *
+ * @v context           Points to the WV_S_ADD_DUMMY to process.
+ */
+static VOID STDCALL WvDummyAdd_(PVOID context) {
+    WV_SP_ADD_DUMMY dummy_context = context;
+    NTSTATUS status;
+    PDEVICE_OBJECT pdo = NULL;
+    WV_SP_DEV_T dev;
+    SIZE_T dummy_ids_size;
+    WV_SP_DUMMY_IDS dummy_ids;
+    static WV_S_DEV_IRP_MJ irp_mj = {
+        (WV_FP_DEV_DISPATCH) 0,
+        (WV_FP_DEV_DISPATCH) 0,
+        (WV_FP_DEV_CTL) 0,
+        (WV_FP_DEV_SCSI) 0,
+        WvDummyPnp,
+      };
+
+    status = IoCreateDevice(
+        WvDriverObj,
+        sizeof (WV_S_DEV_EXT),
+        NULL,
+        dummy_context->DevType,
+        dummy_context->DevCharacteristics,
+        FALSE,
+        &pdo
+      );
+    if (!NT_SUCCESS(status) || !pdo) {
+        DBG("Couldn't create dummy device.\n");
+        dummy_context->Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto err_create_pdo;
+      }
+
+    dev = wv_malloc(sizeof *dev);
+    if (!dev) {
+        DBG("Couldn't allocate dummy device.\n");
+        dummy_context->Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto err_dev;
+      }
+
+    dummy_ids_size =
+      sizeof *dummy_ids +
+      dummy_context->DummyIds->Len * sizeof dummy_ids->Text[0] -
+      sizeof dummy_ids->Text[0];        /* The struct hack uses a WCHAR[1]. */
+    dummy_ids = wv_malloc(dummy_ids_size);
+    if (!dummy_ids) {
+        DBG("Couldn't allocate dummy IDs.\n");
+        dummy_context->Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto err_dummy_ids;
+      }
+    /* Copy the IDs offsets and lengths. */
+    RtlCopyMemory(dummy_ids, dummy_context->DummyIds, sizeof *dummy_ids);
+    /* Copy the text of the IDs. */
+    RtlCopyMemory(
+        &dummy_ids->Text,
+        dummy_context->DummyIds->Ids,
+        dummy_context->DummyIds->Len * sizeof dummy_ids->Text[0]
+      );
+    /* Point to the copy of the text. */
+    dummy_ids->Ids = dummy_ids->Text;
+
+    /* Ok! */
+    WvDevInit(dev);
+    dev->IrpMj = &irp_mj;
+    dev->ext = dummy_ids;       /* TODO: Implement a dummy free.  Leaking. */
+    dev->Self = pdo;
+    WvDevForDevObj(pdo, dev);
+    WvlBusInitNode(&dev->BusNode, pdo);
+    /* Associate the parent bus. */
+    dev->Parent = WvBus.Fdo;
+    /* Add the new PDO device to the bus' list of children. */
+    WvlBusAddNode(&WvBus, &dev->BusNode);
+    dev->DevNum = WvlBusGetNodeNum(&dev->BusNode);
+    pdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+    dummy_context->Status = STATUS_SUCCESS;
+    KeSetEvent(dummy_context->Event, 0, FALSE);
+    return;
+
+    wv_free(dummy_ids);
+    err_dummy_ids:
+
+    wv_free(dev);
+    err_dev:
+
+    IoDeleteDevice(pdo);
+    err_create_pdo:
+
+    KeSetEvent(dummy_context->Event, 0, FALSE);
+    return;
+  }
+
+/**
+ * Produce a dummy PDO node on the main bus.
+ *
+ * @v DummyIds                  The PnP IDs for the dummy.
+ * @v DevType                   The type for the dummy device.
+ * @v DevCharacteristics        The dummy device characteristics.
+ * @ret NTSTATUS                The status of the operation.
+ */
+WVL_M_LIB NTSTATUS STDCALL WvDummyAdd(
+    IN const WV_S_DUMMY_IDS * DummyIds,
+    IN DEVICE_TYPE DevType,
+    IN ULONG DevCharacteristics
+  ) {
+    KEVENT event;
+    WV_S_ADD_DUMMY context = {
+        DummyIds,
+        DevType,
+        DevCharacteristics,
+        &event,
+        STATUS_UNSUCCESSFUL
+      };
+    WVL_S_BUS_CUSTOM_WORK_ITEM work_item = {
+        WvDummyAdd_,
+        &context
+      };
+    NTSTATUS status;
+
+    if (!DummyIds)
+      return STATUS_INVALID_PARAMETER;
+
+    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+
+    status = WvlBusEnqueueCustomWorkItem(&WvBus, &work_item);
+    if (!NT_SUCCESS(status))
+      return status;
+
+    /* Wait for WvDummyAdd_() to complete. */
+    KeWaitForSingleObject(
+        &event,
+        Executive,
+        KernelMode,
+        FALSE,
+        NULL
+      );
+
+    return context.Status;
+  }
+
+/**
+ * Handle a PnP ID query with a WV_S_DUMMY_IDS object.
+ *
+ * @v Irp               The PnP ID query IRP to handle.
+ * @v DummyIds          The object containing the IDs to respond with.
+ * @ret NTSTATUS        The status of the operation.
+ */
+static NTSTATUS STDCALL WvDummyIds(
+    IN PIRP Irp,
+    IN WV_SP_DUMMY_IDS DummyIds
+  ) {
+    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp);
+    BUS_QUERY_ID_TYPE query_type = io_stack_loc->Parameters.QueryId.IdType;
+    const WCHAR * ids;
+    UINT32 len;
+    NTSTATUS status;
+
+    switch (query_type) {
+        case BusQueryDeviceID:
+          ids = DummyIds->Ids + DummyIds->DevOffset;
+          len = DummyIds->DevLen;
+          break;
+
+        case BusQueryInstanceID:
+          ids = DummyIds->Ids + DummyIds->InstanceOffset;
+          len = DummyIds->InstanceLen;
+          break;
+
+        case BusQueryHardwareIDs:
+          ids = DummyIds->Ids + DummyIds->HardwareOffset;
+          len = DummyIds->HardwareLen;
+          break;
+
+        case BusQueryCompatibleIDs:
+          ids = DummyIds->Ids + DummyIds->CompatOffset;
+          len = DummyIds->CompatLen;
+          break;
+
+        default:
+          return WvlIrpComplete(Irp, 0, STATUS_NOT_SUPPORTED);
+      }
+
+    /* Allocate the return buffer. */
+    Irp->IoStatus.Information = (ULONG_PTR) wv_palloc(len * sizeof *ids);
+    if (Irp->IoStatus.Information == 0) {
+        DBG("wv_palloc failed.\n");
+        status = STATUS_INSUFFICIENT_RESOURCES;
+        goto alloc_info;
+      }
+    /* Copy the working buffer to the return buffer. */
+    RtlCopyMemory(
+        (PVOID) Irp->IoStatus.Information,
+        ids,
+        len * sizeof *ids
+      );
+    status = STATUS_SUCCESS;
+
+    /* irp->IoStatus.Information not freed. */
+    alloc_info:
+
+    return WvlIrpComplete(Irp, Irp->IoStatus.Information, status);
+  }
index d63aa71..35a48a7 100644 (file)
@@ -10,7 +10,7 @@ for /d %%a in (%lib%) do (
   popd\r
   )\r
 \r
-set c=debug.c driver.c probe.c registry.c winvblock.rc device.c wv_stdlib.c wv_string.c irp.c\r
+set c=debug.c driver.c probe.c registry.c winvblock.rc device.c wv_stdlib.c wv_string.c irp.c dummy.c\r
 \r
 set name=WVBlk%bits%\r
 \r