[WDF] Add Windows Driver Framework files
[reactos.git] / sdk / lib / drivers / wdf / shared / core / fxcxdeviceinitapi.cpp
diff --git a/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinitapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinitapi.cpp
new file mode 100644 (file)
index 0000000..ecc9d93
--- /dev/null
@@ -0,0 +1,501 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+    FxCxDeviceInitApi.cpp
+
+Abstract:
+
+    This module exposes the "C" interface to the FxDevice object
+    for the class extensions.
+
+Author:
+
+
+
+Environment:
+
+    Both kernel and user mode
+
+Revision History:
+
+
+
+--*/
+
+#include "coreprivshared.hpp"
+
+extern "C" {
+#include "FxCxDeviceInitApi.tmh"
+}
+
+//
+// Extern "C" the entire file
+//
+extern "C" {
+
+__inline
+static
+NTSTATUS
+FxValiateCx(
+    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+    __in PFX_DRIVER_GLOBALS CxDriverGlobals
+    )
+{
+    NTSTATUS status = STATUS_SUCCESS;
+
+    if (FxIsClassExtension(FxDriverGlobals, CxDriverGlobals) == FALSE) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+                            "This function can only be called by a WDF "
+                            "extension driver, Driver 0x%p, %!STATUS!",
+                            CxDriverGlobals->Public.Driver, status);
+        FxVerifierDbgBreakPoint(FxDriverGlobals);
+    }
+
+    return status;
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(DISPATCH_LEVEL)
+WDFAPI
+NTSTATUS
+WDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)(
+    __in
+    PWDF_DRIVER_GLOBALS DriverGlobals,
+    __in
+    PWDFCXDEVICE_INIT   CxDeviceInit,
+    __in
+    PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess,
+    __in
+    UCHAR MajorFunction,
+    __drv_when(NumMinorFunctions > 0, __in_bcount(NumMinorFunctions))
+    __drv_when(NumMinorFunctions == 0, __in_opt)
+    PUCHAR MinorFunctions,
+    __in
+    ULONG NumMinorFunctions
+    )
+{
+    DDI_ENTRY();
+
+    PFX_DRIVER_GLOBALS fxDriverGlobals;
+    PFX_DRIVER_GLOBALS cxDriverGlobals;
+    NTSTATUS status;
+
+    cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
+    FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
+    fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
+
+    //
+    // Caller must be a class extension driver.
+    //
+    status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
+    if (!NT_SUCCESS(status)) {
+        goto Done;
+    }
+
+    FxPointerNotNull(fxDriverGlobals, EvtCxDeviceWdmIrpPreprocess);
+
+    if (NumMinorFunctions > 0) {
+        FxPointerNotNull(fxDriverGlobals, MinorFunctions);
+    }
+
+    //
+    // ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch) just returns a
+    // constant size, it does not actually deref PreprocessInfo (which could
+    // be NULL)
+    //
+    if (MajorFunction >= ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch)) {
+        status = STATUS_INVALID_PARAMETER;
+        DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+                            "MajorFunction %x is invalid, %!STATUS!",
+                            (ULONG)MajorFunction, status);
+
+        goto Done;
+    }
+
+    //
+    // CX must call this API multiple times if it wants to register preprocess callbacks for
+    // multiple IRP major codes.
+    //
+    if (CxDeviceInit->PreprocessInfo == NULL) {
+        CxDeviceInit->PreprocessInfo = new(fxDriverGlobals) FxIrpPreprocessInfo();
+        if (CxDeviceInit->PreprocessInfo == NULL) {
+            status = STATUS_INSUFFICIENT_RESOURCES;
+            DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+                                "Couldn't create object PreprocessInfo, "
+                                "%!STATUS!", status);
+
+            goto Done;
+        }
+        CxDeviceInit->PreprocessInfo->ClassExtension = TRUE;
+    }
+
+    ASSERT(CxDeviceInit->PreprocessInfo->ClassExtension);
+
+    if (NumMinorFunctions > 0) {
+        if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions != 0) {
+            status = STATUS_INVALID_DEVICE_REQUEST;
+            DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+                                "Already assigned Minorfunctions, %!STATUS!",
+                                status);
+            goto Done;
+        }
+
+        CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions =
+            (PUCHAR) FxPoolAllocate(fxDriverGlobals,
+                                    NonPagedPool,
+                                    sizeof(UCHAR) * NumMinorFunctions);
+
+        if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions == NULL) {
+            status = STATUS_INSUFFICIENT_RESOURCES;
+            DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+                                "Couldn't create object MinorFunctions, "
+                                "%!STATUS!", status);
+            goto Done;
+        }
+
+        RtlCopyMemory(
+            &CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions[0],
+            &MinorFunctions[0],
+            NumMinorFunctions
+            );
+
+        CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions =
+            NumMinorFunctions;
+    }
+
+    CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].EvtCxDevicePreprocess =
+        EvtCxDeviceWdmIrpPreprocess;
+
+    status = STATUS_SUCCESS;
+
+Done:
+    return status;
+}
+
+__drv_maxIRQL(DISPATCH_LEVEL)
+VOID
+WDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)(
+    __in
+    PWDF_DRIVER_GLOBALS DriverGlobals,
+    __in
+    PWDFCXDEVICE_INIT CxDeviceInit,
+    __in
+    PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext
+    )
+
+/*++
+
+Routine Description:
+
+    Registers an I/O pre-processing callback for the class extension device.
+
+    If registered, any I/O for the device is first presented to this
+    callback function before being placed in any I/O Queue's.
+
+    The callback is invoked in the thread and/or DPC context of the
+    original WDM caller as presented to the I/O package. No framework
+    threading, locking, synchronization, or queuing occurs, and
+    responsibility for synchronization is up to the device driver.
+
+    This API is intended to support METHOD_NEITHER IRP_MJ_DEVICE_CONTROL's
+    which must access the user buffer in the original callers context. The
+    driver would probe and lock the buffer pages from within this event
+    handler using the functions supplied on the WDFREQUEST object, storing
+    any required mapped buffers and/or pointers on the WDFREQUEST context
+    whose size is set by the RequestContextSize of the WDF_DRIVER_CONFIG structure.
+
+    It is the responsibility of this routine to either complete the request, or
+    pass it on to the I/O package through WdfDeviceEnqueueRequest(Device, Request).
+
+Arguments:
+
+    CxDeviceInit - Class Extension Device initialization structure
+
+    EvtIoInCallerContext - Pointer to driver supplied callback function
+
+Return Value:
+
+    None
+
+--*/
+{
+    DDI_ENTRY();
+
+    PFX_DRIVER_GLOBALS fxDriverGlobals;
+    PFX_DRIVER_GLOBALS cxDriverGlobals;
+    NTSTATUS status;
+
+    cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
+    FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
+    fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
+
+    //
+    // Caller must be a class extension driver.
+    //
+    status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
+    if (!NT_SUCCESS(status)) {
+        goto Done;
+    }
+
+    FxPointerNotNull(fxDriverGlobals, EvtIoInCallerContext);
+
+    CxDeviceInit->IoInCallerContextCallback = EvtIoInCallerContext;
+
+Done:
+    return;
+}
+
+__drv_maxIRQL(DISPATCH_LEVEL)
+VOID
+WDFEXPORT(WdfCxDeviceInitSetRequestAttributes)(
+    __in
+    PWDF_DRIVER_GLOBALS DriverGlobals,
+    __in
+    PWDFCXDEVICE_INIT CxDeviceInit,
+    __in
+    PWDF_OBJECT_ATTRIBUTES RequestAttributes
+    )
+{
+    DDI_ENTRY();
+
+    PFX_DRIVER_GLOBALS fxDriverGlobals;
+    PFX_DRIVER_GLOBALS cxDriverGlobals;
+    NTSTATUS status;
+
+    cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
+    FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
+    fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
+
+    //
+    // Caller must be a class extension driver.
+    //
+    status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
+    if (!NT_SUCCESS(status)) {
+        goto Done;
+    }
+
+    FxPointerNotNull(fxDriverGlobals, RequestAttributes);
+
+    //
+    // Parent of all requests created from WDFDEVICE are parented by the WDFDEVICE.
+    //
+    status = FxValidateObjectAttributes(fxDriverGlobals,
+                                        RequestAttributes,
+                                        FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
+
+    if (!NT_SUCCESS(status)) {
+        FxVerifierDbgBreakPoint(fxDriverGlobals);
+        return;
+    }
+
+    RtlCopyMemory(&CxDeviceInit->RequestAttributes,
+                  RequestAttributes,
+                  sizeof(WDF_OBJECT_ATTRIBUTES));
+
+Done:
+    return;
+}
+
+__drv_maxIRQL(DISPATCH_LEVEL)
+VOID
+WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)(
+    __in
+    PWDF_DRIVER_GLOBALS DriverGlobals,
+    __in
+    PWDFCXDEVICE_INIT CxDeviceInit,
+    __in
+    PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig,
+    __in_opt
+    PWDF_OBJECT_ATTRIBUTES FileObjectAttributes
+    )
+
+/*++
+
+Routine Description:
+
+    Registers file object callbacks for class extensions.
+
+    Defaults to WdfFileObjectNotRequired if no file obj config set.
+
+Arguments:
+
+Returns:
+
+--*/
+
+{
+    DDI_ENTRY();
+
+    PFX_DRIVER_GLOBALS fxDriverGlobals;
+    PFX_DRIVER_GLOBALS cxDriverGlobals;
+    NTSTATUS status;
+    WDF_FILEOBJECT_CLASS normalizedFileClass;
+
+    cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
+    FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
+    fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
+
+    //
+    // Caller must be a class extension driver.
+    //
+    status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
+    if (!NT_SUCCESS(status)) {
+        goto Done;
+    }
+
+    FxPointerNotNull(fxDriverGlobals, CxFileObjectConfig);
+
+    if (CxFileObjectConfig->Size != sizeof(WDFCX_FILEOBJECT_CONFIG)) {
+        DoTraceLevelMessage(
+            fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+            "Invalid CxFileObjectConfig Size %d, expected %d",
+            CxFileObjectConfig->Size, sizeof(WDFCX_FILEOBJECT_CONFIG));
+
+        FxVerifierDbgBreakPoint(fxDriverGlobals);
+        goto Done;
+    }
+
+    status = FxValidateObjectAttributes(
+        fxDriverGlobals,
+        FileObjectAttributes,
+        FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED |
+            FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED |
+            FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED
+        );
+
+    if (!NT_SUCCESS(status)) {
+        FxVerifierDbgBreakPoint(fxDriverGlobals);
+        goto Done;
+    }
+
+    //
+    // Validate AutoForwardCleanupClose.
+    //
+    switch (CxFileObjectConfig->AutoForwardCleanupClose) {
+    case WdfTrue:
+    case WdfFalse:
+    case WdfUseDefault:
+        break;
+
+    default:
+        DoTraceLevelMessage(
+            fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+            "Invalid CxFileObjectConfig->AutoForwardCleanupClose value 0x%x, "
+            "expected WDF_TRI_STATE value",
+            CxFileObjectConfig->AutoForwardCleanupClose);
+
+        FxVerifierDbgBreakPoint(fxDriverGlobals);
+        goto Done;
+    }
+
+    CxDeviceInit->FileObject.Set = TRUE;
+
+    CxDeviceInit->FileObject.AutoForwardCleanupClose =
+        CxFileObjectConfig->AutoForwardCleanupClose;
+
+    //
+    // Remove bit flags and validate file object class value.
+    //
+    normalizedFileClass = FxFileObjectClassNormalize(
+                                CxFileObjectConfig->FileObjectClass);
+
+    if (normalizedFileClass == WdfFileObjectInvalid ||
+        normalizedFileClass > WdfFileObjectWdfCannotUseFsContexts)  {
+        DoTraceLevelMessage(
+            fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+            "Out of range CxFileObjectConfig->FileObjectClass %d",
+            CxFileObjectConfig->FileObjectClass);
+        FxVerifierDbgBreakPoint(fxDriverGlobals);
+        goto Done;
+    }
+
+    //
+    // The optional flag can only be combined with a subset of values.
+    //
+    if (FxIsFileObjectOptional(CxFileObjectConfig->FileObjectClass)) {
+        switch(normalizedFileClass) {
+        case WdfFileObjectWdfCanUseFsContext:
+        case WdfFileObjectWdfCanUseFsContext2:
+        case WdfFileObjectWdfCannotUseFsContexts:
+            break;
+
+        default:
+            DoTraceLevelMessage(
+                fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
+                "Invalid CxFileObjectConfig->FileObjectClass %d",
+                CxFileObjectConfig->FileObjectClass);
+            FxVerifierDbgBreakPoint(fxDriverGlobals);
+            goto Done;
+            break; // just in case static verification tools complain.
+        }
+    }
+
+    CxDeviceInit->FileObject.Class = CxFileObjectConfig->FileObjectClass;
+
+    RtlCopyMemory(&CxDeviceInit->FileObject.Callbacks,
+                  CxFileObjectConfig,
+                  sizeof(CxDeviceInit->FileObject.Callbacks));
+
+    if (FileObjectAttributes != NULL) {
+        RtlCopyMemory(&CxDeviceInit->FileObject.Attributes,
+                      FileObjectAttributes,
+                      sizeof(CxDeviceInit->FileObject.Attributes));
+    }
+
+Done:
+    return;
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+PWDFCXDEVICE_INIT
+WDFEXPORT(WdfCxDeviceInitAllocate)(
+    __in
+    PWDF_DRIVER_GLOBALS DriverGlobals,
+    __in
+    PWDFDEVICE_INIT DeviceInit
+    )
+{
+    DDI_ENTRY();
+
+    PFX_DRIVER_GLOBALS cxDriverGlobals;
+    PFX_DRIVER_GLOBALS fxDriverGlobals;
+    PWDFCXDEVICE_INIT  cxDeviceInit;
+    NTSTATUS status;
+
+    cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
+    FxPointerNotNull(cxDriverGlobals, DeviceInit);
+    fxDriverGlobals = DeviceInit->DriverGlobals;
+    cxDeviceInit = NULL;
+
+    //
+    // Caller must be a class extension driver.
+    //
+    status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
+    if (!NT_SUCCESS(status)) {
+        goto Done;
+    }
+
+    status = FxVerifierCheckIrqlLevel(fxDriverGlobals, PASSIVE_LEVEL);
+    if (!NT_SUCCESS(status)) {
+        goto Done;
+    }
+
+    cxDeviceInit = WDFCXDEVICE_INIT::_AllocateCxDeviceInit(DeviceInit);
+    if (NULL == cxDeviceInit) {
+        goto Done;
+    }
+
+    cxDeviceInit->ClientDriverGlobals = fxDriverGlobals;
+    cxDeviceInit->CxDriverGlobals = cxDriverGlobals;
+
+Done:
+    return cxDeviceInit;
+}
+
+} // extern "C"
+