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(); 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; } Port = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue))->port; if (VIOSerialWillWriteBlock(Port)) { WdfRequestComplete(Request, STATUS_CANT_WAIT); return; } status = WdfRequestMarkCancelableEx(Request, VIOSerialPortWriteRequestCancel); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to mark request as cancelable: %x\n", status); WdfRequestComplete(Request, status); 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; } 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); Port->PendingWriteRequest = NULL; WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__); }
VOID VIOSerialPortRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue)); size_t length; NTSTATUS status; PVOID systemBuffer; BOOLEAN nonBlock; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "-->%s\n", __FUNCTION__); nonBlock = ((WdfFileObjectGetFlags(WdfRequestGetFileObject(Request)) & FO_SYNCHRONOUS_IO) != FO_SYNCHRONOUS_IO); status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &length); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } WdfSpinLockAcquire(pdoData->port->InBufLock); if (!VIOSerialPortHasDataLocked(pdoData->port)) { if (!pdoData->port->HostConnected) { WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } else { ASSERT (pdoData->port->PendingReadRequest == NULL); status = WdfRequestMarkCancelableEx(Request, VIOSerialPortReadRequestCancel); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); } else { pdoData->port->PendingReadRequest = Request; } } } else { length = (ULONG)VIOSerialFillReadBufLocked(pdoData->port, systemBuffer, length); if (length) { WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR)length); } else { WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } } WdfSpinLockRelease(pdoData->port->InBufLock); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ,"<-- %s\n", __FUNCTION__); 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__); }
VOID VIOSerialPortRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue)); PVIOSERIAL_PORT pport = pdoData->port; size_t length; NTSTATUS status; PVOID systemBuffer; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "-->%s\n", __FUNCTION__); status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &length); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } WdfSpinLockAcquire(pport->InBufLock); if (!VIOSerialPortHasDataLocked(pport)) { if (!pport->HostConnected) { status = STATUS_INSUFFICIENT_RESOURCES; length = 0; } else { ASSERT (pport->PendingReadRequest == NULL); status = WdfRequestMarkCancelableEx(Request, VIOSerialPortReadRequestCancel); if (!NT_SUCCESS(status)) { length = 0; } else { pport->PendingReadRequest = Request; Request = NULL; } } } else { length = (ULONG)VIOSerialFillReadBufLocked(pport, systemBuffer, length); if (!length) { status = STATUS_INSUFFICIENT_RESOURCES; } } WdfSpinLockRelease(pport->InBufLock); if (Request != NULL) { // we are completing the request right here, either because of // an error or because data was available in the input buffer WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR)length); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ,"<-- %s\n", __FUNCTION__); }
static VOID XenUsb_EvtIoInternalDeviceControl_PVURB( WDFQUEUE queue, WDFREQUEST request, size_t output_buffer_length, size_t input_buffer_length, ULONG io_control_code) { NTSTATUS status; WDFDEVICE device = WdfIoQueueGetDevice(queue); PXENUSB_DEVICE_DATA xudd = GetXudd(device); WDF_REQUEST_PARAMETERS wrp; pvurb_t *pvurb; partial_pvurb_t *partial_pvurb; KIRQL old_irql; UNREFERENCED_PARAMETER(input_buffer_length); UNREFERENCED_PARAMETER(output_buffer_length); UNREFERENCED_PARAMETER(io_control_code); FUNCTION_ENTER(); ASSERT(io_control_code == IOCTL_INTERNAL_PVUSB_SUBMIT_URB); WDF_REQUEST_PARAMETERS_INIT(&wrp); WdfRequestGetParameters(request, &wrp); pvurb = (pvurb_t *)wrp.Parameters.Others.Arg1; ASSERT(pvurb); RtlZeroMemory(&pvurb->rsp, sizeof(pvurb->rsp)); pvurb->status = STATUS_SUCCESS; pvurb->request = request; pvurb->ref = 1; pvurb->total_length = 0; partial_pvurb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*partial_pvurb), XENUSB_POOL_TAG); /* todo - use lookaside */ if (!partial_pvurb) { WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); FUNCTION_EXIT(); return; } KeAcquireSpinLock(&xudd->urb_ring_lock, &old_irql); status = WdfRequestMarkCancelableEx(request, XenUsb_EvtRequestCancelPvUrb); if (!NT_SUCCESS(status)) { KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql); FUNCTION_MSG("WdfRequestMarkCancelableEx returned %08x\n", status); WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); FUNCTION_EXIT(); return; } partial_pvurb->req = pvurb->req; partial_pvurb->mdl = pvurb->mdl; /* 1:1 right now, but may need to split up large pvurb into smaller partial_pvurb's */ partial_pvurb->pvurb = pvurb; partial_pvurb->other_partial_pvurb = NULL; partial_pvurb->on_ring = FALSE; if (!partial_pvurb->mdl) { partial_pvurb->req.nr_buffer_segs = 0; partial_pvurb->req.buffer_length = 0; } else { ULONG remaining = MmGetMdlByteCount(partial_pvurb->mdl); USHORT offset = (USHORT)MmGetMdlByteOffset(partial_pvurb->mdl); int i; partial_pvurb->req.buffer_length = (USHORT)MmGetMdlByteCount(partial_pvurb->mdl); partial_pvurb->req.nr_buffer_segs = (USHORT)ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(partial_pvurb->mdl), MmGetMdlByteCount(partial_pvurb->mdl)); for (i = 0; i < partial_pvurb->req.nr_buffer_segs; i++) { partial_pvurb->req.seg[i].gref = XnGrantAccess(xudd->handle, (ULONG)MmGetMdlPfnArray(partial_pvurb->mdl)[i], FALSE, INVALID_GRANT_REF, (ULONG)'XUSB'); partial_pvurb->req.seg[i].offset = (USHORT)offset; partial_pvurb->req.seg[i].length = (USHORT)min((USHORT)remaining, (USHORT)PAGE_SIZE - offset); offset = 0; remaining -= partial_pvurb->req.seg[i].length; FUNCTION_MSG("seg = %d\n", i); FUNCTION_MSG(" gref = %d\n", partial_pvurb->req.seg[i].gref); FUNCTION_MSG(" offset = %d\n", partial_pvurb->req.seg[i].offset); FUNCTION_MSG(" length = %d\n", partial_pvurb->req.seg[i].length); } FUNCTION_MSG("buffer_length = %d\n", partial_pvurb->req.buffer_length); FUNCTION_MSG("nr_buffer_segs = %d\n", partial_pvurb->req.nr_buffer_segs); } InsertTailList(&xudd->partial_pvurb_queue, &partial_pvurb->entry); PutRequestsOnRing(xudd); KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql); FUNCTION_EXIT(); }
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; }