NTSTATUS PciDtfDeviceGetInfo(IN WDFDEVICE Device, IN WDFREQUEST Request) { PCIDTF_DEV_INFO *ReqData; ULONG Value, Length; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PCIDTF_DEV_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } Status = WdfDeviceQueryProperty(Device, DevicePropertyBusNumber, sizeof(Value), &Value, &Length); if (!NT_SUCCESS(Status)) { TRACE_ERR ("WdfDeviceQueryProperty(DevicePropertyBusNumber)", Status); __leave; } ReqData->bus = (UINT8) Value; Status = WdfDeviceQueryProperty(Device, DevicePropertyAddress, sizeof(Value), &Value, &Length); if (!NT_SUCCESS(Status)) { TRACE_ERR ("WdfDeviceQueryProperty(DevicePropertyAddress)", Status); __leave; } ReqData->devfn = (UINT8) Value; ReqData->reg_count = (int) WdfCollectionGetCount(GetDeviceData(Device)->RegSpaces); TRACE_MSG(TRACE_LEVEL_VERBOSE, TRACE_FLAG_QUEUE, "bus=0x%X, devfn=0x%X, reg_count=%d\n", ReqData->bus, ReqData->devfn, ReqData->reg_count); WdfRequestSetInformation(Request, sizeof(PCIDTF_DEV_INFO)); } __finally { WdfRequestComplete(Request, Status); } return Status; }
// Fill in the given struct _HID_DEVICE_ATTRIBUTES // NTSTATUS HidFx2GetDeviceAttributes(_In_ WDFREQUEST hRequest) { NTSTATUS status = STATUS_SUCCESS; PHID_DEVICE_ATTRIBUTES pDeviceAttributes = NULL; PUSB_DEVICE_DESCRIPTOR pUsbDeviceDescriptor = NULL; PDEVICE_EXTENSION pDeviceInfo = NULL; TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); pDeviceInfo = GetDeviceContext(WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest))); status = WdfRequestRetrieveOutputBuffer(hRequest, sizeof (HID_DEVICE_ATTRIBUTES), &pDeviceAttributes, NULL); if (NT_SUCCESS(status)) { // Retrieve USB device descriptor saved in device context pUsbDeviceDescriptor = WdfMemoryGetBuffer(pDeviceInfo->hDeviceDescriptor, NULL); pDeviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES); pDeviceAttributes->VendorID = pUsbDeviceDescriptor->idVendor; pDeviceAttributes->ProductID = pUsbDeviceDescriptor->idProduct; pDeviceAttributes->VersionNumber = pUsbDeviceDescriptor->bcdDevice; // Report how many bytes were copied WdfRequestSetInformation(hRequest, sizeof (HID_DEVICE_ATTRIBUTES)); } else // WdfRequestRetrieveOutputBuffer failed { TraceErr(DBG_IOCTL, "(%!FUNC!) WdfRequestRetrieveOutputBuffer failed %!STATUS!\n", status); } TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status); return status; }
NTSTATUS PciDtfDeviceReadWriteReg(IN WDFDEVICE Device, IN WDFREQUEST Request, IN BOOLEAN Read) { PCIDTF_REG_DATA *ReqData; PREG_SPACE_DATA RegSpaceData; WDFOBJECT RegSpace; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_REG_DATA), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } Status = PciDtfRegSpaceGet(Device, ReqData->bar, &RegSpace); if (!NT_SUCCESS(Status)) { TRACE_ERR("PciDtfRegSpaceGet", Status); __leave; } RegSpaceData = GetRegSpaceData(RegSpace); if (Read) { Status = WdfRequestRetrieveOutputBuffer(Request, sizeof (PCIDTF_REG_DATA), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } Status = PciDtfRegSpaceRead(RegSpaceData, ReqData->off, ReqData->len, &ReqData->val); if (!NT_SUCCESS(Status)) { TRACE_ERR("PciDtfRegSpaceRead", Status); __leave; } WdfRequestSetInformation(Request, sizeof(PCIDTF_REG_DATA)); } else { Status = PciDtfRegSpaceWrite(RegSpaceData, ReqData->off, ReqData->len, ReqData->val); if (!NT_SUCCESS(Status)) { TRACE_ERR("PciDtfRegSpaceWrite", Status); __leave; } } } __finally { WdfRequestComplete(Request, Status); } return Status; }
static VOID XenBus_ProcessReadRequest(WDFQUEUE queue, WDFREQUEST request, size_t length) { NTSTATUS status; WDFFILEOBJECT file_object = WdfRequestGetFileObject(request); PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); ULONG dst_length = (ULONG)length; ULONG dst_offset = 0; ULONG copy_length; xenbus_read_queue_item_t *list_entry; PVOID buffer; UNREFERENCED_PARAMETER(queue); status = WdfRequestRetrieveOutputBuffer(request, length, &buffer, NULL); if (!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME, " WdfRequestRetrieveOutputBuffer failed status = %08x\n", status)); WdfRequestSetInformation(request, 0); return; } ASSERT(NT_SUCCESS(status)); // lazy? while(dst_offset < dst_length && (list_entry = (xenbus_read_queue_item_t *)RemoveHeadList(&xpdid->xenbus.read_list_head)) != (xenbus_read_queue_item_t *)&xpdid->xenbus.read_list_head) { copy_length = min(list_entry->length - list_entry->offset, dst_length - dst_offset); memcpy((PUCHAR)buffer + dst_offset, (PUCHAR)list_entry->data + list_entry->offset, copy_length); list_entry->offset += copy_length; dst_offset += copy_length; if (list_entry->offset == list_entry->length) { ExFreePoolWithTag(list_entry->data, XENPCI_POOL_TAG); ExFreePoolWithTag(list_entry, XENPCI_POOL_TAG); } else { InsertHeadList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry); } } WdfRequestSetInformation(request, dst_offset); FUNCTION_EXIT(); }
// // Internal Function: UartCtlGetDtrrts // VOID UartCtlGetDtrrts( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PULONG pBuffer; UCHAR regModemControl; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(ULONG), (PVOID*)(& pBuffer), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { regModemControl = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller); regModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE; *pBuffer = regModemControl; WdfRequestSetInformation(Request, sizeof(ULONG)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetBaudRate // VOID UartCtlGetBaudRate( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_BAUD_RATE pBaudRate = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_BAUD_RATE), (PVOID*)(& pBaudRate), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { // Acquires the interrupt lock and retrieves the current baud rate. WdfInterruptAcquireLock(pDevExt->WdfInterrupt); pBaudRate->BaudRate = pDevExt->CurrentBaud; WdfInterruptReleaseLock(pDevExt->WdfInterrupt); WdfRequestSetInformation(Request, sizeof(SERIAL_BAUD_RATE)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetModemControl // VOID UartCtlGetModemControl( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PULONG pBuffer; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(ULONG), (PVOID*)(&pBuffer), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { // Acquires the interrupt lock and reads the modem control register. WdfInterruptAcquireLock(pDevExt->WdfInterrupt); *pBuffer = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); WdfRequestSetInformation(Request, sizeof(ULONG)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetStats // VOID UartCtlGetStats( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIALPERF_STATS pStats = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIALPERF_STATS), (PVOID*)(& pStats), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { WdfInterruptAcquireLock(pDevExt->WdfInterrupt); *pStats = pDevExt->PerfStats; WdfInterruptReleaseLock(pDevExt->WdfInterrupt); WdfRequestSetInformation(Request, sizeof(SERIALPERF_STATS)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
NTSTATUS PciDtfDeviceReadWriteCfg(IN WDFDEVICE Device, IN WDFREQUEST Request, IN BOOLEAN Read) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_CFG_DATA *ReqData; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_CFG_DATA), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } if (Read) { Status = WdfRequestRetrieveOutputBuffer(Request, sizeof (PCIDTF_CFG_DATA), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } Status = PciDtfConfigRead(&DeviceData->BusIntf, ReqData->off, ReqData->len, &ReqData->val); if (!NT_SUCCESS(Status)) { TRACE_ERR("PciDtfConfigRead", Status); __leave; } WdfRequestSetInformation(Request, sizeof(PCIDTF_CFG_DATA)); } else { Status = PciDtfConfigWrite(&DeviceData->BusIntf, ReqData->off, ReqData->len, ReqData->val); if (!NT_SUCCESS(Status)) { TRACE_ERR("PciDtfConfigWrite", Status); __leave; } } } __finally { WdfRequestComplete(Request, Status); } return Status; }
// // Internal Function: UartCtlGetHandflow // VOID UartCtlGetHandflow( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_HANDFLOW pHandFlow = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_HANDFLOW), (PVOID*)(& pHandFlow), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { *pHandFlow = pDevExt->HandFlow; WdfRequestSetInformation(Request, sizeof(SERIAL_HANDFLOW)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
NTSTATUS PciDtfDeviceGetDma(IN WDFDEVICE Device, IN WDFREQUEST Request) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_DMA_INFO *ReqData; WDFCOMMONBUFFER CommonBuffer; 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; } CommonBuffer = PciDtfCommonBufferFind(DeviceData, ReqData->id, FALSE); if (CommonBuffer == NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } ReqData->addr = WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart; ReqData->len = (int)WdfCommonBufferGetLength(CommonBuffer); WdfRequestSetInformation(Request, sizeof(PCIDTF_DMA_INFO)); } __finally { WdfRequestComplete(Request, Status); } return Status; }
NTSTATUS PciDtfDeviceGetReg(IN WDFDEVICE Device, IN WDFREQUEST Request) { PCIDTF_REG_INFO *ReqData; WDFOBJECT RegSpace; PREG_SPACE_DATA RegSpaceData; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_REG_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } Status = PciDtfRegSpaceGet(Device, ReqData->bar, &RegSpace); if (!NT_SUCCESS(Status)) { TRACE_ERR("PciDtfRegSpaceGet", Status); __leave; } RegSpaceData = GetRegSpaceData(RegSpace); if (RegSpaceData->ResourceDesc.Type == CmResourceTypePort) { ReqData->len = RegSpaceData->ResourceDesc.u.Port.Length; ReqData->addr = RegSpaceData->ResourceDesc.u.Port.Start.QuadPart; } else { ReqData->len = RegSpaceData->ResourceDesc.u.Memory.Length; ReqData->addr = RegSpaceData->ResourceDesc.u.Memory.Start.QuadPart; } WdfRequestSetInformation(Request, sizeof(PCIDTF_REG_INFO)); } __finally { WdfRequestComplete(Request, Status); } return Status; }
VOID UsbSamp_EvtReadWriteCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, _In_ WDFCONTEXT Context ) /*++ Routine Description: This is the completion routine for reads/writes If the irp completes with success, we check if we need to recirculate this irp for another stage of transfer. Arguments: Context - Driver supplied context Device - Device handle Request - Request handle Params - request completion params Return Value: None --*/ { PMDL requestMdl; WDFUSBPIPE pipe; ULONG stageLength; NTSTATUS status; PREQUEST_CONTEXT rwContext; PURB urb; PCHAR operation; ULONG bytesReadWritten; ULONG maxTransferSize; PDEVICE_CONTEXT deviceContext; rwContext = GetRequestContext(Request); deviceContext = Context; if (rwContext->Read) { operation = "Read"; } else { operation = "Write"; } pipe = (WDFUSBPIPE) Target ; status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)){ // // Queue a workitem to reset the pipe because the completion could be // running at DISPATCH_LEVEL. // QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); goto End; } urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL); bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; rwContext->Numxfer += bytesReadWritten; // // If there is anything left to transfer. // if (rwContext->Length == 0) { // // this is the last transfer // WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } // // Start another transfer // UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation)); // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (rwContext->Length > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = rwContext->Length; } // // Following call is required to free any mapping made on the partial MDL // and reset internal MDL state. // MmPrepareMdlForReuse(rwContext->Mdl); if (rwContext->Read) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed %x\n", status)); goto End; } } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed %x\n", status)); goto End; } } IoBuildPartialMdl(requestMdl, rwContext->Mdl, (PVOID) rwContext->VirtualAddress, stageLength); // // reinitialize the urb // urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength; rwContext->VirtualAddress += stageLength; rwContext->Length -= stageLength; // // Format the request to send a URB to a USB pipe. // status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, rwContext->UrbMemory, NULL); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // Send the request asynchronously. // if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation)); status = WdfRequestGetStatus(Request); goto End; } // // Else when the request completes, this completion routine will be // called again. // return; End: // // We are here because the request failed or some other call failed. // Dump the request context, complete the request and return. // DbgPrintRWContext(rwContext); IoFreeMdl(rwContext->Mdl); UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n", operation, status)); WdfRequestComplete(Request, status); return; }
// // Internal Function: UartCtlGetProperties // VOID UartCtlGetProperties( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PSERIAL_COMMPROP pProps = NULL; ULONG bufferSize; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_COMMPROP), (PVOID*)(& pProps), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { RtlZeroMemory(pProps, sizeof(SERIAL_COMMPROP)); pProps->PacketLength = sizeof(SERIAL_COMMPROP); pProps->PacketVersion = 2; pProps->ServiceMask = SERIAL_SP_SERIALCOMM; pProps->MaxTxQueue = 0; pProps->MaxRxQueue = MAXLONG; pProps->MaxBaud = UartMaxBaudRate; pProps->SettableBaud = SERIAL_BAUD_USER; pProps->ProvSubType = SERIAL_SP_UNSPECIFIED; pProps->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS | SERIAL_PCF_CD | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS; pProps->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT; pProps->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; pProps->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; SerCxGetRingBufferUtilization(Device, NULL, &bufferSize); pProps->CurrentTxQueue = 0; pProps->CurrentRxQueue = bufferSize; WdfRequestSetInformation(Request, sizeof(SERIAL_COMMPROP)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetCommstatus // VOID UartCtlGetCommstatus( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_STATUS pStat = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_STATUS), (PVOID*)(& pStat), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { WdfSpinLockAcquire(pDevExt->DpcSpinLock); pStat->Errors = pDevExt->ErrorWord; pDevExt->ErrorWord = 0; WdfSpinLockRelease(pDevExt->DpcSpinLock); // // Software flow control and in-band signaling // have not been implemented in this samples. Parameters // such as HoldReasons, AmountInIn/OutQueue, and // WaitForImmediate have not been populated. // WdfRequestSetInformation(Request, sizeof(SERIAL_STATUS)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// Finds the HID descriptor and copies it into the buffer provided by the Request. // NTSTATUS HidFx2GetHidDescriptor(_In_ WDFDEVICE hDevice, _In_ WDFREQUEST hRequest) { NTSTATUS status = STATUS_SUCCESS; size_t cBytesToCopy = 0; WDFMEMORY memory; PDEVICE_EXTENSION pDevContext = NULL; HID_DESCRIPTOR hidDescriptor; TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); status = WdfRequestRetrieveOutputMemory(hRequest, &memory); if (NT_SUCCESS(status)) { hidDescriptor.bLength= sizeof(hidDescriptor); // length of HID descriptor hidDescriptor.bDescriptorType= HID_HID_DESCRIPTOR_TYPE; // descriptor type == HID 0x21 hidDescriptor.bcdHID= HID_CLASS_SPEC_RELEASE_1_00; // hid spec release hidDescriptor.bCountry= HID_COUNTRY_NON_LOCALIZED; // country code hidDescriptor.bNumDescriptors= 0x01; // number of HID class descriptors hidDescriptor.DescriptorList[0].bReportType =HID_REPORT_DESCRIPTOR_TYPE; hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_ButtonDescriptor); pDevContext = GetDeviceContext(hDevice); if (pDevContext != NULL) { // Set length of non default report descriptor switch (pDevContext->driverMode) { case DM_BUTTON_AND_LED: hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_ButtonWithLedDescriptor); break; case DM_SLIDER_SWITCH: hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_SliderSwitchDescriptor); break; case DM_SLIDER_SWITCH_AND_LED: hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_SliderSwitchWithLedDescriptor); break; case DM_LED_ONLY: hidDescriptor.DescriptorList[0].wReportLength = sizeof(c_LedOnlyDescriptor); break; default: break; } } cBytesToCopy = hidDescriptor.bLength; if (cBytesToCopy != 0) { status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID)&hidDescriptor, cBytesToCopy); if (NT_SUCCESS(status)) { // Report how many bytes were copied WdfRequestSetInformation(hRequest, cBytesToCopy); } else // WdfMemoryCopyFromBuffer failed { TraceErr(DBG_IOCTL, "(%!FUNC!) WdfMemoryCopyFromBuffer failed %!STATUS!\n", status); return status; } } else // length is zero { status = STATUS_INVALID_DEVICE_STATE; TraceErr(DBG_IOCTL, "(%!FUNC!) c_DefaultHidDescriptor is zero, %!STATUS!\n", status); return status; } } else // WdfRequestRetrieveOutputMemory failed { TraceErr(DBG_IOCTL, " (%!FUNC!) WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); return status; } TraceVerbose(DBG_IOCTL, " (%!FUNC!) HidFx2GetHidDescriptor Exit = %!STATUS!\n", status); return status; }
// Finds the Report descriptor and copies it into the buffer provided by the Request. // NTSTATUS HidFx2GetReportDescriptor(_In_ WDFDEVICE hDevice, _In_ WDFREQUEST hRequest) { NTSTATUS status = STATUS_SUCCESS; WDFMEMORY memory; PDEVICE_EXTENSION pDevContext = NULL; PVOID pBuffer = (PVOID)c_ButtonDescriptor; size_t cBytesToCopy = sizeof(c_ButtonDescriptor); TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); status = WdfRequestRetrieveOutputMemory(hRequest, &memory); if (NT_SUCCESS(status)) { pDevContext = GetDeviceContext(hDevice); if (pDevContext != NULL) { // Select a non default report descriptor switch (pDevContext->driverMode) { case DM_BUTTON_AND_LED: pBuffer = (PVOID)c_ButtonWithLedDescriptor; cBytesToCopy = sizeof(c_ButtonWithLedDescriptor); break; case DM_SLIDER_SWITCH: pBuffer = (PVOID)c_SliderSwitchDescriptor; cBytesToCopy = sizeof(c_SliderSwitchDescriptor); break; case DM_SLIDER_SWITCH_AND_LED: pBuffer = (PVOID)c_SliderSwitchWithLedDescriptor; cBytesToCopy = sizeof(c_SliderSwitchWithLedDescriptor); break; case DM_LED_ONLY: pBuffer = (PVOID)c_LedOnlyDescriptor; cBytesToCopy = sizeof(c_LedOnlyDescriptor); break; default: break; } } if (cBytesToCopy != 0) { status = WdfMemoryCopyFromBuffer(memory, 0, pBuffer, cBytesToCopy); if (NT_SUCCESS(status)) { // Report how many bytes were copied WdfRequestSetInformation(hRequest, cBytesToCopy); } else // WdfMemoryCopyFromBuffer failed { TraceErr(DBG_IOCTL, "(%!FUNC!) WdfMemoryCopyFromBuffer failed %!STATUS!\n", status); } } else // report length is zero { status = STATUS_INVALID_DEVICE_STATE; TraceErr(DBG_IOCTL, "(%!FUNC!) c_DefaultHidDescriptor's reportLength is zero, %!STATUS!\n", status); } } else // WdfRequestRetrieveOutputMemory failed { TraceErr(DBG_IOCTL, "(%!FUNC!)WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); } TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status); return status; }
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__); }
/*++ Routine Description: This is the completion routine for reads/writes If the irp completes with success, we check if we need to recirculate this irp for another stage of transfer. Arguments: Context - Driver supplied context Device - Device handle Request - Request handle Params - request completion params Return Value: None --*/ VOID ReadWriteCompletion(IN WDFREQUEST Request, IN WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, IN WDFCONTEXT Context) { PMDL requestMdl; WDFUSBPIPE pipe; ULONG stageLength; NTSTATUS status; PREQUEST_CONTEXT rwContext; PURB urb; PCHAR operation; ULONG bytesReadWritten; UNREFERENCED_PARAMETER(Context); rwContext = GetRequestContext(Request); PSDrv_DbgPrint(3, ("ReadWriteCompletion - begins\n")); if (rwContext->Read) { operation = "Read"; } else { operation = "Write"; } pipe = (WDFUSBPIPE)Target; status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)) { goto End; } urb = (PURB)WdfMemoryGetBuffer(rwContext->UrbMemory, NULL); bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; rwContext->Numxfer += bytesReadWritten; // If there is anything left to transfer. if (rwContext->Length == 0) { // this is the last transfer WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } // Start another transfer PSDrv_DbgPrint(3, ("Stage next %s transfer...\n", operation)); if (rwContext->Length > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = rwContext->Length; } // Following call is required to free any mapping made on the partial MDL and reset internal MDL state. MmPrepareMdlForReuse(rwContext->Mdl); if (rwContext->Read) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed! (Status = %x)\n", status)); goto End; } } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed! (Status = %x)\n", status)); goto End; } } IoBuildPartialMdl(requestMdl, rwContext->Mdl, (PVOID)rwContext->VirtualAddress, stageLength); // Reinitialize the urb urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength; rwContext->VirtualAddress += stageLength; rwContext->Length -= stageLength; // Format the request to send a URB to a USB pipe. status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, rwContext->UrbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Send the request asynchronously. if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { PSDrv_DbgPrint(1, ("WdfRequestSend for %s failed!\n", operation)); status = WdfRequestGetStatus(Request); goto End; } // Else when the request completes, this completion routine will be called again. PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 1\n")); return; End: // Dump the request context, complete the request and return. PSDrv_DbgPrint(3, ("rwContext->UrbMemory = %p\n", rwContext->UrbMemory)); PSDrv_DbgPrint(3, ("rwContext->Mdl = %p\n", rwContext->Mdl)); PSDrv_DbgPrint(3, ("rwContext->Length = %d\n", rwContext->Length)); PSDrv_DbgPrint(3, ("rwContext->Numxfer = %d\n", rwContext->Numxfer)); PSDrv_DbgPrint(3, ("rwContext->VirtualAddress = %p\n", rwContext->VirtualAddress)); IoFreeMdl(rwContext->Mdl); PSDrv_DbgPrint(3, ("Bulk or Interrupt %s request has finished. (Status = %x)\n", operation, status)); WdfRequestComplete(Request, status); PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 2\n")); 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__); }
// // Internal Function: UartCtlGetLineControl // VOID UartCtlGetLineControl( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); UCHAR lineControlRegister = 0; PSERIAL_LINE_CONTROL pLineControl = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_LINE_CONTROL), (PVOID*)(& pLineControl), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { // Acquires the interrupt lock and reads the LCR. WdfInterruptAcquireLock(pDevExt->WdfInterrupt); lineControlRegister = READ_LINE_CONTROL(pDevExt, pDevExt->Controller); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); status = UartRegLCRToStruct(lineControlRegister, pLineControl); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to calculate SERIAL_LINE_CONTROL from LCR %c - " "%!STATUS!", lineControlRegister, status); } } if (NT_SUCCESS(status)) { WdfRequestSetInformation(Request, sizeof(SERIAL_LINE_CONTROL)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
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 bareflankEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) { PVOID in = 0; PVOID out = 0; size_t in_size = 0; size_t out_size = 0; int64_t ret = 0; NTSTATUS status; UNREFERENCED_PARAMETER(Queue); if (InputBufferLength != 0) { status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &in, &in_size); if (!NT_SUCCESS(status)) goto FAILURE; } if (OutputBufferLength != 0) { status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &out, &out_size); if (!NT_SUCCESS(status)) goto FAILURE; } switch (IoControlCode) { case IOCTL_ADD_MODULE: ret = ioctl_add_module((char *)in, (int64_t)in_size); break; case IOCTL_LOAD_VMM: ret = ioctl_load_vmm(); break; case IOCTL_UNLOAD_VMM: ret = ioctl_unload_vmm(); break; case IOCTL_START_VMM: ret = ioctl_start_vmm(); break; case IOCTL_STOP_VMM: ret = ioctl_stop_vmm(); break; case IOCTL_DUMP_VMM: ret = ioctl_dump_vmm((struct debug_ring_resources_t *)out); break; case IOCTL_VMM_STATUS: ret = ioctl_vmm_status((int64_t *)out); break; case IOCTL_SET_VCPUID: ret = ioctl_set_vcpuid((uint64_t *)in); break; default: goto FAILURE; } if (OutputBufferLength != 0) WdfRequestSetInformation(Request, out_size); if (ret != BF_IOCTL_SUCCESS) goto FAILURE; WdfRequestComplete(Request, STATUS_SUCCESS); return; FAILURE: WdfRequestComplete(Request, STATUS_ACCESS_DENIED); return; }
VOID EvtIoDeviceControl( WDFQUEUE Queue, WDFREQUEST Request, size_t OutputBufferLength, size_t InputBufferLength, ULONG IoControlCode) { NTSTATUS status; BOOLEAN completeRequest = TRUE; WDFDEVICE device = WdfIoQueueGetDevice(Queue); PINPUT_DEVICE pContext = GetDeviceContext(device); ULONG uReportSize; HID_XFER_PACKET Packet; WDF_REQUEST_PARAMETERS params; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s, code = %d\n", __FUNCTION__, IoControlCode); switch (IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_DEVICE_DESCRIPTOR\n"); // // Return the device's HID descriptor. // ASSERT(pContext->HidDescriptor.bLength != 0); status = RequestCopyFromBuffer(Request, &pContext->HidDescriptor, pContext->HidDescriptor.bLength); break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_DEVICE_ATTRIBUTES\n"); // // Return the device's attributes in a HID_DEVICE_ATTRIBUTES structure. // status = RequestCopyFromBuffer(Request, &pContext->HidDeviceAttributes, sizeof(HID_DEVICE_ATTRIBUTES)); break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_REPORT_DESCRIPTOR\n"); // // Return the report descriptor for the HID device. // status = RequestCopyFromBuffer(Request, pContext->HidReportDescriptor, pContext->HidDescriptor.DescriptorList[0].wReportLength); break; case IOCTL_HID_READ_REPORT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_READ_REPORT\n"); // // Queue up a report request. We'll complete it when we actually // receive data from the device. // status = WdfRequestForwardToIoQueue( Request, pContext->HidQueue); if (NT_SUCCESS(status)) { completeRequest = FALSE; } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, "WdfRequestForwardToIoQueue failed with 0x%x\n", status); } break; case IOCTL_HID_WRITE_REPORT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_WRITE_REPORT\n"); // // Write a report to the device, commonly used for controlling keyboard // LEDs. We'll complete the request after the host processes all virtio // buffers we add to the status queue. // WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms); if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) { status = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory(&Packet, WdfRequestWdmGetIrp(Request)->UserBuffer, sizeof(HID_XFER_PACKET)); WdfRequestSetInformation(Request, Packet.reportBufferLen); status = ProcessOutputReport(pContext, Request, &Packet); if (NT_SUCCESS(status)) { completeRequest = FALSE; } } break; default: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Unrecognized IOCTL %d\n", IoControlCode); status = STATUS_NOT_IMPLEMENTED; break; } if (completeRequest) { WdfRequestComplete(Request, status); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s\n", __FUNCTION__); }
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; }
VOID UsbSamp_EvtReadWriteCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, _In_ WDFCONTEXT Context ) /*++ Routine Description: This is the completion routine for reads/writes If the irp completes with success, we check if we need to recirculate this irp for another stage of transfer. Arguments: Context - Driver supplied context Device - Device handle Request - Request handle Params - request completion params Return Value: None --*/ { WDFUSBPIPE pipe; ULONG stageLength = 0; NTSTATUS status; PREQUEST_CONTEXT rwContext; ULONG bytesReadWritten; WDFMEMORY_OFFSET offset; PCHAR operation; PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; PPIPE_CONTEXT pipeContext; WDF_USB_PIPE_INFORMATION pipeInfo; ULONG maxTransferSize; PDEVICE_CONTEXT deviceContext; usbCompletionParams = CompletionParams->Parameters.Usb.Completion; rwContext = GetRequestContext(Request); deviceContext = Context; if (rwContext->Read) { operation = "Read"; bytesReadWritten = (ULONG)usbCompletionParams->Parameters.PipeRead.Length; } else { operation = "Write"; bytesReadWritten = (ULONG)usbCompletionParams->Parameters.PipeWrite.Length; } pipe = (WDFUSBPIPE) Target; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe,&pipeInfo); status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)){ // // Queue a workitem to reset the pipe because the completion could be // running at DISPATCH_LEVEL. // TODO: preallocate per pipe workitem to avoid allocation failure. QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); goto End; } rwContext->Numxfer += bytesReadWritten; // // If there is anything left to transfer. // if (rwContext->Length == 0) { // // this is the last transfer // WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } // // Start another transfer // UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation)); // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (rwContext->Length > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = rwContext->Length; } offset.BufferOffset = rwContext->Numxfer; offset.BufferLength = stageLength; rwContext->Length -= stageLength; if (rwContext->Read) { status = WdfUsbTargetPipeFormatRequestForRead( pipe, Request, usbCompletionParams->Parameters.PipeRead.Buffer, &offset); } else { status = WdfUsbTargetPipeFormatRequestForWrite( pipe, Request, usbCompletionParams->Parameters.PipeWrite.Buffer, &offset); } if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeFormat%sRequest failed 0x%x\n", operation, status)); goto End; } #if (NTDDI_VERSION >= NTDDI_WIN8) // // If the request is for a super speed bulk pipe with streams, // configure its urb's PipeHandle with its associated stream's PipeHandle // if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && pipeContext->StreamConfigured == TRUE) { ConfigureStreamPipeHandleForRequest(Request, pipe); } #endif WdfRequestSetCompletionRoutine( Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // Send the request asynchronously. // if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation)); status = WdfRequestGetStatus(Request); goto End; } // // Else when the request completes, this completion routine will be // called again. // return; End: // // We are here because the request failed or some other call failed. // Dump the request context, complete the request and return. // DbgPrintRWContext(rwContext); UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n", operation, status)); WdfRequestComplete(Request, status); return; }
static VOID XenUsb_EvtIoDeviceControl( 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); UNREFERENCED_PARAMETER(queue); UNREFERENCED_PARAMETER(input_buffer_length); UNREFERENCED_PARAMETER(output_buffer_length); FUNCTION_ENTER(); status = STATUS_BAD_INITIAL_PC; // these are in api\usbioctl.h switch(io_control_code) { case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION: FUNCTION_MSG("IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n"); break; case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION: FUNCTION_MSG("IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n"); break; case IOCTL_USB_GET_NODE_CONNECTION_NAME: FUNCTION_MSG("IOCTL_USB_GET_NODE_CONNECTION_NAME\n"); break; case IOCTL_USB_DIAG_IGNORE_HUBS_ON: FUNCTION_MSG("IOCTL_USB_DIAG_IGNORE_HUBS_ON\n"); break; case IOCTL_USB_DIAG_IGNORE_HUBS_OFF: FUNCTION_MSG("IOCTL_USB_DIAG_IGNORE_HUBS_OFF\n"); break; case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME: FUNCTION_MSG("IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n"); break; case IOCTL_USB_GET_HUB_CAPABILITIES: FUNCTION_MSG("IOCTL_USB_GET_HUB_CAPABILITIES\n"); break; case IOCTL_USB_HUB_CYCLE_PORT: FUNCTION_MSG("IOCTL_USB_HUB_CYCLE_PORT\n"); break; case IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES: FUNCTION_MSG("IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES\n"); break; case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX: FUNCTION_MSG("IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX\n"); break; case IOCTL_USB_GET_ROOT_HUB_NAME: { PUSB_HCD_DRIVERKEY_NAME uhdn; size_t length; ULONG required_length = sizeof(USB_HCD_DRIVERKEY_NAME); FUNCTION_MSG("IOCTL_USB_GET_ROOT_HUB_NAME\n"); FUNCTION_MSG(" output_buffer_length = %d\n", output_buffer_length); if (output_buffer_length < sizeof(USB_HCD_DRIVERKEY_NAME)) { status = STATUS_BUFFER_TOO_SMALL; } else { status = WdfRequestRetrieveOutputBuffer(request, output_buffer_length, (PVOID *)&uhdn, &length); if (NT_SUCCESS(status)) { WDFSTRING symbolic_link_wdfstring; UNICODE_STRING symbolic_link; uhdn->DriverKeyName[0] = 0; status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &symbolic_link_wdfstring); if (NT_SUCCESS(status)) { status = WdfDeviceRetrieveDeviceInterfaceString(xudd->root_hub_device, &GUID_DEVINTERFACE_USB_HUB, NULL, symbolic_link_wdfstring); if (NT_SUCCESS(status)) { WdfStringGetUnicodeString(symbolic_link_wdfstring, &symbolic_link); /* remove leading \??\ from name */ symbolic_link.Buffer += 4; symbolic_link.Length -= 4 * sizeof(WCHAR); required_length = FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + symbolic_link.Length + sizeof(WCHAR); FUNCTION_MSG("output_buffer_length = %d\n", output_buffer_length); FUNCTION_MSG("required_length = %d\n", required_length); if (output_buffer_length >= required_length) { uhdn->ActualLength = required_length; memcpy(uhdn->DriverKeyName, symbolic_link.Buffer, symbolic_link.Length); uhdn->DriverKeyName[symbolic_link.Length / 2] = 0; WdfRequestSetInformation(request, required_length); } else { uhdn->ActualLength = required_length; uhdn->DriverKeyName[0] = 0; status = STATUS_SUCCESS; WdfRequestSetInformation(request, output_buffer_length); } } else { FUNCTION_MSG("WdfStringCreate = %08x\n", status); } } else { FUNCTION_MSG("WdfDeviceRetrieveDeviceInterfaceString = %08x\n", status); status = STATUS_INVALID_PARAMETER; } } else { FUNCTION_MSG("WdfRequestRetrieveOutputBuffer = %08x\n", status); } FUNCTION_MSG(" uhdn->ActualLength = %d\n", uhdn->ActualLength); FUNCTION_MSG(" uhdn->DriverKeyName = %S\n", uhdn->DriverKeyName); } break; } case IOCTL_GET_HCD_DRIVERKEY_NAME: { PUSB_HCD_DRIVERKEY_NAME uhdn; size_t length; ULONG required_length = sizeof(USB_HCD_DRIVERKEY_NAME); ULONG key_length; FUNCTION_MSG("IOCTL_GET_HCD_DRIVERKEY_NAME\n"); FUNCTION_MSG(" output_buffer_length = %d\n", output_buffer_length); if (output_buffer_length < sizeof(USB_HCD_DRIVERKEY_NAME)) { FUNCTION_MSG("Buffer too small (%d < %d)\n", output_buffer_length, sizeof(USB_HCD_DRIVERKEY_NAME)); status = STATUS_BUFFER_TOO_SMALL; break; } status = WdfRequestRetrieveOutputBuffer(request, output_buffer_length, (PVOID *)&uhdn, &length); if (!NT_SUCCESS(status)) { FUNCTION_MSG("WdfRequestRetrieveOutputBuffer = %08x\n", status); break; } status = WdfDeviceQueryProperty(device, DevicePropertyDriverKeyName, 0, NULL, &key_length); if (!NT_SUCCESS(status)) { FUNCTION_MSG("WdfDeviceQueryProperty = %08x\n", status); break; } FUNCTION_MSG(" key_length = %d\n", key_length); required_length = FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + key_length + 2; uhdn->ActualLength = required_length; FUNCTION_MSG("output_buffer_length = %d\n", output_buffer_length); FUNCTION_MSG("required_length = %d\n", required_length); if (output_buffer_length >= required_length) { status = WdfDeviceQueryProperty(device, DevicePropertyDriverKeyName, required_length - FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName), uhdn->DriverKeyName, &key_length); WdfRequestSetInformation(request, required_length); } else { uhdn->DriverKeyName[0] = 0; status = STATUS_SUCCESS; WdfRequestSetInformation(request, output_buffer_length); } FUNCTION_MSG(" uhdn->ActualLength = %d\n", uhdn->ActualLength); FUNCTION_MSG(" uhdn->DriverKeyName = %S\n", uhdn->DriverKeyName); break; } #if 0 case IOCTL_USB_RESET_HUB: FUNCTION_MSG("IOCTL_USB_RESET_HUB\n"); break; #endif default: FUNCTION_MSG("Unknown IOCTL %08x\n", io_control_code); break; } FUNCTION_MSG("Calling WdfRequestComplete with status = %08x\n", status); WdfRequestComplete(request, status); FUNCTION_EXIT(); }
VOID FileEvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS;// Assume success PCHAR inBuf = NULL, outBuf = NULL; // pointer to Input and output buffer PCHAR data = "this String is from Device Driver !!!"; ULONG datalen = (ULONG) strlen(data)+1;//Length of data including null PCHAR buffer = NULL; PREQUEST_CONTEXT reqContext = NULL; size_t bufSize; UNREFERENCED_PARAMETER( Queue ); PAGED_CODE(); if(!OutputBufferLength || !InputBufferLength) { WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } // // Determine which I/O control code was specified. // switch (IoControlCode) { case IOCTL_NONPNP_METHOD_BUFFERED: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_BUFFERED\n"); // // For bufffered ioctls WdfRequestRetrieveInputBuffer & // WdfRequestRetrieveOutputBuffer return the same buffer // pointer (Irp->AssociatedIrp.SystemBuffer), so read the // content of the buffer before writing to it. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == InputBufferLength); // // Read the input buffer content. // We are using the following function to print characters instead // TraceEvents with %s format because the string we get may or // may not be null terminated. The buffer may contain non-printable // characters also. // Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)InputBufferLength))); PrintChars(inBuf, InputBufferLength ); status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == OutputBufferLength); // // Writing to the buffer over-writes the input buffer content // RtlCopyMemory(outBuf, data, OutputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n", log_xstr(outBuf, (USHORT)datalen))); PrintChars(outBuf, datalen ); // // Assign the length of the data copied to IoStatus.Information // of the request and complete the request. // WdfRequestSetInformation(Request, OutputBufferLength < datalen? OutputBufferLength:datalen); // // When the request is completed the content of the SystemBuffer // is copied to the User output buffer and the SystemBuffer is // is freed. // break; case IOCTL_NONPNP_METHOD_IN_DIRECT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_IN_DIRECT\n"); // // Get the Input buffer. WdfRequestRetrieveInputBuffer returns // Irp->AssociatedIrp.SystemBuffer. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == InputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)InputBufferLength))); PrintChars(inBuf, InputBufferLength); // // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe // on the Irp->MdlAddress and returns the system address. // Oddity: For this method, this buffer is intended for transfering data // from the application to the driver. // status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize); if(!NT_SUCCESS(status)) { break; } ASSERT(bufSize == OutputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User in OutputBuffer: %!HEXDUMP!\n", log_xstr(buffer, (USHORT)OutputBufferLength))); PrintChars(buffer, OutputBufferLength); // // Return total bytes read from the output buffer. // Note OutputBufferLength = MmGetMdlByteCount(Irp->MdlAddress) // WdfRequestSetInformation(Request, OutputBufferLength); // // NOTE: Changes made to the SystemBuffer are not copied // to the user input buffer by the I/O manager // break; case IOCTL_NONPNP_METHOD_OUT_DIRECT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_OUT_DIRECT\n"); // // Get the Input buffer. WdfRequestRetrieveInputBuffer returns // Irp->AssociatedIrp.SystemBuffer. // status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize); if(!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ASSERT(bufSize == InputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)InputBufferLength))); PrintChars(inBuf, InputBufferLength); // // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe // on the Irp->MdlAddress and returns the system address. // For this method, this buffer is intended for transfering data from the // driver to the application. // status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize); if(!NT_SUCCESS(status)) { break; } ASSERT(bufSize == OutputBufferLength); // // Write data to be sent to the user in this buffer // RtlCopyMemory(buffer, data, OutputBufferLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n", log_xstr(buffer, (USHORT)datalen))); PrintChars(buffer, datalen); WdfRequestSetInformation(Request, OutputBufferLength < datalen? OutputBufferLength: datalen); // // NOTE: Changes made to the SystemBuffer are not copied // to the user input buffer by the I/O manager // break; case IOCTL_NONPNP_METHOD_NEITHER: { size_t inBufLength, outBufLength; // // The NonPnpEvtDeviceIoInCallerContext has already probe and locked the // pages and mapped the user buffer into system address space and // stored memory buffer pointers in the request context. We can get the // buffer pointer by calling WdfMemoryGetBuffer. // TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_NEITHER\n"); reqContext = GetRequestContext(Request); inBuf = WdfMemoryGetBuffer(reqContext->InputMemoryBuffer, &inBufLength); outBuf = WdfMemoryGetBuffer(reqContext->OutputMemoryBuffer, &outBufLength); if(inBuf == NULL || outBuf == NULL) { status = STATUS_INVALID_PARAMETER; } ASSERT(inBufLength == InputBufferLength); ASSERT(outBufLength == OutputBufferLength); // // Now you can safely read the data from the buffer in any arbitrary // context. // Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n", log_xstr(inBuf, (USHORT)inBufLength))); PrintChars(inBuf, inBufLength); // // Write to the buffer in any arbitrary context. // RtlCopyMemory(outBuf, data, outBufLength); Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n", log_xstr(outBuf, (USHORT)datalen))); PrintChars(outBuf, datalen); // // Assign the length of the data copied to IoStatus.Information // of the Irp and complete the Irp. // WdfRequestSetInformation(Request, outBufLength < datalen? outBufLength:datalen); break; } default: // // The specified I/O control code is unrecognized by this driver. // status = STATUS_INVALID_DEVICE_REQUEST; TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ERROR: unrecognized IOCTL %x\n", IoControlCode); break; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Completing Request %p with status %X", Request, status ); WdfRequestComplete( Request, status); }
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 ReadWriteCompletion( IN WDFREQUEST Request, IN WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, IN WDFCONTEXT Context ) /*++ Routine Description: This is the completion routine for reads/writes If the irp completes with success, we check if we need to recirculate this irp for another stage of transfer. Arguments: Context - Driver supplied context Device - Device handle Request - Request handle Params - request completion params Return Value: None --*/ { WDFUSBPIPE pipe; ULONG stageLength; NTSTATUS status; PREQUEST_CONTEXT rwContext; ULONG bytesReadWritten; WDFMEMORY_OFFSET offset; PCHAR operation; PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; UNREFERENCED_PARAMETER(Context); rwContext = GetRequestContext(Request); usbCompletionParams = CompletionParams->Parameters.Usb.Completion; rwContext = GetRequestContext(Request); if (rwContext->Read) { operation = "Read"; bytesReadWritten = usbCompletionParams->Parameters.PipeRead.Length; } else { operation = "Write"; bytesReadWritten = usbCompletionParams->Parameters.PipeWrite.Length; } pipe = (WDFUSBPIPE) Target; status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)){ // // Queue a workitem to reset the pipe because the completion could be // running at DISPATCH_LEVEL. // TODO: preallocate per pipe workitem to avoid allocation failure. QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); goto End; } rwContext->Numxfer += bytesReadWritten; // // If there is anything left to transfer. // if (rwContext->Length == 0) { // // this is the last transfer // WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } // // Start another transfer // kJtag_DbgPrint(3, ("Stage next %s transfer...\n", operation)); if (rwContext->Length > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = rwContext->Length; } offset.BufferOffset = rwContext->Numxfer; offset.BufferLength = stageLength; rwContext->Length -= stageLength; if (rwContext->Read) { status = WdfUsbTargetPipeFormatRequestForRead( pipe, Request, usbCompletionParams->Parameters.PipeRead.Buffer, &offset); } else { status = WdfUsbTargetPipeFormatRequestForWrite( pipe, Request, usbCompletionParams->Parameters.PipeWrite.Buffer, &offset); } if (!NT_SUCCESS(status)) { kJtag_DbgPrint(1, ("WdfUsbTargetPipeFormat%sRequest failed 0x%x\n", operation, status)); goto End; } WdfRequestSetCompletionRoutine( Request, ReadWriteCompletion, NULL); // // Send the request asynchronously. // if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { kJtag_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation)); status = WdfRequestGetStatus(Request); goto End; } // // Else when the request completes, this completion routine will be // called again. // return; End: // // We are here because the request failed or some other call failed. // Dump the request context, complete the request and return. // DbgPrintRWContext(rwContext); kJtag_DbgPrint(3, ("%s request completed with status 0x%x\n", operation, status)); WdfRequestComplete(Request, status); return; }