VOID VIOSerialPortPnpNotifyWork( IN WDFWORKITEM WorkItem ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WorkItem); PVIOSERIAL_PORT pport = pdoData->port; PTARGET_DEVICE_CUSTOM_NOTIFICATION notification; ULONG requiredSize; NTSTATUS status; VIRTIO_PORT_STATUS_CHANGE portStatus = {0}; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); portStatus.Version = 1; portStatus.Reason = pport->HostConnected; status = RtlULongAdd((sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)), sizeof(VIRTIO_PORT_STATUS_CHANGE), &requiredSize); if (NT_SUCCESS(status)) { notification = (PTARGET_DEVICE_CUSTOM_NOTIFICATION) ExAllocatePoolWithTag(NonPagedPool, requiredSize, VIOSERIAL_DRIVER_MEMORY_TAG); if (notification != NULL) { RtlZeroMemory(notification, requiredSize); notification->Version = 1; notification->Size = (USHORT)(requiredSize); notification->FileObject = NULL; notification->NameBufferOffset = -1; notification->Event = GUID_VIOSERIAL_PORT_CHANGE_STATUS; RtlCopyMemory(notification->CustomDataBuffer, &portStatus, sizeof(VIRTIO_PORT_STATUS_CHANGE)); if(WdfDeviceGetDevicePnpState(pport->Device) == WdfDevStatePnpStarted) { status = IoReportTargetDeviceChangeAsynchronous( WdfDeviceWdmGetPhysicalDevice(pport->Device), notification, NULL, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "IoReportTargetDeviceChangeAsynchronous Failed! status = 0x%x\n", status); } } ExFreePoolWithTag(notification, VIOSERIAL_DRIVER_MEMORY_TAG); } } WdfObjectDelete(WorkItem); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); }
__inline VOID MP_FREE_SEND_PACKET( IN PFDO_DATA FdoData, IN PMP_TCB pMpTcb, IN NTSTATUS Status ) /*++ Routine Description: Recycle a MP_TCB and complete the packet if necessary Assumption: This function is called with the Send SPINLOCK held. Arguments: FdoData Pointer to our FdoData pMpTcb Pointer to MP_TCB Return Value: None --*/ { WDFREQUEST request; WDFDMATRANSACTION dmaTransaction; size_t length; ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE)); dmaTransaction = pMpTcb->DmaTransaction; pMpTcb->DmaTransaction = NULL; MP_CLEAR_FLAGS(pMpTcb); FdoData->CurrSendHead = FdoData->CurrSendHead->Next; FdoData->nBusySend--; request = WdfDmaTransactionGetRequest(dmaTransaction); length = WdfDmaTransactionGetBytesTransferred(dmaTransaction); WdfObjectDelete( dmaTransaction ); if (request) { WdfSpinLockRelease(FdoData->SendLock); WdfRequestCompleteWithInformation(request, Status, length); FdoData->BytesTransmitted += length; WdfSpinLockAcquire(FdoData->SendLock); } }
static VOID XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) { PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd; NTSTATUS status; WDFREQUEST request; WDF_REQUEST_SEND_OPTIONS send_options; IO_STACK_LOCATION stack; SCSI_REQUEST_BLOCK srb; SRB_IO_CONTROL sic; FUNCTION_ENTER(); /* send a 'start' down if we are resuming from a suspend */ if (suspend) { status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request); FUNCTION_MSG("WdfRequestCreate = %08x\n", status); RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION)); stack.MajorFunction = IRP_MJ_SCSI; stack.Parameters.Scsi.Srb = &srb; RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE); srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE; srb.Length = SCSI_REQUEST_BLOCK_SIZE; srb.PathId = 0; srb.TargetId = 0; srb.Lun = 0; srb.OriginalRequest = WdfRequestWdmGetIrp(request); srb.Function = SRB_FUNCTION_IO_CONTROL; srb.DataBuffer = &sic; RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL)); sic.HeaderLength = sizeof(SRB_IO_CONTROL); memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8); sic.Timeout = 60; sic.ControlCode = XENVBD_CONTROL_START; WdfRequestWdmFormatUsingStackLocation(request, &stack); WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS); if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) { FUNCTION_MSG("Request was _NOT_ sent\n"); } #if DBG status = WdfRequestGetStatus(request); FUNCTION_MSG("Request Status = %08x\n", status); FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus); #endif WdfObjectDelete(request); } FUNCTION_EXIT(); }
// Internal routine to perform simulator initialization NTSTATUS HardwareSimulator::InitializeInternal( _In_ WDFOBJECT SimulatorInstance) // Instance of the WDF object for the simulator { NTSTATUS Status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES TimerAttributes = {}; WDF_TIMER_CONFIG TimerConfig = {}; SENSOR_FunctionEnter(); // Only initialize the simulator if it is in the "not initialized" state if (SimulatorState_NotInitialized == m_State) { // Create Lock Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); if (!NT_SUCCESS(Status)) { m_Lock = NULL; TraceError("CSTM %!FUNC! WdfWaitLockCreate failed %!STATUS!", Status); goto Exit; } // Create a timer object for simulation updates WDF_TIMER_CONFIG_INIT(&TimerConfig, HardwareSimulator::OnTimerExpire); WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); TimerAttributes.ParentObject = SimulatorInstance; TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); if (!NT_SUCCESS(Status)) { m_Timer = NULL; TraceError("CSTM %!FUNC! WdfTimerCreate failed %!STATUS!", Status); goto Exit; } // Set the simulator state to "initialized" m_State = SimulatorState_Initialized; m_SimulatorInstance = SimulatorInstance; } Exit: if (!NT_SUCCESS(Status) && NULL != m_Lock) { WdfObjectDelete(m_Lock); m_Lock = NULL; } SENSOR_FunctionExit(Status); return Status; }
VOID ToastMon_EvtIoTargetRemoveComplete( WDFIOTARGET IoTarget ) /*++ Routine Description: Called when the Target device is removed ( either the target received IRP_MN_REMOVE_DEVICE or IRP_MN_SURPRISE_REMOVAL) Arguments: IoTarget - Return Value: --*/ { PDEVICE_EXTENSION deviceExtension; PTARGET_DEVICE_INFO targetDeviceInfo = NULL; KdPrint((("Device Removal (remove complete) Notification\n"))); PAGED_CODE(); targetDeviceInfo = GetTargetDeviceInfo(IoTarget); deviceExtension = targetDeviceInfo->DeviceExtension; // // Stop the timer // WdfTimerStop(targetDeviceInfo->TimerForPostingRequests, TRUE); // // Remove the target device from the collection. // WdfWaitLockAcquire(deviceExtension->TargetDeviceCollectionLock, NULL); WdfCollectionRemove(deviceExtension->TargetDeviceCollection, IoTarget); WdfWaitLockRelease(deviceExtension->TargetDeviceCollectionLock); // // Finally delete the target. // WdfObjectDelete(IoTarget); return; }
VOID ToastMon_EvtIoTargetRemoveCanceled( WDFIOTARGET IoTarget ) /*++ Routine Description: Called when the Target device received IRP_MN_CANCEL_REMOVE. This happens if another app or driver talking to the target device doesn't close handle or veto query-remove notification. Arguments: IoTarget - Return Value: --*/ { PTARGET_DEVICE_INFO targetDeviceInfo = NULL; WDF_IO_TARGET_OPEN_PARAMS openParams; NTSTATUS status; PAGED_CODE(); KdPrint((("Device Removal (remove cancelled) Notification\n"))); targetDeviceInfo = GetTargetDeviceInfo(IoTarget); // // Reopen the Target. // WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(&openParams); status = WdfIoTargetOpen(IoTarget, &openParams); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoTargetOpen failed 0x%x\n", status)); WdfObjectDelete(IoTarget); return; } // // Restart the timer. // WdfTimerStart(targetDeviceInfo->TimerForPostingRequests, WDF_REL_TIMEOUT_IN_SEC(1)); }
VOID kmdf1394_AsyncReadCompletion ( IN WDFREQUEST Request, IN WDFIOTARGET Target, IN PWDF_REQUEST_COMPLETION_PARAMS Params, IN WDFCONTEXT Context) /*++ Routine Description: Async Read completion routine. Arguments: Arguments: Request - UNUSED Target - UNUSED Params - UNUSED Context - Pointer to a WDFMemory Object Return Value: VOID --*/ { PIRB pIrb = NULL; UNREFERENCED_PARAMETER (Request); UNREFERENCED_PARAMETER (Target); UNREFERENCED_PARAMETER (Params); Enter(); ASSERT (Context); pIrb = (PIRB) WdfMemoryGetBuffer ((WDFMEMORY)Context, NULL); // // Just basic clean up here. // IoFreeMdl (pIrb->u.AsyncRead.Mdl); ExFreePoolWithTag (pIrb, POOLTAG_KMDF_VDEV); WdfObjectDelete ((WDFMEMORY) Context); Exit(); }
VOID kmdf1394_SubmitIrpAsyncCompletion ( IN WDFREQUEST Request, IN WDFIOTARGET Target, IN PWDF_REQUEST_COMPLETION_PARAMS Params, IN WDFCONTEXT Context) /*++ Routine Description: Asynchronous request completion routine Arguments: Request - current request object Target - I/O Target object Params - WDF request Parameter structure Context - any additional objects the request may need to clean up from the inital submission. Return Value: NTSTATUS value --*/ { // // Here we'll free our memory object from the async request. // UNREFERENCED_PARAMETER (Target); UNREFERENCED_PARAMETER (Request); ASSERT (Context); if (!NT_SUCCESS(Params->IoStatus.Status)) { TRACE( TL_ERROR, ("Request %x Failed with status %x\n", Request, Params->IoStatus.Status)); } WdfObjectDelete (Context); }
void AndroidUsbPipeFileObject::ResetPipePassiveCallbackEntry( WDFWORKITEM wdf_work_item) { ASSERT_IRQL_PASSIVE(); AndroidUsbWorkitemContext* context = GetAndroidUsbWorkitemContext(wdf_work_item); ASSERT((NULL != context) && (AndroidUsbWdfObjectTypeWorkitem == context->object_type)); if ((NULL == context) || (AndroidUsbWdfObjectTypeWorkitem != context->object_type)) { WdfObjectDelete(wdf_work_item); return; } // In the sample they reset the device if pipe reset failed AndroidUsbDeviceObject* wdf_device_ext = context->pipe_file_ext->device_object(); NTSTATUS status = context->pipe_file_ext->ResetPipe(); if (!NT_SUCCESS(status)) status = wdf_device_ext->ResetDevice(); WdfObjectDelete(wdf_work_item); }
/** * @brief deallocate callback item. * Must be called with lock held. * *Note* this is called only to deal with error cases. The normal * callback function re-adds the work item to the collection. * * @param[in] WorkItem allocated WorkItem to be freed. * */ VOID FreeWorkItem( IN WDFWORKITEM WorkItem) { PUSB_FDO_WORK_ITEM_CONTEXT context = WorkItemGetContext(WorkItem); NTSTATUS Status = WdfCollectionAdd(context->FdoContext->FreeWorkItems, WorkItem); if (!NT_SUCCESS(Status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": Device %p WdfCollectionAdd error %x, deleting instead.\n", context->FdoContext->WdfDevice, Status); WdfObjectDelete(WorkItem); } }
static VOID UsbChief_ReadWriteWorkItem(IN WDFWORKITEM WorkItem) { PWORKITEM_CONTEXT pItemContext; NTSTATUS status; UsbChief_DbgPrint(DEBUG_RW, ("called\n")); pItemContext = GetWorkItemContext(WorkItem); status = UsbChief_ResetPipe(pItemContext->Pipe); if (!NT_SUCCESS(status)) { status = UsbChief_ResetDevice(pItemContext->Device); if(!NT_SUCCESS(status)) UsbChief_DbgPrint(0, ("ResetDevice failed 0x%x\n", status)); } WdfObjectDelete(WorkItem); }
NTSTATUS VIOSerialPortEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) { PVIOSERIAL_PORT Port = RawPdoSerialPortGetData(Device)->port; PPORT_BUFFER buf; PSINGLE_LIST_ENTRY iter; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s TargetState: %d\n", __FUNCTION__, TargetState); Port->Removed = TRUE; VIOSerialDisableInterruptQueue(GetInQueue(Port)); WdfSpinLockAcquire(Port->InBufLock); VIOSerialDiscardPortDataLocked(Port); Port->InBuf = NULL; WdfSpinLockRelease(Port->InBufLock); VIOSerialReclaimConsumedBuffers(Port); while (buf = (PPORT_BUFFER)virtqueue_detach_unused_buf(GetInQueue(Port))) { VIOSerialFreeBuffer(buf); } iter = PopEntryList(&Port->WriteBuffersList); while (iter != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry); ExFreePoolWithTag(entry->Buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfObjectDelete(entry->EntryHandle); iter = PopEntryList(&Port->WriteBuffersList); }; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__); return STATUS_SUCCESS; }
NTSTATUS CyGetAndParseUSB30DeviceConfiguration(__in PDEVICE_CONTEXT pDevContext) { NTSTATUS NtStatus = STATUS_SUCCESS; WDFMEMORY pUsb30DeviceConfig =NULL; PVOID pUsb30DeviceConfigBuf =NULL; size_t szUsb30DeviceConfigBufSize =0; // Get Device configuration. NtStatus = CyGetUSB30DeviceConfiguration(pDevContext,&pUsb30DeviceConfig); if (NT_SUCCESS(NtStatus) && pUsb30DeviceConfig) { pUsb30DeviceConfigBuf = WdfMemoryGetBuffer(pUsb30DeviceConfig,&szUsb30DeviceConfigBufSize); //Parse and store the Enpoint companion descriptor CyParseAndStoreUSB30DeviceConfiguration(pDevContext,pUsb30DeviceConfigBuf,szUsb30DeviceConfigBufSize); // Delete the device configuration memory object as it's no longer needed WdfObjectDelete(pUsb30DeviceConfig); } return NtStatus; }
_Use_decl_annotations_ VOID BthEchoEvtConnectionObjectCleanup( WDFOBJECT ConnectionObject ) /*++ Description: This routine is invoked by the Framework when connection object gets deleted (either explicitly or implicitly because of parent deletion). Since we mark ExecutionLevel as passive for connection object we get this callback at passive level and can wait for stopping of continuous readers and for disconnect to complete. Arguments: ConnectionObject - The Connection Object Return Value: None --*/ { PBTHECHO_CONNECTION connection = GetConnectionObjectContext(ConnectionObject); PAGED_CODE(); BthEchoConnectionObjectWaitForAndUninitializeContinuousReader(connection); KeWaitForSingleObject(&connection->DisconnectEvent, Executive, KernelMode, FALSE, NULL); WdfObjectDelete(connection->ConnectDisconnectRequest); }
// This routine perform a simulator cleanup // Returns an NTSTATUS code NTSTATUS HardwareSimulator::Cleanup() { NTSTATUS status = STATUS_SUCCESS; if (SimulatorState_Started == m_State) { Stop(); } // Delete lock if (NULL != m_Lock) { WdfObjectDelete(m_Lock); m_Lock = NULL; } // Set the simulator state to "not initialized" m_State = SimulatorState_NotInitialized; return status; }
/** * @brief generic workitem callback function * calls the specific callback function in the work item context. * * @param[in] WorkItem handle to the workitem object. * */ VOID EvtFdoDeviceGenericWorkItem ( IN WDFWORKITEM WorkItem) { PUSB_FDO_WORK_ITEM_CONTEXT context = WorkItemGetContext(WorkItem); // // NULL indicates somebody screwed up, log it and forget it. // if (context->CallBack) { context->CallBack(WorkItem); } else { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": %s Device %p WorkItem %p NULL callback\n", context->FdoContext->FrontEndPath, context->FdoContext->WdfDevice, WorkItem); } context->CallBack = NULL; // // put this workitem into our collection. // AcquireFdoLock(context->FdoContext); NTSTATUS Status = WdfCollectionAdd(context->FdoContext->FreeWorkItems, WorkItem); ReleaseFdoLock(context->FdoContext); if (!NT_SUCCESS(Status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": %s Device %p WdfCollectionAdd error %x deleting workitem %p\n", context->FdoContext->FrontEndPath, context->FdoContext->WdfDevice, Status, WorkItem); // oh well delete it WdfObjectDelete(WorkItem); } }
VOID EchoEvtIoQueueContextDestroy( WDFOBJECT Object ) /*++ Routine Description: This is called when the Queue that our driver context memory is associated with is destroyed. Arguments: Context - Context that's being freed. Return Value: VOID --*/ { PQUEUE_CONTEXT queueContext = QueueGetContext(Object); // // Release any resources pointed to in the queue context. // // The body of the queue context will be released after // this callback handler returns // // // If Queue context has an I/O buffer, release it // if( queueContext->WriteMemory != NULL ) { WdfObjectDelete(queueContext->WriteMemory); queueContext->WriteMemory = NULL; } return; }
static VOID XenVbd_SendEventComplete(WDFREQUEST request, WDFIOTARGET target, PWDF_REQUEST_COMPLETION_PARAMS params, WDFCONTEXT context) { WDFDEVICE device = WdfIoTargetGetDevice(target); PXENVBD_FILTER_DATA xvfd = GetXvfd(device); NTSTATUS status; PSCSI_REQUEST_BLOCK srb = context; LARGE_INTEGER systemtime; ULONGLONG elapsed; UNREFERENCED_PARAMETER(params); UNREFERENCED_PARAMETER(context); status = WdfRequestGetStatus(request); if (status != 0 || srb->SrbStatus != SRB_STATUS_SUCCESS) { FUNCTION_MSG("Request Status = %08x, SRB Status = %08x\n", status, srb->SrbStatus); } KeQuerySystemTime(&systemtime); elapsed = systemtime.QuadPart - ((PLARGE_INTEGER)((PUCHAR)context + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL)))->QuadPart; elapsed = elapsed / 10000; // now in ms if (elapsed > 1000) { FUNCTION_MSG("Event took %d ms\n", (ULONG)elapsed); } ExFreePoolWithTag(context, XENVBD_POOL_TAG); WdfObjectDelete(request); for (;;) { if (InterlockedCompareExchange(&xvfd->event_state, 0, 1) == 1) { /* no pending event, and we cleared outstanding flag */ break; } if (InterlockedCompareExchange(&xvfd->event_state, 1, 2) == 2) { /* there was a pending event, and we set the flag back to outstanding */ //FUNCTION_MSG("sending pended event\n"); XenVbd_SendEvent(device); break; } /* event_state changed while we were looking at it, go round again */ } }
VOID Interface_DeletePipesAndQueues(__in PINTERFACE_CONTEXT interfaceContext) { UCHAR pipeIndex; for (pipeIndex = 0; pipeIndex < interfaceContext->PipeCount; pipeIndex++) { PPIPE_CONTEXT pipeContext = interfaceContext->PipeContextByIndex[pipeIndex]; // this needs to be re-initialized in subsequent code but we null it here // because nothing else should be using it at this point. interfaceContext->PipeContextByIndex[pipeIndex] = NULL; if (!pipeContext) { // should certainly never happen; indicates corrupted memory USBERRN("NULL pipeContext at index %u. Memory may be corrupt!", pipeIndex); continue; } // the context should always be marked invalid at this point // delete the queues for all pipes associated with this interface if (pipeContext->IsValid == FALSE && pipeContext->Queue != WDF_NO_HANDLE && (pipeContext->PipeInformation.EndpointAddress & 0xF)) { USBDBGN("pipeID=%02Xh Destroying pipe queue.", pipeContext->PipeInformation.EndpointAddress); WdfObjectDelete(pipeContext->Queue); pipeContext->Queue = WDF_NO_HANDLE; } // mark the pipe handle as null. The framework destroys these for us. pipeContext->Pipe = WDF_NO_HANDLE; } // set the pipe count to zero interfaceContext->PipeCount = 0; }
VOID Rio500_EvtReadWriteWorkItem( _In_ WDFWORKITEM WorkItem ) { PWORKITEM_CONTEXT pItemContext; NTSTATUS status; Rio500_DbgPrint(3, ("ReadWriteWorkItem called\n")); pItemContext = GetWorkItemContext(WorkItem); status = ResetPipe(pItemContext->Pipe); if (!NT_SUCCESS(status)) { Rio500_DbgPrint(1, ("ResetPipe failed 0x%x\n", status)); status = ResetDevice(pItemContext->Device); if (!NT_SUCCESS(status)) { Rio500_DbgPrint(1, ("ResetDevice failed 0x%x\n", status)); } } WdfObjectDelete(WorkItem); }
VOID PepWorkerWrapper ( _In_ WDFWORKITEM WorkItem ) /*++ Routine Description: This routine is wrapper for the actual worker routine that processes pending work. Arguments: WorkItem - Supplies a handle to the workitem supplying the context. Return Value: None. --*/ { PPEP_WORK_ITEM_CONTEXT Context; Context = PepGetWorkItemContext(WorkItem); PepProcessPendingWorkRequests(); // // Delete the work item as it is no longer required. // WdfObjectDelete(WorkItem); return; }
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 EchoEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This event is invoked when the framework receives IRP_MJ_WRITE request. This routine allocates memory buffer, copies the data from the request to it, and stores the buffer pointer in the queue-context with the length variable representing the buffers length. The actual completion of the request is defered to the periodic timer dpc. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. Length - number of bytes to be read. 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: VOID --*/ { NTSTATUS Status; WDFMEMORY memory; PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); PVOID writeBuffer = NULL; _Analysis_assume_(Length > 0); KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", Queue,Request,Length)); if( Length > MAX_WRITE_LENGTH ) { KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", Length,MAX_WRITE_LENGTH)); WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); return; } // Get the memory buffer Status = WdfRequestRetrieveInputMemory(Request, &memory); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n", Status)); WdfVerifierDbgBreakPoint(); WdfRequestComplete(Request, Status); return; } // Release previous buffer if set if( queueContext->WriteMemory != NULL ) { WdfObjectDelete(queueContext->WriteMemory); queueContext->WriteMemory = NULL; } Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES, NonPagedPool, 'sam1', Length, &queueContext->WriteMemory, &writeBuffer ); if(!NT_SUCCESS(Status)) { KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length)); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } // Copy the memory in Status = WdfMemoryCopyToBuffer( memory, 0, // offset into the source memory writeBuffer, Length ); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status)); WdfVerifierDbgBreakPoint(); WdfObjectDelete(queueContext->WriteMemory); queueContext->WriteMemory = NULL; WdfRequestComplete(Request, Status); return; } // Set transfer information WdfRequestSetInformation(Request, (ULONG_PTR)Length); // Specify the request is cancelable WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); // Defer the completion to another thread from the timer dpc queueContext->CurrentRequest = Request; queueContext->CurrentStatus = Status; return; }
// This routine is called by the framework when the PnP manager is revoking // ownership of our resources. This may be in response to either // IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. This routine is responsible for // performing cleanup of resources allocated in PrepareHardware callback. // This callback is invoked before passing the request down to the lower driver. // This routine will also be invoked by the framework if the prepare hardware // callback returns a failure. NTSTATUS CustomSensorDevice::OnReleaseHardware( _In_ WDFDEVICE Device, // Supplies a handle to the framework device object _In_ WDFCMRESLIST /*ResourcesTranslated*/) // Supplies a handle to a collection of framework // resource objects. This collection identifies the translated // (system-physical) hardware resources that have been assigned to the // device. The resources appear from the CPU's point of view. { PHardwareSimulator pSimulator = nullptr; PCustomSensorDevice pDevice = nullptr; SENSOROBJECT SensorInstance = nullptr; ULONG SensorInstanceCount = 1; // only expect 1 sensor instance NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); // Get sensor instance Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount); if (!NT_SUCCESS(Status) || 0 == SensorInstanceCount || NULL == SensorInstance) { Status = STATUS_INVALID_PARAMETER; TraceError("CSTM %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); goto Exit; } pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance); if (nullptr == pDevice) { Status = STATUS_INVALID_PARAMETER; TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status); goto Exit; } // Delete lock if (pDevice->m_Lock) { WdfObjectDelete(pDevice->m_Lock); pDevice->m_Lock = NULL; } // Cleanup the CO2 simulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("CSTM %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); goto Exit; } pSimulator->Cleanup(); // Delete hardware simulator instance if (NULL != pDevice->m_SimulatorInstance) { WdfObjectDelete(pDevice->m_SimulatorInstance); pDevice->m_SimulatorInstance = NULL; } // Delete sensor instance if (NULL != pDevice->m_SensorInstance) { WdfObjectDelete(pDevice->m_SensorInstance); } Exit: SENSOR_FunctionExit(Status); return Status; }
NTSTATUS PciDtfDeviceAllocDma(IN WDFDEVICE Device, IN WDFREQUEST Request) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_DMA_INFO *ReqData; WDF_OBJECT_ATTRIBUTES ObjectAttributes; WDFCOMMONBUFFER CommonBuffer = NULL; PCOMMON_BUFFER_DATA CommonBufferData; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&ObjectAttributes, COMMON_BUFFER_DATA); Status = WdfCommonBufferCreate(DeviceData->DmaEnabler, ReqData->len, &ObjectAttributes, &CommonBuffer); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfCommonBufferCreate", Status); __leave; } CommonBufferData = GetCommonBufferData(CommonBuffer); CommonBufferData->ID = PciDtfCommonBufferAssignId(DeviceData); Status = WdfCollectionAdd(DeviceData->CommonBuffers, CommonBuffer); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfCollectionAdd", Status); __leave; } ReqData->id = CommonBufferData->ID; ReqData->addr = WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart; WdfRequestSetInformation(Request, sizeof(PCIDTF_DMA_INFO)); TRACE_MSG(TRACE_LEVEL_VERBOSE, TRACE_FLAG_QUEUE, "va 0x%p, pa 0x%llX, len 0x%X\n", WdfCommonBufferGetAlignedVirtualAddress(CommonBuffer), WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart, WdfCommonBufferGetLength(CommonBuffer)); } __finally { if (!NT_SUCCESS(Status) && CommonBuffer != NULL) { WdfObjectDelete(CommonBuffer); } WdfRequestComplete(Request, Status); } return Status; }
NTSTATUS BthEchoCliRetrieveServerSdpRecord( __in PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, __out PBTH_SDP_STREAM_RESPONSE * ServerSdpRecord ) /*++ Description: Retrive server SDP record. We call this function on every file open to get the PSM Arguments: DevCtx - Client context ServerSdpRecord - SDP record retrieved Return Value: NTSTATUS Status code. --*/ { NTSTATUS status, statusReuse, disconnectStatus; WDF_MEMORY_DESCRIPTOR inMemDesc; WDF_MEMORY_DESCRIPTOR outMemDesc; WDF_REQUEST_REUSE_PARAMS ReuseParams; BTH_SDP_CONNECT connect = {0}; BTH_SDP_DISCONNECT disconnect = {0}; BTH_SDP_SERVICE_ATTRIBUTE_SEARCH_REQUEST requestSdp = {0}; BTH_SDP_STREAM_RESPONSE responseSdp = {0}; ULONG requestSize; PBTH_SDP_STREAM_RESPONSE serverSdpRecord = NULL; WDFREQUEST request; WDF_OBJECT_ATTRIBUTES attributes; PAGED_CODE(); // // Allocate the request we will use for obtaining sdp record // NOTE that we do it for every file open, hence we // // can't use reserve request from the context // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); status = WdfRequestCreate( &attributes, DevCtx->Header.IoTarget, &request ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Failed to allocate request for retriving server sdp record, Status code %!STATUS!\n", status); goto exit; } connect.bthAddress = DevCtx->ServerBthAddress; connect.requestTimeout = SDP_REQUEST_TO_DEFAULT; connect.fSdpConnect = 0; // // Connect to the SDP service. // WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &connect, sizeof(connect) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, &connect, sizeof(connect) ); status = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_CONNECT, &inMemDesc, &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "IOCTL_BTH_SDP_CONNECT failed, Status code %!STATUS!\n", status); goto exit1; } // // Obtain the required size of the SDP record // requestSdp.hConnection = connect.hConnection; requestSdp.uuids[0].u.uuid128 = BTHECHOSAMPLE_SVC_GUID; requestSdp.uuids[0].uuidType = SDP_ST_UUID128; requestSdp.range[0].minAttribute = 0; requestSdp.range[0].maxAttribute = 0xFFFF; WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &requestSdp, sizeof(requestSdp) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, &responseSdp, sizeof(responseSdp) ); status = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH, &inMemDesc, &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed while querying response size, " "status code %!STATUS!\n", status); goto exit2; } // // Allocate the required size for SDP record // status = RtlULongAdd( responseSdp.requiredSize, sizeof(BTH_SDP_STREAM_RESPONSE), &requestSize ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "SDP record size too large, status code %!STATUS!\n", status); goto exit2; } serverSdpRecord = ExAllocatePoolWithTag(NonPagedPool, requestSize, POOLTAG_BTHECHOSAMPLE); if (NULL == serverSdpRecord) { status = STATUS_INSUFFICIENT_RESOURCES; TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "Allocating SDP record failed, returning status code %!STATUS!\n", status); goto exit2; } // // Send request with required size // WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &requestSdp, sizeof(requestSdp) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, serverSdpRecord, requestSize ); status = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH, &inMemDesc, &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed, status code %!STATUS!\n", status); ExFreePoolWithTag(serverSdpRecord, POOLTAG_BTHECHOSAMPLE); } else { *ServerSdpRecord = serverSdpRecord; } exit2: // // Disconnect from SDP service. // WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); disconnect.hConnection = connect.hConnection; WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &disconnect, sizeof(disconnect) ); disconnectStatus = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_DISCONNECT, &inMemDesc, NULL, //outMemDesc NULL, //sendOptions NULL //bytesReturned ); ASSERT(NT_SUCCESS(disconnectStatus)); //Disconnect should not fail if (!NT_SUCCESS(disconnectStatus)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "IOCTL_BTH_SDP_DISCONNECT failed, Status code %!STATUS!\n", status); } exit1: WdfObjectDelete(request); exit: return status; }
// // PRE REQUIREMENTS: // * pipeContext->IsValid == FALSE // * Queue(if any) must be stopped // * IoTarget must be stopped // // On return the pipe and queue are started and the context is marked valid again. // NTSTATUS Pipe_InitContext(__in PDEVICE_CONTEXT deviceContext, __in PPIPE_CONTEXT pipeContext, __in BOOLEAN startIoTarget) { NTSTATUS status = STATUS_INVALID_HANDLE; WDFQUEUE queueOld = pipeContext->Queue; WDFQUEUE queueNew = NULL; if (!pipeContext->Pipe && pipeContext->PipeInformation.PipeType != WdfUsbPipeTypeControl) { USBERR("pipeID=%02Xh invalid pipe handle\n", pipeContext->PipeInformation.EndpointAddress); goto Done; } if (queueOld == NULL || ((pipeContext->PipeInformation.EndpointAddress & 0xF) && pipeContext->IsQueueDirty)) { pipeContext->IsQueueDirty = FALSE; if (queueOld != NULL) { // We need to delete the old pipe queue. USBDBGN("pipeID=%02Xh Destroying old pipe queue.", pipeContext->PipeInformation.EndpointAddress); WdfObjectDelete(queueOld); queueOld = NULL; } USBDBGN("pipeID=%02Xh Creating pipe queue.", pipeContext->PipeInformation.EndpointAddress); status = Pipe_InitQueue(deviceContext, pipeContext, &queueNew); if (!NT_SUCCESS(status)) { pipeContext->Queue = NULL; pipeContext->IsValid = FALSE; USBERRN("Pipe_InitQueue failed. pipeID=%02Xh status=%08Xh", pipeContext->PipeInformation.EndpointAddress, status); goto Done; } pipeContext->Queue = queueNew; } else { // Queue is already created and does not need to be updated. status = STATUS_SUCCESS; queueNew = queueOld; } if (!queueNew && NT_SUCCESS(status)) status = STATUS_INVALID_PIPE_STATE; if (NT_SUCCESS(status)) { if (pipeContext->PipeInformation.PipeType != WdfUsbPipeTypeControl) { if (startIoTarget) { // start pipe USBDBG("pipeID=%02Xh starting..\n", pipeContext->PipeInformation.EndpointAddress); status = PipeStart(pipeContext); if (!NT_SUCCESS(status)) { pipeContext->IsValid = FALSE; USBERR("WdfIoTargetStart failed. status=%Xh\n", status); goto Done; } } } // start queue USBDBG("pipeID=%02Xh queue starting..\n", pipeContext->PipeInformation.EndpointAddress); WdfIoQueueStart(queueNew); pipeContext->IsValid = TRUE; } else { USBERR("WdfIoQueueCreate failed. status=%Xh\n", status); pipeContext->IsValid = FALSE; goto Done; } Done: return status; }
NTSTATUS Pipe_InitQueue( __in PDEVICE_CONTEXT deviceContext, __in PPIPE_CONTEXT pipeContext, __out WDFQUEUE* queueRef) { WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status = STATUS_INVALID_HANDLE; WDFQUEUE queue = NULL; PQUEUE_CONTEXT queueContext; WDF_OBJECT_ATTRIBUTES memAttributes; WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.SynchronizationScope = WdfSynchronizationScopeQueue; *queueRef = NULL; // All queues get a context. At the very least, they will use a local copy of policy and pipe information WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objectAttributes, QUEUE_CONTEXT); queueConfig.DispatchType = WdfIoQueueDispatchInvalid; Pipe_InitQueueConfig(pipeContext, &queueConfig); if (queueConfig.DispatchType != WdfIoQueueDispatchInvalid) { status = WdfIoQueueCreate(deviceContext->WdfDevice, &queueConfig, &objectAttributes, &queue); if (!NT_SUCCESS(status)) { USBERR("WdfIoQueueCreate failed. pipeID=%02Xh status=%Xh\n", pipeContext->PipeInformation.EndpointAddress, status); goto Exit; } // Create the memory for partial read storage queueContext = GetQueueContext(queue); queueContext->IsFreshPipeReset = TRUE; // SET queueContext->OverOfs RtlZeroMemory(&queueContext->OverOfs, sizeof(queueContext->OverOfs)); // SET queueContext->PipeHandle queueContext->PipeHandle = pipeContext->Pipe; // SET queueContext->Info RtlCopyMemory(&queueContext->Info, &pipeContext->PipeInformation, sizeof(queueContext->Info)); WDF_OBJECT_ATTRIBUTES_INIT(&memAttributes); memAttributes.ParentObject = queue; // Only bulk and interrupt pipes have an OverMem buffer and it is only used // when the queue type is sequential. (RAW_IO=FALSE) if ((queueContext->Info.MaximumPacketSize) && (queueContext->Info.PipeType == WdfUsbPipeTypeBulk || queueContext->Info.PipeType == WdfUsbPipeTypeInterrupt)) { // SET queueContext->OverMem // SET queueContext->OverBuf status = WdfMemoryCreate(&memAttributes, NonPagedPool, POOL_TAG, queueContext->Info.MaximumPacketSize, &queueContext->OverMem, &queueContext->OverBuf); if (!NT_SUCCESS(status)) { USBERRN("WdfMemoryCreate failed. status=%08Xh", status); WdfObjectDelete(queue); goto Exit; } } } *queueRef = queue; Exit: return status; }
NTSTATUS NICInitiateDmaTransfer( IN PFDO_DATA FdoData, IN WDFREQUEST Request ) { WDFDMATRANSACTION dmaTransaction; NTSTATUS status; BOOLEAN bCreated = FALSE; do { // // Create a new DmaTransaction. // status = WdfDmaTransactionCreate( FdoData->WdfDmaEnabler, WDF_NO_OBJECT_ATTRIBUTES, &dmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionCreate failed %X\n", status); break; } bCreated = TRUE; // // Initialize the new DmaTransaction. // status = WdfDmaTransactionInitializeUsingRequest( dmaTransaction, Request, NICEvtProgramDmaFunction, WdfDmaDirectionWriteToDevice ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionInitalizeUsingRequest failed %X\n", status); break; } // // Execute this DmaTransaction. // status = WdfDmaTransactionExecute( dmaTransaction, dmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionExecute failed %X\n", status); break; } } WHILE (FALSE); if(!NT_SUCCESS(status)){ if(bCreated) { WdfObjectDelete( dmaTransaction ); } } return status; }
BOOLEAN NICEvtProgramDmaFunction( IN WDFDMATRANSACTION Transaction, IN WDFDEVICE Device, IN PVOID Context, IN WDF_DMA_DIRECTION Direction, IN PSCATTER_GATHER_LIST ScatterGather ) /*++ Routine Description: Arguments: Return Value: --*/ { PFDO_DATA fdoData; WDFREQUEST request; NTSTATUS status; UNREFERENCED_PARAMETER( Context ); UNREFERENCED_PARAMETER( Direction ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICEvtProgramDmaFunction\n"); fdoData = FdoGetData(Device); request = WdfDmaTransactionGetRequest(Transaction); WdfSpinLockAcquire(fdoData->SendLock); // // If tcb or link is not available, queue the request // if (!MP_TCB_RESOURCES_AVAIABLE(fdoData)) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "Resource is not available: queue Request %p\n", request); // // Must abort the transaction before deleting. // (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); ASSERT(NT_SUCCESS(status)); WdfObjectDelete( Transaction ); // // Queue the request for later processing. // status = WdfRequestForwardToIoQueue(request, fdoData->PendingWriteQueue); if(!NT_SUCCESS(status)) { ASSERTMSG(" WdfRequestForwardToIoQueue failed ", FALSE); WdfSpinLockRelease(fdoData->SendLock); WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); return FALSE; } fdoData->nWaitSend++; } else { status = NICWritePacket(fdoData, Transaction, ScatterGather); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- NICEvtProgramDmaFunction returning %!STATUS!\n", status); // // Must abort the transaction before deleting. // (VOID )WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); ASSERT(NT_SUCCESS(status)); WdfObjectDelete( Transaction ); WdfSpinLockRelease(fdoData->SendLock); WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); return FALSE; } } WdfSpinLockRelease(fdoData->SendLock); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICEvtProgramDmaFunction\n"); return TRUE; }