diff --git a/Dmf/Documentation/Driver Module Framework.docx b/Dmf/Documentation/Driver Module Framework.docx index 21a9dc76..fa0ea2d7 100644 Binary files a/Dmf/Documentation/Driver Module Framework.docx and b/Dmf/Documentation/Driver Module Framework.docx differ diff --git a/Dmf/Framework/DmfCall.c b/Dmf/Framework/DmfCall.c index 88a96a3f..fbe388e4 100644 --- a/Dmf/Framework/DmfCall.c +++ b/Dmf/Framework/DmfCall.c @@ -2302,12 +2302,6 @@ Return Value: ntStatus = STATUS_SUCCESS; - DMF_ModuleLock(DmfModule); - - parentDmfObject->ReferenceCount = 1; - - DMF_ModuleUnlock(DmfModule); - if (!DMF_IsObjectTypeOpenNotify(parentDmfObject)) { // Dispatch callback to Child DMF Modules first. @@ -2344,6 +2338,15 @@ Return Value: goto Exit; } + // Allow DMF_ModuleReference to succeed only after the Module is completely open. + // + DMF_ModuleLock(DmfModule); + + ASSERT(parentDmfObject->ReferenceCount == 0); + parentDmfObject->ReferenceCount = 1; + + DMF_ModuleUnlock(DmfModule); + Exit: return ntStatus; @@ -2606,8 +2609,6 @@ Return Value: parentDmfObject = DMF_ModuleToObject(DmfModule); - DMF_ModuleWaitForReferenceCountToClear(DmfModule); - // Dispatch callback to this Module first. // ASSERT(parentDmfObject->InternalCallbacksDmf.DeviceClose != NULL); diff --git a/Dmf/Framework/DmfDefinitions.h b/Dmf/Framework/DmfDefinitions.h index 3a234a05..91bc2aab 100644 --- a/Dmf/Framework/DmfDefinitions.h +++ b/Dmf/Framework/DmfDefinitions.h @@ -138,6 +138,7 @@ extern "C" #endif // defined(DMF_USER_MODE) #include #include +#include //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -501,7 +502,7 @@ DmfDriverContextCleanup( _In_ WDFOBJECT DriverObject \ ) \ { \ - WPP_CLEANUP(DriverObject); \ + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); \ } \ \ @@ -669,8 +670,7 @@ DmfDriverContextCleanup( _In_ WDFOBJECT DriverObject \ ) \ { \ - UNREFERENCED_PARAMETER(DriverObject); \ - WPP_CLEANUP(DriverObject); \ + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); \ } \ #else diff --git a/Dmf/Framework/DmfIncludeInternal.h b/Dmf/Framework/DmfIncludeInternal.h index 2e748be0..2a13ecf6 100644 --- a/Dmf/Framework/DmfIncludeInternal.h +++ b/Dmf/Framework/DmfIncludeInternal.h @@ -1295,6 +1295,11 @@ DMF_Module_CloseOnDestroy( _In_ DMFMODULE DmfModule ); +VOID +DMF_ModuleWaitForReferenceCountToClear( + _In_ DMFMODULE DmfModule + ); + // DmfContainer.c // diff --git a/Dmf/Framework/DmfInternal.c b/Dmf/Framework/DmfInternal.c index db207d95..2fd25aee 100644 --- a/Dmf/Framework/DmfInternal.c +++ b/Dmf/Framework/DmfInternal.c @@ -1640,6 +1640,11 @@ Return Value: dmfObject->NeedToCallPreClose = FALSE; } + // Now that PreClose is done, wait for reference count to clear and close the Module. + // This allows PreClose to access Module Methods if needed. + // + DMF_ModuleWaitForReferenceCountToClear(DmfModule); + dmfObject->ModuleState = ModuleState_Closing; ASSERT(dmfObject->ModuleDescriptor.CallbacksDmf->DeviceClose != NULL); diff --git a/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.c b/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.c index c189be4a..4a16d9bd 100644 --- a/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.c +++ b/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.c @@ -41,6 +41,7 @@ typedef struct // It is a collection of all the Open File Objects that are running "As Administrator". // WDFCOLLECTION AdministratorFileObjectsCollection; + IoctlHandler_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA* IoSetDeviceInterfacePropertyData; } DMF_CONTEXT_IoctlHandler; // This macro declares the following function: @@ -58,6 +59,132 @@ DMF_MODULE_DECLARE_CONFIG(IoctlHandler) /////////////////////////////////////////////////////////////////////////////////////////////////////// // +#if !defined(DMF_USER_MODE) + +#pragma code_seg("PAGE") +static +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +IoctlHandler_PostDeviceInterfaceCreate( + _In_ DMFMODULE DmfModule + ) +{ + NTSTATUS ntStatus; + DMF_CONTEXT_IoctlHandler* moduleContext; + DMF_CONFIG_IoctlHandler* moduleConfig; + WDFDEVICE device; + UNICODE_STRING symbolicLinkName; + WDFSTRING symbolicLinkNameString; + DEVPROP_BOOLEAN isRestricted; + UNICODE_STRING functionName; + + ntStatus = STATUS_SUCCESS; + moduleContext = DMF_CONTEXT_GET(DmfModule); + moduleConfig = DMF_CONFIG_GET(DmfModule); + device = DMF_ParentDeviceGet(DmfModule); + symbolicLinkNameString = NULL; + + // If possible, get the IoSetDeviceInterfacePropertyData. + // + RtlInitUnicodeString(&functionName, L"IoSetDeviceInterfacePropertyData"); + moduleContext->IoSetDeviceInterfacePropertyData = (IoctlHandler_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA*)(ULONG_PTR)MmGetSystemRoutineAddress(&functionName); + + // If the Client has set the IsRestricted or CustomProperty fields, try to set those properties. + // + if ((moduleContext->IoSetDeviceInterfacePropertyData != NULL) && + ((moduleConfig->IsRestricted) || + (moduleConfig->CustomCapabilities != NULL))) + { + ntStatus = WdfStringCreate(NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &symbolicLinkNameString); + if (!NT_SUCCESS(ntStatus)) + { + TraceEvents(TRACE_LEVEL_ERROR, DMF_TRACE_IoctlHandler, "WdfStringCreate fails: ntStatus=%!STATUS!", ntStatus); + goto Exit; + } + + ntStatus = WdfDeviceRetrieveDeviceInterfaceString(device, + &moduleConfig->DeviceInterfaceGuid, + NULL, + symbolicLinkNameString); + if (!NT_SUCCESS(ntStatus)) + { + TraceEvents(TRACE_LEVEL_ERROR, DMF_TRACE_IoctlHandler, "WdfDeviceRetrieveDeviceInterfaceString fails: ntStatus=%!STATUS!", ntStatus); + goto Exit; + } + + WdfStringGetUnicodeString(symbolicLinkNameString, + &symbolicLinkName); + + isRestricted = moduleConfig->IsRestricted; + + ntStatus = moduleContext->IoSetDeviceInterfacePropertyData(&symbolicLinkName, + &DEVPKEY_DeviceInterface_Restricted, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(isRestricted), + &isRestricted ); + if (!NT_SUCCESS(ntStatus)) + { + TraceEvents(TRACE_LEVEL_ERROR, DMF_TRACE_IoctlHandler, "IoSetDeviceInterfacePropertyData fails: ntStatus=%!STATUS!", ntStatus); + goto Exit; + } + +#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2) + if (moduleConfig->CustomCapabilities != NULL) + { + // Adds a custom capability to device interface instance that allows a Windows + // Store device app to access this interface using Windows.Devices.Custom namespace. + + // Get size of buffer. Add space for double \0 terminator. + // + ULONG stringLength = (ULONG)wcslen(moduleConfig->CustomCapabilities); + ULONG bufferSize = (stringLength * sizeof(WCHAR)) + (2 * sizeof(WCHAR)); + + ntStatus = moduleContext->IoSetDeviceInterfacePropertyData(&symbolicLinkName, + &DEVPKEY_DeviceInterface_UnrestrictedAppCapabilities, + 0, + 0, + DEVPROP_TYPE_STRING_LIST, + bufferSize, + (PVOID)moduleConfig->CustomCapabilities); + if (!NT_SUCCESS(ntStatus)) + { + TraceEvents(TRACE_LEVEL_ERROR, DMF_TRACE_IoctlHandler, "IoSetDeviceInterfacePropertyData fails: ntStatus=%!STATUS!", ntStatus); + goto Exit; + } + } +#endif // defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2) + } + + // Optionaly, allow Client to perform other operations. Give Client access to the IoSetDeviceInterfacePropertyData function, + // but Client is responsible for checking if it is NULL and dealing with that. + // + if (moduleConfig->PostDeviceInterfaceCreate != NULL) + { + ntStatus = moduleConfig->PostDeviceInterfaceCreate(DmfModule, + moduleConfig->DeviceInterfaceGuid, + symbolicLinkNameString, + moduleContext->IoSetDeviceInterfacePropertyData); + } + +Exit: + + if (symbolicLinkNameString != NULL) + { + WdfObjectDelete(symbolicLinkNameString); + } + + // NOTE: Module will not open if this function returns an error. + // + return ntStatus; +} + +#endif + /////////////////////////////////////////////////////////////////////////////////////////////////////// // Wdf Module Callbacks /////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -246,6 +373,7 @@ Return Value: // Buffer is validated. Call client handler. // ntStatus = ioctlRecord->EvtIoctlHandlerFunction(DmfModule, + Queue, Request, IoControlCode, inputBuffer, @@ -632,6 +760,14 @@ Return Value: TraceEvents(TRACE_LEVEL_ERROR, DMF_TRACE_IoctlHandler, "WdfDeviceCreateDeviceInterface fails: ntStatus=%!STATUS!", ntStatus); goto Exit; } +#if !defined(DMF_USER_MODE) + ntStatus = IoctlHandler_PostDeviceInterfaceCreate(DmfModule); + if (! NT_SUCCESS(ntStatus)) + { + TraceEvents(TRACE_LEVEL_ERROR, DMF_TRACE_IoctlHandler, "IoctlHandler_PostDeviceInterfaceCreate fails: ntStatus=%!STATUS!", ntStatus); + goto Exit; + } +#endif } else { diff --git a/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.h b/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.h index 454d85de..7fbd7a88 100644 --- a/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.h +++ b/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.h @@ -29,6 +29,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ NTSTATUS EVT_DMF_IoctlHandler_Callback(_In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -54,6 +55,29 @@ EVT_DMF_IoctlHandler_AccessModeFilter(_In_ DMFMODULE DmfModule, _In_ WDFREQUEST Request, _In_ WDFFILEOBJECT FileObject); +typedef +_Function_class_(IoctlHandler_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) +_IRQL_requires_max_(PASSIVE_LEVEL) +_IRQL_requires_same_ +NTSTATUS +IoctlHandler_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA(_In_ PUNICODE_STRING SymbolicLinkName, + _In_ CONST DEVPROPKEY* PropertyKey, + _In_ LCID Lcid, + _In_ ULONG Flags, + _In_ DEVPROPTYPE Type, + _In_ ULONG Size, + _In_opt_ PVOID Data); + +typedef +_Function_class_(EVT_DMF_IoctlHandler_PostDeviceInterfaceCreate) +_IRQL_requires_max_(PASSIVE_LEVEL) +_IRQL_requires_same_ +NTSTATUS +EVT_DMF_IoctlHandler_PostDeviceInterfaceCreate(_In_ DMFMODULE DmfModule, + _In_ GUID DeviceInterfaceGuid, + _In_ WDFSTRING SymbolicLinkNameString, + _In_ IoctlHandler_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA* IoSetDeviceInterfaceProperty); + // The descriptor for each supported IOCTL. // typedef struct @@ -79,22 +103,21 @@ typedef struct typedef enum { - IoctlHandler_AccessModeFilterInvalid = 0, // Do what WDF would normally do (allow User-mode). // - IoctlHandler_AccessModeDefault = 1, + IoctlHandler_AccessModeDefault, // Call the a Client Callback function that will decide. // - IoctlHandler_AccessModeFilterClientCallback = 2, + IoctlHandler_AccessModeFilterClientCallback, // NOTE: This is currently not implemented. // - IoctlHandler_AccessModeFilterDoNotAllowUserMode = 3, + IoctlHandler_AccessModeFilterDoNotAllowUserMode, // Only allows "Run as Administrator". // - IoctlHandler_AccessModeFilterAdministratorOnly = 4, + IoctlHandler_AccessModeFilterAdministratorOnly, // Allow access to Administrator on a per-IOCTL basis. // - IoctlHandler_AccessModeFilterAdministratorOnlyPerIoctl = 5, + IoctlHandler_AccessModeFilterAdministratorOnlyPerIoctl, } IoctlHandler_AccessModeFilterType; // Client uses this structure to configure the Module specific parameters. @@ -116,6 +139,13 @@ typedef struct // The number of records in the above table. // ULONG IoctlRecordCount; + // Windows Store App access settings. + // + WCHAR* CustomCapabilities; + DEVPROP_BOOLEAN IsRestricted; + // Allows Client to perform actions after the Device Interface is created. + // + EVT_DMF_IoctlHandler_PostDeviceInterfaceCreate* PostDeviceInterfaceCreate; } DMF_CONFIG_IoctlHandler; // This macro declares the following functions: diff --git a/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.txt b/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.txt index b38dcea7..1d118a2b 100644 --- a/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.txt +++ b/Dmf/Framework/Modules.Core/Dmf_IoctlHandler.txt @@ -35,6 +35,13 @@ typedef struct // The number of records in the above table. // ULONG IoctlRecordCount; + // Windows Store App access settings. + // + WCHAR* CustomCapabilities; + DEVPROP_BOOLEAN IsRestricted; + // Allows Client to perform actions after the Device Interface is created. + // + EVT_DMF_IoctlHandler_PostDeviceInterfaceCreate* PostDeviceInterfaceCreate; } DMF_CONFIG_IoctlHandler; DeviceInterfaceGuid: @@ -49,26 +56,34 @@ A callback that allows the Client to filter the IOCTL with Client specific logic IoctlRecords: A table of records that specify information about each supported IOCTL. +CustomCapabilities: +Windows Store App access capabilities string. + +IsRestricted: +If set to DEVPROP_TRUE, sets the restricts access to the Device Interface. + +PostDeviceInterfaceCreate: +Allows Client to perform actions after the Device Interface is created. + ====[Module Enumeration Types]====================================================================================================== typedef enum { - IoctlHandler_AccessModeFilterInvalid = 0, // Do what WDF would normally do (allow User-mode). // - IoctlHandler_AccessModeDefault = 1, + IoctlHandler_AccessModeDefault, // Call a Client Callback function that will decide. // - IoctlHandler_AccessModeFilterClientCallback = 2, + IoctlHandler_AccessModeFilterClientCallback, // NOTE: This is currently not implemented. // - IoctlHandler_AccessModeFilterDoNotAllowUserMode = 3, + IoctlHandler_AccessModeFilterDoNotAllowUserMode, // Only allows "Run as Administrator". // - IoctlHandler_AccessModeFilterAdministratorOnly = 4, + IoctlHandler_AccessModeFilterAdministratorOnly, // Allow access to Administrator on a per-IOCTL basis. // - IoctlHandler_AccessModeFilterAdministratorOnlyPerIoctl = 5, + IoctlHandler_AccessModeFilterAdministratorOnlyPerIoctl, } IoctlHandler_AccessModeFilterType; IoctlHandler_AccessModeDefault: @@ -116,6 +131,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ NTSTATUS EVT_DMF_IoctlHandler_Callback(_In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -129,7 +145,8 @@ specified in the IOCTL table passed in during Module instantiation. Returns ------- -NTSTATUS code returned by the Client. +If STATUS_PENDING is returned, then the Request is not completed. If STATUS_SUCCESS or any other NTSTATUS is returned, +then the Request is completed with that NTSTATUS. Parameters ---------- @@ -137,6 +154,9 @@ Parameters DmfModule: An open DMF_IoctlHandler Module handle. +Queue: +The WDFQUEUE handle associated with Request. + Request: The WDFREQUEST that contains the IOCTL parameters and buffers. diff --git a/Dmf/Framework/Modules.Core/Dmf_LiveKernelDump.c b/Dmf/Framework/Modules.Core/Dmf_LiveKernelDump.c index bc5a8ee5..8280800a 100644 --- a/Dmf/Framework/Modules.Core/Dmf_LiveKernelDump.c +++ b/Dmf/Framework/Modules.Core/Dmf_LiveKernelDump.c @@ -797,6 +797,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS LiveKernelDump_IoctlHandler( _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -814,6 +815,7 @@ Routine Description: Arguments: DmfModule - The Child Module from which this callback is called. + Queue - The WDFQUEUE associated with Request. Request - Request data, not used IoctlCode - IOCTL to be used in the command InputBuffer - Input data buffer @@ -833,9 +835,10 @@ Return Value: PLIVEKERNELDUMP_INPUT_BUFFER liveDumpInput; DMFMODULE liveKernelDumpModule; + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(Request); UNREFERENCED_PARAMETER(OutputBuffer); UNREFERENCED_PARAMETER(BytesReturned); - UNREFERENCED_PARAMETER(Request); PAGED_CODE(); diff --git a/Dmf/Modules.Library/Dmf_CrashDump.c b/Dmf/Modules.Library/Dmf_CrashDump.c index 1640d1ba..8b43e622 100644 --- a/Dmf/Modules.Library/Dmf_CrashDump.c +++ b/Dmf/Modules.Library/Dmf_CrashDump.c @@ -2689,6 +2689,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS CrashDump_IoctlHandler( _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -2706,13 +2707,14 @@ Routine Description: Arguments: DmfModule - The Child Module from which this callback is called. - Request - Request data, not used - IoctlCode - IOCTL to be used in the command - InputBuffer - Input data buffer - InputBufferSize - Input data buffer size, not used - OutputBuffer - Output data buffer - OutputBufferSize - Output data buffer size, not used - BytesReturned - Amount of data to be sent back + Queue - The WDFQUEUE associated with Request. + Request - Request data, not used. + IoctlCode - IOCTL to be used in the command. + InputBuffer - Input data buffer. + InputBufferSize - Input data buffer size, not used. + OutputBuffer - Output data buffer. + OutputBufferSize - Output data buffer size, not used. + BytesReturned - Amount of data to be sent back. Return Value: @@ -2724,6 +2726,7 @@ Return Value: DMF_CONTEXT_CrashDump* moduleContext; DMFMODULE dmfModule; + UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(InputBuffer); UNREFERENCED_PARAMETER(OutputBuffer); UNREFERENCED_PARAMETER(BytesReturned); diff --git a/Dmf/Modules.Library/Dmf_GpioTarget.txt b/Dmf/Modules.Library/Dmf_GpioTarget.txt index b8d978ed..675ec684 100644 --- a/Dmf/Modules.Library/Dmf_GpioTarget.txt +++ b/Dmf/Modules.Library/Dmf_GpioTarget.txt @@ -270,7 +270,7 @@ DMF_GpioTarget_IsResourceAssigned( _Out_opt_ BOOLEAN* InterruptAssigned ); -Returns information about how many GPIO lines and interrupts are assigned. +Indicates if the GPIO resources set by the Client have been found. Returns ------- diff --git a/Dmf/Modules.Library/Dmf_I2cTarget.c b/Dmf/Modules.Library/Dmf_I2cTarget.c index 5b8d4c6c..0d281312 100644 --- a/Dmf/Modules.Library/Dmf_I2cTarget.c +++ b/Dmf/Modules.Library/Dmf_I2cTarget.c @@ -43,6 +43,9 @@ Module Name: typedef struct { + // Resources assigned. + // + BOOLEAN I2cConnectionAssigned; // Underlying I2C device. // WDFIOTARGET I2cTarget; @@ -808,6 +811,7 @@ Return Value: { moduleContext->ResourceIndex = i2cResourceCount; moduleContext->I2cConnection = *resource; + moduleContext->I2cConnectionAssigned = TRUE; resourceAssigned = TRUE; } i2cResourceCount++; @@ -817,7 +821,8 @@ Return Value: // Validate the configuration parameters. // - if (0 == i2cResourceCount || (! resourceAssigned)) + if ((moduleConfig->I2cConnectionMandatory) && + (0 == i2cResourceCount || (! resourceAssigned))) { TraceEvents(TRACE_LEVEL_INFORMATION, DMF_TRACE_I2cTarget, "I2C Resources not assigned"); ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR; @@ -1112,5 +1117,50 @@ Return Value: } #pragma code_seg() +#pragma code_seg("PAGE") +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DMF_I2cTarget_IsResourceAssigned( + _In_ DMFMODULE DmfModule, + _Out_opt_ BOOLEAN* I2cConnectionAssigned + ) +/*++ + +Routine Description: + + I2c resources may or may not be present on some systems. This function returns a flag + indicating that the I2c resource requested was found. + +Arguments: + + DmfModule - This Module's handle. + I2xConnectionAssigned - Is I2x connection assigned to this Module instance. + +Return Value: + + None + +--*/ +{ + DMF_CONTEXT_I2cTarget* moduleContext; + + PAGED_CODE(); + + FuncEntry(DMF_TRACE_I2cTarget); + + DMF_HandleValidate_ModuleMethod(DmfModule, + &DmfModuleDescriptor_I2cTarget); + + moduleContext = DMF_CONTEXT_GET(DmfModule); + + if (I2cConnectionAssigned != NULL) + { + *I2cConnectionAssigned = moduleContext->I2cConnectionAssigned; + } + + FuncExitVoid(DMF_TRACE_I2cTarget); +} +#pragma code_seg() + // eof: Dmf_I2cTarget.c // diff --git a/Dmf/Modules.Library/Dmf_I2cTarget.h b/Dmf/Modules.Library/Dmf_I2cTarget.h index 7686fb98..fd5bc8e8 100644 --- a/Dmf/Modules.Library/Dmf_I2cTarget.h +++ b/Dmf/Modules.Library/Dmf_I2cTarget.h @@ -24,6 +24,9 @@ Module Name: // typedef struct { + // Module will not load if I2c Connection not found. + // + BOOLEAN I2cConnectionMandatory; // Indicates the index of I2C resource that the Client wants to access. // ULONG I2cResourceIndex; @@ -90,5 +93,12 @@ DMF_I2cTarget_BufferWrite( _In_ ULONG TimeoutMs ); +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DMF_I2cTarget_IsResourceAssigned( + _In_ DMFMODULE DmfModule, + _Out_opt_ BOOLEAN* I2cConnectionAssigned + ); + // eof: Dmf_I2cTarget.h // diff --git a/Dmf/Modules.Library/Dmf_I2cTarget.txt b/Dmf/Modules.Library/Dmf_I2cTarget.txt index e83b26aa..91556fd6 100644 --- a/Dmf/Modules.Library/Dmf_I2cTarget.txt +++ b/Dmf/Modules.Library/Dmf_I2cTarget.txt @@ -19,6 +19,9 @@ This Module gives the Client access to an underlying I2C device connected on SPB typedef struct { + // Module will not load if Gpio Connection not found. + // + BOOLEAN I2cConnectionMandatory; // Indicates the index of I2C resource that the Client wants to access. // ULONG I2cResourceIndex; @@ -201,6 +204,33 @@ Remarks: ----------------------------------------------------------------------------------------------------------------------------------- +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DMF_I2cTarget_IsResourceAssigned( + _In_ DMFMODULE DmfModule, + _Out_opt_ BOOLEAN* I2cConnectionAssigned + ); + +Indicates if the I2c resource set by the Client has been found. + +Returns +------- +None + +Parameters +---------- +DmfModule: +An open DMF_I2cTarget Module handle. + +I2cConnectionAssigned: +Flag indicating if the I2c resource is found or not. + +Remarks: + * Use this Method to determine if the resources needed are found. This is for the cases where the Client driver runs +regardless of whether or not I2C resource is available. + +----------------------------------------------------------------------------------------------------------------------------------- + ====[Module IOCTLs]================================================================================================================ ====[Module Remarks]=============================================================================================================== diff --git a/Dmf/Modules.Library/Dmf_ResourceHub.c b/Dmf/Modules.Library/Dmf_ResourceHub.c index 9814b21e..770509b3 100644 --- a/Dmf/Modules.Library/Dmf_ResourceHub.c +++ b/Dmf/Modules.Library/Dmf_ResourceHub.c @@ -806,6 +806,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS ResourceHub_IoctlClientCallback_SpbExecuteSequence( _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -818,18 +819,19 @@ ResourceHub_IoctlClientCallback_SpbExecuteSequence( Routine Description: - This routine reads static data of the GPU. + Performs SPB transactions based on IOCTL requests. Arguments: DmfModule - The Child Module from which this callback is called. - Request - Request data - IoctlCode - IOCTL to be used in the command - InputBuffer - Input data buffer - InputBufferSize - Input data buffer size - OutputBuffer - Output data buffer - OutputBufferSize - Output data buffer size - BytesReturned - Amount of data to be sent back + Queue - The WDFQUEUE associated with Request. + Request - Request data. + IoctlCode - IOCTL to be used in the command. + InputBuffer - Input data buffer. + InputBufferSize - Input data buffer size. + OutputBuffer - Output data buffer. + OutputBufferSize - Output data buffer size. + BytesReturned - Amount of data to be sent back. Return Value: @@ -845,6 +847,7 @@ Return Value: WDFFILEOBJECT fileObject; PSPB_TRANSFER_LIST spbTransferList; + UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(IoctlCode); UNREFERENCED_PARAMETER(OutputBuffer); UNREFERENCED_PARAMETER(OutputBufferSize); diff --git a/Dmf/Modules.Template/Dmf_ToasterBus.c b/Dmf/Modules.Template/Dmf_ToasterBus.c index dbf6fd97..e1789c62 100644 --- a/Dmf/Modules.Template/Dmf_ToasterBus.c +++ b/Dmf/Modules.Template/Dmf_ToasterBus.c @@ -311,6 +311,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS ToasterBus_IoctlClientCallback_DevicePlug( _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -328,13 +329,14 @@ Routine Description: Arguments: DmfModule - The Child Module from which this callback is called. - Request - Request data, not used - IoctlCode - IOCTL to be used in the command - InputBuffer - Input data buffer - InputBufferSize - Input data buffer size, not used - OutputBuffer - Output data buffer - OutputBufferSize - Output data buffer size, not used - BytesReturned - Amount of data to be sent back + Queue - The WDFQUEUE associated with Request. + Request - Request data, not used. + IoctlCode - IOCTL to be used in the command. + InputBuffer - Input data buffer. + InputBufferSize - Input data buffer size, not used. + OutputBuffer - Output data buffer. + OutputBufferSize - Output data buffer size, not used. + BytesReturned - Amount of data to be sent back. Return Value: @@ -350,11 +352,12 @@ Return Value: size_t length; BUSENUM_PLUGIN_HARDWARE* plugIn; - UNREFERENCED_PARAMETER(BytesReturned); - UNREFERENCED_PARAMETER(OutputBufferSize); - UNREFERENCED_PARAMETER(OutputBuffer); - UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(Request); + UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(OutputBuffer); + UNREFERENCED_PARAMETER(OutputBufferSize); + UNREFERENCED_PARAMETER(BytesReturned); FuncEntry(DMF_TRACE_ToasterBus); @@ -422,6 +425,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS ToasterBus_IoctlClientCallback_DeviceUnplug( _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -439,13 +443,14 @@ Routine Description: Arguments: DmfModule - The Child Module from which this callback is called. - Request - Request data, not used - IoctlCode - IOCTL to be used in the command - InputBuffer - Input data buffer - InputBufferSize - Input data buffer size, not used - OutputBuffer - Output data buffer - OutputBufferSize - Output data buffer size, not used - BytesReturned - Amount of data to be sent back + Queue - The WDFQUEUE associated with Request. + Request - Request data, not used. + IoctlCode - IOCTL to be used in the command. + InputBuffer - Input data buffer. + InputBufferSize - Input data buffer size, not used. + OutputBuffer - Output data buffer. + OutputBufferSize - Output data buffer size, not used. + BytesReturned - Amount of data to be sent back. Return Value: @@ -459,11 +464,13 @@ Return Value: DMFMODULE dmfModule; BUSENUM_UNPLUG_HARDWARE* unPlug; - UNREFERENCED_PARAMETER(BytesReturned); - UNREFERENCED_PARAMETER(OutputBufferSize); - UNREFERENCED_PARAMETER(OutputBuffer); - UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(Request); + UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(OutputBuffer); + UNREFERENCED_PARAMETER(OutputBufferSize); + UNREFERENCED_PARAMETER(BytesReturned); FuncEntry(DMF_TRACE_ToasterBus); @@ -507,6 +514,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS ToasterBus_IoctlClientCallback_DeviceEject( _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG IoctlCode, _In_reads_(InputBufferSize) VOID* InputBuffer, @@ -524,13 +532,14 @@ Routine Description: Arguments: DmfModule - The Child Module from which this callback is called. - Request - Request data, not used - IoctlCode - IOCTL to be used in the command - InputBuffer - Input data buffer - InputBufferSize - Input data buffer size, not used - OutputBuffer - Output data buffer - OutputBufferSize - Output data buffer size, not used - BytesReturned - Amount of data to be sent back + Queue - The WDFQUEUE associated with Request. + Request - Request data, not used. + IoctlCode - IOCTL to be used in the command. + InputBuffer - Input data buffer. + InputBufferSize - Input data buffer size, not used. + OutputBuffer - Output data buffer. + OutputBufferSize - Output data buffer size, not used. + BytesReturned - Amount of data to be sent back. Return Value: @@ -545,12 +554,13 @@ Return Value: BUSENUM_EJECT_HARDWARE* eject; size_t length; - UNREFERENCED_PARAMETER(BytesReturned); - UNREFERENCED_PARAMETER(OutputBufferSize); - UNREFERENCED_PARAMETER(OutputBuffer); - UNREFERENCED_PARAMETER(InputBufferSize); - UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(Request); + UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(IoctlCode); + UNREFERENCED_PARAMETER(OutputBuffer); + UNREFERENCED_PARAMETER(OutputBufferSize); + UNREFERENCED_PARAMETER(BytesReturned); FuncEntry(DMF_TRACE_ToasterBus); diff --git a/Dmf/Solution/DmfK/DmfK.vcxproj b/Dmf/Solution/DmfK/DmfK.vcxproj index b7278f82..9b7988c5 100644 --- a/Dmf/Solution/DmfK/DmfK.vcxproj +++ b/Dmf/Solution/DmfK/DmfK.vcxproj @@ -82,7 +82,7 @@ - $(OutLibDir)\$(ProjectName)\ + $(SolutionDir)$(ConfigurationName)\$(PlatformName)\lib\$(ProjectName)\ false diff --git a/Dmf/Solution/DmfU/DmfU.vcxproj b/Dmf/Solution/DmfU/DmfU.vcxproj index 99c18051..4002b68e 100644 --- a/Dmf/Solution/DmfU/DmfU.vcxproj +++ b/Dmf/Solution/DmfU/DmfU.vcxproj @@ -77,7 +77,7 @@ - $(OutLibDir)\$(ProjectName)\ + $(SolutionDir)$(ConfigurationName)\$(PlatformName)\lib\$(ProjectName)\ false diff --git a/DmfSamples/DmfSamples.sln b/DmfSamples/DmfSamples.sln new file mode 100644 index 00000000..0aa8a63e --- /dev/null +++ b/DmfSamples/DmfSamples.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2026 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver_Dmf_1", "Driver_Dmf_1", "{BCB7D745-20C8-48E1-A792-F708EF65B29F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{4B2BB962-B51B-42F1-9EF7-06025B7A8E83}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2dmf1", "kmdf_fx2_dmf\driver_dmf_1\osrusbfx2dmf1.vcxproj", "{837F98CF-D3A4-472C-BACC-47950340E57B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "kmdf_fx2_dmf\exe\osrusbfx2.vcxproj", "{6EED5CDD-5526-40DC-97F9-582857E10187}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver_Dmf_2", "Driver_Dmf_2", "{1BD7F179-A112-4E90-8473-2E134F916713}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2dmf2", "kmdf_fx2_dmf\driver_dmf_2\osrusbfx2dmf2.vcxproj", "{E67FD967-2406-4673-9BDC-2A5F5176CB87}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {837F98CF-D3A4-472C-BACC-47950340E57B}.Debug|x64.ActiveCfg = Debug|x64 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Debug|x64.Build.0 = Debug|x64 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Debug|x86.ActiveCfg = Debug|Win32 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Debug|x86.Build.0 = Debug|Win32 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Release|x64.ActiveCfg = Release|x64 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Release|x64.Build.0 = Release|x64 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Release|x86.ActiveCfg = Release|Win32 + {837F98CF-D3A4-472C-BACC-47950340E57B}.Release|x86.Build.0 = Release|Win32 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Debug|x64.ActiveCfg = Debug|x64 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Debug|x64.Build.0 = Debug|x64 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Debug|x86.ActiveCfg = Debug|Win32 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Debug|x86.Build.0 = Debug|Win32 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Release|x64.ActiveCfg = Release|x64 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Release|x64.Build.0 = Release|x64 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Release|x86.ActiveCfg = Release|Win32 + {6EED5CDD-5526-40DC-97F9-582857E10187}.Release|x86.Build.0 = Release|Win32 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Debug|x64.ActiveCfg = Debug|x64 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Debug|x64.Build.0 = Debug|x64 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Debug|x86.ActiveCfg = Debug|Win32 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Debug|x86.Build.0 = Debug|Win32 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Release|x64.ActiveCfg = Release|x64 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Release|x64.Build.0 = Release|x64 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Release|x86.ActiveCfg = Release|Win32 + {E67FD967-2406-4673-9BDC-2A5F5176CB87}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {837F98CF-D3A4-472C-BACC-47950340E57B} = {BCB7D745-20C8-48E1-A792-F708EF65B29F} + {6EED5CDD-5526-40DC-97F9-582857E10187} = {4B2BB962-B51B-42F1-9EF7-06025B7A8E83} + {E67FD967-2406-4673-9BDC-2A5F5176CB87} = {1BD7F179-A112-4E90-8473-2E134F916713} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F165374D-3FC4-4EC6-BC80-70000B7DDA2C} + EndGlobalSection +EndGlobal diff --git a/DmfSamples/kmdf_fx2_dmf/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms b/DmfSamples/kmdf_fx2_dmf/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms new file mode 100644 index 00000000..5f8e82ee Binary files /dev/null and b/DmfSamples/kmdf_fx2_dmf/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms differ diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/README.md b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/README.md new file mode 100644 index 00000000..cc4dbf16 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/README.md @@ -0,0 +1,163 @@ + + +Sample KMDF/DMF Function Driver for OSR USB-FX2 (DMF Sample 1) +============================================================== + +This sample shows the minimum steps needed to use DMF in an existing driver. + +This sample uses the OSR FX2 sample as the driver that is updated to use DMF. + +To keep this sample very simple, no DMF Modules are instantiated. The second sample uses this sample +as a base and shows how to add and use a single Module. + +IMPORTANT: For details about how the OSR USB-FX2 device operates, please see the original (non-DMF) sample. This sample is designed to do everything + the original sample does but also perform the minimum steps necessary to initialize DMF. + +Please perform a file compare between all the files in this sample and the files in the original sample. That is the best way to see the differences. + +Overview +-------- + +In this sample, the following changes are made: + +OsrFxEvtDeviceAdd: + +1. Declare two variables that are used to initialize DMF: + + PDMFDEVICE_INIT dmfDeviceInit; + DMF_EVENT_CALLBACKS dmfEventCallbacks; + +2. Allocate a PDMFDEVICE_INIT structure. This is an opaque structure DMF uses to keep track of what the Client + Driver (the driver that uses DMF is called the Client driver) is doing during initialization. + + // + // DMF: Create the PDMFDEVICE_INIT structure. + // + dmfDeviceInit = DMF_DmfDeviceInitAllocate(DeviceInit); + +3. Hook the Client driver's WDF callbacks so DMF's callbacks will be called. NOTE: These three calls are ALWAYS + necessary even if the Client driver does not register for any of those callbacks. In this case, the Client driver + only registers for PnP Power callbacks. + + // + // DMF: Hook Pnp Power Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use Pnp Power Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for Pnp Power Callbacks later. + // + DMF_DmfDeviceInitHookPnpPowerEventCallbacks(dmfDeviceInit, &pnpPowerCallbacks); + + // + // DMF: Hook Power Policy Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use Power Policy Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for Power Policy Callbacks later. + // + DMF_DmfDeviceInitHookPowerPolicyEventCallbacks(dmfDeviceInit, NULL); + + // + // DMF: Hook File Object Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use File Object Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for File Object Callbacks later. + // + DMF_DmfDeviceInitHookFileObjectConfig(dmfDeviceInit, NULL); + +4. Hook the default queue callbacks. This step is optional if the Client driver does not use a default queue. In + Sample 2, this queue is not necessary because the Client driver will the default queue that DMF creates. + + // + // DMF: Hook Default Queue Config Callbacks. This allows DMF to receive callbacks first + // so it can dispatch them to the tree of instantiated Modules. If the driver does + // not use a default queue, it is NOT NECESSARY to call this function (unlike the + // above three functions) because DMF will set up a default queue for itself. + // + DMF_DmfDeviceInitHookQueueConfig(dmfDeviceInit, &ioQueueConfig); + +5. Initialize the DMF Module Add callback function. This function is called by DMF to ask the Client driver + to initialize the DMF Modules the Client driver will use. In this sample, no Modules are used by the + Client but the callback is set for illustration purposes. + + // + // DMF: Initialize the DMF_EVENT_CALLBACKS to set the callback DMF will call + // to get the list of Modules to instantiate. + // + DMF_EVENT_CALLBACKS_INIT(&dmfEventCallbacks); + dmfEventCallbacks.EvtDmfDeviceModulesAdd = OsrDmfModulesAdd; + + DMF_DmfDeviceInitSetEventCallbacks(dmfDeviceInit, + &dmfEventCallbacks); + +6. Initialize DMF. This allows DMF's core to ask the Client driver what Modules it wants to use and then create + the tree of instantiated Modules. + + // + // DMF: Tell DMF to create its data structures and create the tree of Modules the + // Client driver has specified (using the above callback). After this call + // succeeds DMF has all the information it needs to dispatch WDF entry points + // to the tree of Modules. + // + status = DMF_ModulesCreate(device, + &dmfDeviceInit); + +7. Define the function that tells DMF what Modules the Client driver will use. This sample uses no Modules so this + function does nothing. See Sample 2 to see how to use this function. + +// +// DMF: This is the callback function called by DMF that allows this driver (the Client driver) +// to set the CONFIG for each DMF Module the driver will use. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +OsrDmfModulesAdd( + _In_ WDFDEVICE Device, + _In_ PDMFMODULE_INIT DmfModuleInit + ) +/*++ +Routine Description: + + EvtDmfDeviceModulesAdd is called by DMF during the Client driver's + AddDevice call from the PnP manager. Here the Client driver declares a + CONFIG structure for every instance of every Module the Client driver + uses. Each CONFIG structure is properly initialized for its specific + use. Then, each CONFIG structure is added to the list of Modules that + DMF will instantiate. + +Arguments: + + Device - The Client driver's WDFDEVICE. + DmfModuleInit - An opaque PDMFMODULE_INIT used by DMF. + +Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(DmfModuleInit); + + // In this sample, no Modules are instantiated. + // +} + +8. Finally, the project settings are modified to set include paths and link library names. Also, it is necessary to + set EnableWpp = TRUE because the DMF library requires that setting. + +Code tour +--------- + +There are no changes between the original sample and this sample. Please see the original sample for details. + +Testing the driver +------------------ + +Please see the original sample for details. Nothing is changed in the DMF version. + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/bulkrwr.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/bulkrwr.c new file mode 100644 index 00000000..eabda192 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/bulkrwr.c @@ -0,0 +1,436 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + bulkrwr.c + +Abstract: + + This file has routines to perform reads and writes. + The read and writes are targeted bulk to endpoints. + +Environment: + + Kernel mode + +--*/ + +#include + + +#if defined(EVENT_TRACING) +#include "bulkrwr.tmh" +#endif + +#pragma warning(disable:4267) + +VOID +OsrFxEvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + +--*/ +{ + WDFUSBPIPE pipe; + NTSTATUS status; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + // + // Log read start event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "-->OsrFxEvtIoRead\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkReadPipe; + + status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); + goto Exit; + } + + // + // The format call validates to make sure that you are reading or + // writing to the right pipe type, sets the appropriate transfer flags, + // creates an URB and initializes the request. + // + status = WdfUsbTargetPipeFormatRequestForRead(pipe, + Request, + reqMemory, + NULL // Offsets + ); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfUsbTargetPipeFormatRequestForRead failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestReadCompletionRoutine, + pipe); + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + + +Exit: + if (!NT_SUCCESS(status)) { + // + // log event read failed + // + EventWriteReadFail(&activity, WdfIoQueueGetDevice(Queue), status); + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "<-- OsrFxEvtIoRead\n"); + + return; +} + +VOID +EvtRequestReadCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for reads + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesRead = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesRead = usbCompletionParams->Parameters.PipeRead.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "Number of bytes read: %I64d\n", (INT64)bytesRead); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "Read failed - request status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + + } + + // + // Log read stop event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesRead, + status, + usbCompletionParams->UsbdStatus); + + WdfRequestCompleteWithInformation(Request, status, bytesRead); + + return; +} + +VOID +OsrFxEvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + +--*/ +{ + NTSTATUS status; + WDFUSBPIPE pipe; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + + // + // Log write start event, using IRP activity ID if available or request + // handle otherwise. + // + EventWriteWriteStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "-->OsrFxEvtIoWrite\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkWritePipe; + + status = WdfRequestRetrieveInputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestRetrieveInputBuffer failed\n"); + goto Exit; + } + + status = WdfUsbTargetPipeFormatRequestForWrite(pipe, + Request, + reqMemory, + NULL); // Offset + + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfUsbTargetPipeFormatRequestForWrite failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestWriteCompletionRoutine, + pipe); + + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) { + // + // log event write failed + // + EventWriteWriteFail(&activity, WdfIoQueueGetDevice(Queue), status); + + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- OsrFxEvtIoWrite\n"); + + return; +} + +VOID +EvtRequestWriteCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for writes + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesWritten = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + // + // For usb devices, we should look at the Usb.Completion param. + // + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesWritten = usbCompletionParams->Parameters.PipeWrite.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "Number of bytes written: %I64d\n", (INT64)bytesWritten); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "Write failed: request Status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + } + + // + // Log write stop event, using IRP activtiy ID if available or request + // handle otherwise + // + EventWriteWriteStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesWritten, + status, + usbCompletionParams->UsbdStatus); + + + WdfRequestCompleteWithInformation(Request, status, bytesWritten); + + return; +} + + +VOID +OsrFxEvtIoStop( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG ActionFlags + ) +/*++ + +Routine Description: + + This callback is invoked on every inflight request when the device + is suspended or removed. Since our inflight read and write requests + are actually pending in the target device, we will just acknowledge + its presence. Until we acknowledge, complete, or requeue the requests + framework will wait before allowing the device suspend or remove to + proceeed. When the underlying USB stack gets the request to suspend or + remove, it will fail all the pending requests. + +Arguments: + + Queue - handle to queue object that is associated with the I/O request + + Request - handle to a request object + + ActionFlags - bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS flags + +Return Value: + None + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(ActionFlags); + + if (ActionFlags & WdfRequestStopActionSuspend ) { + WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue + } else if(ActionFlags & WdfRequestStopActionPurge) { + WdfRequestCancelSentRequest(Request); + } + return; +} + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/device.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/device.c new file mode 100644 index 00000000..e4e65d06 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/device.c @@ -0,0 +1,1179 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Device.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + + +--*/ + +#include + +#if defined(EVENT_TRACING) +#include "device.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, OsrFxEvtDeviceAdd) +#pragma alloc_text(PAGE, OsrFxEvtDevicePrepareHardware) +#pragma alloc_text(PAGE, OsrFxEvtDeviceD0Exit) +#pragma alloc_text(PAGE, SelectInterfaces) +#pragma alloc_text(PAGE, OsrFxSetPowerPolicy) +#pragma alloc_text(PAGE, OsrFxReadFdoRegistryKeyValue) +#pragma alloc_text(PAGE, GetDeviceEventLoggingNames) +#pragma alloc_text(PAGE, OsrFxValidateConfigurationDescriptor) +#pragma alloc_text(PAGE, OsrDmfModulesAdd) +#endif + + +NTSTATUS +OsrFxEvtDeviceAdd( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + PDEVICE_CONTEXT pDevContext; + WDFQUEUE queue; + GUID activity; + UNICODE_STRING symbolicLinkName; + WDFSTRING symbolicLinkString = NULL; + DEVPROP_BOOLEAN isRestricted; + PDMFDEVICE_INIT dmfDeviceInit; + DMF_EVENT_CALLBACKS dmfEventCallbacks; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); + + // + // DMF: Create the PDMFDEVICE_INIT structure. + // + dmfDeviceInit = DMF_DmfDeviceInitAllocate(DeviceInit); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + // + // For usb devices, PrepareHardware callback is the to place select the + // interface and configure the device. + // + pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; + + // + // These two callbacks start and stop the wdfusb pipe continuous reader + // as we go in and out of the D0-working state. + // + + pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // DMF: Hook Pnp Power Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use Pnp Power Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for Pnp Power Callbacks later. + // + DMF_DmfDeviceInitHookPnpPowerEventCallbacks(dmfDeviceInit, &pnpPowerCallbacks); + + // + // DMF: Hook Power Policy Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use Power Policy Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for Power Policy Callbacks later. + // + DMF_DmfDeviceInitHookPowerPolicyEventCallbacks(dmfDeviceInit, NULL); + + // + // DMF: Hook File Object Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use File Object Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for File Object Callbacks later. + // + DMF_DmfDeviceInitHookFileObjectConfig(dmfDeviceInit, NULL); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + // + // Now specify the size of device extension where we track per device + // context.DeviceInit is completely initialized. So call the framework + // to create the device and attach it to the lower stack. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with Status code %!STATUS!\n", status); + return status; + } + + // + // Setup the activity ID so that we can log events using it. + // + + activity = DeviceToActivityId(device); + + // + // Get the DeviceObject context by using accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. + // + pDevContext = GetDeviceContext(device); + + // + // Get the device's friendly name and location so that we can use it in + // error logging. If this fails then it will setup dummy strings. + // + + GetDeviceEventLoggingNames(device); + + // + // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so + // that you don't get the popup in usermode when you surprise remove the device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.SurpriseRemovalOK = WdfTrue; + + WdfDeviceSetPnpCapabilities(device, &pnpCaps); + + // + // Create a parallel default queue and register an event callback to + // receive ioctl requests. We will create separate queues for + // handling read and write requests. All other requests will be + // completed with error status automatically by the framework. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + ioQueueConfig.EvtIoDeviceControl = OsrFxEvtIoDeviceControl; + + // + // DMF: Hook Default Queue Config Callbacks. This allows DMF to receive callbacks first + // so it can dispatch them to the tree of instantiated Modules. If the driver does + // not use a default queue, it is NOT NECESSARY to call this function (unlike the + // above three functions) because DMF will set up a default queue for itself. + // + DMF_DmfDeviceInitHookQueueConfig(dmfDeviceInit, &ioQueueConfig); + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests for + // long time or forward them to other drivers. + // If the EvtIoStop callback is not implemented, the framework waits for + // all driver-owned requests to be done before moving in the Dx/sleep + // states or before removing the device, which is the correct behavior + // for this type of driver. If the requests were taking an indeterminate + // amount of time to complete, or if the driver forwarded the requests + // to a lower driver/another stack, the queue should have an + // EvtIoStop/EvtIoResume. + // + __analysis_assume(ioQueueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue);// pointer to default queue + __analysis_assume(ioQueueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // We will create a separate sequential queue and configure it + // to receive read requests. We also need to register a EvtIoStop + // handler so that we can acknowledge requests that are pending + // at the target driver. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeRead); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + + // + // We will create another sequential queue and configure it + // to receive write requests. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeWrite); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + // + // Register a manual I/O queue for handling Interrupt Message Read Requests. + // This queue will be used for storing Requests that need to wait for an + // interrupt to occur before they can be completed. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); + + // + // This queue is used for requests that dont directly access the device. The + // requests in this queue are serviced only when the device is in a fully + // powered state and sends an interrupt. So we can use a non-power managed + // queue to park the requests since we dont care whether the device is idle + // or fully powered up. + // + ioQueueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &pDevContext->InterruptMsgQueue + ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + // + // Register a device interface so that app can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL); // Reference String + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); + goto Error; + } + + // + // Create the lock that we use to serialize calls to ResetDevice(). As an + // alternative to using a WDFWAITLOCK to serialize the calls, a sequential + // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = device; + + status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfWaitLockCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // Get the string for the device interface and set the restricted + // property on it to allow applications bound with device metadata + // to access the interface. + // + if (g_pIoSetDeviceInterfacePropertyData != NULL) { + + status = WdfStringCreate(NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfStringCreate failed %!STATUS!\n", status); + goto Error; + } + + status = WdfDeviceRetrieveDeviceInterfaceString(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL, + symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceRetrieveDeviceInterfaceString failed %!STATUS!\n", status); + goto Error; + } + + WdfStringGetUnicodeString(symbolicLinkString, &symbolicLinkName); + + isRestricted = DEVPROP_TRUE; + + status = g_pIoSetDeviceInterfacePropertyData(&symbolicLinkName, + &DEVPKEY_DeviceInterface_Restricted, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(isRestricted), + &isRestricted ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IoSetDeviceInterfacePropertyData failed to set restricted property %!STATUS!\n", status); + goto Error; + } +#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2) + + // + // Adding Custom Capability: + // + // Adds a custom capability to device interface instance that allows a Windows + // Store device app to access this interface using Windows.Devices.Custom namespace. + // This capability can be defined either in INF or here as shown below. In order + // to define it from the INF, uncomment the section "OsrUsb Interface installation" + // from the INF and remove the block of code below. + // + + static const wchar_t customCapabilities[] = L"microsoft.hsaTestCustomCapability_q536wpkpf5cy2\0"; + + status = g_pIoSetDeviceInterfacePropertyData(&symbolicLinkName, + &DEVPKEY_DeviceInterface_UnrestrictedAppCapabilities, + 0, + 0, + DEVPROP_TYPE_STRING_LIST, + sizeof(customCapabilities), + (PVOID)&customCapabilities); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IoSetDeviceInterfacePropertyData failed to set custom capability property %!STATUS!\n", status); + goto Error; + } + +#endif + WdfObjectDelete(symbolicLinkString); + } + + // + // DMF: Initialize the DMF_EVENT_CALLBACKS to set the callback DMF will call + // to get the list of Modules to instantiate. + // + DMF_EVENT_CALLBACKS_INIT(&dmfEventCallbacks); + dmfEventCallbacks.EvtDmfDeviceModulesAdd = OsrDmfModulesAdd; + + DMF_DmfDeviceInitSetEventCallbacks(dmfDeviceInit, + &dmfEventCallbacks); + + // + // DMF: Tell DMF to create its data structures and create the tree of Modules the + // Client driver has specified (using the above callback). After this call + // succeeds DMF has all the information it needs to dispatch WDF entry points + // to the tree of Modules. + // + status = DMF_ModulesCreate(device, + &dmfDeviceInit); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); + + return status; + +Error: + + if(symbolicLinkString != NULL) { + WdfObjectDelete(symbolicLinkString); + } + + // + // Log fail to add device to the event log + // + EventWriteFailAddDevice(&activity, + pDevContext->DeviceName, + pDevContext->Location, + status); + + return status; +} + +// +// DMF: This is the callback function called by DMF that allows this driver (the Client Driver) +// to set the CONFIG for each DMF Module the driver will use. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +OsrDmfModulesAdd( + _In_ WDFDEVICE Device, + _In_ PDMFMODULE_INIT DmfModuleInit + ) +/*++ +Routine Description: + + EvtDmfDeviceModulesAdd is called by DMF during the Client driver's + AddDevice call from the PnP manager. Here the Client driver declares a + CONFIG structure for every instance of every Module the Client driver + uses. Each CONFIG structure is properly initialized for its specific + use. Then, each CONFIG structure is added to the list of Modules that + DMF will instantiate. + +Arguments: + + Device - The Client driver's WDFDEVICE. + DmfModuleInit - An opaque PDMFMODULE_INIT used by DMF. + +Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(DmfModuleInit); + + // In this sample, no Modules are instantiated. + // +} + +NTSTATUS +OsrFxEvtDevicePrepareHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourceList, + WDFCMRESLIST ResourceListTranslated + ) +/*++ + +Routine Description: + + In this callback, the driver does whatever is necessary to make the + hardware ready to use. In the case of a USB device, this involves + reading and selecting descriptors. + +Arguments: + + Device - handle to a device + + ResourceList - handle to a resource-list object that identifies the + raw hardware resources that the PnP manager assigned + to the device + + ResourceListTranslated - handle to a resource-list object that + identifies the translated hardware resources + that the PnP manager assigned to the device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + WDF_USB_DEVICE_INFORMATION deviceInfo; + ULONG waitWakeEnable; + + UNREFERENCED_PARAMETER(ResourceList); + UNREFERENCED_PARAMETER(ResourceListTranslated); + waitWakeEnable = FALSE; + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // Create a USB device handle so that we can communicate with the + // underlying USB stack. The WDFUSBDEVICE handle is used to query, + // configure, and manage all aspects of the USB device. + // These aspects include device properties, bus properties, + // and I/O creation and synchronization. We only create device the first + // the PrepareHardware is called. If the device is restarted by pnp manager + // for resource rebalance, we will use the same device handle but then select + // the interfaces again because the USB stack could reconfigure the device on + // restart. + // + if (pDeviceContext->UsbDevice == NULL) { + WDF_USB_DEVICE_CREATE_CONFIG config; + + WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, + USBD_CLIENT_CONTRACT_VERSION_602); + + status = WdfUsbTargetDeviceCreateWithParameters(Device, + &config, + WDF_NO_OBJECT_ATTRIBUTES, + &pDeviceContext->UsbDevice); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceCreateWithParameters failed with Status code %!STATUS!\n", status); + return status; + } + + // + // TODO: If you are fetching configuration descriptor from device for + // selecting a configuration or to parse other descriptors, call OsrFxValidateConfigurationDescriptor + // to do basic validation on the descriptors before you access them . + // + } + + // + // Retrieve USBD version information, port driver capabilites and device + // capabilites such as speed, power, etc. + // + WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); + + status = WdfUsbTargetDeviceRetrieveInformation( + pDeviceContext->UsbDevice, + &deviceInfo); + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceSelfPowered: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); + + waitWakeEnable = deviceInfo.Traits & + WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceRemoteWakeable: %s\n", + waitWakeEnable ? "TRUE" : "FALSE"); + // + // Save these for use later. + // + pDeviceContext->UsbDeviceTraits = deviceInfo.Traits; + } + else { + pDeviceContext->UsbDeviceTraits = 0; + } + + status = SelectInterfaces(Device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "SelectInterfaces failed 0x%x\n", status); + return status; + } + + // + // Enable wait-wake and idle timeout if the device supports it + // + if (waitWakeEnable) { + status = OsrFxSetPowerPolicy(Device); + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxSetPowerPolicy failed %!STATUS!\n", status); + return status; + } + } + + status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Entry( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + EvtDeviceD0Entry event callback must perform any operations that are + necessary before the specified device is used. It will be called every + time the hardware needs to be (re-)initialized. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + + This function runs at PASSIVE_LEVEL, even though it is not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE + is set. Even if DO_POWER_PAGABLE isn't set, this function still runs + at PASSIVE_LEVEL. In this case, though, the function absolutely must + not do anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + PreviousState - Device power state which the device was in most recently. + If the device is being newly started, this will be + PowerDeviceUnspecified. + +Return Value: + + NTSTATUS + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + BOOLEAN isTargetStarted; + + pDeviceContext = GetDeviceContext(Device); + isTargetStarted = FALSE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtEvtDeviceD0Entry - coming from %s\n", + DbgDevicePowerString(PreviousState)); + + // + // Since continuous reader is configured for this interrupt-pipe, we must explicitly start + // the I/O target to get the framework to post read requests. + // + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "Failed to start interrupt pipe %!STATUS!\n", status); + goto End; + } + + isTargetStarted = TRUE; + +End: + + if (!NT_SUCCESS(status)) { + // + // Failure in D0Entry will lead to device being removed. So let us stop the continuous + // reader in preparation for the ensuing remove. + // + if (isTargetStarted) { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtEvtDeviceD0Entry\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Exit( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This routine undoes anything done in EvtDeviceD0Entry. It is called + whenever the device leaves the D0 state, which happens when the device is + stopped, when it is removed, and when it is powered off. + + The device is still in D0 when this callback is invoked, which means that + the driver can still touch hardware in this routine. + + + EvtDeviceD0Exit event callback must perform any operations that are + necessary before the specified device is moved out of the D0 state. If the + driver needs to save hardware state before the device is powered down, then + that should be done here. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + TargetState - Device power state which the device will be put in once this + callback is complete. + +Return Value: + + Success implies that the device can be used. Failure will result in the + device stack being torn down. + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtDeviceD0Exit - moving to %s\n", + DbgDevicePowerString(TargetState)); + + pDeviceContext = GetDeviceContext(Device); + + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtDeviceD0Exit\n"); + + return STATUS_SUCCESS; +} + +VOID +OsrFxEvtDeviceSelfManagedIoFlush( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine handles flush activity for the device's + self-managed I/O operations. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + None + +--*/ +{ + // Service the interrupt message queue to drain any outstanding + // requests + OsrUsbIoctlGetInterruptMessage(Device, STATUS_DEVICE_REMOVED); +} + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ) +/*++ + +Routine Description: + + Validates a USB Configuration Descriptor + +Parameters: + + ConfigDesc: Pointer to the entire USB Configuration descriptor returned by the device + + BufferLength: Known size of buffer pointed to by ConfigDesc (Not wTotalLength) + + Offset: if the USBD_STATUS returned is not USBD_STATUS_SUCCESS, offet will + be set to the address within the ConfigDesc buffer where the failure occured. + +Return Value: + + USBD_STATUS + Success implies the configuration descriptor is valid. + +--*/ +{ + + + USBD_STATUS status = USBD_STATUS_SUCCESS; + USHORT ValidationLevel = 3; + + PAGED_CODE(); + + // + // Call USBD_ValidateConfigurationDescriptor to validate the descriptors which are present in this supplied configuration descriptor. + // USBD_ValidateConfigurationDescriptor validates that all descriptors are completely contained within the configuration descriptor buffer. + // It also checks for interface numbers, number of endpoints in an interface etc. + // Please refer to msdn documentation for this function for more information. + // + + status = USBD_ValidateConfigurationDescriptor( ConfigDesc, BufferLength , ValidationLevel , Offset , POOL_TAG ); + if (!(NT_SUCCESS (status)) ){ + return status; + } + + // + // TODO: You should validate the correctness of other descriptors which are not taken care by USBD_ValidateConfigurationDescriptor + // Check that all such descriptors have size >= sizeof(the descriptor they point to) + // Check for any association between them if required + // + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ) +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings); + if ( !NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", status); + return status; + } + + // + // Init wait-wake policy structure. + // + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); + + status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceAssignSxWakeSettings failed %x\n", status); + return status; + } + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This helper routine selects the configuration, interface and + creates a context for every pipe (end point) in that interface. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_CONTEXT pDeviceContext; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + UCHAR index; + UCHAR numberConfiguredPipes; + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); + + status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, + WDF_NO_OBJECT_ATTRIBUTES, + &configParams); + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", + status); + + // + // Since the Osr USB fx2 device is capable of working at high speed, the only reason + // the device would not be working at high speed is if the port doesn't + // support it. If the port doesn't support high speed it is a 1.1 port + // + if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { + GUID activity = DeviceToActivityId(Device); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + " On a 1.1 USB port on Windows Vista" + " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" + " doesn't conform to the USB specification. Windows Vista detects this and" + " returns an error. \n" + ); + EventWriteSelectConfigFailure( + &activity, + pDeviceContext->DeviceName, + pDeviceContext->Location, + status + ); + } + + return status; + } + + pDeviceContext->UsbInterface = + configParams.Types.SingleInterface.ConfiguredUsbInterface; + + numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; + + // + // Get pipe handles + // + for(index=0; index < numberConfiguredPipes; index++) { + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + pDeviceContext->UsbInterface, + index, //PipeIndex, + &pipeInfo + ); + // + // Tell the framework that it's okay to read less than + // MaximumPacketSize + // + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); + + if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "Interrupt Pipe is 0x%p\n", pipe); + pDeviceContext->InterruptPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsInEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkInput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkReadPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsOutEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkOutput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkWritePipe = pipe; + } + + } + + // + // If we didn't find all the 3 pipes, fail the start. + // + if(!(pDeviceContext->BulkWritePipe + && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { + status = STATUS_INVALID_DEVICE_STATE; + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Device is not configured properly %!STATUS!\n", + status); + + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + Retrieve the friendly name and the location string into WDFMEMORY objects + and store them in the device context. + +Arguments: + +Return Value: + + None + +--*/ +{ + PDEVICE_CONTEXT pDevContext = GetDeviceContext(Device); + + WDF_OBJECT_ATTRIBUTES objectAttributes; + + WDFMEMORY deviceNameMemory = NULL; + WDFMEMORY locationMemory = NULL; + + NTSTATUS status; + + PAGED_CODE(); + + // + // We want both memory objects to be children of the device so they will + // be deleted automatically when the device is removed. + // + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); + objectAttributes.ParentObject = Device; + + // + // First get the length of the string. If the FriendlyName + // is not there then get the lenght of device description. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyFriendlyName, + NonPagedPoolNx, + &objectAttributes, + &deviceNameMemory); + + if (!NT_SUCCESS(status)) + { + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyDeviceDescription, + NonPagedPoolNx, + &objectAttributes, + &deviceNameMemory); + } + + if (NT_SUCCESS(status)) + { + pDevContext->DeviceNameMemory = deviceNameMemory; + pDevContext->DeviceName = WdfMemoryGetBuffer(deviceNameMemory, NULL); + } + else + { + pDevContext->DeviceNameMemory = NULL; + pDevContext->DeviceName = L"(error retrieving name)"; + } + + // + // Retrieve the device location string. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyLocationInformation, + NonPagedPoolNx, + WDF_NO_OBJECT_ATTRIBUTES, + &locationMemory); + + if (NT_SUCCESS(status)) + { + pDevContext->LocationMemory = locationMemory; + pDevContext->Location = WdfMemoryGetBuffer(locationMemory, NULL); + } + else + { + pDevContext->LocationMemory = NULL; + pDevContext->Location = L"(error retrieving location)"; + } + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ) +{ + switch (Type) + { + case WdfPowerDeviceInvalid: + return "WdfPowerDeviceInvalid"; + case WdfPowerDeviceD0: + return "WdfPowerDeviceD0"; + case WdfPowerDeviceD1: + return "WdfPowerDeviceD1"; + case WdfPowerDeviceD2: + return "WdfPowerDeviceD2"; + case WdfPowerDeviceD3: + return "WdfPowerDeviceD3"; + case WdfPowerDeviceD3Final: + return "WdfPowerDeviceD3Final"; + case WdfPowerDevicePrepareForHibernation: + return "WdfPowerDevicePrepareForHibernation"; + case WdfPowerDeviceMaximum: + return "WdfPowerDeviceMaximum"; + default: + return "UnKnown Device Power State"; + } +} + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/driver.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/driver.c new file mode 100644 index 00000000..2c73cab2 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/driver.c @@ -0,0 +1,301 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + Main module. + + This driver is for Open System Resources USB-FX2 Learning Kit designed + and built by OSR specifically for use in teaching software developers how to write + drivers for USB devices. + + The board supports a single configuration. The board automatically + detects the speed of the host controller, and supplies either the + high or full speed configuration based on the host controller's speed. + + The firmware supports 3 endpoints: + + Endpoint number 1 is used to indicate the state of the 8-switch + switch-pack on the OSR USB-FX2 board. A single byte representing + the switch state is sent (a) when the board is first started, + (b) when the board resumes after selective-suspend, + (c) whenever the state of the switches is changed. + + Endpoints 6 and 8 perform an internal loop-back function. + Data that is sent to the board at EP6 is returned to the host on EP8. + + For further information on the endpoints, please refer to the spec + http://www.osronline.com/hardware/OSRFX2_32.pdf. + + Vendor ID of the device is 0x4705 and Product ID is 0x210. + +Environment: + + Kernel mode only + +--*/ + +#include + +#if defined(EVENT_TRACING) +// +// The trace message header (.tmh) file must be included in a source file +// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS +// macro (defined in trace.h). During the compilation, WPP scans the source +// files for DoTraceMessage() calls and builds a .tmh file which stores a unique +// data GUID for each message, the text resource string for each message, +// and the data types of the variables passed in for each message. This file +// is automatically generated and used during post-processing. +// +#include "driver.tmh" +#else +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; +PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, OsrFxEvtDriverContextCleanup) +#endif + +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL or another NTSTATUS error code otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + UNICODE_STRING funcName; + + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OSRUSBFX2 Driver Sample - Driver Framework Edition.\n"); + + // + // IRP activity ID functions are available on some versions, save them into + // globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoGetActivityIdIrp"); + g_pIoGetActivityIdIrp = (PFN_IO_GET_ACTIVITY_ID_IRP) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // The Device interface property set is available on some version, save it + // into globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoSetDeviceInterfacePropertyData"); + g_pIoSetDeviceInterfacePropertyData = (PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // Register with ETW (unified tracing) + // + EventRegisterOSRUSBFX2(); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + OsrFxEvtDeviceAdd + ); + + // + // Register a cleanup callback so that we can call WPP_CLEANUP when + // the framework driver object is deleted during driver unload. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = OsrFxEvtDriverContextCleanup; + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + &attributes, // Driver Object Attributes + &config, // Driver Config Info + WDF_NO_HANDLE // hDriver + ); + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfDriverCreate failed with status 0x%x\n", status); + // + // Cleanup tracing here because DriverContextCleanup will not be called + // as we have failed to create WDFDRIVER object itself. + // Please note that if your return failure from DriverEntry after the + // WDFDRIVER object is created successfully, you don't have to + // call WPP cleanup because in those cases DriverContextCleanup + // will be executed when the framework deletes the DriverObject. + // + WPP_CLEANUP(DriverObject); + EventUnregisterOSRUSBFX2(); + } + + return status; +} + +VOID +OsrFxEvtDriverContextCleanup( + WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free resources allocated in DriverEntry that are not automatically + cleaned up by the framework. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + // + // EvtCleanupCallback for WDFDRIVER is always called at PASSIVE_LEVEL + // + _IRQL_limited_to_(PASSIVE_LEVEL); + + PAGED_CODE (); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "--> OsrFxEvtDriverContextCleanup\n"); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver )); + + UNREFERENCED_PARAMETER(Driver); // For the case when WPP is not being used. + + EventUnregisterOSRUSBFX2(); +} + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + DebugPrintLevel - print level between 0 and 3, with 3 the most verbose + DebugPrintFlag - message mask + DebugMessage - format string of the message to print + ... - values used by the format string + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!NT_SUCCESS(status)) { + + DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed 0x%x\n", status); + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { + DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/interrupt.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/interrupt.c new file mode 100644 index 00000000..00ea3550 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/interrupt.c @@ -0,0 +1,184 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Interrupt.c + +Abstract: + + This modules has routines configure a continuous reader on an + interrupt pipe to asynchronously read toggle switch states. + +Environment: + + Kernel mode + +--*/ + +#include + +#if defined(EVENT_TRACING) +#include "interrupt.tmh" +#endif + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ) +/*++ + +Routine Description: + + This routine configures a continuous reader on the + interrupt endpoint. It's called from the PrepareHarware event. + +Arguments: + + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; + NTSTATUS status; + + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, + OsrFxEvtUsbInterruptPipeReadComplete, + DeviceContext, // Context + sizeof(UCHAR)); // TransferLength + + contReaderConfig.EvtUsbTargetPipeReadersFailed = OsrFxEvtUsbInterruptReadersFailed; + + // + // Reader requests are not posted to the target automatically. + // Driver must explictly call WdfIoTargetStart to kick start the + // reader. In this sample, it's done in D0Entry. + // By defaut, framework queues two requests to the target + // endpoint. Driver can configure up to 10 requests with CONFIG macro. + // + status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe, + &contReaderConfig); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxConfigContReaderForInterruptEndPoint failed %x\n", + status); + return status; + } + + return status; +} + +VOID +OsrFxEvtUsbInterruptPipeReadComplete( + WDFUSBPIPE Pipe, + WDFMEMORY Buffer, + size_t NumBytesTransferred, + WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This the completion routine of the continour reader. This can + called concurrently on multiprocessor system if there are + more than one readers configured. So make sure to protect + access to global resources. + +Arguments: + + Buffer - This buffer is freed when this call returns. + If the driver wants to delay processing of the buffer, it + can take an additional referrence. + + Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro + +Return Value: + + NT status value + +--*/ +{ + PUCHAR switchState = NULL; + WDFDEVICE device; + PDEVICE_CONTEXT pDeviceContext = Context; + + UNREFERENCED_PARAMETER(Pipe); + + device = WdfObjectContextGetObject(pDeviceContext); + + // + // Make sure that there is data in the read packet. Depending on the device + // specification, it is possible for it to return a 0 length read in + // certain conditions. + // + + if (NumBytesTransferred == 0) { + TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete Zero length read " + "occured on the Interrupt Pipe's Continuous Reader\n" + ); + return; + } + + + NT_ASSERT(NumBytesTransferred == sizeof(UCHAR)); + + switchState = WdfMemoryGetBuffer(Buffer, NULL); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n", + *switchState); + + pDeviceContext->CurrentSwitchState = *switchState; + + // + // Handle any pending Interrupt Message IOCTLs. Note that the OSR USB device + // will generate an interrupt message when the the device resumes from a low + // power state. So if the Interrupt Message IOCTL was sent after the device + // has gone to a low power state, the pending Interrupt Message IOCTL will + // get completed in the function call below, before the user twiddles the + // dip switches on the OSR USB device. If this is not the desired behavior + // for your driver, then you could handle this condition by maintaining a + // state variable on D0Entry to track interrupt messages caused by power up. + // + OsrUsbIoctlGetInterruptMessage(device, STATUS_SUCCESS); + +} + +BOOLEAN +OsrFxEvtUsbInterruptReadersFailed( + _In_ WDFUSBPIPE Pipe, + _In_ NTSTATUS Status, + _In_ USBD_STATUS UsbdStatus + ) +{ + WDFDEVICE device = WdfIoTargetGetDevice(WdfUsbTargetPipeGetIoTarget(Pipe)); + PDEVICE_CONTEXT pDeviceContext = GetDeviceContext(device); + + UNREFERENCED_PARAMETER(UsbdStatus); + + // + // Clear the current switch state. + // + pDeviceContext->CurrentSwitchState = 0; + + // + // Service the pending interrupt switch change request + // + OsrUsbIoctlGetInterruptMessage(device, Status); + + return TRUE; +} + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/ioctl.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/ioctl.c new file mode 100644 index 00000000..e36bcef1 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/ioctl.c @@ -0,0 +1,1063 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Ioctl.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + +--*/ + +#include + +#if defined(EVENT_TRACING) +#include "ioctl.tmh" +#endif + +#pragma alloc_text(PAGE, OsrFxEvtIoDeviceControl) +#pragma alloc_text(PAGE, ResetPipe) +#pragma alloc_text(PAGE, ResetDevice) +#pragma alloc_text(PAGE, ReenumerateDevice) +#pragma alloc_text(PAGE, GetBarGraphState) +#pragma alloc_text(PAGE, SetBarGraphState) +#pragma alloc_text(PAGE, GetSevenSegmentState) +#pragma alloc_text(PAGE, SetSevenSegmentState) +#pragma alloc_text(PAGE, GetSwitchState) + +VOID +OsrFxEvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. +Return Value: + + VOID + +--*/ +{ + WDFDEVICE device; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PBAR_GRAPH_STATE barGraphState = NULL; + PSWITCH_STATE switchState = NULL; + PUCHAR sevenSegment = NULL; + BOOLEAN requestPending = FALSE; + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(OutputBufferLength); + + // + // If your driver is at the top of its driver stack, EvtIoDeviceControl is called + // at IRQL = PASSIVE_LEVEL. + // + _IRQL_limited_to_(PASSIVE_LEVEL); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n"); + // + // initialize variables + // + device = WdfIoQueueGetDevice(Queue); + pDevContext = GetDeviceContext(device); + + switch(IoControlCode) { + + case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: { + + PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; + USHORT requiredSize = 0; + + // + // First get the size of the config descriptor + // + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + NULL, + &requiredSize); + + if (status != STATUS_BUFFER_TOO_SMALL) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + // + // Get the buffer - make sure the buffer is big enough + // + status = WdfRequestRetrieveOutputBuffer(Request, + (size_t)requiredSize, // MinimumRequired + &configurationDescriptor, + NULL); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); + break; + } + + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + configurationDescriptor, + &requiredSize); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + bytesReturned = requiredSize; + + } + break; + + case IOCTL_OSRUSBFX2_RESET_DEVICE: + + status = ResetDevice(device); + break; + + case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: + + // + // Otherwise, call our function to reenumerate the + // device + // + status = ReenumerateDevice(pDevContext); + + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: + + // + // Make sure the caller's output buffer is large enough + // to hold the state of the bar graph + // + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(BAR_GRAPH_STATE), + &barGraphState, + NULL); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); + break; + } + // + // Call our function to get the bar graph state + // + status = GetBarGraphState(pDevContext, barGraphState); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(BAR_GRAPH_STATE); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(BAR_GRAPH_STATE), + &barGraphState, + NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's input buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); + break; + } + + // + // Call our routine to set the bar graph state + // + status = SetBarGraphState(pDevContext, barGraphState); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(UCHAR), + &sevenSegment, + NULL); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting an UCHAR\n"); + break; + } + + // + // Call our function to get the 7 segment state + // + status = GetSevenSegmentState(pDevContext, sevenSegment); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(UCHAR); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(UCHAR), + &sevenSegment, + NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's input buffer is too small for this IOCTL, expecting an UCHAR\n"); + bytesReturned = sizeof(UCHAR); + break; + } + + // + // Call our routine to set the 7 segment state + // + status = SetSevenSegmentState(pDevContext, sevenSegment); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_READ_SWITCHES: + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + break; + + } + + // + // Call our routine to get the state of the switches + // + status = GetSwitchState(pDevContext, switchState); + + // + // If successful, return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(SWITCH_STATE); + + } else { + // + // Don't return any data + // + bytesReturned = 0; + } + break; + + case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: + + // + // Forward the request to an interrupt message queue and dont complete + // the request until an interrupt from the USB device occurs. + // + status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue); + if (NT_SUCCESS(status)) { + requestPending = TRUE; + } + + break; + + default : + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + if (requestPending == FALSE) { + WdfRequestCompleteWithInformation(Request, status, bytesReturned); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n"); + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine resets the pipe. + +Arguments: + + Pipe - framework pipe handle + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // This routine synchronously submits a URB_FUNCTION_RESET_PIPE + // request down the stack. + // + status = WdfUsbTargetPipeResetSynchronously(Pipe, + WDF_NO_HANDLE, // WDFREQUEST + NULL // PWDF_REQUEST_SEND_OPTIONS + ); + + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "ResetPipe - success\n"); + status = STATUS_SUCCESS; + } + else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetPipe - failed\n"); + } + + return status; +} + +VOID +StopAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe), + WdfIoTargetCancelSentIo); +} + +NTSTATUS +StartAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still + connected. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> ResetDevice\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // A NULL timeout indicates an infinite wake + // + status = WdfWaitLockAcquire(pDeviceContext->ResetDeviceWaitLock, NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice - could not acquire lock\n"); + return status; + } + + StopAllPipes(pDeviceContext); + + status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->UsbDevice); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice failed - 0x%x\n", status); + } + + status = StartAllPipes(pDeviceContext); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Failed to start all pipes - 0x%x\n", status); + } + + WdfWaitLockRelease(pDeviceContext->ResetDeviceWaitLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- ResetDevice\n"); + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ) +/*++ + +Routine Description + + This routine re-enumerates the USB device. + +Arguments: + + pDevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + GUID activity; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_REENUMERATE, // Request + 0, // Value + 0); // Index + + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + NULL, // MemoryDescriptor + NULL); // BytesTransferred + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n"); + + // + // Send event to eventlog + // + + activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext)); + EventWriteDeviceReenumerated(&activity, + DevContext->DeviceName, + DevContext->Location, + status); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine gets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that receives the bar graph's state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + BarGraphState->BarsAsUChar = 0; + + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetBarGraphState: Failed to GetBarGraphState - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine sets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that describes the bar graph's desired state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetBarGraphState: Failed - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine gets the state of the 7 segment display on the board + by sending a synchronous control command. + + NOTE: It's not a good practice to send a synchronous request in the + context of the user thread because if the transfer takes long + time to complete, you end up holding the user thread. + + I'm choosing to do synchronous transfer because a) I know this one + completes immediately b) and for demonstration. + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - receives the state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Enter\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + *SevenSegment = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSevenSegmentState: Failed to get 7 Segment state - 0x%x \n", status); + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Exit\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine sets the state of the 7 segment display on the board + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - desired state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetSevenSegmentState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetSevenSegmentState: Failed to set 7 Segment state - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetSevenSegmentState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ) +/*++ + +Routine Description + + This routine gets the state of the switches on the board + +Arguments: + + DevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetSwitchState\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_SWITCHES, // Request + 0, // Value + 0); // Index + + SwitchState->SwitchesAsUChar = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SwitchState, + sizeof(SWITCH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSwitchState: Failed to Get switches - 0x%x \n", status); + + } else { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSwitchState: Switch mask is 0x%x\n", SwitchState->SwitchesAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetSwitchState\n"); + + return status; + +} + + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ) +/*++ + +Routine Description + + This method handles the completion of the pended request for the IOCTL + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE. + +Arguments: + + Device - Handle to a framework device. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + WDFREQUEST request; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PSWITCH_STATE switchState = NULL; + + pDevContext = GetDeviceContext(Device); + + do { + + // + // Check if there are any pending requests in the Interrupt Message Queue. + // If a request is found then complete the pending request. + // + status = WdfIoQueueRetrieveNextRequest(pDevContext->InterruptMsgQueue, &request); + + if (NT_SUCCESS(status)) { + status = WdfRequestRetrieveOutputBuffer(request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + + } else { + + // + // Copy the state information saved by the continuous reader. + // + if (NT_SUCCESS(ReaderStatus)) { + switchState->SwitchesAsUChar = pDevContext->CurrentSwitchState; + bytesReturned = sizeof(SWITCH_STATE); + } else { + bytesReturned = 0; + } + } + + // + // Complete the request. If we failed to get the output buffer then + // complete with that status. Otherwise complete with the status from the reader. + // + WdfRequestCompleteWithInformation(request, + NT_SUCCESS(status) ? ReaderStatus : status, + bytesReturned); + status = STATUS_SUCCESS; + + } else if (status != STATUS_NO_MORE_ENTRIES) { + KdPrint(("WdfIoQueueRetrieveNextRequest status %08x\n", status)); + } + + request = NULL; + + } while (status == STATUS_SUCCESS); + + return; + +} + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.h b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.h new file mode 100644 index 00000000..d83b5e43 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.h @@ -0,0 +1,342 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the driver. + +Environment: + + Kernel mode + +--*/ + +#include +#include +#include +#include "usbdi.h" +#include "usbdlib.h" +#include "public.h" +#include "driverspecs.h" +//#include +#include +#define NTSTRSAFE_LIB +#include + +#include "trace.h" + +// +// Include auto-generated ETW event functions (created by MC.EXE from +// osrusbfx2.man) +// +#include "fx2Events.h" + +#ifndef _PRIVATE_H +#define _PRIVATE_H + +#define POOL_TAG (ULONG) 'FRSO' +#define _DRIVER_NAME_ "OSRUSBFX2" + +#define TEST_BOARD_TRANSFER_BUFFER_SIZE (64*1024) +#define DEVICE_DESC_LENGTH 256 + +extern const __declspec(selectany) LONGLONG DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; + +// +// Define the vendor commands supported by our device +// +#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4 +#define USBFX2LK_READ_SWITCHES 0xD6 +#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7 +#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8 +#define USBFX2LK_IS_HIGH_SPEED 0xD9 +#define USBFX2LK_REENUMERATE 0xDA +#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB + +// +// Define the features that we can clear +// and set on our device +// +#define USBFX2LK_FEATURE_EPSTALL 0x00 +#define USBFX2LK_FEATURE_WAKE 0x01 + +// +// Order of endpoints in the interface descriptor +// +#define INTERRUPT_IN_ENDPOINT_INDEX 0 +#define BULK_OUT_ENDPOINT_INDEX 1 +#define BULK_IN_ENDPOINT_INDEX 2 + +// +// A structure representing the instance information associated with +// this particular device. +// + +typedef struct _DEVICE_CONTEXT { + + WDFUSBDEVICE UsbDevice; + + WDFUSBINTERFACE UsbInterface; + + WDFUSBPIPE BulkReadPipe; + + WDFUSBPIPE BulkWritePipe; + + WDFUSBPIPE InterruptPipe; + + WDFWAITLOCK ResetDeviceWaitLock; + + UCHAR CurrentSwitchState; + + WDFQUEUE InterruptMsgQueue; + + ULONG UsbDeviceTraits; + + // + // The following fields are used during event logging to + // report the events relative to this specific instance + // of the device. + // + + WDFMEMORY DeviceNameMemory; + PCWSTR DeviceName; + + WDFMEMORY LocationMemory; + PCWSTR Location; + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) + +extern ULONG DebugLevel; + +typedef +NTSTATUS +(*PFN_IO_GET_ACTIVITY_ID_IRP) ( + _In_ PIRP Irp, + _Out_ LPGUID Guid + ); + +typedef +NTSTATUS +(*PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) ( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ CONST DEVPROPKEY *PropertyKey, + _In_ LCID Lcid, + _In_ ULONG Flags, + _In_ DEVPROPTYPE Type, + _In_ ULONG Size, + _In_opt_ PVOID Data + ); + +// +// Global function pointer set in DriverEntry +// Check for NULL before using +// +extern PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; + +extern PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP OsrFxEvtDriverContextCleanup; + +EVT_WDF_DRIVER_DEVICE_ADD OsrFxEvtDeviceAdd; + +EVT_WDF_DEVICE_PREPARE_HARDWARE OsrFxEvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_READ OsrFxEvtIoRead; + +EVT_WDF_IO_QUEUE_IO_WRITE OsrFxEvtIoWrite; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OsrFxEvtIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ); + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +EVT_WDF_USB_READER_COMPLETION_ROUTINE OsrFxEvtUsbInterruptPipeReadComplete; + +EVT_WDF_USB_READERS_FAILED OsrFxEvtUsbInterruptReadersFailed; + +EVT_WDF_IO_QUEUE_IO_STOP OsrFxEvtIoStop; + +EVT_WDF_DEVICE_D0_ENTRY OsrFxEvtDeviceD0Entry; + +EVT_WDF_DEVICE_D0_EXIT OsrFxEvtDeviceD0Exit; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH OsrFxEvtDeviceSelfManagedIoFlush; + +// +// DMF: This is the callback function called by DMF that allows this driver (the Client Driver) +// to set the CONFIG for each DMF Module the driver will use. +// +EVT_DMF_DEVICE_MODULES_ADD OsrDmfModulesAdd; + +_IRQL_requires_(PASSIVE_LEVEL) +BOOLEAN +OsrFxReadFdoRegistryKeyValue( + _In_ PWDFDEVICE_INIT DeviceInit, + _In_ PWCHAR Name, + _Out_ PULONG Value + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +OsrFxEnumerateChildren( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ); + + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ); + +FORCEINLINE +GUID +RequestToActivityId( + _In_ WDFREQUEST Request + ) +{ + GUID activity = {0}; + NTSTATUS status = STATUS_SUCCESS; + + if (g_pIoGetActivityIdIrp != NULL) { + + // + // Use activity ID generated by application (or IO manager) + // + status = g_pIoGetActivityIdIrp(WdfRequestWdmGetIrp(Request), &activity); + } + + if (g_pIoGetActivityIdIrp == NULL || !NT_SUCCESS(status)) { + + // + // Fall back to using the WDFREQUEST handle as the activity ID + // + RtlCopyMemory(&activity, &Request, sizeof(WDFREQUEST)); + } + + + return activity; +} + +FORCEINLINE +GUID +DeviceToActivityId( + _In_ WDFDEVICE Device + ) +{ + GUID activity = {0}; + RtlCopyMemory(&activity, &Device, sizeof(WDFDEVICE)); + return activity; +} + + +#endif + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.man b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.man new file mode 100644 index 00000000..176dfc89 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.man @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.rc b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.rc new file mode 100644 index 00000000..092ec195 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2.rc @@ -0,0 +1,18 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDF Sample Driver for OSR USB-FX2 Learning Kit" +#define VER_INTERNALNAME_STR "osrusbfx2.sys" +#define VER_ORIGINALFILENAME_STR "osrusbfx2.sys" + +#include "common.ver" + +// +// Include auto-generated string resources (created by MC.EXE from +// osrusbfx2.man) +// + +#include "fx2Events.rc" diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.inx b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.inx new file mode 100644 index 00000000..24fdc23d Binary files /dev/null and b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.inx differ diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.vcxproj b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.vcxproj new file mode 100644 index 00000000..2771a16b --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.vcxproj @@ -0,0 +1,250 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {837F98CF-D3A4-472C-BACC-47950340E57B} + $(MSBuildProjectName) + 1 + false + true + Debug + Win32 + {3EBA8CBF-2E65-4819-9EEA-E10825BB0705} + osrusbfx2dmf1 + $(LatestTargetPlatformVersion) + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + true + true + .\$(IntDir) + true + .\$(IntDir) + true + fx2Events + true + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + + osrusbfx2dmf1 + + + osrusbfx2dmf1 + + + osrusbfx2 + + + osrusbfx2 + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\Dmf\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Release\x64\lib\\DmfK\DmfK.lib + + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Debug\x64\lib\DmfK\DmfK.lib + + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Release\Win32\lib\\DmfK\DmfK.lib + + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Debug\Win32\lib\DmfK\DmfK.lib + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.vcxproj.Filters b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.vcxproj.Filters new file mode 100644 index 00000000..e140fb16 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/osrusbfx2dmf1.vcxproj.Filters @@ -0,0 +1,89 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {F859293F-10B7-4E6D-99E2-120A09448FF9} + + + h;hpp;hxx;hm;inl;inc;xsd + {3DCE0FEA-C37D-448E-B9E4-B69865E71B5F} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {A1BB449A-54EF-4B2B-BD68-2254963FF387} + + + inf;inv;inx;mof;mc; + {A03D3DFA-E9BD-48A3-BEDE-E8AAED283D03} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Driver Files + + + \ No newline at end of file diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/trace.h b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/trace.h new file mode 100644 index 00000000..518ff5f1 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_1/trace.h @@ -0,0 +1,115 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TRACE.h + +Abstract: + + Header file for the debug tracing related function defintions and macros. + +Environment: + + Kernel mode + +--*/ + +#include // For TRACE_LEVEL definitions + +#if !defined(EVENT_TRACING) + +// +// TODO: These defines are missing in evntrace.h +// in some DDK build environments (XP). +// +#if !defined(TRACE_LEVEL_NONE) + #define TRACE_LEVEL_NONE 0 + #define TRACE_LEVEL_CRITICAL 1 + #define TRACE_LEVEL_FATAL 1 + #define TRACE_LEVEL_ERROR 2 + #define TRACE_LEVEL_WARNING 3 + #define TRACE_LEVEL_INFORMATION 4 + #define TRACE_LEVEL_VERBOSE 5 + #define TRACE_LEVEL_RESERVED6 6 + #define TRACE_LEVEL_RESERVED7 7 + #define TRACE_LEVEL_RESERVED8 8 + #define TRACE_LEVEL_RESERVED9 9 +#endif + + +// +// Define Debug Flags +// +#define DBG_INIT 0x00000001 +#define DBG_PNP 0x00000002 +#define DBG_POWER 0x00000004 +#define DBG_WMI 0x00000008 +#define DBG_CREATE_CLOSE 0x00000010 +#define DBG_IOCTL 0x00000020 +#define DBG_WRITE 0x00000040 +#define DBG_READ 0x00000080 + + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ); + +#define WPP_INIT_TRACING(DriverObject, RegistryPath) +#define WPP_CLEANUP(DriverObject) + +#else +// +// If software tracing is defined in the sources file.. +// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. +// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** +// WPP_DEFINE_BIT allows setting debug bit masks to selectively print. +// The names defined in the WPP_DEFINE_BIT call define the actual names +// that are used to control the level of tracing for the control guid +// specified. +// +// NOTE: If you are adopting this sample for your driver, please generate +// a new guid, using tools\other\i386\guidgen.exe present in the +// DDK. +// +// Name of the logger is OSRUSBFX2 and the guid is +// {D23A0C5A-D307-4f0e-AE8E-E2A355AD5DAB} +// (0xd23a0c5a, 0xd307, 0x4f0e, 0xae, 0x8e, 0xe2, 0xa3, 0x55, 0xad, 0x5d, 0xab); +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ + WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + /* You can have up to 32 defines. If you want more than that,\ + you have to provide another trace control GUID */\ + ) + + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + + +#endif + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/README.md b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/README.md new file mode 100644 index 00000000..7f641036 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/README.md @@ -0,0 +1,80 @@ + + +Sample KMDF/DMF Function Driver for OSR USB-FX2 (DMF Sample 2) +============================================================== + +This sammple is an incremental change from the first DMF Sample driver. It shows how to instantiate a DMF Module. This sample instantiates the +Dmf_IoctlHandler Module which simplyfies IOCTL handling in a driver. + +IMPORTANT: For details about how the OSR USB-FX2 device operates, please see the original (non-DMF) sample. This sample is designed to do everything + the original sample does but also perform the minimum steps necessary to initialize DMF. + +Please perform a file compare between all the files in this sample and the files in the original sample. That is the best way to see the differences. + +Overview +-------- + +In this sample, as a demonstration of how to use a Module, the Dmf_IoctlHandler Module is selected. The purpose of this Module +is to simplyfy IOCTL handling. The Client driver supplies a table of the IOCTLs the driver supports as well as the minimum sizes +of the input/output buffers and a callback for each IOCTL. + +As IOCTLs are sent to the Client driver, DMF intercepts them and sends them to the Dmf_IoctlHandler Module that is instantiated. +This Module validates the IOCTLs and if the validation passes, sends them to the Client driver's callback. There, the Client driver +can process the IOCTL without needing to validate the parameters. + +Thus, in this sample, the following changes are made: + +1. In Device.c a table is created which contains all the information about the IOCTLs that the driver supports. This information +is based on the code in the original sample. + +2. In the function DmfModulesAdd, this variable is declared. It needs to be declared a single time regardless of how many Modules +are to be instantiated. + + DMF_MODULE_ATTRIBUTES moduleAttributes; + +3. Next, a variable that contains the Dmf_IoctlHandler specific configuration information is declared: + + DMF_CONFIG_IoctlHandler moduleConfigIoctlHandler; + +4. Next, moduleConfigIoctlHandler is initialized: + + DMF_CONFIG_IoctlHandler_AND_ATTRIBUTES_INIT(&moduleConfigIoctlHandler, + &moduleAttributes); + +5. Next, Module specific parameters are set in the Module's Config. This is how the Module knows about the Client driver's +supported IOCTLs. + + moduleConfigIoctlHandler.IoctlRecords = OsrFx2_IoctlHandlerTable; + moduleConfigIoctlHandler.IoctlRecordCount = _countof(OsrFx2_IoctlHandlerTable); + moduleConfigIoctlHandler.DeviceInterfaceGuid = GUID_DEVINTERFACE_OSRUSBFX2; + moduleConfigIoctlHandler.AccessModeFilter = IoctlHandler_AccessModeDefault; + +6. Finally, this Module is added to the list of Modules that DMF will instantiate: + + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + &pDevContext->DmfModuleIoctlHandler); + +7. To instantiate more Modules, simply declare the Module's Config structure (if any), initialize it if necesssary and +call DMF_DmfModuleAdd() again using hte same moduleAttributes and the new Module Config. + +Code tour +--------- + +There are no changes between the original sample and this sample. Please see the original sample for details. + +Testing the driver +------------------ + +Please see the original sample for details. Nothing is changed in the DMF version. You can place a breakpoint in the IOCTL handler +specified by the Client driver to single step and see how it works. You will it contains less code and is simpler. Of course, +this is a trivial example of using a Module, but it is useful for demonstration purposes. + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/bulkrwr.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/bulkrwr.c new file mode 100644 index 00000000..eabda192 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/bulkrwr.c @@ -0,0 +1,436 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + bulkrwr.c + +Abstract: + + This file has routines to perform reads and writes. + The read and writes are targeted bulk to endpoints. + +Environment: + + Kernel mode + +--*/ + +#include + + +#if defined(EVENT_TRACING) +#include "bulkrwr.tmh" +#endif + +#pragma warning(disable:4267) + +VOID +OsrFxEvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + +--*/ +{ + WDFUSBPIPE pipe; + NTSTATUS status; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + // + // Log read start event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "-->OsrFxEvtIoRead\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkReadPipe; + + status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); + goto Exit; + } + + // + // The format call validates to make sure that you are reading or + // writing to the right pipe type, sets the appropriate transfer flags, + // creates an URB and initializes the request. + // + status = WdfUsbTargetPipeFormatRequestForRead(pipe, + Request, + reqMemory, + NULL // Offsets + ); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfUsbTargetPipeFormatRequestForRead failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestReadCompletionRoutine, + pipe); + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + + +Exit: + if (!NT_SUCCESS(status)) { + // + // log event read failed + // + EventWriteReadFail(&activity, WdfIoQueueGetDevice(Queue), status); + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "<-- OsrFxEvtIoRead\n"); + + return; +} + +VOID +EvtRequestReadCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for reads + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesRead = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesRead = usbCompletionParams->Parameters.PipeRead.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "Number of bytes read: %I64d\n", (INT64)bytesRead); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "Read failed - request status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + + } + + // + // Log read stop event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesRead, + status, + usbCompletionParams->UsbdStatus); + + WdfRequestCompleteWithInformation(Request, status, bytesRead); + + return; +} + +VOID +OsrFxEvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + +--*/ +{ + NTSTATUS status; + WDFUSBPIPE pipe; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + + // + // Log write start event, using IRP activity ID if available or request + // handle otherwise. + // + EventWriteWriteStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "-->OsrFxEvtIoWrite\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkWritePipe; + + status = WdfRequestRetrieveInputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestRetrieveInputBuffer failed\n"); + goto Exit; + } + + status = WdfUsbTargetPipeFormatRequestForWrite(pipe, + Request, + reqMemory, + NULL); // Offset + + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfUsbTargetPipeFormatRequestForWrite failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestWriteCompletionRoutine, + pipe); + + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) { + // + // log event write failed + // + EventWriteWriteFail(&activity, WdfIoQueueGetDevice(Queue), status); + + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- OsrFxEvtIoWrite\n"); + + return; +} + +VOID +EvtRequestWriteCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for writes + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesWritten = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + // + // For usb devices, we should look at the Usb.Completion param. + // + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesWritten = usbCompletionParams->Parameters.PipeWrite.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "Number of bytes written: %I64d\n", (INT64)bytesWritten); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "Write failed: request Status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + } + + // + // Log write stop event, using IRP activtiy ID if available or request + // handle otherwise + // + EventWriteWriteStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesWritten, + status, + usbCompletionParams->UsbdStatus); + + + WdfRequestCompleteWithInformation(Request, status, bytesWritten); + + return; +} + + +VOID +OsrFxEvtIoStop( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG ActionFlags + ) +/*++ + +Routine Description: + + This callback is invoked on every inflight request when the device + is suspended or removed. Since our inflight read and write requests + are actually pending in the target device, we will just acknowledge + its presence. Until we acknowledge, complete, or requeue the requests + framework will wait before allowing the device suspend or remove to + proceeed. When the underlying USB stack gets the request to suspend or + remove, it will fail all the pending requests. + +Arguments: + + Queue - handle to queue object that is associated with the I/O request + + Request - handle to a request object + + ActionFlags - bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS flags + +Return Value: + None + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(ActionFlags); + + if (ActionFlags & WdfRequestStopActionSuspend ) { + WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue + } else if(ActionFlags & WdfRequestStopActionPurge) { + WdfRequestCancelSentRequest(Request); + } + return; +} + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/device.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/device.c new file mode 100644 index 00000000..3c2ff147 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/device.c @@ -0,0 +1,1088 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Device.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + + +--*/ + +#include + +#if defined(EVENT_TRACING) +#include "device.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, OsrFxEvtDeviceAdd) +#pragma alloc_text(PAGE, OsrFxEvtDevicePrepareHardware) +#pragma alloc_text(PAGE, OsrFxEvtDeviceD0Exit) +#pragma alloc_text(PAGE, SelectInterfaces) +#pragma alloc_text(PAGE, OsrFxSetPowerPolicy) +#pragma alloc_text(PAGE, OsrFxReadFdoRegistryKeyValue) +#pragma alloc_text(PAGE, GetDeviceEventLoggingNames) +#pragma alloc_text(PAGE, OsrFxValidateConfigurationDescriptor) +#pragma alloc_text(PAGE, OsrDmfModulesAdd) +#endif + + +NTSTATUS +OsrFxEvtDeviceAdd( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + PDEVICE_CONTEXT pDevContext; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + WDFQUEUE queue; + GUID activity; + PDMFDEVICE_INIT dmfDeviceInit; + DMF_EVENT_CALLBACKS dmfEventCallbacks; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); + + // + // DMF: Create the PDMFDEVICE_INIT structure. + // + dmfDeviceInit = DMF_DmfDeviceInitAllocate(DeviceInit); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + // + // For usb devices, PrepareHardware callback is the to place select the + // interface and configure the device. + // + pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; + + // + // These two callbacks start and stop the wdfusb pipe continuous reader + // as we go in and out of the D0-working state. + // + + pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // DMF: Hook Pnp Power Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use Pnp Power Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for Pnp Power Callbacks later. + // + DMF_DmfDeviceInitHookPnpPowerEventCallbacks(dmfDeviceInit, &pnpPowerCallbacks); + + // + // DMF: Hook Power Policy Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use Power Policy Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for Power Policy Callbacks later. + // + DMF_DmfDeviceInitHookPowerPolicyEventCallbacks(dmfDeviceInit, NULL); + + // + // DMF: Hook File Object Callbacks. This allows DMF to receive callbacks first so it can dispatch them + // to the tree of instantiated Modules. If the driver does not use File Object Callbacks, you must + // call this function with NULL as the second parameter. This is to prevent developers from + // forgetting this step if the driver adds support for File Object Callbacks later. + // + DMF_DmfDeviceInitHookFileObjectConfig(dmfDeviceInit, NULL); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + // + // Now specify the size of device extension where we track per device + // context.DeviceInit is completely initialized. So call the framework + // to create the device and attach it to the lower stack. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with Status code %!STATUS!\n", status); + return status; + } + + // + // Setup the activity ID so that we can log events using it. + // + + activity = DeviceToActivityId(device); + + // + // Get the DeviceObject context by using accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. + // + pDevContext = GetDeviceContext(device); + + // + // Get the device's friendly name and location so that we can use it in + // error logging. If this fails then it will setup dummy strings. + // + + GetDeviceEventLoggingNames(device); + + // + // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so + // that you don't get the popup in usermode when you surprise remove the device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.SurpriseRemovalOK = WdfTrue; + + WdfDeviceSetPnpCapabilities(device, &pnpCaps); + + // + // DMF: DMF always creates a default queue, so is not necessary for the Client driver to create it. + // Since this driver will not create a default queue it is not necessary to call + // DMF_DmfDeviceInitHookQueueConfig. + // + + // + // We will create a separate sequential queue and configure it + // to receive read requests. We also need to register a EvtIoStop + // handler so that we can acknowledge requests that are pending + // at the target driver. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeRead); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + + // + // We will create another sequential queue and configure it + // to receive write requests. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeWrite); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + // + // Register a manual I/O queue for handling Interrupt Message Read Requests. + // This queue will be used for storing Requests that need to wait for an + // interrupt to occur before they can be completed. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); + + // + // This queue is used for requests that dont directly access the device. The + // requests in this queue are serviced only when the device is in a fully + // powered state and sends an interrupt. So we can use a non-power managed + // queue to park the requests since we dont care whether the device is idle + // or fully powered up. + // + ioQueueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &pDevContext->InterruptMsgQueue + ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + // + // Register a device interface so that app can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL); // Reference String + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); + goto Error; + } + + // + // Create the lock that we use to serialize calls to ResetDevice(). As an + // alternative to using a WDFWAITLOCK to serialize the calls, a sequential + // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = device; + + status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfWaitLockCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // DMF: Initialize the DMF_EVENT_CALLBACKS to set the callback DMF will call + // to get the list of Modules to instantiate. + // + DMF_EVENT_CALLBACKS_INIT(&dmfEventCallbacks); + dmfEventCallbacks.EvtDmfDeviceModulesAdd = OsrDmfModulesAdd; + + DMF_DmfDeviceInitSetEventCallbacks(dmfDeviceInit, + &dmfEventCallbacks); + + // + // DMF: Tell DMF to create its data structures and create the tree of Modules the + // Client driver has specified (using the above callback). After this call + // succeeds DMF has all the information it needs to dispatch WDF entry points + // to the tree of Modules. + // + status = DMF_ModulesCreate(device, + &dmfDeviceInit); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); + + return status; + +Error: + + // + // Log fail to add device to the event log + // + EventWriteFailAddDevice(&activity, + pDevContext->DeviceName, + pDevContext->Location, + status); + + return status; +} + +// +// DMF: Sometimes Modules require static data passed via their CONFIG. Dmf_IoctlHandler is such a Module. +// This Module requires a table of the IOCTLs that the Client driver handles. Each record contains the +// minimum sizes of the IOCTLs input/output buffers, as well as a callback that handles that IOCTL when +// it is received. Using that information Dmf_IoctlHandler will validate the input/output buffers sizes +// for each IOCTL in the table. If the sizes are correct, the correspdonding callbck is called. +// +IoctlHandler_IoctlRecord OsrFx2_IoctlHandlerTable[] = +{ + { (LONG)IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR, 0, 0, OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_RESET_DEVICE, 0, 0, OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_REENUMERATE_DEVICE, 0, 0, OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, 0, sizeof(BAR_GRAPH_STATE), OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, sizeof(BAR_GRAPH_STATE),0, OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY, 0, sizeof(UCHAR), OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY, sizeof(UCHAR), 0, OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_READ_SWITCHES, 0, sizeof(SWITCH_STATE), OsrFxIoDeviceControl, FALSE }, + { (LONG)IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE, 0, 0, OsrFxIoDeviceControl, FALSE }, +}; + +// +// DMF: This is the callback function called by DMF that allows this driver (the Client Driver) +// to set the CONFIG for each DMF Module the driver will use. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +OsrDmfModulesAdd( + _In_ WDFDEVICE Device, + _In_ PDMFMODULE_INIT DmfModuleInit + ) +/*++ +Routine Description: + + EvtDmfDeviceModulesAdd is called by DMF during the Client driver's + AddDevice call from the PnP manager. Here the Client driver declares a + CONFIG structure for every instance of every Module the Client driver + uses. Each CONFIG structure is properly initialized for its specific + use. Then, each CONFIG structure is added to the list of Modules that + DMF will instantiate. + +Arguments: + + Device - The Client driver's WDFDEVICE. + DmfModuleInit - An opaque PDMFMODULE_INIT used by DMF. + +Return Value: + + None + +--*/ +{ + DMF_MODULE_ATTRIBUTES moduleAttributes; + DMF_CONFIG_IoctlHandler moduleConfigIoctlHandler; + DEVICE_CONTEXT* pDevContext; + + pDevContext = GetDeviceContext(Device); + + // IoctlHandler + // ------------ + // + DMF_CONFIG_IoctlHandler_AND_ATTRIBUTES_INIT(&moduleConfigIoctlHandler, + &moduleAttributes); + moduleConfigIoctlHandler.IoctlRecords = OsrFx2_IoctlHandlerTable; + moduleConfigIoctlHandler.IoctlRecordCount = _countof(OsrFx2_IoctlHandlerTable); + moduleConfigIoctlHandler.DeviceInterfaceGuid = GUID_DEVINTERFACE_OSRUSBFX2; + moduleConfigIoctlHandler.AccessModeFilter = IoctlHandler_AccessModeDefault; + moduleConfigIoctlHandler.CustomCapabilities = L"microsoft.hsaTestCustomCapability_q536wpkpf5cy2\0"; + moduleConfigIoctlHandler.IsRestricted = DEVPROP_TRUE; + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + &pDevContext->DmfModuleIoctlHandler); +} + +NTSTATUS +OsrFxEvtDevicePrepareHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourceList, + WDFCMRESLIST ResourceListTranslated + ) +/*++ + +Routine Description: + + In this callback, the driver does whatever is necessary to make the + hardware ready to use. In the case of a USB device, this involves + reading and selecting descriptors. + +Arguments: + + Device - handle to a device + + ResourceList - handle to a resource-list object that identifies the + raw hardware resources that the PnP manager assigned + to the device + + ResourceListTranslated - handle to a resource-list object that + identifies the translated hardware resources + that the PnP manager assigned to the device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + WDF_USB_DEVICE_INFORMATION deviceInfo; + ULONG waitWakeEnable; + + UNREFERENCED_PARAMETER(ResourceList); + UNREFERENCED_PARAMETER(ResourceListTranslated); + waitWakeEnable = FALSE; + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // Create a USB device handle so that we can communicate with the + // underlying USB stack. The WDFUSBDEVICE handle is used to query, + // configure, and manage all aspects of the USB device. + // These aspects include device properties, bus properties, + // and I/O creation and synchronization. We only create device the first + // the PrepareHardware is called. If the device is restarted by pnp manager + // for resource rebalance, we will use the same device handle but then select + // the interfaces again because the USB stack could reconfigure the device on + // restart. + // + if (pDeviceContext->UsbDevice == NULL) { + WDF_USB_DEVICE_CREATE_CONFIG config; + + WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, + USBD_CLIENT_CONTRACT_VERSION_602); + + status = WdfUsbTargetDeviceCreateWithParameters(Device, + &config, + WDF_NO_OBJECT_ATTRIBUTES, + &pDeviceContext->UsbDevice); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceCreateWithParameters failed with Status code %!STATUS!\n", status); + return status; + } + + // + // TODO: If you are fetching configuration descriptor from device for + // selecting a configuration or to parse other descriptors, call OsrFxValidateConfigurationDescriptor + // to do basic validation on the descriptors before you access them . + // + } + + // + // Retrieve USBD version information, port driver capabilites and device + // capabilites such as speed, power, etc. + // + WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); + + status = WdfUsbTargetDeviceRetrieveInformation( + pDeviceContext->UsbDevice, + &deviceInfo); + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceSelfPowered: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); + + waitWakeEnable = deviceInfo.Traits & + WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceRemoteWakeable: %s\n", + waitWakeEnable ? "TRUE" : "FALSE"); + // + // Save these for use later. + // + pDeviceContext->UsbDeviceTraits = deviceInfo.Traits; + } + else { + pDeviceContext->UsbDeviceTraits = 0; + } + + status = SelectInterfaces(Device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "SelectInterfaces failed 0x%x\n", status); + return status; + } + + // + // Enable wait-wake and idle timeout if the device supports it + // + if (waitWakeEnable) { + status = OsrFxSetPowerPolicy(Device); + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxSetPowerPolicy failed %!STATUS!\n", status); + return status; + } + } + + status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Entry( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + EvtDeviceD0Entry event callback must perform any operations that are + necessary before the specified device is used. It will be called every + time the hardware needs to be (re-)initialized. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + + This function runs at PASSIVE_LEVEL, even though it is not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE + is set. Even if DO_POWER_PAGABLE isn't set, this function still runs + at PASSIVE_LEVEL. In this case, though, the function absolutely must + not do anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + PreviousState - Device power state which the device was in most recently. + If the device is being newly started, this will be + PowerDeviceUnspecified. + +Return Value: + + NTSTATUS + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + BOOLEAN isTargetStarted; + + pDeviceContext = GetDeviceContext(Device); + isTargetStarted = FALSE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtEvtDeviceD0Entry - coming from %s\n", + DbgDevicePowerString(PreviousState)); + + // + // Since continuous reader is configured for this interrupt-pipe, we must explicitly start + // the I/O target to get the framework to post read requests. + // + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "Failed to start interrupt pipe %!STATUS!\n", status); + goto End; + } + + isTargetStarted = TRUE; + +End: + + if (!NT_SUCCESS(status)) { + // + // Failure in D0Entry will lead to device being removed. So let us stop the continuous + // reader in preparation for the ensuing remove. + // + if (isTargetStarted) { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtEvtDeviceD0Entry\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Exit( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This routine undoes anything done in EvtDeviceD0Entry. It is called + whenever the device leaves the D0 state, which happens when the device is + stopped, when it is removed, and when it is powered off. + + The device is still in D0 when this callback is invoked, which means that + the driver can still touch hardware in this routine. + + + EvtDeviceD0Exit event callback must perform any operations that are + necessary before the specified device is moved out of the D0 state. If the + driver needs to save hardware state before the device is powered down, then + that should be done here. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + TargetState - Device power state which the device will be put in once this + callback is complete. + +Return Value: + + Success implies that the device can be used. Failure will result in the + device stack being torn down. + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtDeviceD0Exit - moving to %s\n", + DbgDevicePowerString(TargetState)); + + pDeviceContext = GetDeviceContext(Device); + + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtDeviceD0Exit\n"); + + return STATUS_SUCCESS; +} + +VOID +OsrFxEvtDeviceSelfManagedIoFlush( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine handles flush activity for the device's + self-managed I/O operations. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + None + +--*/ +{ + // Service the interrupt message queue to drain any outstanding + // requests + OsrUsbIoctlGetInterruptMessage(Device, STATUS_DEVICE_REMOVED); +} + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ) +/*++ + +Routine Description: + + Validates a USB Configuration Descriptor + +Parameters: + + ConfigDesc: Pointer to the entire USB Configuration descriptor returned by the device + + BufferLength: Known size of buffer pointed to by ConfigDesc (Not wTotalLength) + + Offset: if the USBD_STATUS returned is not USBD_STATUS_SUCCESS, offet will + be set to the address within the ConfigDesc buffer where the failure occured. + +Return Value: + + USBD_STATUS + Success implies the configuration descriptor is valid. + +--*/ +{ + + + USBD_STATUS status = USBD_STATUS_SUCCESS; + USHORT ValidationLevel = 3; + + PAGED_CODE(); + + // + // Call USBD_ValidateConfigurationDescriptor to validate the descriptors which are present in this supplied configuration descriptor. + // USBD_ValidateConfigurationDescriptor validates that all descriptors are completely contained within the configuration descriptor buffer. + // It also checks for interface numbers, number of endpoints in an interface etc. + // Please refer to msdn documentation for this function for more information. + // + + status = USBD_ValidateConfigurationDescriptor( ConfigDesc, BufferLength , ValidationLevel , Offset , POOL_TAG ); + if (!(NT_SUCCESS (status)) ){ + return status; + } + + // + // TODO: You should validate the correctness of other descriptors which are not taken care by USBD_ValidateConfigurationDescriptor + // Check that all such descriptors have size >= sizeof(the descriptor they point to) + // Check for any association between them if required + // + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ) +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings); + if ( !NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", status); + return status; + } + + // + // Init wait-wake policy structure. + // + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); + + status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceAssignSxWakeSettings failed %x\n", status); + return status; + } + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This helper routine selects the configuration, interface and + creates a context for every pipe (end point) in that interface. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_CONTEXT pDeviceContext; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + UCHAR index; + UCHAR numberConfiguredPipes; + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); + + status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, + WDF_NO_OBJECT_ATTRIBUTES, + &configParams); + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", + status); + + // + // Since the Osr USB fx2 device is capable of working at high speed, the only reason + // the device would not be working at high speed is if the port doesn't + // support it. If the port doesn't support high speed it is a 1.1 port + // + if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { + GUID activity = DeviceToActivityId(Device); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + " On a 1.1 USB port on Windows Vista" + " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" + " doesn't conform to the USB specification. Windows Vista detects this and" + " returns an error. \n" + ); + EventWriteSelectConfigFailure( + &activity, + pDeviceContext->DeviceName, + pDeviceContext->Location, + status + ); + } + + return status; + } + + pDeviceContext->UsbInterface = + configParams.Types.SingleInterface.ConfiguredUsbInterface; + + numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; + + // + // Get pipe handles + // + for(index=0; index < numberConfiguredPipes; index++) { + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + pDeviceContext->UsbInterface, + index, //PipeIndex, + &pipeInfo + ); + // + // Tell the framework that it's okay to read less than + // MaximumPacketSize + // + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); + + if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "Interrupt Pipe is 0x%p\n", pipe); + pDeviceContext->InterruptPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsInEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkInput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkReadPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsOutEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkOutput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkWritePipe = pipe; + } + + } + + // + // If we didn't find all the 3 pipes, fail the start. + // + if(!(pDeviceContext->BulkWritePipe + && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { + status = STATUS_INVALID_DEVICE_STATE; + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Device is not configured properly %!STATUS!\n", + status); + + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + Retrieve the friendly name and the location string into WDFMEMORY objects + and store them in the device context. + +Arguments: + +Return Value: + + None + +--*/ +{ + PDEVICE_CONTEXT pDevContext = GetDeviceContext(Device); + + WDF_OBJECT_ATTRIBUTES objectAttributes; + + WDFMEMORY deviceNameMemory = NULL; + WDFMEMORY locationMemory = NULL; + + NTSTATUS status; + + PAGED_CODE(); + + // + // We want both memory objects to be children of the device so they will + // be deleted automatically when the device is removed. + // + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); + objectAttributes.ParentObject = Device; + + // + // First get the length of the string. If the FriendlyName + // is not there then get the lenght of device description. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyFriendlyName, + NonPagedPoolNx, + &objectAttributes, + &deviceNameMemory); + + if (!NT_SUCCESS(status)) + { + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyDeviceDescription, + NonPagedPoolNx, + &objectAttributes, + &deviceNameMemory); + } + + if (NT_SUCCESS(status)) + { + pDevContext->DeviceNameMemory = deviceNameMemory; + pDevContext->DeviceName = WdfMemoryGetBuffer(deviceNameMemory, NULL); + } + else + { + pDevContext->DeviceNameMemory = NULL; + pDevContext->DeviceName = L"(error retrieving name)"; + } + + // + // Retrieve the device location string. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyLocationInformation, + NonPagedPoolNx, + WDF_NO_OBJECT_ATTRIBUTES, + &locationMemory); + + if (NT_SUCCESS(status)) + { + pDevContext->LocationMemory = locationMemory; + pDevContext->Location = WdfMemoryGetBuffer(locationMemory, NULL); + } + else + { + pDevContext->LocationMemory = NULL; + pDevContext->Location = L"(error retrieving location)"; + } + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ) +{ + switch (Type) + { + case WdfPowerDeviceInvalid: + return "WdfPowerDeviceInvalid"; + case WdfPowerDeviceD0: + return "WdfPowerDeviceD0"; + case WdfPowerDeviceD1: + return "WdfPowerDeviceD1"; + case WdfPowerDeviceD2: + return "WdfPowerDeviceD2"; + case WdfPowerDeviceD3: + return "WdfPowerDeviceD3"; + case WdfPowerDeviceD3Final: + return "WdfPowerDeviceD3Final"; + case WdfPowerDevicePrepareForHibernation: + return "WdfPowerDevicePrepareForHibernation"; + case WdfPowerDeviceMaximum: + return "WdfPowerDeviceMaximum"; + default: + return "UnKnown Device Power State"; + } +} + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/driver.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/driver.c new file mode 100644 index 00000000..65b3cd3b --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/driver.c @@ -0,0 +1,292 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + Main module. + + This driver is for Open System Resources USB-FX2 Learning Kit designed + and built by OSR specifically for use in teaching software developers how to write + drivers for USB devices. + + The board supports a single configuration. The board automatically + detects the speed of the host controller, and supplies either the + high or full speed configuration based on the host controller's speed. + + The firmware supports 3 endpoints: + + Endpoint number 1 is used to indicate the state of the 8-switch + switch-pack on the OSR USB-FX2 board. A single byte representing + the switch state is sent (a) when the board is first started, + (b) when the board resumes after selective-suspend, + (c) whenever the state of the switches is changed. + + Endpoints 6 and 8 perform an internal loop-back function. + Data that is sent to the board at EP6 is returned to the host on EP8. + + For further information on the endpoints, please refer to the spec + http://www.osronline.com/hardware/OSRFX2_32.pdf. + + Vendor ID of the device is 0x4705 and Product ID is 0x210. + +Environment: + + Kernel mode only + +--*/ + +#include + +#if defined(EVENT_TRACING) +// +// The trace message header (.tmh) file must be included in a source file +// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS +// macro (defined in trace.h). During the compilation, WPP scans the source +// files for DoTraceMessage() calls and builds a .tmh file which stores a unique +// data GUID for each message, the text resource string for each message, +// and the data types of the variables passed in for each message. This file +// is automatically generated and used during post-processing. +// +#include "driver.tmh" +#else +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, OsrFxEvtDriverContextCleanup) +#endif + +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL or another NTSTATUS error code otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + UNICODE_STRING funcName; + + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OSRUSBFX2 Driver Sample - Driver Framework Edition.\n"); + + // + // IRP activity ID functions are available on some versions, save them into + // globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoGetActivityIdIrp"); + g_pIoGetActivityIdIrp = (PFN_IO_GET_ACTIVITY_ID_IRP) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // Register with ETW (unified tracing) + // + EventRegisterOSRUSBFX2(); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + OsrFxEvtDeviceAdd + ); + + // + // Register a cleanup callback so that we can call WPP_CLEANUP when + // the framework driver object is deleted during driver unload. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = OsrFxEvtDriverContextCleanup; + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + &attributes, // Driver Object Attributes + &config, // Driver Config Info + WDF_NO_HANDLE // hDriver + ); + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfDriverCreate failed with status 0x%x\n", status); + // + // Cleanup tracing here because DriverContextCleanup will not be called + // as we have failed to create WDFDRIVER object itself. + // Please note that if your return failure from DriverEntry after the + // WDFDRIVER object is created successfully, you don't have to + // call WPP cleanup because in those cases DriverContextCleanup + // will be executed when the framework deletes the DriverObject. + // + WPP_CLEANUP(DriverObject); + EventUnregisterOSRUSBFX2(); + } + + return status; +} + +VOID +OsrFxEvtDriverContextCleanup( + WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free resources allocated in DriverEntry that are not automatically + cleaned up by the framework. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + // + // EvtCleanupCallback for WDFDRIVER is always called at PASSIVE_LEVEL + // + _IRQL_limited_to_(PASSIVE_LEVEL); + + PAGED_CODE (); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "--> OsrFxEvtDriverContextCleanup\n"); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver )); + + UNREFERENCED_PARAMETER(Driver); // For the case when WPP is not being used. + + EventUnregisterOSRUSBFX2(); +} + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + DebugPrintLevel - print level between 0 and 3, with 3 the most verbose + DebugPrintFlag - message mask + DebugMessage - format string of the message to print + ... - values used by the format string + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!NT_SUCCESS(status)) { + + DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed 0x%x\n", status); + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { + DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/interrupt.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/interrupt.c new file mode 100644 index 00000000..00ea3550 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/interrupt.c @@ -0,0 +1,184 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Interrupt.c + +Abstract: + + This modules has routines configure a continuous reader on an + interrupt pipe to asynchronously read toggle switch states. + +Environment: + + Kernel mode + +--*/ + +#include + +#if defined(EVENT_TRACING) +#include "interrupt.tmh" +#endif + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ) +/*++ + +Routine Description: + + This routine configures a continuous reader on the + interrupt endpoint. It's called from the PrepareHarware event. + +Arguments: + + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; + NTSTATUS status; + + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, + OsrFxEvtUsbInterruptPipeReadComplete, + DeviceContext, // Context + sizeof(UCHAR)); // TransferLength + + contReaderConfig.EvtUsbTargetPipeReadersFailed = OsrFxEvtUsbInterruptReadersFailed; + + // + // Reader requests are not posted to the target automatically. + // Driver must explictly call WdfIoTargetStart to kick start the + // reader. In this sample, it's done in D0Entry. + // By defaut, framework queues two requests to the target + // endpoint. Driver can configure up to 10 requests with CONFIG macro. + // + status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe, + &contReaderConfig); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxConfigContReaderForInterruptEndPoint failed %x\n", + status); + return status; + } + + return status; +} + +VOID +OsrFxEvtUsbInterruptPipeReadComplete( + WDFUSBPIPE Pipe, + WDFMEMORY Buffer, + size_t NumBytesTransferred, + WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This the completion routine of the continour reader. This can + called concurrently on multiprocessor system if there are + more than one readers configured. So make sure to protect + access to global resources. + +Arguments: + + Buffer - This buffer is freed when this call returns. + If the driver wants to delay processing of the buffer, it + can take an additional referrence. + + Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro + +Return Value: + + NT status value + +--*/ +{ + PUCHAR switchState = NULL; + WDFDEVICE device; + PDEVICE_CONTEXT pDeviceContext = Context; + + UNREFERENCED_PARAMETER(Pipe); + + device = WdfObjectContextGetObject(pDeviceContext); + + // + // Make sure that there is data in the read packet. Depending on the device + // specification, it is possible for it to return a 0 length read in + // certain conditions. + // + + if (NumBytesTransferred == 0) { + TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete Zero length read " + "occured on the Interrupt Pipe's Continuous Reader\n" + ); + return; + } + + + NT_ASSERT(NumBytesTransferred == sizeof(UCHAR)); + + switchState = WdfMemoryGetBuffer(Buffer, NULL); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n", + *switchState); + + pDeviceContext->CurrentSwitchState = *switchState; + + // + // Handle any pending Interrupt Message IOCTLs. Note that the OSR USB device + // will generate an interrupt message when the the device resumes from a low + // power state. So if the Interrupt Message IOCTL was sent after the device + // has gone to a low power state, the pending Interrupt Message IOCTL will + // get completed in the function call below, before the user twiddles the + // dip switches on the OSR USB device. If this is not the desired behavior + // for your driver, then you could handle this condition by maintaining a + // state variable on D0Entry to track interrupt messages caused by power up. + // + OsrUsbIoctlGetInterruptMessage(device, STATUS_SUCCESS); + +} + +BOOLEAN +OsrFxEvtUsbInterruptReadersFailed( + _In_ WDFUSBPIPE Pipe, + _In_ NTSTATUS Status, + _In_ USBD_STATUS UsbdStatus + ) +{ + WDFDEVICE device = WdfIoTargetGetDevice(WdfUsbTargetPipeGetIoTarget(Pipe)); + PDEVICE_CONTEXT pDeviceContext = GetDeviceContext(device); + + UNREFERENCED_PARAMETER(UsbdStatus); + + // + // Clear the current switch state. + // + pDeviceContext->CurrentSwitchState = 0; + + // + // Service the pending interrupt switch change request + // + OsrUsbIoctlGetInterruptMessage(device, Status); + + return TRUE; +} + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/ioctl.c b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/ioctl.c new file mode 100644 index 00000000..2b0356bd --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/ioctl.c @@ -0,0 +1,1057 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Ioctl.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + +--*/ + +#include + +#if defined(EVENT_TRACING) +#include "ioctl.tmh" +#endif + +#pragma alloc_text(PAGE, OsrFxIoDeviceControl) +#pragma alloc_text(PAGE, ResetPipe) +#pragma alloc_text(PAGE, ResetDevice) +#pragma alloc_text(PAGE, ReenumerateDevice) +#pragma alloc_text(PAGE, GetBarGraphState) +#pragma alloc_text(PAGE, SetBarGraphState) +#pragma alloc_text(PAGE, GetSevenSegmentState) +#pragma alloc_text(PAGE, SetSevenSegmentState) +#pragma alloc_text(PAGE, GetSwitchState) + +// +// DMF: This callback is called by Dmf_IoctlHandler based on the CONIFG set by the Client driver +// earlier. When this callback runs, the IOCTL, input/output buffers have been validated. +// +NTSTATUS +OsrFxIoDeviceControl( + _In_ DMFMODULE DmfModule, + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG IoControlCode, + _In_reads_(InputBufferSize) VOID* InputBuffer, + _In_ size_t InputBufferSize, + _Out_writes_(OutputBufferSize) VOID* OutputBuffer, + _In_ size_t OutputBufferSize, + _Out_ size_t* BytesReturned + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. +Return Value: + + VOID + +--*/ +{ + WDFDEVICE device; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PBAR_GRAPH_STATE barGraphState = NULL; + PSWITCH_STATE switchState = NULL; + PUCHAR sevenSegment = NULL; + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(InputBufferSize); + UNREFERENCED_PARAMETER(OutputBufferSize); + + // + // If your driver is at the top of its driver stack, EvtIoDeviceControl is called + // at IRQL = PASSIVE_LEVEL. + // + _IRQL_limited_to_(PASSIVE_LEVEL); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n"); + // + // initialize variables + // + + // + // DMF: A frequent programming DMF programming pattern is that callbacks made by DMF Modules + // pass the corresponding DMFMODULE handle. From that handle, it is possible to get the + // Client driver's WDFDEVICE and device context. + // + device = DMF_ParentDeviceGet(DmfModule); + pDevContext = GetDeviceContext(device); + + switch(IoControlCode) { + + case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: { + + PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; + USHORT requiredSize = 0; + + // + // First get the size of the config descriptor + // + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + NULL, + &requiredSize); + + if (status != STATUS_BUFFER_TOO_SMALL) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + // + // Get the buffer - make sure the buffer is big enough + // + status = WdfRequestRetrieveOutputBuffer(Request, + (size_t)requiredSize, // MinimumRequired + &configurationDescriptor, + NULL); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); + break; + } + + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + configurationDescriptor, + &requiredSize); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + bytesReturned = requiredSize; + + } + break; + + case IOCTL_OSRUSBFX2_RESET_DEVICE: + + status = ResetDevice(device); + break; + + case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: + + // + // Otherwise, call our function to reenumerate the + // device + // + status = ReenumerateDevice(pDevContext); + + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: + + // + // DMF: Dmf_IoctlHandler has already retreived the buffer and validated its size. + // The buffer is usable now. + // + barGraphState = (BAR_GRAPH_STATE*)OutputBuffer; + + // + // Call our function to get the bar graph state + // + status = GetBarGraphState(pDevContext, barGraphState); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(BAR_GRAPH_STATE); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: + + // + // DMF: Dmf_IoctlHandler has already retreived the buffer and validated its size. + // The buffer is usable now. + // + barGraphState = (BAR_GRAPH_STATE*)InputBuffer; + + // + // Call our routine to set the bar graph state + // + status = SetBarGraphState(pDevContext, barGraphState); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: + + // + // DMF: Dmf_IoctlHandler has already retreived the buffer and validated its size. + // The buffer is usable now. + // + sevenSegment = (UCHAR*)OutputBuffer; + + // + // Call our function to get the 7 segment state + // + status = GetSevenSegmentState(pDevContext, sevenSegment); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(UCHAR); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: + + // + // DMF: Dmf_IoctlHandler has already retreived the buffer and validated its size. + // The buffer is usable now. + // + sevenSegment = (UCHAR*)InputBuffer; + + // + // Call our routine to set the 7 segment state + // + status = SetSevenSegmentState(pDevContext, sevenSegment); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_READ_SWITCHES: + + // + // DMF: Dmf_IoctlHandler has already retreived the buffer and validated its size. + // The buffer is usable now. + // + switchState = (SWITCH_STATE*)OutputBuffer; + + // + // Call our routine to get the state of the switches + // + status = GetSwitchState(pDevContext, switchState); + + // + // If successful, return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(SWITCH_STATE); + + } else { + // + // Don't return any data + // + bytesReturned = 0; + } + break; + + case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: + + // + // Forward the request to an interrupt message queue and dont complete + // the request until an interrupt from the USB device occurs. + // + status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue); + if (NT_SUCCESS(status)) { + // + // DMF: Dmf_IoctlHandler will complete all requests unless status == STATUS_PENDING. + // + status = STATUS_PENDING; + } + + break; + + // + // DMF: "default" will never happen because IOCTL codes have bee validated already. + // + } + + // + // DMF: Dmf_IoctlHandler will complete all requests unless status == STATUS_PENDING. + // + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n"); + + // + // DMF: Dmf_IoctlHandler will return this information with the request if it completes it. + // Local variable is not necessary, of course. It is left here to reduce changes. + // + *BytesReturned = bytesReturned; + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine resets the pipe. + +Arguments: + + Pipe - framework pipe handle + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // This routine synchronously submits a URB_FUNCTION_RESET_PIPE + // request down the stack. + // + status = WdfUsbTargetPipeResetSynchronously(Pipe, + WDF_NO_HANDLE, // WDFREQUEST + NULL // PWDF_REQUEST_SEND_OPTIONS + ); + + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "ResetPipe - success\n"); + status = STATUS_SUCCESS; + } + else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetPipe - failed\n"); + } + + return status; +} + +VOID +StopAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe), + WdfIoTargetCancelSentIo); +} + +NTSTATUS +StartAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still + connected. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> ResetDevice\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // A NULL timeout indicates an infinite wake + // + status = WdfWaitLockAcquire(pDeviceContext->ResetDeviceWaitLock, NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice - could not acquire lock\n"); + return status; + } + + StopAllPipes(pDeviceContext); + + status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->UsbDevice); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice failed - 0x%x\n", status); + } + + status = StartAllPipes(pDeviceContext); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Failed to start all pipes - 0x%x\n", status); + } + + WdfWaitLockRelease(pDeviceContext->ResetDeviceWaitLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- ResetDevice\n"); + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ) +/*++ + +Routine Description + + This routine re-enumerates the USB device. + +Arguments: + + pDevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + GUID activity; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_REENUMERATE, // Request + 0, // Value + 0); // Index + + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + NULL, // MemoryDescriptor + NULL); // BytesTransferred + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n"); + + // + // Send event to eventlog + // + + activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext)); + EventWriteDeviceReenumerated(&activity, + DevContext->DeviceName, + DevContext->Location, + status); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine gets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that receives the bar graph's state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + BarGraphState->BarsAsUChar = 0; + + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetBarGraphState: Failed to GetBarGraphState - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine sets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that describes the bar graph's desired state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetBarGraphState: Failed - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine gets the state of the 7 segment display on the board + by sending a synchronous control command. + + NOTE: It's not a good practice to send a synchronous request in the + context of the user thread because if the transfer takes long + time to complete, you end up holding the user thread. + + I'm choosing to do synchronous transfer because a) I know this one + completes immediately b) and for demonstration. + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - receives the state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Enter\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + *SevenSegment = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSevenSegmentState: Failed to get 7 Segment state - 0x%x \n", status); + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Exit\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine sets the state of the 7 segment display on the board + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - desired state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetSevenSegmentState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetSevenSegmentState: Failed to set 7 Segment state - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetSevenSegmentState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ) +/*++ + +Routine Description + + This routine gets the state of the switches on the board + +Arguments: + + DevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetSwitchState\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_SWITCHES, // Request + 0, // Value + 0); // Index + + SwitchState->SwitchesAsUChar = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SwitchState, + sizeof(SWITCH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSwitchState: Failed to Get switches - 0x%x \n", status); + + } else { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSwitchState: Switch mask is 0x%x\n", SwitchState->SwitchesAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetSwitchState\n"); + + return status; + +} + + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ) +/*++ + +Routine Description + + This method handles the completion of the pended request for the IOCTL + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE. + +Arguments: + + Device - Handle to a framework device. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + WDFREQUEST request; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PSWITCH_STATE switchState = NULL; + + pDevContext = GetDeviceContext(Device); + + do { + + // + // Check if there are any pending requests in the Interrupt Message Queue. + // If a request is found then complete the pending request. + // + status = WdfIoQueueRetrieveNextRequest(pDevContext->InterruptMsgQueue, &request); + + if (NT_SUCCESS(status)) { + status = WdfRequestRetrieveOutputBuffer(request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + + } else { + + // + // Copy the state information saved by the continuous reader. + // + if (NT_SUCCESS(ReaderStatus)) { + switchState->SwitchesAsUChar = pDevContext->CurrentSwitchState; + bytesReturned = sizeof(SWITCH_STATE); + } else { + bytesReturned = 0; + } + } + + // + // Complete the request. If we failed to get the output buffer then + // complete with that status. Otherwise complete with the status from the reader. + // + WdfRequestCompleteWithInformation(request, + NT_SUCCESS(status) ? ReaderStatus : status, + bytesReturned); + status = STATUS_SUCCESS; + + } else if (status != STATUS_NO_MORE_ENTRIES) { + KdPrint(("WdfIoQueueRetrieveNextRequest status %08x\n", status)); + } + + request = NULL; + + } while (status == STATUS_SUCCESS); + + return; + +} + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.h b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.h new file mode 100644 index 00000000..cf5b209f --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.h @@ -0,0 +1,328 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the driver. + +Environment: + + Kernel mode + +--*/ + +#include +#include +#include +#include "usbdi.h" +#include "usbdlib.h" +#include "public.h" +#include "driverspecs.h" +#include +#define NTSTRSAFE_LIB +#include + +#include "trace.h" + +// +// Include auto-generated ETW event functions (created by MC.EXE from +// osrusbfx2.man) +// +#include "fx2Events.h" + +#ifndef _PRIVATE_H +#define _PRIVATE_H + +#define POOL_TAG (ULONG) 'FRSO' +#define _DRIVER_NAME_ "OSRUSBFX2" + +#define TEST_BOARD_TRANSFER_BUFFER_SIZE (64*1024) +#define DEVICE_DESC_LENGTH 256 + +extern const __declspec(selectany) LONGLONG DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; + +// +// Define the vendor commands supported by our device +// +#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4 +#define USBFX2LK_READ_SWITCHES 0xD6 +#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7 +#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8 +#define USBFX2LK_IS_HIGH_SPEED 0xD9 +#define USBFX2LK_REENUMERATE 0xDA +#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB + +// +// Define the features that we can clear +// and set on our device +// +#define USBFX2LK_FEATURE_EPSTALL 0x00 +#define USBFX2LK_FEATURE_WAKE 0x01 + +// +// Order of endpoints in the interface descriptor +// +#define INTERRUPT_IN_ENDPOINT_INDEX 0 +#define BULK_OUT_ENDPOINT_INDEX 1 +#define BULK_IN_ENDPOINT_INDEX 2 + +// +// A structure representing the instance information associated with +// this particular device. +// + +typedef struct _DEVICE_CONTEXT { + + WDFUSBDEVICE UsbDevice; + + WDFUSBINTERFACE UsbInterface; + + WDFUSBPIPE BulkReadPipe; + + WDFUSBPIPE BulkWritePipe; + + WDFUSBPIPE InterruptPipe; + + WDFWAITLOCK ResetDeviceWaitLock; + + UCHAR CurrentSwitchState; + + WDFQUEUE InterruptMsgQueue; + + ULONG UsbDeviceTraits; + + // + // The following fields are used during event logging to + // report the events relative to this specific instance + // of the device. + // + + WDFMEMORY DeviceNameMemory; + PCWSTR DeviceName; + + WDFMEMORY LocationMemory; + PCWSTR Location; + + DMFMODULE DmfModuleIoctlHandler; +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) + +extern ULONG DebugLevel; + +typedef +NTSTATUS +(*PFN_IO_GET_ACTIVITY_ID_IRP) ( + _In_ PIRP Irp, + _Out_ LPGUID Guid + ); + +// +// Global function pointer set in DriverEntry +// Check for NULL before using +// +extern PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP OsrFxEvtDriverContextCleanup; + +EVT_WDF_DRIVER_DEVICE_ADD OsrFxEvtDeviceAdd; + +EVT_WDF_DEVICE_PREPARE_HARDWARE OsrFxEvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_READ OsrFxEvtIoRead; + +EVT_WDF_IO_QUEUE_IO_WRITE OsrFxEvtIoWrite; + +EVT_DMF_IoctlHandler_Callback OsrFxIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ); + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +EVT_WDF_USB_READER_COMPLETION_ROUTINE OsrFxEvtUsbInterruptPipeReadComplete; + +EVT_WDF_USB_READERS_FAILED OsrFxEvtUsbInterruptReadersFailed; + +EVT_WDF_IO_QUEUE_IO_STOP OsrFxEvtIoStop; + +EVT_WDF_DEVICE_D0_ENTRY OsrFxEvtDeviceD0Entry; + +EVT_WDF_DEVICE_D0_EXIT OsrFxEvtDeviceD0Exit; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH OsrFxEvtDeviceSelfManagedIoFlush; + +// +// DMF: This is the callback function called by DMF that allows this driver (the Client Driver) +// to set the CONFIG for each DMF Module the driver will use. +// +EVT_DMF_DEVICE_MODULES_ADD OsrDmfModulesAdd; + +_IRQL_requires_(PASSIVE_LEVEL) +BOOLEAN +OsrFxReadFdoRegistryKeyValue( + _In_ PWDFDEVICE_INIT DeviceInit, + _In_ PWCHAR Name, + _Out_ PULONG Value + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +OsrFxEnumerateChildren( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ); + + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ); + +FORCEINLINE +GUID +RequestToActivityId( + _In_ WDFREQUEST Request + ) +{ + GUID activity = {0}; + NTSTATUS status = STATUS_SUCCESS; + + if (g_pIoGetActivityIdIrp != NULL) { + + // + // Use activity ID generated by application (or IO manager) + // + status = g_pIoGetActivityIdIrp(WdfRequestWdmGetIrp(Request), &activity); + } + + if (g_pIoGetActivityIdIrp == NULL || !NT_SUCCESS(status)) { + + // + // Fall back to using the WDFREQUEST handle as the activity ID + // + RtlCopyMemory(&activity, &Request, sizeof(WDFREQUEST)); + } + + + return activity; +} + +FORCEINLINE +GUID +DeviceToActivityId( + _In_ WDFDEVICE Device + ) +{ + GUID activity = {0}; + RtlCopyMemory(&activity, &Device, sizeof(WDFDEVICE)); + return activity; +} + + +#endif + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.man b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.man new file mode 100644 index 00000000..176dfc89 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.man @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.rc b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.rc new file mode 100644 index 00000000..092ec195 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2.rc @@ -0,0 +1,18 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDF Sample Driver for OSR USB-FX2 Learning Kit" +#define VER_INTERNALNAME_STR "osrusbfx2.sys" +#define VER_ORIGINALFILENAME_STR "osrusbfx2.sys" + +#include "common.ver" + +// +// Include auto-generated string resources (created by MC.EXE from +// osrusbfx2.man) +// + +#include "fx2Events.rc" diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.inx b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.inx new file mode 100644 index 00000000..63d5d42a Binary files /dev/null and b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.inx differ diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.vcxproj b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.vcxproj new file mode 100644 index 00000000..aa9a9341 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.vcxproj @@ -0,0 +1,252 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {E67FD967-2406-4673-9BDC-2A5F5176CB87} + $(MSBuildProjectName) + 1 + false + true + Debug + Win32 + {3EBA8CBF-2E65-4819-9EEA-E10825BB0705} + osrusbfx2dmf2 + $(LatestTargetPlatformVersion) + + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + False + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + Windows10 + True + Desktop + KMDF + WindowsKernelModeDriver10.0 + Driver + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + true + true + .\$(IntDir) + true + .\$(IntDir) + true + fx2Events + true + + + true + true + TraceEvents(LEVEL,FLAGS,MSG,...) + {km-WdfDefault.tpl}*.tmh + + + + osrusbfx2dmf2 + + + osrusbfx2dmf2 + + + osrusbfx2dmf2 + + + osrusbfx2dmf2 + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Release\x64\lib\\DmfK\DmfK.lib + + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Debug\x64\lib\DmfK\DmfK.lib + + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Release\Win32\lib\\DmfK\DmfK.lib + + + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;.;..\..\..\DMF\Modules.Library + true + Level4 + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalIncludeDirectories);..\inc;. + %(PreprocessorDefinitions);EVENT_TRACING + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;..\..\..\Debug\Win32\lib\DmfK\DmfK.lib + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.vcxproj.Filters b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.vcxproj.Filters new file mode 100644 index 00000000..b960649f --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/osrusbfx2dmf2.vcxproj.Filters @@ -0,0 +1,89 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {F859293F-10B7-4E6D-99E2-120A09448FF9} + + + h;hpp;hxx;hm;inl;inc;xsd + {3DCE0FEA-C37D-448E-B9E4-B69865E71B5F} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {A1BB449A-54EF-4B2B-BD68-2254963FF387} + + + inf;inv;inx;mof;mc; + {A03D3DFA-E9BD-48A3-BEDE-E8AAED283D03} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Driver Files + + + \ No newline at end of file diff --git a/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/trace.h b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/trace.h new file mode 100644 index 00000000..518ff5f1 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/driver_dmf_2/trace.h @@ -0,0 +1,115 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TRACE.h + +Abstract: + + Header file for the debug tracing related function defintions and macros. + +Environment: + + Kernel mode + +--*/ + +#include // For TRACE_LEVEL definitions + +#if !defined(EVENT_TRACING) + +// +// TODO: These defines are missing in evntrace.h +// in some DDK build environments (XP). +// +#if !defined(TRACE_LEVEL_NONE) + #define TRACE_LEVEL_NONE 0 + #define TRACE_LEVEL_CRITICAL 1 + #define TRACE_LEVEL_FATAL 1 + #define TRACE_LEVEL_ERROR 2 + #define TRACE_LEVEL_WARNING 3 + #define TRACE_LEVEL_INFORMATION 4 + #define TRACE_LEVEL_VERBOSE 5 + #define TRACE_LEVEL_RESERVED6 6 + #define TRACE_LEVEL_RESERVED7 7 + #define TRACE_LEVEL_RESERVED8 8 + #define TRACE_LEVEL_RESERVED9 9 +#endif + + +// +// Define Debug Flags +// +#define DBG_INIT 0x00000001 +#define DBG_PNP 0x00000002 +#define DBG_POWER 0x00000004 +#define DBG_WMI 0x00000008 +#define DBG_CREATE_CLOSE 0x00000010 +#define DBG_IOCTL 0x00000020 +#define DBG_WRITE 0x00000040 +#define DBG_READ 0x00000080 + + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ); + +#define WPP_INIT_TRACING(DriverObject, RegistryPath) +#define WPP_CLEANUP(DriverObject) + +#else +// +// If software tracing is defined in the sources file.. +// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. +// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** +// WPP_DEFINE_BIT allows setting debug bit masks to selectively print. +// The names defined in the WPP_DEFINE_BIT call define the actual names +// that are used to control the level of tracing for the control guid +// specified. +// +// NOTE: If you are adopting this sample for your driver, please generate +// a new guid, using tools\other\i386\guidgen.exe present in the +// DDK. +// +// Name of the logger is OSRUSBFX2 and the guid is +// {D23A0C5A-D307-4f0e-AE8E-E2A355AD5DAB} +// (0xd23a0c5a, 0xd307, 0x4f0e, 0xae, 0x8e, 0xe2, 0xa3, 0x55, 0xad, 0x5d, 0xab); +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ + WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + /* You can have up to 32 defines. If you want more than that,\ + you have to provide another trace control GUID */\ + ) + + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + + +#endif + + + diff --git a/DmfSamples/kmdf_fx2_dmf/exe/dump.c b/DmfSamples/kmdf_fx2_dmf/exe/dump.c new file mode 100644 index 00000000..69074bf1 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/exe/dump.c @@ -0,0 +1,444 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + DUMP.C + +Abstract: + + Routines to dump the descriptors information in a human readable form. + +Environment: + + user mode only + +--*/ + +#include +#include +#include +#include "devioctl.h" + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include +#include "usbdi.h" +#include "public.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +HANDLE +OpenDevice( + _In_ BOOL Synchronous + ); + + +char* +usbDescriptorTypeString(UCHAR bDescriptorType ) +/*++ +Routine Description: + + Called to get ascii string of USB descriptor + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bDescriptorType or + PUSB_DEVICE_DESCRIPTOR->bDescriptorType or + PUSB_INTERFACE_DESCRIPTOR->bDescriptorType or + PUSB_STRING_DESCRIPTOR->bDescriptorType or + PUSB_POWER_DESCRIPTOR->bDescriptorType or + PUSB_CONFIGURATION_DESCRIPTOR->bDescriptorType + +Return Value: + + ptr to string + +--*/ +{ + + switch(bDescriptorType) { + + case USB_DEVICE_DESCRIPTOR_TYPE: + return "USB_DEVICE_DESCRIPTOR_TYPE"; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + return "USB_CONFIGURATION_DESCRIPTOR_TYPE"; + + + case USB_STRING_DESCRIPTOR_TYPE: + return "USB_STRING_DESCRIPTOR_TYPE"; + + + case USB_INTERFACE_DESCRIPTOR_TYPE: + return "USB_INTERFACE_DESCRIPTOR_TYPE"; + + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + return "USB_ENDPOINT_DESCRIPTOR_TYPE"; + + +#ifdef USB_POWER_DESCRIPTOR_TYPE // this is the older definintion which is actually obsolete + // workaround for temporary bug in 98ddk, older USB100.h file + case USB_POWER_DESCRIPTOR_TYPE: + return "USB_POWER_DESCRIPTOR_TYPE"; +#endif + +#ifdef USB_RESERVED_DESCRIPTOR_TYPE // this is the current version of USB100.h as in NT5DDK + + case USB_RESERVED_DESCRIPTOR_TYPE: + return "USB_RESERVED_DESCRIPTOR_TYPE"; + + case USB_CONFIG_POWER_DESCRIPTOR_TYPE: + return "USB_CONFIG_POWER_DESCRIPTOR_TYPE"; + + case USB_INTERFACE_POWER_DESCRIPTOR_TYPE: + return "USB_INTERFACE_POWER_DESCRIPTOR_TYPE"; +#endif // for current nt5ddk version of USB100.h + + default: + return "??? UNKNOWN!!"; + } +} + + +char * +usbEndPointTypeString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of endpt descriptor type + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_ENDPOINT_TYPE_MASK; + + + switch( typ) { + case USB_ENDPOINT_TYPE_INTERRUPT: + return "USB_ENDPOINT_TYPE_INTERRUPT"; + + case USB_ENDPOINT_TYPE_BULK: + return "USB_ENDPOINT_TYPE_BULK"; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + return "USB_ENDPOINT_TYPE_ISOCHRONOUS"; + + case USB_ENDPOINT_TYPE_CONTROL: + return "USB_ENDPOINT_TYPE_CONTROL"; + + default: + return "??? UNKNOWN!!"; + } +} + + +char * +usbConfigAttributesString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of USB_CONFIGURATION_DESCRIPTOR attributes + +Arguments: + + PUSB_CONFIGURATION_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_CONFIG_POWERED_MASK; + + + switch( typ) { + + case USB_CONFIG_BUS_POWERED: + return "USB_CONFIG_BUS_POWERED"; + + case USB_CONFIG_SELF_POWERED: + return "USB_CONFIG_SELF_POWERED"; + + case USB_CONFIG_REMOTE_WAKEUP: + return "USB_CONFIG_REMOTE_WAKEUP"; + + + default: + return "??? UNKNOWN!!"; + } +} + + +void +print_USB_CONFIGURATION_DESCRIPTOR(PUSB_CONFIGURATION_DESCRIPTOR cd) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB config descriptor + +Arguments: + + ptr to USB configuration descriptor + +Return Value: + + none + +--*/ +{ + printf("\n===================\nUSB_CONFIGURATION_DESCRIPTOR\n"); + + printf( + "bLength = 0x%x, decimal %d\n", cd->bLength, cd->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", cd->bDescriptorType, + usbDescriptorTypeString( cd->bDescriptorType ) + ); + + printf( + "wTotalLength = 0x%x, decimal %d\n", cd->wTotalLength, cd->wTotalLength + ); + + printf( + "bNumInterfaces = 0x%x, decimal %d\n", cd->bNumInterfaces, cd->bNumInterfaces + ); + + printf( + "bConfigurationValue = 0x%x, decimal %d\n", + cd->bConfigurationValue, cd->bConfigurationValue + ); + + printf( + "iConfiguration = 0x%x, decimal %d\n", cd->iConfiguration, cd->iConfiguration + ); + + printf( + "bmAttributes = 0x%x ( %s )\n", cd->bmAttributes, + usbConfigAttributesString( cd->bmAttributes ) + ); + + printf( + "MaxPower = 0x%x, decimal %d\n", cd->MaxPower, cd->MaxPower + ); +} + + +void +print_USB_INTERFACE_DESCRIPTOR(PUSB_INTERFACE_DESCRIPTOR id, UINT ix) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB interface descriptor + +Arguments: + + ptr to USB interface descriptor + +Return Value: + + none + +--*/ +{ + printf("\n-----------------------------\nUSB_INTERFACE_DESCRIPTOR #%d\n", ix); + + + printf( + "bLength = 0x%x\n", id->bLength + ); + + + printf( + "bDescriptorType = 0x%x ( %s )\n", id->bDescriptorType, + usbDescriptorTypeString( id->bDescriptorType ) + ); + + + printf( + "bInterfaceNumber = 0x%x\n", id->bInterfaceNumber + ); + printf( + "bAlternateSetting = 0x%x\n", id->bAlternateSetting + ); + printf( + "bNumEndpoints = 0x%x\n", id->bNumEndpoints + ); + printf( + "bInterfaceClass = 0x%x\n", id->bInterfaceClass + ); + printf( + "bInterfaceSubClass = 0x%x\n", id->bInterfaceSubClass + ); + printf( + "bInterfaceProtocol = 0x%x\n", id->bInterfaceProtocol + ); + printf( + "bInterface = 0x%x\n", id->iInterface + ); +} + + +void +print_USB_ENDPOINT_DESCRIPTOR(PUSB_ENDPOINT_DESCRIPTOR ed, int i) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB endpoint descriptor + +Arguments: + + ptr to USB endpoint descriptor, + index of this endpt in interface desc + +Return Value: + + none + +--*/ +{ + printf( + "------------------------------\nUSB_ENDPOINT_DESCRIPTOR for Pipe%02d\n", i + ); + + printf( + "bLength = 0x%x\n", ed->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", ed->bDescriptorType, + usbDescriptorTypeString( ed->bDescriptorType ) + ); + + if ( USB_ENDPOINT_DIRECTION_IN( ed->bEndpointAddress ) ) { + printf( + "bEndpointAddress= 0x%x ( INPUT )\n", ed->bEndpointAddress + ); + } else { + printf( + "bEndpointAddress= 0x%x ( OUTPUT )\n", ed->bEndpointAddress + ); + } + + printf( + "bmAttributes= 0x%x ( %s )\n", ed->bmAttributes, + usbEndPointTypeString ( ed->bmAttributes ) + ); + + printf( + "wMaxPacketSize= 0x%x, decimal %d\n", ed->wMaxPacketSize, + ed->wMaxPacketSize + ); + + printf( + "bInterval = 0x%x, decimal %d\n", ed->bInterval, ed->bInterval + ); +} + + +BOOL +DumpUsbConfig() +/*++ +Routine Description: + + Called to do formatted ascii dump to console of USB + configuration, interface, and endpoint descriptors. + +Arguments: + + none + +Return Value: + + TRUE or FALSE + +--*/ +{ + HANDLE hDev; + UINT success; + int siz, nBytes; + char buf[256] = {'\0'}; + + hDev = OpenDevice(TRUE); + if(hDev == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + siz = sizeof(buf); + + success = DeviceIoControl(hDev, + IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR, + buf, + siz, + buf, + siz, + (PULONG) &nBytes, + NULL); + + if(success == FALSE) { + printf("Ioct - GetConfigDesc failed %d\n", GetLastError()); + } else { + + ULONG i; + UINT j, n; + char *pch; + PUSB_CONFIGURATION_DESCRIPTOR cd; + PUSB_INTERFACE_DESCRIPTOR id; + PUSB_ENDPOINT_DESCRIPTOR ed; + + pch = buf; + n = 0; + + cd = (PUSB_CONFIGURATION_DESCRIPTOR) pch; + + print_USB_CONFIGURATION_DESCRIPTOR( cd ); + + pch += cd->bLength; + + do { + id = (PUSB_INTERFACE_DESCRIPTOR) pch; + + print_USB_INTERFACE_DESCRIPTOR(id, n++); + + pch += id->bLength; + for (j=0; jbNumEndpoints; j++) { + + ed = (PUSB_ENDPOINT_DESCRIPTOR) pch; + + print_USB_ENDPOINT_DESCRIPTOR(ed,j); + + pch += ed->bLength; + } + i = (ULONG)(pch - buf); + + } while (iwTotalLength); + } + + CloseHandle(hDev); + + return success; + +} + diff --git a/DmfSamples/kmdf_fx2_dmf/exe/osrusbfx2.vcxproj b/DmfSamples/kmdf_fx2_dmf/exe/osrusbfx2.vcxproj new file mode 100644 index 00000000..9da8f04b --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/exe/osrusbfx2.vcxproj @@ -0,0 +1,192 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6EED5CDD-5526-40DC-97F9-582857E10187} + $(MSBuildProjectName) + Debug + Win32 + {F19E45AF-8B05-4204-A66B-9BDBFE333233} + + + + Windows10 + False + Universal + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Universal + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + False + Universal + + WindowsApplicationForDrivers10.0 + Application + + + Windows10 + True + Universal + + WindowsApplicationForDrivers10.0 + Application + + + + $(IntDir) + + + + + + + + + + + + + + + + osrusbfx2 + + + osrusbfx2 + + + osrusbfx2 + + + osrusbfx2 + + + + true + Level4 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalDependencies);mincore.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalDependencies);mincore.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalDependencies);mincore.lib + + + + + true + Level4 + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc + %(PreprocessorDefinitions);UNICODE;_UNICODE + + + %(AdditionalDependencies);mincore.lib + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DmfSamples/kmdf_fx2_dmf/exe/osrusbfx2.vcxproj.Filters b/DmfSamples/kmdf_fx2_dmf/exe/osrusbfx2.vcxproj.Filters new file mode 100644 index 00000000..f9efc3e3 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/exe/osrusbfx2.vcxproj.Filters @@ -0,0 +1,30 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {D5BFAD22-1AD2-44F8-AC33-05C04A9C26D9} + + + h;hpp;hxx;hm;inl;inc;xsd + {14E678C7-EAC3-42F6-9F4B-2CDD17427D73} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {CEE0A75C-90B6-472A-8FC1-9375F1EAD2C9} + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/DmfSamples/kmdf_fx2_dmf/exe/test.cmd b/DmfSamples/kmdf_fx2_dmf/exe/test.cmd new file mode 100644 index 00000000..30b18b85 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/exe/test.cmd @@ -0,0 +1,6 @@ +FOR /L %%i IN (0,1,100000) do ( + + osrusbfx2.exe -r 512 -w 512 -c 1000000 -v + +) + diff --git a/DmfSamples/kmdf_fx2_dmf/exe/testapp.c b/DmfSamples/kmdf_fx2_dmf/exe/testapp.c new file mode 100644 index 00000000..43b6c7a2 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/exe/testapp.c @@ -0,0 +1,1213 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TESTAPP.C + +Abstract: + + Console test app for osrusbfx2 driver. + +Environment: + + user mode only + +--*/ + + +#include +_Analysis_mode_(_Analysis_code_type_user_code_) + +#include +#include +#include +#include + +#include "devioctl.h" +#include "strsafe.h" + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include +#include +#include "usbdi.h" +#include "public.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +#define WHILE(a) \ +while(__pragma(warning(disable:4127)) a __pragma(warning(disable:4127))) + +#define MAX_DEVPATH_LENGTH 256 +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE 1024 +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +BOOL G_fDumpUsbConfig = FALSE; // flags set in response to console command line switches +BOOL G_fDumpReadData = FALSE; +BOOL G_fRead = FALSE; +BOOL G_fWrite = FALSE; +BOOL G_fPlayWithDevice = FALSE; +BOOL G_fPerformAsyncIo = FALSE; +ULONG G_IterationCount = 1; //count of iterations of the test we are to perform +ULONG G_WriteLen = 512; // #bytes to write +ULONG G_ReadLen = 512; // #bytes to read + +BOOL +DumpUsbConfig( // defined in dump.c + ); + +typedef enum _INPUT_FUNCTION { + LIGHT_ONE_BAR = 1, + CLEAR_ONE_BAR, + LIGHT_ALL_BARS, + CLEAR_ALL_BARS, + GET_BAR_GRAPH_LIGHT_STATE, + GET_SWITCH_STATE, + GET_SWITCH_STATE_AS_INTERRUPT_MESSAGE, + GET_7_SEGEMENT_STATE, + SET_7_SEGEMENT_STATE, + RESET_DEVICE, + REENUMERATE_DEVICE, +} INPUT_FUNCTION; + +_Success_(return) +BOOL +GetDevicePath( + _In_ LPGUID InterfaceGuid, + _Out_writes_z_(BufLen) PWCHAR DevicePath, + _In_ size_t BufLen + ) +{ + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; + } + + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; + } + + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + bRet = FALSE; + printf("Error allocating memory for device interface list.\n"); + goto clean0; + } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); + + cr = CM_Get_Device_Interface_List( + InterfaceGuid, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; + } + + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); + } + + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) { + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; + } + +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } + + return bRet; +} + + +_Check_return_ +_Ret_notnull_ +_Success_(return != INVALID_HANDLE_VALUE) +HANDLE +OpenDevice( + _In_ BOOL Synchronous + ) + +/*++ +Routine Description: + + Called by main() to open an instance of our device after obtaining its name + +Arguments: + + Synchronous - TRUE, if Device is to be opened for synchronous access. + FALSE, otherwise. + +Return Value: + + Device handle on success else INVALID_HANDLE_VALUE + +--*/ + +{ + HANDLE hDev; + WCHAR completeDeviceName[MAX_DEVPATH_LENGTH]; + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + completeDeviceName, + sizeof(completeDeviceName)/sizeof(completeDeviceName[0])) ) + { + return INVALID_HANDLE_VALUE; + } + + printf("DeviceName = (%S)\n", completeDeviceName); + + if(Synchronous) { + hDev = CreateFile(completeDeviceName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, // default security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + } else { + + hDev = CreateFile(completeDeviceName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, // default security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + } + + if (hDev == INVALID_HANDLE_VALUE) { + printf("Failed to open the device, error - %d", GetLastError()); + } else { + printf("Opened the device successfully.\n"); + } + + return hDev; +} + + + +VOID +Usage() + +/*++ +Routine Description: + + Called by main() to dump usage info to the console when + the app is called with no parms or with an invalid parm + +Arguments: + + None + +Return Value: + + None + +--*/ + +{ + printf("Usage for osrusbfx2 testapp:\n"); + printf("-r [n] where n is number of bytes to read\n"); + printf("-w [n] where n is number of bytes to write\n"); + printf("-c [n] where n is number of iterations (default = 1)\n"); + printf("-v verbose -- dumps read data\n"); + printf("-p to control bar LEDs, seven segment, and dip switch\n"); + printf("-a to perform asynchronous I/O\n"); + printf("-u to dump USB configuration and pipe info \n"); + + return; +} + + +void +Parse( + _In_ int argc, + _In_reads_(argc) LPSTR *argv + ) + +/*++ +Routine Description: + + Called by main() to parse command line parms + +Arguments: + + argc and argv that was passed to main() + +Return Value: + + Sets global flags as per user function request + +--*/ + +{ + int i; + + if ( argc < 2 ) // give usage if invoked with no parms + Usage(); + + for (i=0; i= argc) { + Usage(); + exit(1); + } + else { +#pragma warning(suppress: 6385) + G_ReadLen = atoi(&argv[i+1][0]); + G_fRead = TRUE; + } + i++; + break; + case 'w': + case 'W': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_WriteLen = atoi(&argv[i+1][0]); + G_fWrite = TRUE; + } + i++; + break; + case 'c': + case 'C': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_IterationCount = atoi(&argv[i+1][0]); + } + i++; + break; + case 'u': + case 'U': + G_fDumpUsbConfig = TRUE; + break; + case 'p': + case 'P': + G_fPlayWithDevice = TRUE; + break; + case 'a': + case 'A': + G_fPerformAsyncIo = TRUE; + break; + case 'v': + case 'V': + G_fDumpReadData = TRUE; + break; + default: + Usage(); + } + } + } +} + +BOOL +Compare_Buffs( + _In_reads_bytes_(buff1length) char *buff1, + _In_ ULONG buff1length, + _In_reads_bytes_(buff2length) char *buff2, + _In_ ULONG buff2length + ) +/*++ +Routine Description: + + Called to verify read and write buffers match for loopback test + +Arguments: + + buffers to compare and length + +Return Value: + + TRUE if buffers match, else FALSE + +--*/ +{ + int ok = 1; + + if (buff1length != buff2length || memcmp(buff1, buff2, buff1length )) { + // Edi, and Esi point to the mismatching char and ecx indicates the + // remaining length. + ok = 0; + } + + return ok; +} + +#define NPERLN 8 + +VOID +Dump( + UCHAR *b, + int len +) + +/*++ +Routine Description: + + Called to do formatted ascii dump to console of the io buffer + +Arguments: + + buffer and length + +Return Value: + + none + +--*/ + +{ + ULONG i; + ULONG longLen = (ULONG)len / sizeof( ULONG ); + PULONG pBuf = (PULONG) b; + + // dump an ordinal ULONG for each sizeof(ULONG)'th byte + printf("\n****** BEGIN DUMP LEN decimal %d, 0x%x\n", len,len); + for (i=0; i 8){ + printf("Invalid bar number!\n"); + goto Error; + } + + bar--; // normalize to 0 to 7 + + barGraphState.BarsAsUChar = 1 << (UCHAR)bar; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case CLEAR_ONE_BAR: + + + printf("Which Bar (input number 1 thru 8)?\n"); + if (scanf_s ("%d", &bar) <= 0) { + + printf("Error reading input!\n"); + goto Error; + + } + + if(bar == 0 || bar > 8){ + printf("Invalid bar number!\n"); + goto Error; + } + + bar--; + + // + // Read the current state + // + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &barGraphState, // Ptr to OutBuffer + sizeof(BAR_GRAPH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + if (barGraphState.BarsAsUChar & (1 << bar)) { + + printf("Bar is set...Clearing it\n"); + barGraphState.BarsAsUChar &= ~(1 << bar); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + + } + + } else { + + printf("Bar not set.\n"); + + } + + break; + + case LIGHT_ALL_BARS: + + barGraphState.BarsAsUChar = 0xFF; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case CLEAR_ALL_BARS: + + barGraphState.BarsAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + + case GET_BAR_GRAPH_LIGHT_STATE: + + barGraphState.BarsAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &barGraphState, // Ptr to OutBuffer + sizeof(BAR_GRAPH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("Bar Graph: \n"); + printf(" Bar8 is %s\n", barGraphState.Bar8 ? "ON" : "OFF"); + printf(" Bar7 is %s\n", barGraphState.Bar7 ? "ON" : "OFF"); + printf(" Bar6 is %s\n", barGraphState.Bar6 ? "ON" : "OFF"); + printf(" Bar5 is %s\n", barGraphState.Bar5 ? "ON" : "OFF"); + printf(" Bar4 is %s\n", barGraphState.Bar4 ? "ON" : "OFF"); + printf(" Bar3 is %s\n", barGraphState.Bar3 ? "ON" : "OFF"); + printf(" Bar2 is %s\n", barGraphState.Bar2 ? "ON" : "OFF"); + printf(" Bar1 is %s\n", barGraphState.Bar1 ? "ON" : "OFF"); + + break; + + case GET_SWITCH_STATE: + + switchState.SwitchesAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_READ_SWITCHES, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &switchState, // Ptr to OutBuffer + sizeof(SWITCH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("Switches: \n"); + printf(" Switch8 is %s\n", switchState.Switch8 ? "ON" : "OFF"); + printf(" Switch7 is %s\n", switchState.Switch7 ? "ON" : "OFF"); + printf(" Switch6 is %s\n", switchState.Switch6 ? "ON" : "OFF"); + printf(" Switch5 is %s\n", switchState.Switch5 ? "ON" : "OFF"); + printf(" Switch4 is %s\n", switchState.Switch4 ? "ON" : "OFF"); + printf(" Switch3 is %s\n", switchState.Switch3 ? "ON" : "OFF"); + printf(" Switch2 is %s\n", switchState.Switch2 ? "ON" : "OFF"); + printf(" Switch1 is %s\n", switchState.Switch1 ? "ON" : "OFF"); + + break; + + case GET_SWITCH_STATE_AS_INTERRUPT_MESSAGE: + + switchState.SwitchesAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &switchState, // Ptr to OutBuffer + sizeof(switchState), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("Switches: %d\n",index); + printf(" Switch8 is %s\n", switchState.Switch8 ? "ON" : "OFF"); + printf(" Switch7 is %s\n", switchState.Switch7 ? "ON" : "OFF"); + printf(" Switch6 is %s\n", switchState.Switch6 ? "ON" : "OFF"); + printf(" Switch5 is %s\n", switchState.Switch5 ? "ON" : "OFF"); + printf(" Switch4 is %s\n", switchState.Switch4 ? "ON" : "OFF"); + printf(" Switch3 is %s\n", switchState.Switch3 ? "ON" : "OFF"); + printf(" Switch2 is %s\n", switchState.Switch2 ? "ON" : "OFF"); + printf(" Switch1 is %s\n", switchState.Switch1 ? "ON" : "OFF"); + + break; + + case GET_7_SEGEMENT_STATE: + + sevenSegment = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &sevenSegment, // Ptr to OutBuffer + sizeof(UCHAR), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("7 Segment mask: 0x%x\n", sevenSegment); + break; + + case SET_7_SEGEMENT_STATE: + + for (i = 0; i < 8; i++) { + + sevenSegment = 1 << i; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY, + &sevenSegment, // Ptr to InBuffer + sizeof(UCHAR), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("This is %d\n", i); + Sleep(500); + + } + + printf("7 Segment mask: 0x%x\n", sevenSegment); + break; + + case RESET_DEVICE: + + printf("Reset the device\n"); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_RESET_DEVICE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + NULL)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case REENUMERATE_DEVICE: + + printf("Re-enumerate the device\n"); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_REENUMERATE_DEVICE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + NULL)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + // + // Close the handle to the device and exit out so that + // the driver can unload when the device is surprise-removed + // and reenumerated. + // + default: + + result = TRUE; + goto Error; + + } + + } // end of while loop + +Error: + + CloseHandle(deviceHandle); + return result; + +} + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG error; + + hDevice = OpenDevice(FALSE); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open device %d\n", GetLastError()); + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + goto Error; + } + + pOvList = (OVERLAPPED *)malloc(NUM_ASYNCH_IO * sizeof(OVERLAPPED)); + + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + goto Error; + } + + buf = (PUCHAR)malloc(NUM_ASYNCH_IO * BUFFER_SIZE); + + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + goto Error; + } + + ZeroMemory(pOvList, NUM_ASYNCH_IO * sizeof(OVERLAPPED)); + ZeroMemory(buf, NUM_ASYNCH_IO * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < NUM_ASYNCH_IO; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %Iu th read failed %d \n",i, GetLastError()); + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %Iu th write failed %d \n",i, GetLastError()); + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + OVERLAPPED *completedOv; + ULONG_PTR key; + ULONG numberOfBytesTransferred; + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, + &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + goto Error; + } + + // + // Read successfully completed. Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + + printf("Number of bytes read by request number %Iu is %d\n", + i, numberOfBytesTransferred); + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%Iu th Read failed %d \n", i, GetLastError()); + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %Iu is %d\n", + i, numberOfBytesTransferred); + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%Iu th write failed %d \n", i, GetLastError()); + goto Error; + } + } + } + } + +Error: + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if (hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if (pOvList) { + free(pOvList); + } + if (buf) { + free(buf); + } + + return 1; + +} + + +int +_cdecl +main( + _In_ int argc, + _In_reads_(argc) LPSTR *argv + ) +/*++ +Routine Description: + + Entry point to rwbulk.exe + Parses cmdline, performs user-requested tests + +Arguments: + + argc, argv standard console 'c' app arguments + +Return Value: + + Zero + +--*/ + +{ + char * pinBuf = NULL; + char * poutBuf = NULL; + ULONG nBytesRead; + ULONG nBytesWrite = 0; + int ok; + int retValue = 0; + UINT success; + HANDLE hRead = INVALID_HANDLE_VALUE; + HANDLE hWrite = INVALID_HANDLE_VALUE; + ULONG fail = 0L; + ULONG i; + + + Parse(argc, argv ); + + // + // dump USB configuation and pipe info + // + if (G_fDumpUsbConfig) { + DumpUsbConfig(); + } + + if (G_fPlayWithDevice) { + PlayWithDevice(); + goto exit; + } + + if (G_fPerformAsyncIo) { + HANDLE th1; + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + retValue = 1; + goto exit; + } + + // + // Use this thread for peforming write. + // + AsyncIo((PVOID)WRITER_TYPE); + + goto exit; + } + + // + // doing a read, write, or both test + // + if ((G_fRead) || (G_fWrite)) { + + if (G_fRead) { + if ( G_fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( G_ReadLen % sizeof( ULONG ) ) { + G_ReadLen++; + } + } + + // + // open the output file + // + hRead = OpenDevice(TRUE); + if(hRead == INVALID_HANDLE_VALUE) { + retValue = 1; + goto exit; + } + + pinBuf = malloc(G_ReadLen); + } + + if (G_fWrite) { + if ( G_fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( G_WriteLen % sizeof( ULONG ) ) { + G_WriteLen++; + } + } + + // + // open the output file + // + hWrite = OpenDevice(TRUE); + if(hWrite == INVALID_HANDLE_VALUE) { + retValue = 1; + goto exit; + } + + poutBuf = malloc(G_WriteLen); + } + + for (i = 0; i < G_IterationCount; i++) { + ULONG j; + + if (G_fWrite && poutBuf && hWrite != INVALID_HANDLE_VALUE) { + + PULONG pOut = (PULONG) poutBuf; + ULONG numLongs = G_WriteLen / sizeof( ULONG ); + + // + // put some data in the output buffer + // + for (j=0; j + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "OSRUSBFX2 Bulk & Isoch Read and Write test App" +#define VER_INTERNALNAME_STR "osrusbfx2.exe" +#define VER_ORIGINALFILENAME_STR "osrusbfx2.exe" + +#include + diff --git a/DmfSamples/kmdf_fx2_dmf/inc/prototypes.h b/DmfSamples/kmdf_fx2_dmf/inc/prototypes.h new file mode 100644 index 00000000..cc99cdfe --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/inc/prototypes.h @@ -0,0 +1,14 @@ +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd; + +EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDriverContextCleanup; +EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_READ EvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; + diff --git a/DmfSamples/kmdf_fx2_dmf/inc/public.h b/DmfSamples/kmdf_fx2_dmf/inc/public.h new file mode 100644 index 00000000..f1fc6be3 --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/inc/public.h @@ -0,0 +1,173 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + public.h + +Abstract: + +Environment: + + User & Kernel mode + +--*/ + +#ifndef _PUBLIC_H +#define _PUBLIC_H + +#include + +// {573E8C73-0CB4-4471-A1BF-FAB26C31D384} +DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, + 0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84); + +#pragma warning(push) +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +// +// Define the structures that will be used by the IOCTL +// interface to the driver +// + +// +// BAR_GRAPH_STATE +// +// BAR_GRAPH_STATE is a bit field structure with each +// bit corresponding to one of the bar graph on the +// OSRFX2 Development Board +// +#include +typedef struct _BAR_GRAPH_STATE { + + union { + + struct { + // + // Individual bars starting from the + // top of the stack of bars + // + // NOTE: There are actually 10 bars, + // but the very top two do not light + // and are not counted here + // + UCHAR Bar1 : 1; + UCHAR Bar2 : 1; + UCHAR Bar3 : 1; + UCHAR Bar4 : 1; + UCHAR Bar5 : 1; + UCHAR Bar6 : 1; + UCHAR Bar7 : 1; + UCHAR Bar8 : 1; + }; + + // + // The state of all the bar graph as a single + // UCHAR + // + UCHAR BarsAsUChar; + + }; + +}BAR_GRAPH_STATE, *PBAR_GRAPH_STATE; + +// +// SWITCH_STATE +// +// SWITCH_STATE is a bit field structure with each +// bit corresponding to one of the switches on the +// OSRFX2 Development Board +// +typedef struct _SWITCH_STATE { + + union { + struct { + // + // Individual switches starting from the + // left of the set of switches + // + UCHAR Switch1 : 1; + UCHAR Switch2 : 1; + UCHAR Switch3 : 1; + UCHAR Switch4 : 1; + UCHAR Switch5 : 1; + UCHAR Switch6 : 1; + UCHAR Switch7 : 1; + UCHAR Switch8 : 1; + }; + + // + // The state of all the switches as a single + // UCHAR + // + UCHAR SwitchesAsUChar; + + }; + + +}SWITCH_STATE, *PSWITCH_STATE; + +#include + +#pragma warning(pop) + +#define IOCTL_INDEX 0x800 +#define FILE_DEVICE_OSRUSBFX2 65500U + +#define IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + +#define IOCTL_OSRUSBFX2_RESET_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 1, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_REENUMERATE_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 3, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 4, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 5, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + + +#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 6, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 7, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 8, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 9, \ + METHOD_OUT_DIRECT, \ + FILE_READ_ACCESS) + +#endif diff --git a/DmfSamples/kmdf_fx2_dmf/usb-kmdf-fx2.yaml b/DmfSamples/kmdf_fx2_dmf/usb-kmdf-fx2.yaml new file mode 100644 index 00000000..b9fc8bec --- /dev/null +++ b/DmfSamples/kmdf_fx2_dmf/usb-kmdf-fx2.yaml @@ -0,0 +1,10 @@ +### YamlMime:Sample +sample: +- name: Sample KMDF Function Driver for OSR USB-FX2 + description: Demonstrates how to use KMDF to perform bulk and interrupt data transfers to a USB device. + generateZip: true + author: windows-driver-samples + languages: + - cpp + technologies: + - windows diff --git a/DmfTest/DmfKTest/pkg/DmfKTestPackage.vcxproj b/DmfTest/DmfKTest/pkg/DmfKTestPackage.vcxproj new file mode 100644 index 00000000..78c01921 --- /dev/null +++ b/DmfTest/DmfKTest/pkg/DmfKTestPackage.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {C175B160-1EE2-4B29-B09B-C32B121222EC} + {4605da2c-74a5-4865-98e1-152ef136825f} + v4.5.2 + 12.0 + Debug_RS1 + x64 + DmfKTestPackage + SAK + SAK + SAK + SAK + Utility + Package + true + DmfKTestPackage + + + + true + WindowsKernelModeDriver10.0 + $(LatestTargetPlatformVersion) + + + WindowsKernelModeDriver10.0 + 10.0.14393.0 + + + WindowsKernelModeDriver10.0 + 10.0.15063.0 + + + WindowsKernelModeDriver10.0 + 10.0.16299.0 + + + WindowsKernelModeDriver10.0 + 10.0.17134.0 + + + WindowsKernelModeDriver10.0 + $(LatestTargetPlatformVersion) + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + + + + + + + + false + + false + + + + + + + + + + {ADBA2F9D-D994-4691-838F-927D55DF7C74} + + + + \ No newline at end of file diff --git a/DmfTest/DmfKTest/sys/DmfInterface.c b/DmfTest/DmfKTest/sys/DmfInterface.c new file mode 100644 index 00000000..759237b0 --- /dev/null +++ b/DmfTest/DmfKTest/sys/DmfInterface.c @@ -0,0 +1,167 @@ +/*++ + + Copyright (c) 2018 Microsoft Corporation. All rights reserved + +Module Name: + + DmfInterface.c + +Abstract: + + Instantiate Dmf Library Modules used by THIS driver. + + (This is the only code file in the driver that contains unique code for this driver. All other code the + driver executes is in the Dmf Framework.) + +Environment: + + Kernel-mode Driver Framework + +--*/ + +// The Dmf Library and the Dmf Library Modules this driver uses. +// +#include +#include "DmfModules.Library.h" +#include "DmfModules.Library.Tests.h" + +// Event logging +// +#include "DmfKTestEventLog.h" + +#include "Trace.h" +#include "DmfInterface.tmh" + +/////////////////////////////////////////////////////////////////////////////////////////// +// PRIVATE +/////////////////////////////////////////////////////////////////////////////////////////// +// + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD DmfKTestEvtDeviceAdd; +EVT_WDF_OBJECT_CONTEXT_CLEANUP DmfKTestEvtDriverContextCleanup; +EVT_DMF_DEVICE_MODULES_ADD DmfDeviceModulesAdd; + +// BranchTrack name. +// +#define BRANCHTRACK_NAME "DmfKTest" + +// BranchTrack Initialize routine. +// +VOID +DmfKTestBranchTrackInitialize( + _In_ DMFMODULE DmfModuleBranchTrack + ); + +/*WPP_INIT_TRACING(); (This comment is necessary for WPP Scanner.)*/ +#pragma code_seg("INIT") +DMF_DEFAULT_DRIVERENTRY(DriverEntry, + DmfKTestEvtDriverContextCleanup, + DmfKTestEvtDeviceAdd) +#pragma code_seg() + +#pragma code_seg("PAGED") +DMF_DEFAULT_DRIVERCLEANUP(DmfKTestEvtDriverContextCleanup) +DMF_DEFAULT_DEVICEADD_WITH_BRANCHTRACK(DmfKTestEvtDeviceAdd, + DmfDeviceModulesAdd, + DmfKTestBranchTrackInitialize, + BRANCHTRACK_NAME, + BRANCHTRACK_DEFAULT_MAXIMUM_BRANCHES) +#pragma code_seg() + +#pragma code_seg("PAGED") +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DmfDeviceModulesAdd( + _In_ WDFDEVICE Device, + _In_ PDMFMODULE_INIT DmfModuleInit + ) +/*++ + +Routine Description: + + Add all the Dmf Modules used by this driver. + +Arguments: + + Device - WDFDEVICE handle. + DmfModuleInit - Opaque structure to be passed to DMF_DmfModuleAdd. + +Return Value: + + NTSTATUS + +--*/ +{ + DMF_MODULE_ATTRIBUTES moduleAttributes; + + UNREFERENCED_PARAMETER(Device); + + PAGED_CODE(); + + // Tests_BufferPool + // ---------------- + // + DMF_Tests_BufferPool_ATTRIBUTES_INIT(&moduleAttributes); + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); + + // Tests_BufferQueue + // ---------------- + // + DMF_Tests_BufferQueue_ATTRIBUTES_INIT(&moduleAttributes); + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); + + // Tests_RingBuffer + // ---------------- + // + DMF_Tests_RingBuffer_ATTRIBUTES_INIT(&moduleAttributes); + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); + + // Tests_Registry + // -------------- + // + DMF_Tests_Registry_ATTRIBUTES_INIT(&moduleAttributes); + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); + + // Tests_PingPongBuffer + // -------------------- + // + DMF_Tests_PingPongBuffer_ATTRIBUTES_INIT(&moduleAttributes); + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); + + // Tests_ScheduledTask + // -------------------- + // + DMF_Tests_ScheduledTask_ATTRIBUTES_INIT(&moduleAttributes); + DMF_DmfModuleAdd(DmfModuleInit, + &moduleAttributes, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); +} +#pragma code_seg() + +VOID +DmfKTestBranchTrackInitialize( + _In_ DMFMODULE DmfModuleBranchTrack + ) +{ + UNREFERENCED_PARAMETER(DmfModuleBranchTrack); +} + +// eof: DmfInterface.c +// diff --git a/DmfTest/DmfKTest/sys/DmfKTest.inx b/DmfTest/DmfKTest/sys/DmfKTest.inx new file mode 100644 index 00000000..d197893c --- /dev/null +++ b/DmfTest/DmfKTest/sys/DmfKTest.inx @@ -0,0 +1,84 @@ +; +; DmfKTest.inf +; +; Copyright (C) 2018 Microsoft Corporation. All Rights Reserved. + +[Version] +Signature="$WINDOWS NT$" +Class=System +ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} +Provider=%VENDOR% +CatalogFile=DmfKTest.cat +DriverVer= ; Set in target output .inf +PnpLockdown=1 + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[SourceDisksNames] +1 = %DiskName%,,,"" + +[SourceDisksFiles] +DmfKTest.sys=1,, + +;***************************************** +; Install Section +;***************************************** + +[Manufacturer] +%VENDOR%=Vendor,NT$ARCH$ + +[Vendor.NT$ARCH$] +; To install the driver run the following command from driver's package folder: +; devcon install DmfKTest.inf root\DmfKTest +%DmfKTest%=DmfKTest.Inst, root\DmfKTest + +[DmfKTest.Inst.NT] +CopyFiles = Drivers_Dir + +;-------------- Service installation + +[DmfKTest.Inst.NT.Services] +AddService = DmfKTest,%SERVICE_DEMAND_START%,DmfKTest_Service_Inst, DmfKTest_EventLogInst + +[Drivers_Dir] +DmfKTest.sys + +[DmfKTest_Service_Inst] +DisplayName = %DmfKTest% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\DmfKTest.sys + +[DmfKTest_EventLogInst] +AddReg = DmfKTest_EventLogAddReg + +[DmfKTest_EventLogAddReg] +HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\DmfKTest.sys" +HKR,,TypesSupported,0x00010001,7 + +[Strings] +VENDOR="Surface" +DmfKTest="Surface DmfK Test Driver" +DiskName = "Surface DmfK Test Driver Installation Disk" + +SERVICE_BOOT_START = 0x0 +SERVICE_SYSTEM_START = 0x1 +SERVICE_AUTO_START = 0x2 +SERVICE_DEMAND_START = 0x3 +SERVICE_DISABLED = 0x4 + +SERVICE_KERNEL_DRIVER = 0x1 +SERVICE_ERROR_IGNORE = 0x0 +SERVICE_ERROR_NORMAL = 0x1 +SERVICE_ERROR_SEVERE = 0x2 +SERVICE_ERROR_CRITICAL = 0x3 + +REG_EXPAND_SZ = 0x00020000 +REG_DWORD = 0x00010001 +REG_MULTI_SZ = 0x00010000 +REG_BINARY = 0x00000001 +REG_SZ = 0x00000000 diff --git a/DmfTest/DmfKTest/sys/DmfKTest.rc b/DmfTest/DmfKTest/sys/DmfKTest.rc new file mode 100644 index 00000000..96d19255 --- /dev/null +++ b/DmfTest/DmfKTest/sys/DmfKTest.rc @@ -0,0 +1,50 @@ +// +// DmfKTest.rc +// + + +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_INTERNALNAME_STR "DmfKTest.sys" +#define VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR + +#undef VER_FILEDESCRIPTION_STR +#define VER_FILEDESCRIPTION_STR "Surface DmfK Test Driver" + +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR VER_FILEDESCRIPTION_STR + +#define VER_FILEVERSION 1,0,0,0 +#define VER_FILEVERSION_STR "1.0.0.0" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION VER_FILEVERSION + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR + +#define VER_LEGALCOPYRIGHT_STR "(C) 2018 Microsoft. All rights reserved." +#ifdef VER_COMPANYNAME_STR + +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR "Microsoft Corporation" +#endif + +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR "Surface" + +#include "common.ver" + +// This is the main driver's resource file. It is numbered 1. +// Automatically generated resource files also are numbered 1 which causes +// an error. So, add additinal resources manually. +// +#include "DmfKTestEventLog.rc" + +// eof: DmfKTest.rc +// + diff --git a/DmfTest/DmfKTest/sys/DmfKTest.vcxproj b/DmfTest/DmfKTest/sys/DmfKTest.vcxproj new file mode 100644 index 00000000..97385c90 --- /dev/null +++ b/DmfTest/DmfKTest/sys/DmfKTest.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + {ADBA2F9D-D994-4691-838F-927D55DF7C74} + {497e31cb-056b-4f31-abb8-447fd55ee5a5} + v4.5.2 + 12.0 + DmfKTest + SAK + SAK + SAK + SAK + Driver + KMDF + DmfKTest + + + + true + WindowsKernelModeDriver10.0 + $(LatestTargetPlatformVersion) + + + DbgengKernelDebugger + + + + + + + + true + true + .\Trace.h + true + Disabled + DEBUG;DBG;%(PreprocessorDefinitions); + NDEBUG;%(PreprocessorDefinitions); + %(AdditionalIncludeDirectories);..\..\..\Dmf\Modules.Library.Tests;..\..\..\Dmf\Modules.Library + + + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib;..\..\..\$(Configuration)\$(Platform)\lib\DmfK\DmfK.lib + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DmfTest/DmfKTest/sys/DmfKTest.vcxproj.filters b/DmfTest/DmfKTest/sys/DmfKTest.vcxproj.filters new file mode 100644 index 00000000..6fab766f --- /dev/null +++ b/DmfTest/DmfKTest/sys/DmfKTest.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4753b553-8305-44a8-aa1a-e7ac7233bdd3} + + + {b93b1cd7-fef0-4770-8794-d81e63c73a6e} + + + {8bba2704-dbec-4763-82b7-71f5fb2889ad} + + + {4a6e4458-cdba-450b-86cc-5d29999f6dca} + + + + + Modules + + + + + Headers + + + + + Resources + + + + + Inx + + + + + Resources + + + \ No newline at end of file diff --git a/DmfTest/DmfKTest/sys/DmfKTestEventLog.mc b/DmfTest/DmfKTest/sys/DmfKTestEventLog.mc new file mode 100644 index 00000000..4107d5cd --- /dev/null +++ b/DmfTest/DmfKTest/sys/DmfKTestEventLog.mc @@ -0,0 +1,111 @@ +;/*++ +; +; Copyright (C) Microsoft. All rights reserved. +; +;Module Name: +; +; EventLog.h generated from EventLog.mc using Visual Studio Message Compiler. +; +;Abstract: +; +; Event log resources. +; +;Environment: +; +; User/Kernel mode drivers. +; +;--*/ +; + +;#pragma once +; + +;// +;// Status values are 32 bit values layed out as follows: +;// +;// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +;// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +;// +---+-+-------------------------+-------------------------------+ +;// |Sev|C| Facility | Code | +;// +---+-+-------------------------+-------------------------------+ +;// +;// where +;// +;// Sev - is the severity code +;// +;// 00 - Success +;// 01 - Informational +;// 10 - Warning +;// 11 - Error +;// +;// C - is the Customer code flag +;// +;// Facility - is the facility code +;// +;// Code - is the facility's status code +;// +; + +MessageIdTypedef=NTSTATUS + +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS + Informational=0x1:STATUS_SEVERITY_INFORMATIONAL + Warning=0x2:STATUS_SEVERITY_WARNING + Error=0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames=(System=0x0 + Driver=0x1:FACILITY_DRIVER_ERROR_CODE + ) + +;// Copy of Dmf_DataTransferViaAcpi_EventLog.mc messages +;// +MessageId=0x4400 +Facility=Driver +Severity=Error +SymbolicName=EVENTLOG_MESSAGE_ACPI_MESSAGE_ERROR +Language=English +%2 +. + +MessageId=0x4401 +Facility=Driver +Severity=Warning +SymbolicName=EVENTLOG_MESSAGE_ACPI_MESSAGE_WARNING +Language=English +%2 +. + +MessageId=0x4402 +Facility=Driver +Severity=Informational +SymbolicName=EVENTLOG_MESSAGE_ACPI_MESSAGE_INFORMATIONAL +Language=English +%2 +. + +;// Copy of Dmf_SamNotificationViaSsh_EventLog.mc messages +;// +MessageId=0x4500 +Facility=Driver +Severity=Informational +SymbolicName=EVENTLOG_MESSAGE_EVENT_RECEIVED +Language=English +SamNotificationViaSsh received event. Notified OS with status: %2. %3, %4, %5, %6. +. + +;// Copy of Dmf_AcpiNotificationViaSsh_EventLog.mc messages +;// +MessageId=0x4600 +Facility=Driver +Severity=Informational +SymbolicName=EVENTLOG_MESSAGE_THERMAL_CMDID_SET_DPTF_TRIP_POINT +Language=English +AcpiNotificationViaSsh received thermal set trip point event. %2, %3, %4. +. + +;// TODO: Add codes as needed. (Be sure to set the proper Severity for new codes.) +;// + +;// eof: EventLog.mc +;// diff --git a/DmfTest/DmfKTest/sys/Trace.h b/DmfTest/DmfKTest/sys/Trace.h new file mode 100644 index 00000000..39c2229a --- /dev/null +++ b/DmfTest/DmfKTest/sys/Trace.h @@ -0,0 +1,73 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Trace.h + +Abstract: + + Header file for the debug tracing related function definitions and macros. + +Environment: + + Kernel mode + +--*/ +#pragma once + +// +// Define the tracing flags. +// +// DmfKTest Tracing GUID - {61C379CE-3A6B-4E34-B8B1-BEF18A0F6209} +// SurfaceLibrary Tracing GUID - {4DA41ED6-B8E6-473E-A7DF-E9C958B86167} +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + DmfKTestDriverTraceGuid, (61C379CE,3A6B,4E34,B8B1,BEF18A0F6209), \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(TRACE_DRIVER) \ + ) \ + WPP_DEFINE_CONTROL_GUID( \ + SurfaceLibraryTraceGuid, (4DA41ED6,B8E6,473E,A7DF,E9C958B86167), \ + WPP_DEFINE_BIT(DMF_TRACE_Tests_BufferPool) \ + WPP_DEFINE_BIT(DMF_TRACE_Tests_BufferQueue) \ + WPP_DEFINE_BIT(DMF_TRACE_Tests_PingPongBuffer) \ + WPP_DEFINE_BIT(DMF_TRACE_Tests_Registry) \ + WPP_DEFINE_BIT(DMF_TRACE_Tests_RingBuffer) \ + WPP_DEFINE_BIT(DMF_TRACE_Tests_ScheduledTask) \ + ) \ +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// USEPREFIX and USESUFFIX strip all trailing whitespace, so we need to surround +// FuncExit messages with brackets +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); +// FUNC FuncEntryArguments{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// FUNC FuncExitVoid{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); +// FUNC TraceError{LEVEL=TRACE_LEVEL_ERROR}(FLAGS, MSG, ...); +// FUNC TraceInformation{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS, MSG, ...); +// FUNC TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// FUNC FuncExitNoReturn{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); +// USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> Entry"); +// USEPREFIX(FuncEntryArguments, "%!STDPREFIX! [%!FUNC!] --> Entry"); +// USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <-- Exit <"); +// USESUFFIX(FuncExit, ">"); +// USEPREFIX(FuncExitVoid, "%!STDPREFIX! [%!FUNC!] <-- Exit"); +// USEPREFIX(TraceError, "%!STDPREFIX! [%!FUNC!] ERROR:"); +// USEPREFIX(TraceEvents, "%!STDPREFIX! [%!FUNC!]"); +// USEPREFIX(TraceInformation, "%!STDPREFIX! [%!FUNC!]"); +// USEPREFIX(TraceVerbose, "%!STDPREFIX! [%!FUNC!]"); +// USEPREFIX(FuncExitNoReturn, "%!STDPREFIX! [%!FUNC!] <--"); +// end_wpp + +// eof: Trace.h +// diff --git a/DmfTest/DmfTest.sln b/DmfTest/DmfTest.sln new file mode 100644 index 00000000..b1ac2816 --- /dev/null +++ b/DmfTest/DmfTest.sln @@ -0,0 +1,63 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DmfKTest", "DmfKTest\sys\DmfKTest.vcxproj", "{ADBA2F9D-D994-4691-838F-927D55DF7C74}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DmfKTestPackage", "DmfKTest\pkg\DmfKTestPackage.vcxproj", "{C175B160-1EE2-4B29-B09B-C32B121222EC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|win32 = Debug|win32 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|win32 = Release|win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|ARM64.Build.0 = Debug|ARM64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|win32.ActiveCfg = Debug|Win32 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|win32.Build.0 = Debug|Win32 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|win32.Deploy.0 = Debug|Win32 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|x64.ActiveCfg = Debug|x64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|x64.Build.0 = Debug|x64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Debug|x64.Deploy.0 = Debug|x64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|ARM64.ActiveCfg = Release|ARM64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|ARM64.Build.0 = Release|ARM64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|ARM64.Deploy.0 = Release|ARM64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|win32.ActiveCfg = Release|Win32 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|win32.Build.0 = Release|Win32 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|win32.Deploy.0 = Release|Win32 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|x64.ActiveCfg = Release|x64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|x64.Build.0 = Release|x64 + {ADBA2F9D-D994-4691-838F-927D55DF7C74}.Release|x64.Deploy.0 = Release|x64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|ARM64.Build.0 = Debug|ARM64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|win32.ActiveCfg = Debug|Win32 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|win32.Build.0 = Debug|Win32 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|win32.Deploy.0 = Debug|Win32 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|x64.ActiveCfg = Debug|x64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|x64.Build.0 = Debug|x64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Debug|x64.Deploy.0 = Debug|x64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|ARM64.ActiveCfg = Release|ARM64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|ARM64.Build.0 = Release|ARM64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|ARM64.Deploy.0 = Release|ARM64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|win32.ActiveCfg = Release|Win32 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|win32.Build.0 = Release|Win32 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|win32.Deploy.0 = Release|Win32 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|x64.ActiveCfg = Release|x64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|x64.Build.0 = Release|x64 + {C175B160-1EE2-4B29-B09B-C32B121222EC}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {12DE9783-2571-4C78-AD9C-0112BBF30A80} + EndGlobalSection +EndGlobal