ULONG HwSimReadComponent( _In_ WDFDEVICE Device ) /*++ Routine Description: This routine simulates the reading of data from a component Arguments: Device - Handle to the framework device object Component - Component from which data is being read Return Value: A ULONG value representing the data that was read from the component --*/ { ULONG componentData; PHWSIM_CONTEXT devCtx; ULONG component = 0; Trace(TRACE_LEVEL_INFORMATION, "%!FUNC! Entry\n"); devCtx = HwSimGetDeviceContext(Device); // // Verify that the device is powered on // if (FALSE == devCtx->DevicePoweredOn) { // // This means that our driver is attempting to read from the component // while the device is not powered on. // Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Expected device to be powered on, but it was not."); WdfVerifierDbgBreakPoint(); } assert(devCtx->DevicePoweredOn); // // In this sample, component data is just a bit-wise complement of the // component number. // componentData = ~component; Trace(TRACE_LEVEL_INFORMATION, "%!FUNC! Exit\n"); return componentData; }
VOID HwSimFStateChange( _In_ WDFDEVICE Device, _In_ ULONG State ) /*++ Routine Description: This routine simulates a component changing its F-state Arguments: Device - Handle to the framework device object State - New F-state for the component Return Value: None --*/ { PHWSIM_CONTEXT devCtx; devCtx = HwSimGetDeviceContext(Device); // // Verify that the device is powered on // if (FALSE == devCtx->DevicePoweredOn) { // // This means that our driver is handling an F state transition while // device is not in D0. // Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Expected device to be powered on, but it was not."); WdfVerifierDbgBreakPoint(); } ASSERT(devCtx->DevicePoweredOn); // // Put the component in the requested F-state // devCtx->ComponentFState = State; // // For an actual hardware, save any hardware state on Fx transition // and restore state on F0 transition. // return; }
/* EvtIoStop Invoked for every inflight pipe write request. The callback executes when: 1) libusbK will stop the queue because of queue policy changes. 2) The system requests stand-by 3) The device is removed */ VOID Queue_OnStop( __in WDFQUEUE Queue, __in WDFREQUEST Request, __in ULONG ActionFlags) { PQUEUE_CONTEXT queueContext; PREQUEST_CONTEXT requestContext; if (Request == NULL || Queue == NULL) { USBERRN("Invalid wdf object."); return; } if ((queueContext = GetQueueContext(Queue)) == NULL) { USBERRN("Invalid queue context."); return; } if ((requestContext = GetRequestContext(Request)) == NULL) { USBERRN("Invalid request context."); return; } // None of the libusbK transfer functions set EvtRequestCancel, hence this should never happen. if (ActionFlags & WdfRequestStopRequestCancelable) { USBERRN("WdfRequestStopRequestCancelable! pipeID=%02Xh", queueContext->Info.EndpointAddress); WdfVerifierDbgBreakPoint(); return; } if (ActionFlags & WdfRequestStopActionSuspend) { USBDBGN("StopAcknowledge for ActionSuspend. pipeID=%02Xh request=%p timeout=%d", queueContext->Info.EndpointAddress, Request, requestContext->Timeout); WdfRequestStopAcknowledge(Request, FALSE); } else if(ActionFlags & WdfRequestStopActionPurge) { USBDBGN("CancelSentRequest for ActionPurge. pipeID=%02Xh request=%p timeout=%d", queueContext->Info.EndpointAddress, Request, requestContext->Timeout); WdfRequestCancelSentRequest(Request); } }
VOID HwSimFStateChange( _In_ WDFDEVICE Device, _In_ ULONG Component, _In_ ULONG State ) /*++ Routine Description: This routine simulates a component changing its F-state Arguments: Device - Handle to the framework device object Component - Index of the component whose F-state is changing State - New F-state for the component Return Value: None --*/ { PHWSIM_CONTEXT devCtx; devCtx = HwSimGetDeviceContext(Device); // // The caller should have ensured that this routine is called only when the // device is powered on. Verify this. If false, we'll generate a verifier // breakpoint. // if (FALSE == devCtx->DevicePoweredOn) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Expected device to be powered on, but it was not."); WdfVerifierDbgBreakPoint(); } // // Put the component in the requested F-state // devCtx->ComponentFState[Component] = State; return; }
VOID tgwinkEvtIoRead( WDFQUEUE Queue, WDFREQUEST Request, size_t Length ) { NTSTATUS status; WDFMEMORY mem; WDF_REQUEST_PARAMETERS params; ULONG offset; ULONG result; PDEVICE_CONTEXT context; WDFDEVICE device; device = WdfIoQueueGetDevice(Queue); context = DeviceGetContext(device); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms); offset = (ULONG)params.Parameters.Read.DeviceOffset; status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoRead could not get request memory buffer, status 0x%x\n", status); WdfVerifierDbgBreakPoint(); WdfRequestCompleteWithInformation(Request, status, 0); return; } result = context->busInterface.GetBusData(context->busInterface.Context, PCI_WHICHSPACE_CONFIG, WdfMemoryGetBuffer(mem, NULL), offset, (ULONG)Length); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)result); }
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; }
VOID EchoEvtIoRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_READ request. It will copy the content from the queue-context buffer to the request buffer. If the driver hasn't received any write request earlier, the read returns zero. 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; PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); WDFMEMORY memory; size_t writeMemoryLength; _Analysis_assume_(Length > 0); KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", Queue,Request,Length)); // // No data to read // if( (queueContext->WriteMemory == NULL) ) { WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L); return; } // // Read what we have // WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength); _Analysis_assume_(writeMemoryLength > 0); if( writeMemoryLength < Length ) { Length = writeMemoryLength; } // // Get the request memory // Status = WdfRequestRetrieveOutputMemory(Request, &memory); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status)); WdfVerifierDbgBreakPoint(); WdfRequestCompleteWithInformation(Request, Status, 0L); return; } // Copy the memory out Status = WdfMemoryCopyFromBuffer( memory, // destination 0, // offset into the destination memory WdfMemoryGetBuffer(queueContext->WriteMemory, NULL), Length ); if( !NT_SUCCESS(Status) ) { KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status)); WdfRequestComplete(Request, Status); return; } // Set transfer information WdfRequestSetInformation(Request, (ULONG_PTR)Length); // Mark the request is cancelable WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); // Defer the completion to another thread from the timer dpc queueContext->CurrentRequest = Request; queueContext->CurrentStatus = Status; return; }
VOID SingleCompEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: Callback invoked by WDFQUEUE for a Device Io Control request. Arguments: Queue - Device I/O control queue Request - Device I/O control request OutputBufferLength - Output buffer length for the I/O control InputBufferLength - Input buffer length for the I/O control IoControlCode - I/O control code --*/ { NTSTATUS status; PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL; WDFDEVICE device = NULL; ULONG componentData; ULONG_PTR information = 0; FDO_DATA *fdoContext = NULL; // // When we complete the request, make sure we don't get the I/O manager to // copy any more data to the client address space than what we write to the // output buffer. The only data that we write to the output buffer is the // component data and the C_ASSERT below ensures that the output buffer does // not have room to contain anything other than that. // C_ASSERT(sizeof(componentData) == sizeof(*outputBuffer)); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); // // This is a power-managed queue. So our queue stop/start logic should have // ensured that we are in the active condition when a request is dispatched // from this queue. // device = WdfIoQueueGetDevice(Queue); fdoContext = FdoGetContext(device); if (FALSE == fdoContext->IsActive) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - IOCTL %d was dispatched from WDFQUEUE %p when the " "component was not in an active condition.", IOCTL_POWERFX_READ_COMPONENT, Queue); WdfVerifierDbgBreakPoint(); } // // Validate Ioctl code // if (IOCTL_POWERFX_READ_COMPONENT != IoControlCode) { status = STATUS_NOT_SUPPORTED; Trace(TRACE_LEVEL_ERROR, "%!FUNC! -Unsupported IoControlCode. Expected: %d. Actual: %d." " %!status!.", IOCTL_POWERFX_READ_COMPONENT, IoControlCode, status); goto exit; } // // Get the output buffer // status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*outputBuffer), (PVOID*) &outputBuffer, NULL // Length ); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfRequestRetrieveOutputBuffer failed with %!status!.", status); goto exit; } // // Read the data from the component // componentData = HwSimReadComponent(device); outputBuffer->ComponentData = componentData; information = sizeof(*outputBuffer); status = STATUS_SUCCESS; exit: // // Complete the request // WdfRequestCompleteWithInformation(Request, status, information); return; }
VOID tgwinkEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) { WDFMEMORY mem; NTSTATUS status; WDFDEVICE dev; PDEVICE_CONTEXT context; void *uBase = NULL; LARGE_INTEGER offset; size_t size; dev = WdfIoQueueGetDevice(Queue); context = DeviceGetContext(dev); switch (IoControlCode) { case IOCTL_TGWINK_SAY_HELLO: if (OutputBufferLength != 4) { WdfRequestComplete(Request, STATUS_BAD_DATA); break; } status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfVerifierDbgBreakPoint(); WdfRequestComplete(Request, status); break; } *((DWORD32 *)(WdfMemoryGetBuffer(mem, NULL))) = 0x5a5aa5a5; WdfRequestComplete(Request, STATUS_SUCCESS); break; case IOCTL_TGWINK_MAP_BAR_0: if (sizeof(void *) > OutputBufferLength) { KdPrint("tgwinkEvtIoDeviceControl needs a larger buffer (%d > %d)!\n", sizeof(void *), OutputBufferLength); WdfRequestComplete(Request, STATUS_BUFFER_TOO_SMALL); break; } offset = context->bar[0].phyAddr; size = context->bar[0].length; status = ZwMapViewOfSection(context->hMemory, ZwCurrentProcess(), &uBase, 0, 0, &offset, &size, ViewUnmap, 0, PAGE_READWRITE); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not map view of section, status "); switch (status) { case STATUS_CONFLICTING_ADDRESSES: KdPrint("STATUS_CONFLICTING_ADDRESSES\n"); break; case STATUS_INVALID_PAGE_PROTECTION: KdPrint("STATUS_INVALID_PAGE_PROTECTION\n"); break; case STATUS_SECTION_PROTECTION: KdPrint("STATUS_SECTION_PROTECTION\n"); break; default: KdPrint("0x % x\n", status); break; } WdfRequestComplete(Request, status); break; } status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfVerifierDbgBreakPoint(); WdfRequestComplete(Request, status); break; } *((void **)(WdfMemoryGetBuffer(mem, NULL))) = uBase; WdfRequestComplete(Request, STATUS_SUCCESS); break; case IOCTL_TGWINK_READ_PHYS: { PVOID buf; ULONG_PTR page, ofs, vtgt = 0; SIZE_T vsz = 0; if (InputBufferLength != sizeof(PVOID)) { KdPrint("tgwinkEvtIoDeviceControl requires a %d-byte buffer for this ioctl (got %d)\n", sizeof(PVOID), OutputBufferLength); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); break; } status = WdfRequestRetrieveInputBuffer(Request, sizeof(PVOID), &buf, NULL); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } ofs = *((ULONG_PTR *)buf); page = ofs & ~0xfff; vsz = OutputBufferLength + (page ^ ofs); buf = NULL; status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } status = ZwMapViewOfSection(context->hMemory, (HANDLE)-1, (PVOID *)&vtgt, 0, 0, (PLARGE_INTEGER)&page, &vsz, ViewUnmap, 0, PAGE_READONLY); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not map view of physical memory section, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } ofs -= page; status = WdfMemoryCopyFromBuffer(mem, 0, (PVOID)(vtgt + ofs), OutputBufferLength); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to copy data from memory to buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } status = ZwUnmapViewOfSection((HANDLE)-1, (PVOID)vtgt); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to unmap view of physical memory section, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, OutputBufferLength); } break; case IOCTL_TGWINK_PEND_INTR: { WdfWaitLockAcquire(context->nnLock, NULL); if (context->notifyNext) { PINTERRUPT_CONTEXT pCtx = InterruptGetContext(context->hIrq); status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to retrieve output memory, status 0x%x\n", status); WdfRequestComplete(Request, status); } status = WdfMemoryCopyFromBuffer(mem, 0, &pCtx->serial, 8); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to copy interrupt number to buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); } WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, 8); context->notifyNext = 0; KdPrint("tgwinkEvtIoDeviceControl satisfied interrupt notification request synchronously.\n"); //WdfInterruptEnable(context->hIrq); } else { KdPrint("tgwinkEvtIoDeviceControl forwarding PEND_INTR request to notification queue\n"); WdfRequestForwardToIoQueue(Request, context->NotificationQueue); } WdfWaitLockRelease(context->nnLock); } break; default: WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); } }