]> xenbits.xensource.com Git - pvdrivers/win/xencons.git/commitdiff
Add console functionality
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 5 May 2017 14:24:27 +0000 (15:24 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 5 May 2017 15:09:32 +0000 (16:09 +0100)
This patch adds a new interface so that user-space code can open a
character device to the PV console along with all the necessary dispatch
handling for basic functionality.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
include/console_interface.h [new file with mode: 0644]
include/xencons_device.h [new file with mode: 0644]
src/xencons/driver.h
src/xencons/fdo.c
src/xencons/fdo.h
src/xencons/names.h
src/xencons/stream.c [new file with mode: 0644]
src/xencons/stream.h [new file with mode: 0644]
vs2015/xencons/xencons.vcxproj

diff --git a/include/console_interface.h b/include/console_interface.h
new file mode 100644 (file)
index 0000000..7c10cef
--- /dev/null
@@ -0,0 +1,184 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*! \file console_interface.h
+    \brief XENBUS CONSOLE Interface
+
+    This interface provides access to XenConsole
+*/
+
+#ifndef _XENBUS_CONSOLE_INTERFACE_H
+#define _XENBUS_CONSOLE_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_CONSOLE_WAKEUP
+    \brief XenStore watch handle
+*/
+typedef struct _XENBUS_CONSOLE_WAKEUP   XENBUS_CONSOLE_WAKEUP, *PXENBUS_CONSOLE_WAKEUP;
+
+/*! \typedef XENBUS_CONSOLE_ACQUIRE
+    \brief Acquire a reference to the CONSOLE interface
+
+    \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_CONSOLE_ACQUIRE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_CONSOLE_RELEASE
+    \brief Release a reference to the CONSOLE interface
+
+    \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_CONSOLE_RELEASE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_CONSOLE_CAN_READ
+    \brief Get characters from the console
+
+    \param Interface The interface header
+
+    \return A boolean which is true if there is data to read
+*/
+typedef BOOLEAN
+(*XENBUS_CONSOLE_CAN_READ)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_CONSOLE_READ
+    \brief Get characters from the console
+
+    \param Interface The interface header
+    \param Buffer A character buffer
+    \param Length The length of the buffer
+
+    \return The number of characters read
+*/
+typedef ULONG
+(*XENBUS_CONSOLE_READ)(
+    IN  PINTERFACE  Interface,
+    IN  PCHAR       Data,
+    IN  ULONG       Length
+    );
+
+/*! \typedef XENBUS_CONSOLE_CAN_WRITE
+    \brief Get characters from the console
+
+    \param Interface The interface header
+
+    \return A boolean which is true if there is space to write
+*/
+typedef BOOLEAN
+(*XENBUS_CONSOLE_CAN_WRITE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_CONSOLE_WRITE
+    \brief Send characters to the console
+
+    \param Interface The interface header
+    \param Buffer A character buffer
+    \param Length The length of the buffer
+
+    \return The number of characters written
+*/
+typedef ULONG
+(*XENBUS_CONSOLE_WRITE)(
+    IN  PINTERFACE  Interface,
+    IN  PCHAR       Data,
+    IN  ULONG       Length
+    );
+
+/*! \typedef XENBUS_CONSOLE_WAKEUP_ADD
+    \brief Add a wakeup item
+
+    \param Interface The interface header
+    \param Event A pointer to an event object to be signalled when there
+    is activity on the rings
+    \param Wakeup A pointer to a wakeup handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_CONSOLE_WAKEUP_ADD)(
+    IN  PINTERFACE             Interface,
+    IN  PKEVENT                Event,
+    OUT PXENBUS_CONSOLE_WAKEUP *Wakeup
+    );
+
+/*! \typedef XENBUS_CONSOLE_WAKEUP_REMOVE
+    \brief Remove a wakeup item
+
+    \param Interface The interface header
+    \param Wakeup The wakeup handle
+*/
+typedef VOID
+(*XENBUS_CONSOLE_WAKEUP_REMOVE)(
+    IN  PINTERFACE              Interface,
+    IN  PXENBUS_CONSOLE_WAKEUP  Wakeup
+    );
+
+// {04c4f738-034a-4268-bd20-a92ac90d4f82}
+DEFINE_GUID(GUID_XENBUS_CONSOLE_INTERFACE,
+0x04c4f738, 0x034a, 0x4268, 0xbd, 0x20, 0xa9, 0x2a, 0xc9, 0x0d, 0x4f, 0x82);
+
+/*! \struct _XENBUS_CONSOLE_INTERFACE_V1
+    \brief CONSOLE interface version 1
+    \ingroup interfaces
+*/
+struct _XENBUS_CONSOLE_INTERFACE_V1 {
+    INTERFACE                       Interface;
+    XENBUS_CONSOLE_ACQUIRE          ConsoleAcquire;
+    XENBUS_CONSOLE_RELEASE          ConsoleRelease;
+    XENBUS_CONSOLE_CAN_READ         ConsoleCanRead;
+    XENBUS_CONSOLE_READ             ConsoleRead;
+    XENBUS_CONSOLE_CAN_WRITE        ConsoleCanWrite;
+    XENBUS_CONSOLE_WRITE            ConsoleWrite;
+    XENBUS_CONSOLE_WAKEUP_ADD       ConsoleWakeupAdd;
+    XENBUS_CONSOLE_WAKEUP_REMOVE    ConsoleWakeupRemove;
+};
+
+typedef struct _XENBUS_CONSOLE_INTERFACE_V1 XENBUS_CONSOLE_INTERFACE, *PXENBUS_CONSOLE_INTERFACE;
+
+/*! \def XENBUS_CONSOLE
+    \brief Macro at assist in method invocation
+*/
+#define XENBUS_CONSOLE(_Method, _Interface, ...)    \
+    (_Interface)->Console ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif  // _WINDLL
+
+#define XENBUS_CONSOLE_INTERFACE_VERSION_MIN  1
+#define XENBUS_CONSOLE_INTERFACE_VERSION_MAX  1
+
+#endif  // _XENBUS_CONSOLE_INTERFACE_H
diff --git a/include/xencons_device.h b/include/xencons_device.h
new file mode 100644 (file)
index 0000000..eaf57d8
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENCONS_DEVICE_H
+#define _XENCONS_DEVICE_H
+
+// {0D3EDD21-8EF9-4DFF-856C-8C68BF4FDCA3}
+DEFINE_GUID(GUID_XENCONS_DEVICE,
+            0xd3edd21, 0x8ef9, 0x4dff, 0x85, 0x6c, 0x8c, 0x68, 0xbf, 0x4f, 0xdc, 0xa3);
+
+#endif  // _XENCONS_DEVICE_H
index 05c5407e25f4376892317f442ef8be868b9af753..4a2eb61f4101cf8b75b8d6e6ca11d7d9911471ab 100644 (file)
@@ -60,6 +60,8 @@ typedef struct _XENCONS_DX {
     PDEVICE_OBJECT      DeviceObject;
     DEVICE_OBJECT_TYPE  Type;
 
+    UNICODE_STRING      Link;
+
     DEVICE_PNP_STATE    DevicePnpState;
     DEVICE_PNP_STATE    PreviousDevicePnpState;
 
index 9f39c6d03f6794ee616bbba62413946753b31499..57e7f6de21709aca76a58873425e53f7e4c3ea68 100644 (file)
 
 #include <ntddk.h>
 #include <wdmguid.h>
+#include <wdmsec.h>
 #include <ntstrsafe.h>
 #include <stdlib.h>
 
 #include <debug_interface.h>
 #include <suspend_interface.h>
 #include <store_interface.h>
+#include <console_interface.h>
+#include <xencons_device.h>
 #include <version.h>
 
 #include "driver.h"
 #include "registry.h"
 #include "fdo.h"
+#include "stream.h"
 #include "thread.h"
 #include "names.h"
 #include "dbg_print.h"
@@ -65,6 +69,12 @@ typedef struct _FDO_RESOURCE {
     CM_PARTIAL_RESOURCE_DESCRIPTOR Translated;
 } FDO_RESOURCE, *PFDO_RESOURCE;
 
+typedef struct _FDO_HANDLE {
+    LIST_ENTRY      ListEntry;
+    PFILE_OBJECT    FileObject;
+    PXENCONS_STREAM Stream;
+} FDO_HANDLE, *PFDO_HANDLE;
+
 struct _XENCONS_FDO {
     PXENCONS_DX                 Dx;
     PDEVICE_OBJECT              LowerDeviceObject;
@@ -83,9 +93,13 @@ struct _XENCONS_FDO {
 
     FDO_RESOURCE                Resource[RESOURCE_COUNT];
 
+    LIST_ENTRY                  HandleList;
+    KSPIN_LOCK                  HandleLock;
+
     XENBUS_DEBUG_INTERFACE      DebugInterface;
     XENBUS_SUSPEND_INTERFACE    SuspendInterface;
     XENBUS_STORE_INTERFACE      StoreInterface;
+    XENBUS_CONSOLE_INTERFACE    ConsoleInterface;
 
     PXENBUS_SUSPEND_CALLBACK    SuspendCallbackLate;
 };
@@ -819,6 +833,7 @@ FdoD3ToD0(
     IN  PXENCONS_FDO    Fdo
     )
 {
+    PXENCONS_DX         Dx = Fdo->Dx;
     POWER_STATE         PowerState;
     KIRQL               Irql;
     NTSTATUS            status;
@@ -858,12 +873,15 @@ FdoD3ToD0(
                     DevicePowerState,
                     PowerState);
 
+#pragma prefast(suppress:28123)
+    (VOID) IoSetDeviceInterfaceState(&Dx->Link, TRUE);
+
     Trace("<====\n");
 
     return STATUS_SUCCESS;
 
 fail3:
-    Error("fail3\n");
+    Error("fail4\n");
 
     __FdoD0ToD3(Fdo);
 
@@ -890,6 +908,7 @@ FdoD0ToD3(
     IN  PXENCONS_FDO    Fdo
     )
 {
+    PXENCONS_DX         Dx = Fdo->Dx;
     POWER_STATE         PowerState;
     KIRQL               Irql;
 
@@ -898,6 +917,9 @@ FdoD0ToD3(
 
     Trace("====>\n");
 
+#pragma prefast(suppress:28123)
+    (VOID) IoSetDeviceInterfaceState(&Dx->Link, FALSE);
+
     PowerState.DeviceState = PowerDeviceD3;
     PoSetPowerState(Fdo->Dx->DeviceObject,
                     DevicePowerState,
@@ -2071,6 +2093,223 @@ done:
     return status;
 }
 
+static NTSTATUS
+FdoCreateHandle(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PFILE_OBJECT    FileObject
+    )
+{
+    PFDO_HANDLE         Handle;
+    KIRQL               Irql;
+    NTSTATUS            status;
+
+    Handle = __FdoAllocate(sizeof (FDO_HANDLE));
+
+    status = STATUS_NO_MEMORY;
+    if (Handle == NULL)
+        goto fail1;
+
+    status = StreamCreate(Fdo, &Handle->Stream);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    Handle->FileObject = FileObject;
+
+    KeAcquireSpinLock(&Fdo->HandleLock, &Irql);
+    InsertTailList(&Fdo->HandleList, &Handle->ListEntry);
+    KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+    Trace("%p\n", Handle->FileObject);
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+    ASSERT(IsZeroMemory(Handle, sizeof (FDO_HANDLE)));
+    __FdoFree(Handle);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static PFDO_HANDLE
+FdoFindHandle(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PFILE_OBJECT    FileObject
+    )
+{
+    KIRQL               Irql;
+    PLIST_ENTRY         ListEntry;
+    PFDO_HANDLE         Handle;
+    NTSTATUS            status;
+
+    KeAcquireSpinLock(&Fdo->HandleLock, &Irql);
+
+    for (ListEntry = Fdo->HandleList.Flink;
+         ListEntry != &Fdo->HandleList;
+         ListEntry = ListEntry->Flink) {
+        Handle = CONTAINING_RECORD(ListEntry,
+                                   FDO_HANDLE,
+                                   ListEntry);
+
+        if (Handle->FileObject == FileObject)
+            goto found;
+    }
+
+    status = STATUS_UNSUCCESSFUL;
+    goto fail1;
+
+found:
+    KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+    return Handle;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+    return NULL;
+}
+
+static VOID
+FdoDestroyHandle(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PFDO_HANDLE     Handle
+    )
+{
+    KIRQL               Irql;
+
+    KeAcquireSpinLock(&Fdo->HandleLock, &Irql);
+    RemoveEntryList(&Handle->ListEntry);
+    KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+    RtlZeroMemory(&Handle->ListEntry, sizeof (LIST_ENTRY));
+
+    Trace("%p\n", Handle->FileObject);
+
+    StreamDestroy(Handle->Stream);
+    Handle->Stream = NULL;
+
+    Handle->FileObject = NULL;
+
+    ASSERT(IsZeroMemory(Handle, sizeof (FDO_HANDLE)));
+    __FdoFree(Handle);
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchCreate(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PIRP            Irp
+    )
+{
+    PIO_STACK_LOCATION  StackLocation;
+    NTSTATUS            status;
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    status = FdoCreateHandle(Fdo, StackLocation->FileObject);
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchCleanup(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PIRP            Irp
+    )
+{
+    PIO_STACK_LOCATION  StackLocation;
+    PFDO_HANDLE         Handle;
+    NTSTATUS            status;
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    Handle = FdoFindHandle(Fdo, StackLocation->FileObject);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Handle == NULL)
+        goto fail1;
+
+    FdoDestroyHandle(Fdo, Handle);
+    status = STATUS_SUCCESS;
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchClose(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PIRP            Irp
+    )
+{
+    NTSTATUS            status;
+
+    UNREFERENCED_PARAMETER(Fdo);
+
+    status = STATUS_SUCCESS;
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchReadWrite(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PIRP            Irp
+    )
+{
+    PIO_STACK_LOCATION  StackLocation;
+    PFDO_HANDLE         Handle;
+    NTSTATUS            status;
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    Handle = FdoFindHandle(Fdo, StackLocation->FileObject);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Handle == NULL)
+        goto fail1;
+
+    IoMarkIrpPending(Irp);
+
+    status = StreamPutQueue(Handle->Stream, Irp);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    return STATUS_PENDING;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+}
+
 static DECLSPEC_NOINLINE NTSTATUS
 FdoDispatchDefault(
     IN  PXENCONS_FDO    Fdo,
@@ -2092,11 +2331,17 @@ FdoDispatch(
     )
 {
     PIO_STACK_LOCATION  StackLocation;
+    UCHAR               MajorFunction;
     NTSTATUS            status;
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    MajorFunction = StackLocation->MajorFunction;
+
+    Trace("====> (%02x:%s)\n",
+          MajorFunction,
+          MajorFunctionName(MajorFunction));
 
-    switch (StackLocation->MajorFunction) {
+    switch (MajorFunction) {
     case IRP_MJ_PNP:
         status = FdoDispatchPnp(Fdo, Irp);
         break;
@@ -2105,11 +2350,33 @@ FdoDispatch(
         status = FdoDispatchPower(Fdo, Irp);
         break;
 
+    case IRP_MJ_CREATE:
+        status = FdoDispatchCreate(Fdo, Irp);
+        break;
+
+    case IRP_MJ_CLEANUP:
+        status = FdoDispatchCleanup(Fdo, Irp);
+        break;
+
+    case IRP_MJ_CLOSE:
+        status = FdoDispatchClose(Fdo, Irp);
+        break;
+
+    case IRP_MJ_READ:
+    case IRP_MJ_WRITE:
+        status = FdoDispatchReadWrite(Fdo, Irp);
+        break;
+
     default:
         status = FdoDispatchDefault(Fdo, Irp);
         break;
     }
 
+    Trace("<==== (%02x:%s)(%08x)\n",
+          MajorFunction,
+          MajorFunctionName(MajorFunction),
+          status);
+
     return status;
 }
 
@@ -2213,6 +2480,7 @@ FdoGet ## _Interface ## Interface(                                      \
 DEFINE_FDO_GET_INTERFACE(Debug, PXENBUS_DEBUG_INTERFACE)
 DEFINE_FDO_GET_INTERFACE(Suspend, PXENBUS_SUSPEND_INTERFACE)
 DEFINE_FDO_GET_INTERFACE(Store, PXENBUS_STORE_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Console, PXENBUS_CONSOLE_INTERFACE)
 
 NTSTATUS
 FdoCreate(
@@ -2239,6 +2507,13 @@ FdoCreate(
     Dx = (PXENCONS_DX)FunctionDeviceObject->DeviceExtension;
     RtlZeroMemory(Dx, sizeof (XENCONS_DX));
 
+    status = IoRegisterDeviceInterface(PhysicalDeviceObject,
+                                       &GUID_XENCONS_DEVICE,
+                                       NULL,
+                                       &Dx->Link);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
     Dx->Type = FUNCTION_DEVICE_OBJECT;
     Dx->DeviceObject = FunctionDeviceObject;
     Dx->DevicePnpState = Added;
@@ -2249,7 +2524,7 @@ FdoCreate(
 
     status = STATUS_NO_MEMORY;
     if (Fdo == NULL)
-        goto fail2;
+        goto fail3;
 
     Fdo->Dx = Dx;
     Fdo->PhysicalDeviceObject = PhysicalDeviceObject;
@@ -2258,22 +2533,22 @@ FdoCreate(
 
     status = ThreadCreate(FdoSystemPower, Fdo, &Fdo->SystemPowerThread);
     if (!NT_SUCCESS(status))
-        goto fail3;
+        goto fail4;
 
     status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
     if (!NT_SUCCESS(status))
-        goto fail4;
+        goto fail5;
 
     status = __FdoAcquireLowerBusInterface(Fdo);
     if (!NT_SUCCESS(status))
-        goto fail5;
+        goto fail6;
 
     if (FdoGetBusData(Fdo,
                       PCI_WHICHSPACE_CONFIG,
                       &DeviceID,
                       FIELD_OFFSET(PCI_COMMON_HEADER, DeviceID),
                       FIELD_SIZE(PCI_COMMON_HEADER, DeviceID)) == 0)
-        goto fail6;
+        goto fail7;
 
     __FdoSetVendorName(Fdo, DeviceID);
 
@@ -2286,7 +2561,7 @@ FdoCreate(
                                  sizeof (Fdo->DebugInterface),
                                  FALSE);
     if (!NT_SUCCESS(status))
-        goto fail7;
+        goto fail8;
 
     status = FDO_QUERY_INTERFACE(Fdo,
                                  XENBUS,
@@ -2295,7 +2570,7 @@ FdoCreate(
                                  sizeof (Fdo->SuspendInterface),
                                  FALSE);
     if (!NT_SUCCESS(status))
-        goto fail8;
+        goto fail9;
 
     status = FDO_QUERY_INTERFACE(Fdo,
                                  XENBUS,
@@ -2304,7 +2579,21 @@ FdoCreate(
                                  sizeof (Fdo->StoreInterface),
                                  FALSE);
     if (!NT_SUCCESS(status))
-        goto fail9;
+        goto fail10;
+
+    status = FDO_QUERY_INTERFACE(Fdo,
+                                 XENBUS,
+                                 CONSOLE,
+                                 (PINTERFACE)&Fdo->ConsoleInterface,
+                                 sizeof (Fdo->ConsoleInterface),
+                                 FALSE);
+    if (!NT_SUCCESS(status))
+        goto fail11;
+
+    InitializeListHead(&Fdo->HandleList);
+    KeInitializeSpinLock(&Fdo->HandleLock);
+
+    FunctionDeviceObject->Flags |= DO_BUFFERED_IO;
 
     Dx->Fdo = Fdo;
 
@@ -2315,44 +2604,50 @@ FdoCreate(
     FunctionDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
     return STATUS_SUCCESS;
 
-fail9:
-    Error("fail9\n");
+fail11:
+    Error("fail11\n");
+
+    RtlZeroMemory(&Fdo->ConsoleInterface,
+                  sizeof (XENBUS_CONSOLE_INTERFACE));
+
+fail10:
+    Error("fail10\n");
 
     RtlZeroMemory(&Fdo->SuspendInterface,
                   sizeof (XENBUS_SUSPEND_INTERFACE));
 
-fail8:
-    Error("fail8\n");
+fail9:
+    Error("fail9\n");
 
     RtlZeroMemory(&Fdo->DebugInterface,
                   sizeof (XENBUS_DEBUG_INTERFACE));
 
-fail7:
-    Error("fail7\n");
+fail8:
+    Error("fail8\n");
 
     RtlZeroMemory(Fdo->VendorName, MAXNAMELEN);
 
-fail6:
-    Error("fail6\n");
+fail7:
+    Error("fail7\n");
 
     __FdoReleaseLowerBusInterface(Fdo);
 
-fail5:
-    Error("fail5\n");
+fail6:
+    Error("fail6\n");
 
     ThreadAlert(Fdo->DevicePowerThread);
     ThreadJoin(Fdo->DevicePowerThread);
     Fdo->DevicePowerThread = NULL;
 
-fail4:
-    Error("fail4\n");
+fail5:
+    Error("fail5\n");
 
     ThreadAlert(Fdo->SystemPowerThread);
     ThreadJoin(Fdo->SystemPowerThread);
     Fdo->SystemPowerThread = NULL;
 
-fail3:
-    Error("fail3\n");
+fail4:
+    Error("fail4\n");
 
 #pragma prefast(suppress:28183) // Fdo->LowerDeviceObject could be NULL
     IoDetachDevice(Fdo->LowerDeviceObject);
@@ -2364,6 +2659,11 @@ fail3:
     ASSERT(IsZeroMemory(Fdo, sizeof (XENCONS_FDO)));
     __FdoFree(Fdo);
 
+fail3:
+    Error("fail3\n");
+
+    RtlFreeUnicodeString(&Dx->Link);
+
 fail2:
     Error("fail2\n");
 
@@ -2393,6 +2693,14 @@ FdoDestroy(
 
     Dx->Fdo = NULL;
 
+    RtlZeroMemory(&Fdo->HandleLock, sizeof (KSPIN_LOCK));
+
+    ASSERT(IsListEmpty(&Fdo->HandleList));
+    RtlZeroMemory(&Fdo->HandleList, sizeof (LIST_ENTRY));
+
+    RtlZeroMemory(&Fdo->ConsoleInterface,
+                  sizeof (XENBUS_CONSOLE_INTERFACE));
+
     RtlZeroMemory(&Fdo->StoreInterface,
                   sizeof (XENBUS_STORE_INTERFACE));
 
@@ -2424,5 +2732,7 @@ FdoDestroy(
     ASSERT(IsZeroMemory(Fdo, sizeof (XENCONS_FDO)));
     __FdoFree(Fdo);
 
+    RtlFreeUnicodeString(&Dx->Link);
+
     IoDeleteDevice(FunctionDeviceObject);
 }
index d8cdb5581400d043def0a9815cf13d2c89e50f14..19eaa42618d28ba816e0a5fe3daf60e6d4d503cf 100644 (file)
@@ -35,6 +35,8 @@
 #include <ntddk.h>
 #include <debug_interface.h>
 #include <suspend_interface.h>
+#include <store_interface.h>
+#include <console_interface.h>
 
 #include "driver.h"
 
@@ -44,6 +46,18 @@ FdoDispatch(
     IN  PIRP            Irp
     );
 
+#define DECLARE_FDO_GET_INTERFACE(_Interface, _Type)    \
+extern VOID                                             \
+FdoGet ## _Interface ## Interface(                      \
+    IN  PXENCONS_FDO Fdo,                               \
+    OUT _Type        _Interface ## Interface            \
+    );
+
+DECLARE_FDO_GET_INTERFACE(Debug, PXENBUS_DEBUG_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Suspend, PXENBUS_SUSPEND_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Store, PXENBUS_STORE_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Console, PXENBUS_CONSOLE_INTERFACE)
+
 extern NTSTATUS
 FdoCreate(
     IN  PDEVICE_OBJECT  PhysicalDeviceObject
index 9cbcc03be7850192db4ec023b949e67831290d8f..1c0656304239462772c0bb8892be4150b67af26d 100644 (file)
@@ -247,4 +247,51 @@ DeviceUsageTypeName(
 #undef  _DEVICE_USAGE_TYPE_NAME
 }
 
+static FORCEINLINE const CHAR *
+MajorFunctionName(
+    IN  ULONG   Function
+    )
+{
+#define _MAJOR_FUNCTION_NAME(_Function) \
+    case IRP_MJ_ ## _Function:          \
+        return #_Function;
+
+    switch (Function) {
+    _MAJOR_FUNCTION_NAME(CREATE);
+    _MAJOR_FUNCTION_NAME(CREATE_NAMED_PIPE);
+    _MAJOR_FUNCTION_NAME(CLOSE);
+    _MAJOR_FUNCTION_NAME(READ);
+    _MAJOR_FUNCTION_NAME(WRITE);
+    _MAJOR_FUNCTION_NAME(QUERY_INFORMATION);
+    _MAJOR_FUNCTION_NAME(SET_INFORMATION);
+    _MAJOR_FUNCTION_NAME(QUERY_EA);
+    _MAJOR_FUNCTION_NAME(SET_EA);
+    _MAJOR_FUNCTION_NAME(FLUSH_BUFFERS);
+    _MAJOR_FUNCTION_NAME(QUERY_VOLUME_INFORMATION);
+    _MAJOR_FUNCTION_NAME(SET_VOLUME_INFORMATION);
+    _MAJOR_FUNCTION_NAME(DIRECTORY_CONTROL);
+    _MAJOR_FUNCTION_NAME(FILE_SYSTEM_CONTROL);
+    _MAJOR_FUNCTION_NAME(DEVICE_CONTROL);
+    _MAJOR_FUNCTION_NAME(INTERNAL_DEVICE_CONTROL);
+    _MAJOR_FUNCTION_NAME(SHUTDOWN);
+    _MAJOR_FUNCTION_NAME(LOCK_CONTROL);
+    _MAJOR_FUNCTION_NAME(CLEANUP);
+    _MAJOR_FUNCTION_NAME(CREATE_MAILSLOT);
+    _MAJOR_FUNCTION_NAME(QUERY_SECURITY);
+    _MAJOR_FUNCTION_NAME(SET_SECURITY);
+    _MAJOR_FUNCTION_NAME(POWER);
+    _MAJOR_FUNCTION_NAME(SYSTEM_CONTROL);
+    _MAJOR_FUNCTION_NAME(DEVICE_CHANGE);
+    _MAJOR_FUNCTION_NAME(QUERY_QUOTA);
+    _MAJOR_FUNCTION_NAME(SET_QUOTA);
+    _MAJOR_FUNCTION_NAME(PNP);
+    default:
+        break;
+    }
+
+    return "UNKNOWN";
+
+#undef  _MAJOR_FUNCTION_NAME
+}
+
 #endif // _XENCONS_NAMES_H_
diff --git a/src/xencons/stream.c b/src/xencons/stream.c
new file mode 100644 (file)
index 0000000..0f4c129
--- /dev/null
@@ -0,0 +1,440 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+
+#include "fdo.h"
+#include "stream.h"
+#include "thread.h"
+#include "names.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define STREAM_POOL 'ETRS'
+
+struct _XENCONS_STREAM {
+    PXENCONS_FDO               Fdo;
+    PXENCONS_THREAD            Thread;
+    IO_CSQ                     Csq;
+    LIST_ENTRY                 List;
+    KSPIN_LOCK                 Lock;
+    XENBUS_CONSOLE_INTERFACE   ConsoleInterface;
+};
+
+static FORCEINLINE PVOID
+__StreamAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, STREAM_POOL);
+}
+
+static FORCEINLINE VOID
+__StreamFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, STREAM_POOL);
+}
+
+IO_CSQ_INSERT_IRP_EX StreamCsqInsertIrpEx;
+
+NTSTATUS
+StreamCsqInsertIrpEx(
+    IN  PIO_CSQ         Csq,
+    IN  PIRP            Irp,
+    IN  PVOID           InsertContext OPTIONAL
+    )
+{
+    BOOLEAN             ReInsert = (BOOLEAN)(ULONG_PTR)InsertContext;
+    PXENCONS_STREAM     Stream;
+
+    Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+    if (ReInsert) {
+        // This only occurs if the worker thread de-queued the IRP but
+        // then found the console to be blocked.
+        InsertHeadList(&Stream->List, &Irp->Tail.Overlay.ListEntry);
+    } else {
+        InsertTailList(&Stream->List, &Irp->Tail.Overlay.ListEntry);
+        ThreadWake(Stream->Thread);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+IO_CSQ_REMOVE_IRP StreamCsqRemoveIrp;
+
+VOID
+StreamCsqRemoveIrp(
+    IN  PIO_CSQ Csq,
+    IN  PIRP    Irp
+    )
+{
+    UNREFERENCED_PARAMETER(Csq);
+
+    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+IO_CSQ_PEEK_NEXT_IRP StreamCsqPeekNextIrp;
+
+PIRP
+StreamCsqPeekNextIrp(
+    IN  PIO_CSQ     Csq,
+    IN  PIRP        Irp,
+    IN  PVOID       PeekContext OPTIONAL
+    )
+{
+    PXENCONS_STREAM Stream;
+    PLIST_ENTRY     ListEntry;
+    PIRP            NextIrp;
+
+    UNREFERENCED_PARAMETER(PeekContext);
+
+    Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+    ListEntry = (Irp == NULL) ?
+                Stream->List.Flink :
+                Irp->Tail.Overlay.ListEntry.Flink;
+
+    if (ListEntry == &Stream->List)
+        return NULL;
+
+    NextIrp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
+
+    return NextIrp;
+}
+
+#pragma warning(push)
+#pragma warning(disable:28167) // function changes IRQL
+
+IO_CSQ_ACQUIRE_LOCK StreamCsqAcquireLock;
+
+VOID
+StreamCsqAcquireLock(
+    IN  PIO_CSQ Csq,
+    OUT PKIRQL  Irql
+    )
+{
+    PXENCONS_STREAM Stream;
+
+    Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+    KeAcquireSpinLock(&Stream->Lock, Irql);
+}
+
+IO_CSQ_RELEASE_LOCK StreamCsqReleaseLock;
+
+VOID
+StreamCsqReleaseLock(
+    IN  PIO_CSQ Csq,
+    IN  KIRQL   Irql
+    )
+{
+    PXENCONS_STREAM Stream;
+
+    Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+    KeReleaseSpinLock(&Stream->Lock, Irql);
+}
+
+#pragma warning(pop)
+
+IO_CSQ_COMPLETE_CANCELED_IRP StreamCsqCompleteCanceledIrp;
+
+VOID
+StreamCsqCompleteCanceledIrp(
+    IN  PIO_CSQ Csq,
+    IN  PIRP    Irp
+    )
+{
+    PIO_STACK_LOCATION  StackLocation;
+    UCHAR               MajorFunction;
+
+    UNREFERENCED_PARAMETER(Csq);
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    MajorFunction = StackLocation->MajorFunction;
+
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+
+    Trace("COMPLETE (%02x:%s)\n",
+          MajorFunction,
+          MajorFunctionName(MajorFunction));
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+static NTSTATUS
+StreamWorker(
+    IN  PXENCONS_THREAD     Self,
+    IN  PVOID               Context
+    )
+{
+    PXENCONS_STREAM         Stream = Context;
+    PKEVENT                 Event;
+    PXENBUS_CONSOLE_WAKEUP  Wakeup;
+    NTSTATUS                status;
+
+    Trace("====>\n");
+
+    Event = ThreadGetEvent(Self);
+
+    status = XENBUS_CONSOLE(Acquire,
+                            &Stream->ConsoleInterface);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = XENBUS_CONSOLE(WakeupAdd,
+                            &Stream->ConsoleInterface,
+                            Event,
+                            &Wakeup);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    for (;;) {
+        PIRP    Irp;
+
+        (VOID) KeWaitForSingleObject(Event,
+                                     Executive,
+                                     KernelMode,
+                                     FALSE,
+                                     NULL);
+        KeClearEvent(Event);
+
+        if (ThreadIsAlerted(Self))
+            break;
+
+        for (Irp = IoCsqRemoveNextIrp(&Stream->Csq, NULL);
+             Irp != NULL;
+             Irp = IoCsqRemoveNextIrp(&Stream->Csq, NULL)) {
+            PIO_STACK_LOCATION  StackLocation;
+            UCHAR               MajorFunction;
+            BOOLEAN             Blocked;
+
+            StackLocation = IoGetCurrentIrpStackLocation(Irp);
+            MajorFunction = StackLocation->MajorFunction;
+
+            switch (MajorFunction) {
+            case IRP_MJ_READ:
+                Blocked = !XENBUS_CONSOLE(CanRead,
+                                          &Stream->ConsoleInterface);
+                break;
+
+            case IRP_MJ_WRITE:
+                Blocked = !XENBUS_CONSOLE(CanWrite,
+                                          &Stream->ConsoleInterface);
+                break;
+
+            default:
+                ASSERT(FALSE);
+
+                Blocked = TRUE;
+                break;
+            }
+
+            if (Blocked) {
+                status = IoCsqInsertIrpEx(&Stream->Csq,
+                                          Irp,
+                                          NULL,
+                                          (PVOID)TRUE);
+                ASSERT(NT_SUCCESS(status));
+
+                break;
+            }
+
+            switch (MajorFunction) {
+            case IRP_MJ_READ: {
+                ULONG   Length;
+                PCHAR   Buffer;
+                ULONG   Read;
+
+                Length = StackLocation->Parameters.Read.Length;
+                Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+                Read = XENBUS_CONSOLE(Read,
+                                      &Stream->ConsoleInterface,
+                                      Buffer,
+                                      Length);
+
+                Irp->IoStatus.Information = Read;
+                Irp->IoStatus.Status = STATUS_SUCCESS;
+                break;
+            }
+            case IRP_MJ_WRITE: {
+                ULONG   Length;
+                PCHAR   Buffer;
+                ULONG   Written;
+
+                Length = StackLocation->Parameters.Write.Length;
+                Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+                Written = XENBUS_CONSOLE(Write,
+                                         &Stream->ConsoleInterface,
+                                         Buffer,
+                                         Length);
+
+                Irp->IoStatus.Information = Written;
+                Irp->IoStatus.Status = STATUS_SUCCESS;
+                break;
+            }
+            default:
+                ASSERT(FALSE);
+
+                Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+                break;
+            }
+
+            Trace("COMPLETE (%02x:%s) (%u bytes)\n",
+                  MajorFunction,
+                  MajorFunctionName(MajorFunction),
+                  Irp->IoStatus.Information);
+
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        }
+    }
+
+    XENBUS_CONSOLE(WakeupRemove,
+                   &Stream->ConsoleInterface,
+                   Wakeup);
+
+    XENBUS_CONSOLE(Release, &Stream->ConsoleInterface);
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+    XENBUS_CONSOLE(Release, &Stream->ConsoleInterface);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+StreamCreate(
+    IN  PXENCONS_FDO    Fdo,
+    OUT PXENCONS_STREAM *Stream
+    )
+{
+    NTSTATUS            status;
+
+    *Stream = __StreamAllocate(sizeof (XENCONS_STREAM));
+
+    status = STATUS_NO_MEMORY;
+    if (*Stream == NULL)
+        goto fail1;
+
+    FdoGetConsoleInterface(Fdo, &(*Stream)->ConsoleInterface);
+
+    KeInitializeSpinLock(&(*Stream)->Lock);
+    InitializeListHead(&(*Stream)->List);
+
+    status = IoCsqInitializeEx(&(*Stream)->Csq,
+                               StreamCsqInsertIrpEx,
+                               StreamCsqRemoveIrp,
+                               StreamCsqPeekNextIrp,
+                               StreamCsqAcquireLock,
+                               StreamCsqReleaseLock,
+                               StreamCsqCompleteCanceledIrp);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ThreadCreate(StreamWorker,
+                          *Stream,
+                          &(*Stream)->Thread);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    (*Stream)->Fdo = Fdo;
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+    RtlZeroMemory(&(*Stream)->Csq, sizeof (IO_CSQ));
+
+fail2:
+    Error("fail2\n");
+
+    RtlZeroMemory(&(*Stream)->List, sizeof (LIST_ENTRY));
+    RtlZeroMemory(&(*Stream)->Lock, sizeof (KSPIN_LOCK));
+
+    RtlZeroMemory(&(*Stream)->ConsoleInterface,
+                  sizeof (XENBUS_CONSOLE_INTERFACE));
+
+    ASSERT(IsZeroMemory(*Stream, sizeof (XENCONS_STREAM)));
+    __StreamFree(*Stream);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+VOID
+StreamDestroy(
+    IN  PXENCONS_STREAM Stream
+    )
+{
+    Stream->Fdo = NULL;
+
+    ThreadAlert(Stream->Thread);
+    ThreadJoin(Stream->Thread);
+    Stream->Thread = NULL;
+
+    RtlZeroMemory(&Stream->Csq, sizeof (IO_CSQ));
+
+    RtlZeroMemory(&Stream->List, sizeof (LIST_ENTRY));
+    RtlZeroMemory(&Stream->Lock, sizeof (KSPIN_LOCK));
+
+    RtlZeroMemory(&Stream->ConsoleInterface,
+                  sizeof (XENBUS_CONSOLE_INTERFACE));
+
+    ASSERT(IsZeroMemory(Stream, sizeof (XENCONS_STREAM)));
+    __StreamFree(Stream);
+}
+
+NTSTATUS
+StreamPutQueue(
+    IN  PXENCONS_STREAM Stream,
+    IN  PIRP            Irp
+    )
+{
+    return IoCsqInsertIrpEx(&Stream->Csq, Irp, NULL, (PVOID)FALSE);
+}
diff --git a/src/xencons/stream.h b/src/xencons/stream.h
new file mode 100644 (file)
index 0000000..5fa85ce
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENCONS_STREAM_H
+#define _XENCONS_STREAM_H
+
+#include <ntddk.h>
+
+#include "fdo.h"
+
+typedef struct _XENCONS_STREAM XENCONS_STREAM, *PXENCONS_STREAM;
+
+extern NTSTATUS
+StreamCreate(
+    IN  PXENCONS_FDO    Fdo,
+    OUT PXENCONS_STREAM *Stream
+    );
+
+extern VOID
+StreamDestroy(
+    IN  PXENCONS_STREAM Stream
+    );
+
+extern NTSTATUS
+StreamPutQueue(
+    IN  PXENCONS_STREAM Stream,
+    IN  PIRP            Irp
+    );
+
+#endif  // _XENCONS_STREAM_H
index 9f8d4ee2a125ee635c6d016bcf66126af58ee666..ff65d9f7deb87f2f84238362a1a80bea6a80e76a 100644 (file)
@@ -67,6 +67,7 @@
     <ClCompile Include="../../src/xencons/driver.c" />
     <ClCompile Include="../../src/xencons/fdo.c" />
     <ClCompile Include="../../src/xencons/registry.c" />
+    <ClCompile Include="../../src/xencons/stream.c" />
     <ClCompile Include="../../src/xencons/thread.c" />
   </ItemGroup>
   <ItemGroup>