VOID VioCryptIoStop(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG ActionFlags) { BOOLEAN bCancellable = (ActionFlags & WdfRequestStopRequestCancelable) != 0; UNREFERENCED_PARAMETER(Queue); Trace(TRACE_LEVEL_INFORMATION, "[%s] Req %p, action %X, the request is %scancellable", __FUNCTION__, Request, ActionFlags, bCancellable ? "" : "not "); if (ActionFlags & WdfRequestStopActionSuspend) { // the driver owns the request and it will not be able to process it Trace(TRACE_LEVEL_INFORMATION, "[%s] Req %p can't be suspended", __FUNCTION__, Request); if (!bCancellable || WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { WdfRequestComplete(Request, STATUS_CANCELLED); } } else if (ActionFlags & WdfRequestStopActionPurge) { Trace(TRACE_LEVEL_INFORMATION, "[%s] Req %p purged", __FUNCTION__, Request); if (!bCancellable || WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { WdfRequestComplete(Request, STATUS_CANCELLED); } } }
VOID VIOSerialPortIoStop( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG ActionFlags ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue)); PVIOSERIAL_PORT pport = pdoData->port; ASSERT(pport->PendingReadRequest == Request); TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "-->%s\n", __FUNCTION__); WdfSpinLockAcquire(pport->InBufLock); if (ActionFlags & WdfRequestStopActionSuspend ) { WdfRequestStopAcknowledge(Request, FALSE); } else if(ActionFlags & WdfRequestStopActionPurge) { if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { pport->PendingReadRequest = NULL; WdfRequestCompleteWithInformation(Request , STATUS_CANCELLED, 0L); } } WdfSpinLockRelease(pport->InBufLock); return; }
VOID VIOSerialPortWriteIoStop(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG ActionFlags) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData( WdfIoQueueGetDevice(Queue)); PVIOSERIAL_PORT pport = pdoData->port; TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "--> %s\n", __FUNCTION__); WdfSpinLockAcquire(pport->OutVqLock); if (ActionFlags & WdfRequestStopActionSuspend) { WdfRequestStopAcknowledge(Request, FALSE); } else if (ActionFlags & WdfRequestStopActionPurge) { if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { pport->PendingWriteRequest = NULL; WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS); } } WdfSpinLockRelease(pport->OutVqLock); TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- %s\n", __FUNCTION__); }
VOID BalloonInterruptDpc( IN WDFINTERRUPT WdfInterrupt, IN WDFOBJECT WdfDevice ) { unsigned int len; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); BOOLEAN bHostAck = FALSE; UNREFERENCED_PARAMETER( WdfInterrupt ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> %s\n", __FUNCTION__); if (virtqueue_get_buf(devCtx->InfVirtQueue, &len)) { bHostAck = TRUE; } if (virtqueue_get_buf(devCtx->DefVirtQueue, &len)) { bHostAck = TRUE; } if(bHostAck) { KeSetEvent (&devCtx->HostAckEvent, IO_NO_INCREMENT, FALSE); } if (devCtx->StatVirtQueue && virtqueue_get_buf(devCtx->StatVirtQueue, &len)) { WDFREQUEST request = devCtx->PendingWriteRequest; devCtx->HandleWriteRequest = TRUE; if ((request != NULL) && (WdfRequestUnmarkCancelable(request) != STATUS_CANCELLED)) { NTSTATUS status; PVOID buffer; size_t length = 0; devCtx->PendingWriteRequest = NULL; status = WdfRequestRetrieveInputBuffer(request, 0, &buffer, &length); if (!NT_SUCCESS(status)) { length = 0; } WdfRequestCompleteWithInformation(request, status, length); } } if(devCtx->Thread) { KeSetEvent(&devCtx->WakeUpThread, 0, FALSE); } }
VOID VIOSerialReclaimConsumedBuffers(IN PVIOSERIAL_PORT Port) { WDFREQUEST request; PSINGLE_LIST_ENTRY iter; PVOID buffer; UINT len; struct virtqueue *vq = GetOutQueue(Port); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "--> %s\n", __FUNCTION__); if (vq) { while ((buffer = virtqueue_get_buf(vq, &len)) != NULL) { if (Port->PendingWriteRequest != NULL) { request = Port->PendingWriteRequest; Port->PendingWriteRequest = NULL; if (WdfRequestUnmarkCancelable(request) != STATUS_CANCELLED) { WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, (size_t)WdfRequestGetInformation(request)); } else { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_QUEUEING, "Request %p was cancelled.\n", request); } } iter = &Port->WriteBuffersList; while (iter->Next != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter->Next, WRITE_BUFFER_ENTRY, ListEntry); if (buffer == entry->Buffer) { iter->Next = entry->ListEntry.Next; ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG); } else { iter = iter->Next; } }; Port->OutVqFull = FALSE; } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "<-- %s Full: %d\n", __FUNCTION__, Port->OutVqFull); }
VOID SimSensorQueueIoStop ( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG ActionFlags ) /*++ Routine Description: This routine is called when the framework is stopping the request's I/O queue. Arguments: Queue - Supplies handle to the framework queue object that is associated with the I/O request. Request - Supplies handle to a framework request object. ActionFlags - Supplies the reason that the callback is being called. Return Value: None. --*/ { NTSTATUS Status; UNREFERENCED_PARAMETER(Queue); if(ActionFlags & WdfRequestStopRequestCancelable) { Status = WdfRequestUnmarkCancelable(Request); if (Status == STATUS_CANCELLED) { goto SimSensorQueueIoStopEnd; } NT_ASSERT(NT_SUCCESS(Status)); } WdfRequestStopAcknowledge(Request, FALSE); SimSensorQueueIoStopEnd: return; }
VOID VirtRngEvtIoRead(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { PDEVICE_CONTEXT context = GetDeviceContext(WdfIoQueueGetDevice(Queue)); NTSTATUS status; PVOID buffer; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> %!FUNC! Queue: %p Request: %p Length: %d", Queue, Request, (ULONG)Length); status = WdfRequestRetrieveOutputBuffer(Request, Length, &buffer, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestRetrieveOutputBuffer failed: %!STATUS!", status); WdfRequestComplete(Request, status); return; } status = WdfRequestMarkCancelableEx(Request, VirtRngEvtRequestCancel); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestMarkCancelableEx failed: %!STATUS!", status); WdfRequestComplete(Request, status); return; } status = VirtQueueAddBuffer(context, Request, Length); if (!NT_SUCCESS(status)) { if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { WdfRequestComplete(Request, status); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %!FUNC!"); }
VOID VirtRngEvtIoStop(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG ActionFlags) { UNREFERENCED_PARAMETER(Queue); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> %!FUNC! Request: %p", Request); if (ActionFlags & WdfRequestStopActionSuspend) { WdfRequestStopAcknowledge(Request, FALSE); } else if (ActionFlags & WdfRequestStopActionPurge) { if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { WdfRequestComplete(Request , STATUS_CANCELLED); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %!FUNC!"); }
VOID VIOSerialPortWriteIoStop(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG ActionFlags) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData( WdfIoQueueGetDevice(Queue)); PVIOSERIAL_PORT pport = pdoData->port; TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "--> %s\n", __FUNCTION__); WdfSpinLockAcquire(pport->OutVqLock); if (ActionFlags & WdfRequestStopActionSuspend) { WdfRequestStopAcknowledge(Request, FALSE); } else if (ActionFlags & WdfRequestStopActionPurge) { if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { PSINGLE_LIST_ENTRY iter = &pport->WriteBuffersList; while ((iter = iter->Next) != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry); if (entry->Request == Request) { entry->Request = NULL; break; } } WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS); } } WdfSpinLockRelease(pport->OutVqLock); TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- %s\n", __FUNCTION__); }
VOID EchoEvtTimerFunc( IN WDFTIMER Timer ) /*++ Routine Description: This is the TimerDPC the driver sets up to complete requests. This function is registered when the WDFTIMER object is created, and will automatically synchronize with the I/O Queue callbacks and cancel routine. Arguments: Timer - Handle to a framework Timer object. Return Value: VOID --*/ { NTSTATUS Status; WDFREQUEST Request; WDFQUEUE queue; PQUEUE_CONTEXT queueContext ; queue = WdfTimerGetParentObject(Timer); queueContext = QueueGetContext(queue); // // DPC is automatically synchronized to the Queue lock, // so this is race free without explicit driver managed locking. // Request = queueContext->CurrentRequest; if( Request != NULL ) { // // Attempt to remove cancel status from the request. // // The request is not completed if it is already cancelled // since the EchoEvtIoCancel function has run, or is about to run // and we are racing with it. // Status = WdfRequestUnmarkCancelable(Request); if( Status != STATUS_CANCELLED ) { queueContext->CurrentRequest = NULL; Status = queueContext->CurrentStatus; KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status)); WdfRequestComplete(Request, Status); } else { KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n", Request)); } } // // Restart the Timer since WDF does not allow periodic timer // with autosynchronization at passive level // WdfTimerStart(Timer, TIMER_PERIOD); return; }
VOID ControllerCompleteTransfer( _In_ PPBC_DEVICE pDevice, _In_ PPBC_REQUEST pRequest, _In_ BOOLEAN AbortSequence ) /*++ Routine Description: This routine completes a data transfer. Unless there are more transfers remaining in the sequence, the request is completed. Arguments: pDevice - a pointer to the PBC device context pRequest - a pointer to the PBC request context AbortSequence - specifies whether the driver should abort the ongoing sequence or begin the next transfer Return Value: None. The request is completed asynchronously. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); NT_ASSERT(pDevice != NULL); NT_ASSERT(pRequest != NULL); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Transfer (index %lu) %s with %Iu bytes for address 0x%lx " "(SPBREQUEST %p)", pRequest->TransferIndex, NT_SUCCESS(pRequest->Status) ? "complete" : "error", pRequest->Information, pDevice->pCurrentTarget->Settings.Address, pRequest->SpbRequest); // // Update request context with information from this transfer. // pRequest->TotalInformation += pRequest->Information; pRequest->Information = 0; // // Check if there are more transfers // in the sequence. // if (!AbortSequence) { pRequest->TransferIndex++; if (pRequest->TransferIndex < pRequest->TransferCount) { // // Configure the request for the next transfer. // pRequest->Status = PbcRequestConfigureForIndex( pRequest, pRequest->TransferIndex); if (NT_SUCCESS(pRequest->Status)) { // // Configure controller and kick-off read. // Request will be completed asynchronously. // PbcRequestDoTransfer(pDevice,pRequest); goto exit; } } } // // If not already cancelled, unmark request cancellable. // if (pRequest->Status != STATUS_CANCELLED) { NTSTATUS cancelStatus; cancelStatus = WdfRequestUnmarkCancelable(pRequest->SpbRequest); if (!NT_SUCCESS(cancelStatus)) { // // WdfRequestUnmarkCancelable should only fail if the request // has already been or is about to be cancelled. If it does fail // the request must NOT be completed - the cancel callback will do // this. // NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if the request has already been or is about to be cancelled", cancelStatus == STATUS_CANCELLED); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Failed to unmark SPBREQUEST %p as cancelable - %!STATUS!", pRequest->SpbRequest, cancelStatus); goto exit; } } // // Done or error occurred. Set interrupt mask to 0. // Doing this keeps the DPC from re-enabling interrupts. // PbcDeviceSetInterruptMask(pDevice, 0); // // Clear the target's current request. This will prevent // the request context from being accessed once the request // is completed (and the context is invalid). // pDevice->pCurrentTarget->pCurrentRequest = NULL; // // Clear the controller's current target if any of // 1. request is type sequence // 2. request position is single // (did not come between lock/unlock) // Otherwise wait until unlock. // if ((pRequest->Type == SpbRequestTypeSequence) || (pRequest->SequencePosition == SpbRequestSequencePositionSingle)) { pDevice->pCurrentTarget = NULL; } // // Mark the IO complete. Request not // completed here. // pRequest->bIoComplete = TRUE; exit: FuncExit(TRACE_FLAG_TRANSFER); }
VOID NfcCxSCPresentAbsentDispatcherCompleteRequest( _In_ PNFCCX_FDO_CONTEXT FdoContext, _In_ PNFCCX_SC_PRESENT_ABSENT_DISPATCHER Dispatcher ) /*++ Routine Description: If there is a request in the dispatcher, the request is completed. Arguments: FdoContext - Pointer to the FDO Context Dispatcher - Pointer to the Dispatcher Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS; TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); // Remove the current request from the dispatcher. WDFREQUEST request = (WDFREQUEST)InterlockedExchangePointer((void**)&Dispatcher->CurrentRequest, nullptr); // Check if another thread has already completed the request. if (request == nullptr) { // Nothing to do. goto Done; } WDFFILEOBJECT fileObject = WdfRequestGetFileObject(request); PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject); // Try to unset the request's cancel callback. status = WdfRequestUnmarkCancelable(request); if (status != STATUS_CANCELLED) { // The cancel callback will not be called. // So we have to release its ref-count for it. WdfObjectDereference(request); if (!NT_SUCCESS(status)) { // Something is pretty wrong. NT_ASSERT(false); TRACE_LINE(LEVEL_ERROR, "Failed to unset request canceled callback. %!STATUS!", status); goto Done; } } // Release power reference (if required). if (Dispatcher->PowerManaged) { NfcCxPowerFileRemoveReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); } // Complete the request WdfRequestComplete(request, STATUS_SUCCESS); Done: TRACE_FUNCTION_EXIT(LEVEL_VERBOSE); return; }
VOID VIOSerialPortWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status; PVOID InBuf; PVOID buffer; PVIOSERIAL_PORT Port; PWRITE_BUFFER_ENTRY entry; WDFDEVICE Device; PDRIVER_CONTEXT Context; WDFMEMORY EntryHandle; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> %s Request: %p Length: %d\n", __FUNCTION__, Request, Length); PAGED_CODE(); Device = WdfIoQueueGetDevice(Queue); Port = RawPdoSerialPortGetData(Device)->port; if (Port->Removed) { TraceEvents(TRACE_LEVEL_WARNING, DBG_WRITE, "Write request on a removed port %d\n", Port->PortId); WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS); return; } status = WdfRequestRetrieveInputBuffer(Request, Length, &InBuf, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to retrieve input buffer: %x\n", status); WdfRequestComplete(Request, status); return; } if (VIOSerialWillWriteBlock(Port)) { WdfRequestComplete(Request, STATUS_CANT_WAIT); return; } buffer = ExAllocatePoolWithTag(NonPagedPool, Length, VIOSERIAL_DRIVER_MEMORY_TAG); if (buffer == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate.\n"); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } Context = GetDriverContext(WdfDeviceGetDriver(Device)); status = WdfMemoryCreateFromLookaside(Context->WriteBufferLookaside, &EntryHandle); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate write buffer entry: %x.\n", status); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } status = WdfRequestMarkCancelableEx(Request, VIOSerialPortWriteRequestCancel); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to mark request as cancelable: %x\n", status); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfObjectDelete(EntryHandle); WdfRequestComplete(Request, status); return; } RtlCopyMemory(buffer, InBuf, Length); WdfRequestSetInformation(Request, (ULONG_PTR)Length); entry = (PWRITE_BUFFER_ENTRY)WdfMemoryGetBuffer(EntryHandle, NULL); entry->EntryHandle = EntryHandle; entry->Buffer = buffer; entry->Request = Request; if (VIOSerialSendBuffers(Port, entry, Length) <= 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to send user's buffer.\n"); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfObjectDelete(EntryHandle); if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED) { WdfRequestComplete(Request, Port->Removed ? STATUS_INVALID_DEVICE_STATE : STATUS_INSUFFICIENT_RESOURCES); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__); }
static VOID XenUsb_HandleEventDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2) { NTSTATUS status; PXENUSB_DEVICE_DATA xudd = context; RING_IDX prod, cons; usbif_urb_response_t *urb_rsp; usbif_conn_response_t *conn_rsp; usbif_conn_request_t *conn_req; int more_to_do; pvurb_t *pvurb, *complete_head = NULL, *complete_tail = NULL; partial_pvurb_t *partial_pvurb; BOOLEAN port_changed = FALSE; UNREFERENCED_PARAMETER(dpc); UNREFERENCED_PARAMETER(arg1); UNREFERENCED_PARAMETER(arg2); FUNCTION_ENTER(); more_to_do = TRUE; KeAcquireSpinLockAtDpcLevel(&xudd->urb_ring_lock); while (more_to_do) { prod = xudd->urb_ring.sring->rsp_prod; KeMemoryBarrier(); for (cons = xudd->urb_ring.rsp_cons; cons != prod; cons++) { urb_rsp = RING_GET_RESPONSE(&xudd->urb_ring, cons); // FUNCTION_MSG("urb_rsp->id = %d\n", urb_rsp->id); partial_pvurb = xudd->partial_pvurbs[urb_rsp->id]; RemoveEntryList(&partial_pvurb->entry); partial_pvurb->rsp = *urb_rsp; // FUNCTION_MSG("shadow = %p\n", shadow); // FUNCTION_MSG("shadow->rsp = %p\n", shadow->rsp); if (usbif_pipeunlink(partial_pvurb->req.pipe)) { FUNCTION_MSG("is a cancel request for request %p\n", partial_pvurb->pvurb->request); FUNCTION_MSG("urb_ring rsp status = %d\n", urb_rsp->status); // status should be 115 == EINPROGRESS } else { partial_pvurb->pvurb->total_length += urb_rsp->actual_length; if (!partial_pvurb->pvurb->rsp.status) partial_pvurb->pvurb->rsp.status = urb_rsp->status; partial_pvurb->pvurb->rsp.error_count += urb_rsp->error_count;; if (partial_pvurb->mdl) { int i; for (i = 0; i < partial_pvurb->req.nr_buffer_segs; i++) { XnEndAccess(xudd->handle, partial_pvurb->req.seg[i].gref, FALSE, (ULONG)'XUSB'); } } FUNCTION_MSG("urb_ring rsp id = %d\n", partial_pvurb->rsp.id); FUNCTION_MSG("urb_ring rsp start_frame = %d\n", partial_pvurb->rsp.start_frame); FUNCTION_MSG("urb_ring rsp status = %d\n", partial_pvurb->rsp.status); FUNCTION_MSG("urb_ring rsp actual_length = %d\n", partial_pvurb->rsp.actual_length); FUNCTION_MSG("urb_ring rsp error_count = %d\n", partial_pvurb->rsp.error_count); } if (partial_pvurb->other_partial_pvurb) { if (!partial_pvurb->other_partial_pvurb->on_ring) { /* cancel hasn't been put on the ring yet - remove it */ RemoveEntryList(&partial_pvurb->other_partial_pvurb->entry); ASSERT(usbif_pipeunlink(partial_pvurb->other_partial_pvurb->req.pipe)); partial_pvurb->pvurb->ref--; ExFreePoolWithTag(partial_pvurb->other_partial_pvurb, XENUSB_POOL_TAG); } } partial_pvurb->pvurb->ref--; switch (partial_pvurb->rsp.status) { case EINPROGRESS: /* unlink request */ case ECONNRESET: /* cancelled request */ ASSERT(partial_pvurb->pvurb->status == STATUS_CANCELLED); break; default: break; } put_id_on_freelist(xudd->req_id_ss, partial_pvurb->rsp.id); partial_pvurb->pvurb->next = NULL; if (!partial_pvurb->pvurb->ref) { if (complete_tail) { complete_tail->next = partial_pvurb->pvurb; } else { complete_head = partial_pvurb->pvurb; } complete_tail = partial_pvurb->pvurb; } } xudd->urb_ring.rsp_cons = cons; if (cons != xudd->urb_ring.req_prod_pvt) { RING_FINAL_CHECK_FOR_RESPONSES(&xudd->urb_ring, more_to_do); } else { xudd->urb_ring.sring->rsp_event = cons + 1; more_to_do = FALSE; } } PutRequestsOnRing(xudd); KeReleaseSpinLockFromDpcLevel(&xudd->urb_ring_lock); pvurb = complete_head; while (pvurb != NULL) { complete_head = pvurb->next; status = WdfRequestUnmarkCancelable(pvurb->request); if (status == STATUS_CANCELLED) { FUNCTION_MSG("Cancel was called\n"); } WdfRequestCompleteWithInformation(pvurb->request, pvurb->status, pvurb->total_length); /* the WDFREQUEST is always successfull here even if the pvurb->rsp has an error */ pvurb = complete_head; } more_to_do = TRUE; KeAcquireSpinLockAtDpcLevel(&xudd->conn_ring_lock); while (more_to_do) { prod = xudd->conn_ring.sring->rsp_prod; KeMemoryBarrier(); for (cons = xudd->conn_ring.rsp_cons; cons != prod; cons++) { USHORT old_port_status; conn_rsp = RING_GET_RESPONSE(&xudd->conn_ring, cons); FUNCTION_MSG("conn_rsp->portnum = %d\n", conn_rsp->portnum); FUNCTION_MSG("conn_rsp->speed = %d\n", conn_rsp->speed); old_port_status = xudd->ports[conn_rsp->portnum - 1].port_status; xudd->ports[conn_rsp->portnum - 1].port_type = conn_rsp->speed; xudd->ports[conn_rsp->portnum - 1].port_status &= ~((1 << PORT_LOW_SPEED) | (1 << PORT_HIGH_SPEED) | (1 << PORT_CONNECTION)); switch (conn_rsp->speed) { case USB_PORT_TYPE_NOT_CONNECTED: xudd->ports[conn_rsp->portnum - 1].port_status &= ~(1 << PORT_ENABLE); break; case USB_PORT_TYPE_LOW_SPEED: xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_LOW_SPEED) | (1 << PORT_CONNECTION); break; case USB_PORT_TYPE_FULL_SPEED: xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_CONNECTION); break; case USB_PORT_TYPE_HIGH_SPEED: xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_HIGH_SPEED) | (1 << PORT_CONNECTION); break; } xudd->ports[conn_rsp->portnum - 1].port_change |= (xudd->ports[conn_rsp->portnum - 1].port_status ^ old_port_status) & ((1 << PORT_ENABLE) | (1 << PORT_CONNECTION)); if (xudd->ports[conn_rsp->portnum - 1].port_change) port_changed = TRUE; conn_req = RING_GET_REQUEST(&xudd->conn_ring, xudd->conn_ring.req_prod_pvt); conn_req->id = conn_rsp->id; xudd->conn_ring.req_prod_pvt++; } xudd->conn_ring.rsp_cons = cons; if (cons != xudd->conn_ring.req_prod_pvt) { RING_FINAL_CHECK_FOR_RESPONSES(&xudd->conn_ring, more_to_do); } else { xudd->conn_ring.sring->rsp_event = cons + 1; more_to_do = FALSE; } } KeReleaseSpinLockFromDpcLevel(&xudd->conn_ring_lock); if (port_changed) { PXENUSB_PDO_DEVICE_DATA xupdd = GetXupdd(xudd->root_hub_device); XenUsbHub_ProcessHubInterruptEvent(xupdd->usb_device->configs[0]->interfaces[0]->endpoints[0]); } FUNCTION_EXIT(); return; }
NTSTATUS NfcCxSCPresentAbsentDispatcherSetRequest( _In_ PNFCCX_FDO_CONTEXT FdoContext, _In_ PNFCCX_SC_PRESENT_ABSENT_DISPATCHER Dispatcher, _In_ WDFREQUEST Request ) /*++ Routine Description: Stores a request in the dispatcher. If a request is already pending in the dispatcher, the new request will be completed with STATUS_DEVICE_BUSY. Arguments: FdoContext - Pointer to the FDO Context Dispatcher - Pointer to the Dispatcher. Request - The request to store in the dispatcher. Return Value: NTSTATUS --*/ { NTSTATUS status; bool powerReferenceAcquired = false; bool cancelCallbackSet = false; TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject); // Pre-check if there is a current request. if (ReadPointerAcquire((void**)&Dispatcher->CurrentRequest) != nullptr) { status = STATUS_DEVICE_BUSY; TRACE_LINE(LEVEL_ERROR, "An Is Present/Absent request is already pending. %!STATUS!", status); goto Done; } // Allocate and initialize the request context PNFCCX_SC_REQUEST_CONTEXT requestContext = nullptr; WDF_OBJECT_ATTRIBUTES contextAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&contextAttributes, NFCCX_SC_REQUEST_CONTEXT); status = WdfObjectAllocateContext(Request, &contextAttributes, (void**)&requestContext); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "Failed to set request's context. %!STATUS!", status); goto Done; } requestContext->Dispatcher = Dispatcher; // Add a power reference (if required). if (Dispatcher->PowerManaged) { status = NfcCxPowerFileAddReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_VERBOSE, "Failed to acquire power reference. %!STATUS!", status); goto Done; } powerReferenceAcquired = true; } // Setup cancel callback. status = WdfRequestMarkCancelableEx(Request, NfcCxSCPresentAbsentDispatcherRequestCanceled); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "Failed to set request canceled callback. %!STATUS!", status); goto Done; } // Add a ref-count to the request, which is owned by the cancel callback. WdfObjectReference(Request); cancelCallbackSet = true; // Try to set the current request. void* previousRequest = InterlockedCompareExchangePointer((void**)&Dispatcher->CurrentRequest, /*exchange*/ Request, /*compare*/ nullptr); // Check if we already have a pending request. if (previousRequest != nullptr) { status = STATUS_DEVICE_BUSY; TRACE_LINE(LEVEL_ERROR, "An Is Present/Absent request is already pending. %!STATUS!", status); goto Done; } Done: if (!NT_SUCCESS(status)) { if (cancelCallbackSet) { NTSTATUS unmarkStatus = WdfRequestUnmarkCancelable(Request); if (unmarkStatus != STATUS_CANCELLED) { // Cancel callback will not be called. // So release cancel callback's request ref-count. WdfObjectDereference(Request); } } if (powerReferenceAcquired) { NfcCxPowerFileRemoveReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); } } TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status); return status; }
VOID VirtRngEvtInterruptDpc(IN WDFINTERRUPT Interrupt, IN WDFOBJECT AssociatedObject) { PDEVICE_CONTEXT context = GetDeviceContext( WdfInterruptGetDevice(Interrupt)); struct virtqueue *vq = context->VirtQueue; PREAD_BUFFER_ENTRY entry; PSINGLE_LIST_ENTRY iter; NTSTATUS status; PVOID buffer; size_t bufferLen; unsigned int length; UNREFERENCED_PARAMETER(AssociatedObject); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "--> %!FUNC! Interrupt: %p", Interrupt); for (;;) { WdfSpinLockAcquire(context->VirtQueueLock); entry = (PREAD_BUFFER_ENTRY)virtqueue_get_buf(vq, &length); if (entry == NULL) { WdfSpinLockRelease(context->VirtQueueLock); break; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Got %p Request: %p Buffer: %p", entry, entry->Request, entry->Buffer); iter = &context->ReadBuffersList; while (iter->Next != NULL) { PREAD_BUFFER_ENTRY current = CONTAINING_RECORD(iter->Next, READ_BUFFER_ENTRY, ListEntry); if (entry == current) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Delete %p Request: %p Buffer: %p", entry, entry->Request, entry->Buffer); iter->Next = current->ListEntry.Next; break; } else { iter = iter->Next; } }; if ((entry->Request == NULL) || (WdfRequestUnmarkCancelable(entry->Request) == STATUS_CANCELLED)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "Ignoring a canceled read request: %p", entry->Request); entry->Request = NULL; } WdfSpinLockRelease(context->VirtQueueLock); if (entry->Request != NULL) { status = WdfRequestRetrieveOutputBuffer(entry->Request, length, &buffer, &bufferLen); if (NT_SUCCESS(status)) { length = min(length, (unsigned)bufferLen); RtlCopyMemory(buffer, entry->Buffer, length); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "Complete Request: %p Length: %d", entry->Request, length); WdfRequestCompleteWithInformation(entry->Request, STATUS_SUCCESS, (ULONG_PTR)length); } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestRetrieveOutputBuffer failed: %!STATUS!", status); WdfRequestComplete(entry->Request, status); } } ExFreePoolWithTag(entry->Buffer, VIRT_RNG_MEMORY_TAG); ExFreePoolWithTag(entry, VIRT_RNG_MEMORY_TAG); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- %!FUNC!"); }
VOID CleanupDisconnectedDevice( PUSB_FDO_CONTEXT fdoContext) { AcquireFdoLock(fdoContext); if (fdoContext->CtlrDisconnected) { ReleaseFdoLock(fdoContext); return; } fdoContext->CtlrDisconnected = TRUE; ReleaseFdoLock(fdoContext); WdfTimerStop(fdoContext->WatchdogTimer, TRUE); // --XT-- WdfDpcCancel(fdoContext->WdfDpc, TRUE); // // --XT-- This also looks like a reasonable place to turn off the event channel. // XenDisconnectDPC(fdoContext->Xen); AcquireFdoLock(fdoContext); FdoUnplugDevice(fdoContext); BOOLEAN completeRequest = TRUE; if (fdoContext->IdleRequest) { if (RequestGetRequestContext(fdoContext->IdleRequest)->RequestCompleted) { // should never happen if fdoContext->IdleRequest is not NULL. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": Device %p Request %p marked completed\n", fdoContext->WdfDevice, fdoContext->IdleRequest); completeRequest = FALSE; } else if (RequestGetRequestContext(fdoContext->IdleRequest)->CancelSet) { NTSTATUS Status = WdfRequestUnmarkCancelable(fdoContext->IdleRequest); if (!NT_SUCCESS(Status)) { if (Status == STATUS_CANCELLED) { // // don't complete the request here it is owned by the // cancel routine. XXX_TODO("Trace level probably too high"); TraceEvents(TRACE_LEVEL_WARNING, TRACE_DEVICE, __FUNCTION__": Device %p Request %p Cancelled\n", fdoContext->WdfDevice, fdoContext->IdleRequest); completeRequest = FALSE; } else { // // note but ignore. // TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": Device %p Request %p WdfRequestUnmarkCancelable error %x\n", fdoContext->WdfDevice, fdoContext->IdleRequest, Status); } } } WDFREQUEST idleRequest = fdoContext->IdleRequest; fdoContext->IdleRequest = NULL; if (completeRequest) { RequestGetRequestContext(idleRequest)->RequestCompleted = 0; ReleaseFdoLock(fdoContext); WdfRequestComplete(idleRequest, STATUS_CANCELLED); AcquireFdoLock(fdoContext); } } ReleaseFdoLock(fdoContext); if (fdoContext->XenConfigured) { CompleteRequestsFromShadow(fdoContext); } }
VOID VIOSerialPortWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status; PVOID InBuf; PVOID buffer; PVIOSERIAL_PORT Port; PWRITE_BUFFER_ENTRY entry; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> %s Request: %p Length: %d\n", __FUNCTION__, Request, Length); PAGED_CODE(); Port = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue))->port; if (Port->Removed) { TraceEvents(TRACE_LEVEL_WARNING, DBG_WRITE, "Write request on a removed port %d\n", Port->PortId); WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS); return; } status = WdfRequestRetrieveInputBuffer(Request, Length, &InBuf, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to retrieve input buffer: %x\n", status); WdfRequestComplete(Request, status); return; } if (VIOSerialWillWriteBlock(Port)) { WdfRequestComplete(Request, STATUS_CANT_WAIT); return; } buffer = ExAllocatePoolWithTag(NonPagedPool, Length, VIOSERIAL_DRIVER_MEMORY_TAG); if (buffer == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate.\n"); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } entry = (PWRITE_BUFFER_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(WRITE_BUFFER_ENTRY), VIOSERIAL_DRIVER_MEMORY_TAG); if (entry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate write buffer entry.\n"); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } status = WdfRequestMarkCancelableEx(Request, VIOSerialPortWriteRequestCancel); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to mark request as cancelable: %x\n", status); ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfRequestComplete(Request, status); return; } RtlCopyMemory(buffer, InBuf, Length); WdfRequestSetInformation(Request, (ULONG_PTR)Length); entry->Buffer = buffer; PushEntryList(&Port->WriteBuffersList, &entry->ListEntry); Port->PendingWriteRequest = Request; if (VIOSerialSendBuffers(Port, buffer, Length) <= 0) { PSINGLE_LIST_ENTRY removed; TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to send user's buffer.\n"); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); removed = PopEntryList(&Port->WriteBuffersList); NT_ASSERT(entry == CONTAINING_RECORD(removed, WRITE_BUFFER_ENTRY, ListEntry)); ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG); if ((Port->PendingWriteRequest != NULL) && (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)) { Port->PendingWriteRequest = NULL; WdfRequestComplete(Request, Port->Removed ? STATUS_INVALID_DEVICE_STATE : STATUS_INSUFFICIENT_RESOURCES); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__); }