static NTSTATUS UsbChief_QueuePassiveLevelCallback(IN WDFDEVICE Device, IN WDFUSBPIPE Pipe) { NTSTATUS status = STATUS_SUCCESS; PWORKITEM_CONTEXT context; WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; WDFWORKITEM hWorkItem; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, WORKITEM_CONTEXT); attributes.ParentObject = Device; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, UsbChief_ReadWriteWorkItem); status = WdfWorkItemCreate( &workitemConfig, &attributes, &hWorkItem); if (!NT_SUCCESS(status)) return status; context = GetWorkItemContext(hWorkItem); context->Device = Device; context->Pipe = Pipe; WdfWorkItemEnqueue(hWorkItem); return STATUS_SUCCESS; }
NTSTATUS QueuePassiveLevelCallback( _In_ WDFDEVICE Device, _In_ WDFUSBPIPE Pipe ) /*++ Routine Description: This routine is used to queue workitems so that the callback functions can be executed at PASSIVE_LEVEL in the context of a system thread. Arguments: Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; PWORKITEM_CONTEXT context; WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; WDFWORKITEM hWorkItem; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, WORKITEM_CONTEXT); attributes.ParentObject = Device; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, Rio500_EvtReadWriteWorkItem); status = WdfWorkItemCreate( &workitemConfig, &attributes, &hWorkItem ); if (!NT_SUCCESS(status)) { return status; } context = GetWorkItemContext(hWorkItem); context->Device = Device; context->Pipe = Pipe; // // Execute this work item. // WdfWorkItemEnqueue(hWorkItem); return STATUS_SUCCESS; }
NTSTATUS StatInitializeWorkItem( IN WDFDEVICE Device ) { WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; PDEVICE_CONTEXT devCtx = GetDeviceContext(Device); RtlZeroMemory(Counters, sizeof(Counters)); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = Device; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, StatWorkItemWorker); return WdfWorkItemCreate(&workitemConfig, &attributes, &devCtx->StatWorkItem); }
void CyapaBootTimer(_In_ WDFTIMER hTimer) { WDFDEVICE Device = (WDFDEVICE)WdfTimerGetParentObject(hTimer); PDEVICE_CONTEXT pDevice = GetDeviceContext(Device); WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; WDFWORKITEM hWorkItem; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); attributes.ParentObject = Device; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, CyapaBootWorkItem); WdfWorkItemCreate(&workitemConfig, &attributes, &hWorkItem); WdfWorkItemEnqueue(hWorkItem); WdfTimerStop(hTimer, FALSE); }
VOID VIOSerialPortPnpNotify ( IN WDFDEVICE WdfDevice, IN PVIOSERIAL_PORT port, IN BOOLEAN connected ) { WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; WDFWORKITEM hWorkItem; PRAWPDO_VIOSERIAL_PORT pdoData = NULL; NTSTATUS status = STATUS_SUCCESS; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); port->HostConnected = connected; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, RAWPDO_VIOSERIAL_PORT); attributes.ParentObject = WdfDevice; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, VIOSerialPortPnpNotifyWork); status = WdfWorkItemCreate( &workitemConfig, &attributes, &hWorkItem); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "WdfWorkItemCreate failed with status = 0x%08x\n", status); return; } pdoData = RawPdoSerialPortGetData(hWorkItem); pdoData->port = port; WdfWorkItemEnqueue(hWorkItem); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); }
NTSTATUS AndroidUsbPipeFileObject::QueueResetPipePassiveCallback() { ASSERT_IRQL_LOW_OR_DISPATCH(); // Initialize workitem WDF_OBJECT_ATTRIBUTES attr; WDF_OBJECT_ATTRIBUTES_INIT(&attr); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attr, AndroidUsbWorkitemContext); attr.ParentObject = wdf_device(); WDFWORKITEM wdf_work_item = NULL; WDF_WORKITEM_CONFIG workitem_config; WDF_WORKITEM_CONFIG_INIT(&workitem_config, ResetPipePassiveCallbackEntry); NTSTATUS status = WdfWorkItemCreate(&workitem_config, &attr, &wdf_work_item); ASSERT(NT_SUCCESS(status) && (NULL != wdf_work_item)); if (!NT_SUCCESS(status)) return status; // Initialize our extension to work item AndroidUsbWorkitemContext* context = GetAndroidUsbWorkitemContext(wdf_work_item); ASSERT(NULL != context); if (NULL == context) { WdfObjectDelete(wdf_work_item); return STATUS_INTERNAL_ERROR; } context->object_type = AndroidUsbWdfObjectTypeWorkitem; context->pipe_file_ext = this; // Enqueue this work item. WdfWorkItemEnqueue(wdf_work_item); return STATUS_SUCCESS; }
VOID VIOSerialPortCreateName( IN WDFDEVICE WdfDevice, IN PVIOSERIAL_PORT port, IN PPORT_BUFFER buf ) { WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; WDFWORKITEM hWorkItem; PRAWPDO_VIOSERIAL_PORT pdoData = NULL; NTSTATUS status = STATUS_SUCCESS; size_t length; PVIRTIO_CONSOLE_CONTROL cpkt; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, "--> %s\n", __FUNCTION__); cpkt = (PVIRTIO_CONSOLE_CONTROL)((ULONG_PTR)buf->va_buf + buf->offset); if (port && !port->NameString.Buffer) { length = buf->len - buf->offset - sizeof(VIRTIO_CONSOLE_CONTROL); port->NameString.Length = (USHORT)( length ); port->NameString.MaximumLength = port->NameString.Length + 1; port->NameString.Buffer = (PCHAR)ExAllocatePoolWithTag( NonPagedPool, port->NameString.MaximumLength, VIOSERIAL_DRIVER_MEMORY_TAG ); if (port->NameString.Buffer) { RtlCopyMemory( port->NameString.Buffer, (PVOID)((LONG_PTR)buf->va_buf + buf->offset + sizeof(*cpkt)), length ); port->NameString.Buffer[length] = '\0'; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_PORT_NAME name_size = %d %s\n", length, port->NameString.Buffer); } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_NAME: Unable to alloc string buffer\n" ); } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, RAWPDO_VIOSERIAL_PORT); attributes.ParentObject = WdfDevice; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, VIOSerialPortSymbolicNameWork); status = WdfWorkItemCreate( &workitemConfig, &attributes, &hWorkItem); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "WdfWorkItemCreate failed with status = 0x%08x\n", status); return; } pdoData = RawPdoSerialPortGetData(hWorkItem); pdoData->port = port; WdfWorkItemEnqueue(hWorkItem); } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_NAME invalid id = %d\n", cpkt->id); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, "<-- %s\n", __FUNCTION__); }
NTSTATUS PepScheduleWorker ( _In_ PPEP_WORK_CONTEXT WorkContext ) /*++ Routine Description: This function schedules a worker thread to process pending work requests. Arguments: WorkContext - Supplies the context of the work. Return Value: NTSTATUS. --*/ { WDF_OBJECT_ATTRIBUTES Attributes; NTSTATUS Status; BOOLEAN Synchronous; WDFWORKITEM WorkItem; WDF_WORKITEM_CONFIG WorkItemConfiguration; WorkItem = NULL; Synchronous = FALSE; // // Create a workitem to process events. // WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&Attributes, PEP_WORK_ITEM_CONTEXT); Attributes.ParentObject = PepGlobalWdfDevice; // // Initialize the handler routine and create a new workitem. // WDF_WORKITEM_CONFIG_INIT(&WorkItemConfiguration, PepWorkerWrapper); // // Disable automatic serialization by the framework for the worker thread. // The parent device object is being serialized at device level (i.e., // WdfSynchronizationScopeDevice), and the framework requires it to be // passive level (i.e., WdfExecutionLevelPassive) if automatic // synchronization is desired. // WorkItemConfiguration.AutomaticSerialization = FALSE; // // Create the work item and queue it. If the workitem cannot be created // for some reason, just call the worker routine synchronously. // Status = WdfWorkItemCreate(&WorkItemConfiguration, &Attributes, &WorkItem); if (!NT_SUCCESS(Status)) { Synchronous = TRUE; TraceEvents(INFO, DBG_PEP, "%s: Failed to allocate work item to process pending" "work! Status = %!STATUS!. Will synchronously process.\n", __FUNCTION__, Status); } // // If the operation is to be performed synchronously, then directly // invoke the worker routine. Otherwise, queue a workitem to run the // worker routine. // if (Synchronous != FALSE) { PepProcessPendingWorkRequests(); } else { TraceEvents(INFO, DBG_PEP, "%s: Work request scheduled to run asynchronously. " "Device=%p, WorkType=%d, NotificationId=%d.\n", __FUNCTION__, (PVOID)WorkContext->PepInternalDevice, (ULONG)WorkContext->WorkType, (ULONG)WorkContext->NotificationId); WdfWorkItemEnqueue(WorkItem); } return STATUS_SUCCESS; }
/** * @brief Allocate a workitem from or for our collection of workitems. * Must be called with the device lock held. * * @param[in] Device handle to the WDFDEVICE created by FdoEvtDeviceAdd. * @param[in] callback only optional if this is add device doing an allocation! * @param[in] Param0 arbitrary context data * @param[in] Param1 arbitrary context data * @param[in] Param2 arbitrary context data * @param[in] Param3 arbitrary context data * * @returns a WDFWORKITEM handle or NULL on failure. * */ WDFWORKITEM NewWorkItem( IN PUSB_FDO_CONTEXT fdoContext, IN PFN_WDF_WORKITEM callback, IN ULONG_PTR Param0, IN ULONG_PTR Param1, IN ULONG_PTR Param2, IN ULONG_PTR Param3) { // // First try to get a workitem from our collection of them. // WDFWORKITEM WorkItem = (WDFWORKITEM) WdfCollectionGetFirstItem(fdoContext->FreeWorkItems); if (WorkItem == NULL) { // // ok - allocate a new one. // TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DEVICE, __FUNCTION__": Device %p FreeWorkItems is empty, init count %d\n", fdoContext->WdfDevice, INIT_WORK_ITEM_COUNT); NTSTATUS status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES attributes; WDF_WORKITEM_CONFIG workitemConfig; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE( &attributes, USB_FDO_WORK_ITEM_CONTEXT); attributes.ParentObject = fdoContext->WdfDevice; WDF_WORKITEM_CONFIG_INIT( &workitemConfig, EvtFdoDeviceGenericWorkItem); status = WdfWorkItemCreate( &workitemConfig, &attributes, &WorkItem); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfWorkItemCreate error %x\n", status); return NULL; } } else { // note that WdfCollectionGetFirstItem doesn't remove it from the collection. WdfCollectionRemove(fdoContext->FreeWorkItems, WorkItem); } if (WorkItem) { // initialize it. PUSB_FDO_WORK_ITEM_CONTEXT context = WorkItemGetContext(WorkItem); context->FdoContext = fdoContext; context->CallBack = callback; context->Params[0] = Param0; context->Params[1] = Param1; context->Params[2] = Param2; context->Params[3] = Param3; } return WorkItem; }
NTSTATUS I2COpen( _In_ PDEVICE_CONTEXT DeviceContext ) /*++ Routine Description: This routine opens a handle to the I2C controller. Arguments: DeviceContext - a pointer to the device context Return Value: NTSTATUS --*/ { TRACE_FUNC_ENTRY(TRACE_I2C); PAGED_CODE(); NTSTATUS status; WDF_IO_TARGET_OPEN_PARAMS openParams; WDF_OBJECT_ATTRIBUTES requestAttributes; WDF_OBJECT_ATTRIBUTES workitemAttributes; WDF_WORKITEM_CONFIG workitemConfig; // Create the device path using the connection ID. DECLARE_UNICODE_STRING_SIZE(DevicePath, RESOURCE_HUB_PATH_SIZE); RESOURCE_HUB_CREATE_PATH_FROM_ID( &DevicePath, DeviceContext->I2CConnectionId.LowPart, DeviceContext->I2CConnectionId.HighPart); TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_I2C, "Opening handle to I2C target via %wZ", &DevicePath); status = WdfIoTargetCreate(DeviceContext->Device, WDF_NO_OBJECT_ATTRIBUTES, &DeviceContext->I2CIoTarget); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfIoTargetCreate failed - %!STATUS!", status); goto Exit; } // Open a handle to the I2C controller. WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, &DevicePath, (GENERIC_READ | GENERIC_WRITE)); openParams.ShareAccess = 0; openParams.CreateDisposition = FILE_OPEN; openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; status = WdfIoTargetOpen(DeviceContext->I2CIoTarget, &openParams); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "Failed to open I2C I/O target - %!STATUS!", status); goto Exit; } // Create a WDFMEMORY object. Do call WdfMemoryAssignBuffer before use it, status = WdfMemoryCreatePreallocated( WDF_NO_OBJECT_ATTRIBUTES, static_cast<PVOID>(&status), // initial value does not matter sizeof(status), &DeviceContext->I2CMemory); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfMemoryCreatePreallocated failed with status %!STATUS!", status); goto Exit; } WDF_OBJECT_ATTRIBUTES_INIT(&requestAttributes); requestAttributes.ParentObject = DeviceContext->I2CIoTarget; for (ULONG i = 0; i < I2CRequestSourceMax; i++) { status = WdfRequestCreate(&requestAttributes, DeviceContext->I2CIoTarget, &DeviceContext->OutgoingRequests[i]); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfRequestCreate failed with status %!STATUS!", status); goto Exit; } } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitemAttributes, WORKITEM_CONTEXT); workitemAttributes.ParentObject = DeviceContext->I2CIoTarget; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, EvtWorkItemGetStatus); status = WdfWorkItemCreate(&workitemConfig, &workitemAttributes, &DeviceContext->I2CWorkItemGetStatus); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfWorkItemCreate failed with status %!STATUS!", status); goto Exit; } WDF_WORKITEM_CONFIG_INIT(&workitemConfig, EvtWorkItemGetControl); status = WdfWorkItemCreate(&workitemConfig, &workitemAttributes, &DeviceContext->I2CWorkItemGetControl); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfWorkItemCreate failed with status %!STATUS!", status); goto Exit; } Exit: TRACE_FUNC_EXIT(TRACE_I2C); return status; }
VOID kmdf1394_BusResetRoutine( IN PVOID Context) { WDFDEVICE device= Context; PDEVICE_EXTENSION deviceExtension = GetDeviceContext(device); NTSTATUS ntStatus = STATUS_SUCCESS; WDFREQUEST request; WDF_WORKITEM_CONFIG workItemConfig; WDFWORKITEM workItem; WDF_OBJECT_ATTRIBUTES attributes; ENTER("kmdf1394_BusResetRoutine"); TRACE(TL_TRACE, ("Context = 0x%x\n", Context)); WDF_WORKITEM_CONFIG_INIT (&workItemConfig, kmdf1394_BusResetRoutineWorkItem); WDF_OBJECT_ATTRIBUTES_INIT (&attributes); attributes.ParentObject = device; ntStatus = WdfWorkItemCreate( &workItemConfig, &attributes, &workItem); if (!NT_SUCCESS (ntStatus)) { TRACE(TL_ERROR, ("Failed to create workitem %x\n", ntStatus)); return; } // // Execute this work item. // WdfWorkItemEnqueue (workItem); // // If we have any bus reset notify irps, then nows the // time to complete them. // WHILE (TRUE) { ntStatus = WdfIoQueueRetrieveNextRequest ( deviceExtension->BusResetRequestsQueue, &request); if(NT_SUCCESS (ntStatus)) { TRACE(TL_TRACE, ("Completing BusReset Request = 0x%p\n", request)); WdfRequestCompleteWithInformation (request, STATUS_SUCCESS, 0); // continue; } else if (STATUS_NO_MORE_ENTRIES == ntStatus) { TRACE (TL_TRACE, ("Request Queue is empty.\n")); break; } else { ASSERTMSG ( "WdfIoQueueRetrieveNextRequest failed", ntStatus); break; } } EXIT("kmdf1394_BusResetRoutine", ntStatus); } // kmdf1394_BusResetRoutine
NTSTATUS SimSensorDriverDeviceAdd ( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDriverDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. A WDF device object is created and initialized to represent a new instance of the battery device. Arguments: Driver - Supplies a handle to the WDF Driver object. DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { WDF_OBJECT_ATTRIBUTES DeviceAttributes; WDFDEVICE DeviceHandle; PFDO_DATA DevExt; BOOLEAN LockHeld; WDF_IO_QUEUE_CONFIG PendingRequestQueueConfig; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks; WDFQUEUE Queue; WDF_IO_QUEUE_CONFIG QueueConfig; NTSTATUS Status; WDF_OBJECT_ATTRIBUTES WorkitemAttributes; WDF_WORKITEM_CONFIG WorkitemConfig; UNREFERENCED_PARAMETER(Driver); DebugEnter(); PAGED_CODE(); LockHeld = FALSE; // // Initialize attributes and a context area for the device object. // WDF_OBJECT_ATTRIBUTES_INIT(&DeviceAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&DeviceAttributes, FDO_DATA); // // Initailize power callbacks // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks); PnpPowerCallbacks.EvtDeviceD0Entry = SimSensorDeviceD0Entry; PnpPowerCallbacks.EvtDeviceD0Exit = SimSensorDeviceD0Exit; PnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = SimSensorSelfManagedIoSuspend; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks); // // Create a framework device object. This call will in turn create // a WDM device object, attach to the lower stack, and set the // appropriate flags and attributes. // Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &DeviceHandle); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfDeviceCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } DevExt = GetDeviceExtension(DeviceHandle); // // Configure a default queue for IO requests. This queue processes requests // to read the sensor state. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, WdfIoQueueDispatchParallel); QueueConfig.EvtIoDeviceControl = SimSensorIoDeviceControl; // // The system uses IoInternalDeviceControl requests to communicate with the // ACPI driver on the device stack. For proper operation of thermal zones, // these requests must be forwarded unless the driver knows how to handle // them. // QueueConfig.EvtIoInternalDeviceControl = SimSensorIoInternalDeviceControl; Status = WdfIoQueueCreate(DeviceHandle, &QueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &Queue); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfIoQueueCreate() (Default) Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Configure a manual dispatch queue for pending requests. This queue // stores requests to read the sensor state which can't be retired // immediately. // WDF_IO_QUEUE_CONFIG_INIT(&PendingRequestQueueConfig, WdfIoQueueDispatchManual); Status = WdfIoQueueCreate(DeviceHandle, &PendingRequestQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &DevExt->PendingRequestQueue); PendingRequestQueueConfig.EvtIoStop = SimSensorQueueIoStop; if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfIoQueueCreate() (Pending) Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Configure a workitem to process the simulated interrupt. // WDF_OBJECT_ATTRIBUTES_INIT(&WorkitemAttributes); WorkitemAttributes.ParentObject = DeviceHandle; WDF_WORKITEM_CONFIG_INIT(&WorkitemConfig, SimSensorTemperatureInterruptWorker); Status = WdfWorkItemCreate(&WorkitemConfig, &WorkitemAttributes, &DevExt->InterruptWorker); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfWorkItemCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Create the request queue waitlock. // Status = WdfWaitLockCreate(NULL, &DevExt->QueueLock); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfWaitLockCreate() Failed. Status 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Initilize the simulated sensor hardware. // DevExt->Sensor.LowerBound = 0; DevExt->Sensor.UpperBound = (ULONG)-1; DevExt->Sensor.Temperature = VIRTUAL_SENSOR_RESET_TEMPERATURE; Status = WdfWaitLockCreate(NULL, &DevExt->Sensor.Lock); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfWaitLockCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } DriverDeviceAddEnd: DebugExitStatus(Status); return Status; }