VOID FilterForwardRequest( IN WDFREQUEST Request, IN WDFIOTARGET Target ) /*++ Routine Description: Passes a request on to the lower driver. --*/ { WDF_REQUEST_SEND_OPTIONS options; BOOLEAN ret; NTSTATUS status; // // We are not interested in post processing the IRP so // fire and forget. // WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); ret = WdfRequestSend(Request, Target, &options); if (ret == FALSE) { status = WdfRequestGetStatus (Request); KdPrint( ("WdfRequestSend failed: 0x%x\n", status)); WdfRequestComplete(Request, status); } return; }
// Pass down Idle notification request to lower driver // NTSTATUS HidFx2SendIdleNotification(_In_ WDFREQUEST hRequest) { NTSTATUS status = STATUS_SUCCESS; WDF_REQUEST_SEND_OPTIONS options; WDFIOTARGET hNextLowerDriver; WDFDEVICE hDevice; PIO_STACK_LOCATION pCurrentIrpStack = NULL; IO_STACK_LOCATION nextIrpStack; TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n"); hDevice = WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest)); pCurrentIrpStack = IoGetCurrentIrpStackLocation(WdfRequestWdmGetIrp(hRequest)); // Convert the request to corresponding USB Idle notification request if (pCurrentIrpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)) { ASSERT(sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) == sizeof(USB_IDLE_CALLBACK_INFO)); #pragma warning(suppress :4127) // conditional expression is constant warning if (sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) == sizeof(USB_IDLE_CALLBACK_INFO)) { // prepare next stack location RtlZeroMemory(&nextIrpStack, sizeof(IO_STACK_LOCATION)); nextIrpStack.MajorFunction = pCurrentIrpStack->MajorFunction; nextIrpStack.Parameters.DeviceIoControl.InputBufferLength = pCurrentIrpStack->Parameters.DeviceIoControl.InputBufferLength; nextIrpStack.Parameters.DeviceIoControl.Type3InputBuffer = pCurrentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; nextIrpStack.Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION; nextIrpStack.DeviceObject = WdfIoTargetWdmGetTargetDeviceObject(WdfDeviceGetIoTarget(hDevice)); // Format the I/O request for the driver's local I/O target by using the contents of the specified WDM I/O stack location structure. WdfRequestWdmFormatUsingStackLocation(hRequest, &nextIrpStack); // Send the request down using Fire and forget option. WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); hNextLowerDriver = WdfDeviceGetIoTarget(hDevice); if (WdfRequestSend(hRequest, hNextLowerDriver, &options) == FALSE) { status = STATUS_UNSUCCESSFUL; } } else // Incorrect DeviceIoControl.InputBufferLength { status = STATUS_INFO_LENGTH_MISMATCH; TraceErr(DBG_IOCTL, "(%!FUNC!) Incorrect DeviceIoControl.InputBufferLength, %!STATUS!\n", status); return status; } } else // DeviceIoControl.InputBufferLength too small { status = STATUS_BUFFER_TOO_SMALL; TraceErr(DBG_IOCTL, "(%!FUNC!) DeviceIoControl.InputBufferLength too small, %!STATUS!\n", status); return status; } TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status); return status; }
static VOID XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) { PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd; NTSTATUS status; WDFREQUEST request; WDF_REQUEST_SEND_OPTIONS send_options; IO_STACK_LOCATION stack; SCSI_REQUEST_BLOCK srb; SRB_IO_CONTROL sic; FUNCTION_ENTER(); /* send a 'stop' down if we are suspending */ if (suspend) { status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request); FUNCTION_MSG("WdfRequestCreate = %08x\n", status); RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION)); stack.MajorFunction = IRP_MJ_SCSI; stack.MinorFunction = IRP_MN_SCSI_CLASS; stack.Parameters.Scsi.Srb = &srb; RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE); srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE; srb.Length = SCSI_REQUEST_BLOCK_SIZE; srb.PathId = 0; srb.TargetId = 0; srb.Lun = 0; srb.OriginalRequest = WdfRequestWdmGetIrp(request); srb.Function = SRB_FUNCTION_IO_CONTROL; srb.DataBuffer = &sic; RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL)); sic.HeaderLength = sizeof(SRB_IO_CONTROL); memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8); sic.Timeout = 60; sic.ControlCode = XENVBD_CONTROL_STOP; WdfRequestWdmFormatUsingStackLocation(request, &stack); WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS); if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) { FUNCTION_MSG("Request was _NOT_ sent\n"); } #if DBG status = WdfRequestGetStatus(request); FUNCTION_MSG("Request Status = %08x\n", status); FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus); #endif WdfObjectDelete(request); } status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing); FUNCTION_EXIT(); }
void MouseTrapEvtIoInternalDeviceControl(WDFQUEUE queue, WDFREQUEST request, size_t outputBufferLength, size_t inputBufferLength, ULONG ioControlCode) { UNREFERENCED_PARAMETER(outputBufferLength); UNREFERENCED_PARAMETER(inputBufferLength); NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); // Ensure paging is allowed in current IRQL // Get extension data WDFDEVICE hDevice = WdfIoQueueGetDevice(queue); PDEVICE_CONTEXT context = DeviceGetContext(hDevice); if(ioControlCode == IOCTL_INTERNAL_MOUSE_CONNECT) { // Only allow one connection. if(context->UpperConnectData.ClassService == NULL) { // Copy the connection parameters to the device extension. PCONNECT_DATA connectData; size_t length; status = WdfRequestRetrieveInputBuffer(request, sizeof(CONNECT_DATA), &connectData, &length); if(NT_SUCCESS(status)) { // Hook into the report chain (I am not sure this is correct) context->UpperConnectData = *connectData; connectData->ClassDeviceObject = WdfDeviceWdmGetDeviceObject(hDevice); #pragma warning(push) #pragma warning(disable:4152) connectData->ClassService = MouseTrapServiceCallback; #pragma warning(pop) } else { DebugPrint(("[MouseTrap] WdfRequestRetrieveInputBuffer failed %x\n", status)); } } else { status = STATUS_SHARING_VIOLATION; } } else if(ioControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT) { status = STATUS_NOT_IMPLEMENTED; } // Complete on error if(!NT_SUCCESS(status)) { WdfRequestComplete(request, status); return; } // Dispatch to higher level driver WDF_REQUEST_SEND_OPTIONS options; WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); if(WdfRequestSend(request, WdfDeviceGetIoTarget(hDevice), &options) == FALSE) { NTSTATUS status = WdfRequestGetStatus(request); DebugPrint(("[MouseTrap] WdfRequestSend failed: 0x%x\n", status)); WdfRequestComplete(request, status); } }
// Bulk管道写操作 // VOID BulkWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status = STATUS_SUCCESS; WDFMEMORY hMem = NULL; WDFDEVICE hDevice = NULL; WDFUSBPIPE BulkOutputPipe = NULL; UCHAR* lpBuf; UNREFERENCED_PARAMETER(Length); KDBG(DPFLTR_INFO_LEVEL, "[BulkWrite] size: %d", Length); // 获取管道句柄 hDevice = WdfIoQueueGetDevice(Queue); BulkOutputPipe = GetBulkPipe(FALSE, hDevice); if(NULL == BulkOutputPipe) { KDBG(DPFLTR_ERROR_LEVEL, "BulkOutputPipe = NULL"); WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); return; } status = WdfRequestRetrieveInputMemory(Request, &hMem); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_ERROR_LEVEL, "WdfRequestRetrieveInputMemory failed(status = 0x%0.8x)!!!", status); WdfRequestComplete(Request, status); return; } // 打印出offset值。 // 在写缓冲的前两个字节中存有write offset的值 lpBuf = (UCHAR*)WdfMemoryGetBuffer(hMem, 0); KDBG(DPFLTR_TRACE_LEVEL, "write offset: %hd", *(WORD*)lpBuf); // 把当前的Request对象进行重利用,发送给USB总线。 // 格式化Request对象,设置Pipe句柄、完成函数等。 status = WdfUsbTargetPipeFormatRequestForWrite(BulkOutputPipe, Request, hMem, NULL); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_ERROR_LEVEL, "WdfUsbTargetPipeFormatRequestForWrite(status 0x%0.8x)!!!", status); WdfRequestComplete(Request, status); return; } WdfRequestSetCompletionRoutine(Request, BulkWriteComplete, BulkOutputPipe); if(FALSE == WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(BulkOutputPipe), NULL)) { status = WdfRequestGetStatus(Request); KDBG(DPFLTR_ERROR_LEVEL, "WdfRequestSend failed with status 0x%0.8x\n", status); WdfRequestComplete(Request, status); } }
static VOID XenVbd_SendEvent(WDFDEVICE device) { PXENVBD_FILTER_DATA xvfd = GetXvfd(device); NTSTATUS status; WDFREQUEST request; WDF_REQUEST_SEND_OPTIONS send_options; IO_STACK_LOCATION stack; PUCHAR buf; PSCSI_REQUEST_BLOCK srb; PSRB_IO_CONTROL sic; status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request); if (status != STATUS_SUCCESS) { FUNCTION_MSG("WdfRequestCreate failed %08x\n", status); /* this is bad - event will be dropped */ return; } buf = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL) + sizeof(LARGE_INTEGER), XENVBD_POOL_TAG); RtlZeroMemory(buf, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL)); srb = (PSCSI_REQUEST_BLOCK)(buf); sic = (PSRB_IO_CONTROL)(buf + sizeof(SCSI_REQUEST_BLOCK)); srb->Length = sizeof(SCSI_REQUEST_BLOCK); srb->SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE; srb->PathId = 0; srb->TargetId = 0; srb->Lun = 0; srb->OriginalRequest = WdfRequestWdmGetIrp(request); srb->Function = SRB_FUNCTION_IO_CONTROL; srb->DataBuffer = sic; srb->DataTransferLength = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL); srb->TimeOutValue = (ULONG)-1; sic->HeaderLength = sizeof(SRB_IO_CONTROL); memcpy(sic->Signature, XENVBD_CONTROL_SIG, 8); sic->Timeout = (ULONG)-1; sic->ControlCode = XENVBD_CONTROL_EVENT; KeQuerySystemTime((PLARGE_INTEGER)((PUCHAR)buf + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL))); RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION)); stack.MajorFunction = IRP_MJ_SCSI; stack.MinorFunction = IRP_MN_SCSI_CLASS; stack.Parameters.Scsi.Srb = srb; WdfRequestWdmFormatUsingStackLocation(request, &stack); WdfRequestSetCompletionRoutine(request, XenVbd_SendEventComplete, buf); WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, 0); //WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) { FUNCTION_MSG("Error sending request\n"); } }
VOID EvtIoRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) { WDFUSBPIPE pipe; NTSTATUS status; WDFMEMORY reqMemory; PDEVICE_CONTEXT pDeviceContext; BOOLEAN ret; UNREFERENCED_PARAMETER(Length); pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); pipe = pDeviceContext->BulkReadPipe; status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); if(!NT_SUCCESS(status)){ goto Exit; } status = WdfUsbTargetPipeFormatRequestForRead(pipe, Request, reqMemory, NULL // Offsets ); if (!NT_SUCCESS(status)) { goto Exit; } WdfRequestSetCompletionRoutine( Request, EvtRequestReadCompletionRoutine, pipe); ret = WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS); if (ret == FALSE) { status = WdfRequestGetStatus(Request); goto Exit; } else { return; } Exit: WdfRequestCompleteWithInformation(Request, status, 0); return; }
VOID SimSensorIoInternalDeviceControl ( WDFQUEUE Queue, WDFREQUEST Request, size_t OutputBufferLength, size_t InputBufferLength, ULONG IoControlCode) /*++ Description: The system uses IoInternalDeviceControl requests to communicate with the ACPI driver on the device stack. For proper operation of thermal zones, these requests must be forwarded unless the driver knows how to handle them. --*/ { WDF_REQUEST_SEND_OPTIONS RequestSendOptions; BOOLEAN Return; NTSTATUS Status; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); UNREFERENCED_PARAMETER(IoControlCode); DebugEnter(); WdfRequestFormatRequestUsingCurrentType(Request); WDF_REQUEST_SEND_OPTIONS_INIT( &RequestSendOptions, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); Return = WdfRequestSend( Request, WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue)), &RequestSendOptions); if (Return == FALSE) { Status = WdfRequestGetStatus(Request); DebugPrint(SIMSENSOR_WARN, "WdfRequestSend() Failed. Request Status=0x%x\n", Status); WdfRequestComplete(Request, Status); } DebugExit(); }
/////////////////////////////////////////////////////////////////////////////// // SmplFilterEvtIoDefault /////////////////////////////////////////////////////////////////////////////// VOID SmplFilterEvtIoDefault( __in WDFQUEUE Queue, __in WDFREQUEST Request ) { WDF_REQUEST_PARAMETERS RequestParameters; BOOLEAN bResult; WDF_REQUEST_PARAMETERS_INIT(&RequestParameters); WdfRequestGetParameters(Request, &RequestParameters); if(WdfRequestTypeRead == RequestParameters.Type) { DbgPrintEx( DPFLTR_IHVDRIVER_ID, 1234, "SmplFilterEvtIoDefault WdfRequestTypeRead\n"); WdfRequestFormatRequestUsingCurrentType(Request); WdfRequestSetCompletionRoutine(Request, SmplFilterCompletionRoutineRead, NULL); bResult = WdfRequestSend(Request, WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue)), NULL); } else { WDF_REQUEST_SEND_OPTIONS Options; WDF_REQUEST_SEND_OPTIONS_INIT(&Options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); DbgPrintEx( DPFLTR_IHVDRIVER_ID, 1234, "SmplFilterEvtIoDefault other Request type\n"); bResult = WdfRequestSend(Request, WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue)), &Options); } if(FALSE == bResult) { DbgPrintEx( DPFLTR_IHVDRIVER_ID, 1234, "WdfRequestSend failed!\n"); WdfRequestComplete(Request, WdfRequestGetStatus(Request)); } } // end SmplFilterEvtIoDefault
/////////////////////////////////////////////////////////////////////////////// // // CDFilterEvtRead // // This routine is called by the framework for read requests // being sent to the device we're filtering // // INPUTS: // // Queue - Our default queue // // Request - A read request // // Length - The length of the read operation // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL <= DISPATCH_LEVEL // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// VOID CDFilterEvtRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length) { NTSTATUS status; PFILTER_DEVICE_CONTEXT devContext; #if DBG DbgPrint("CDFilterEvtRead: Processing read. Length = 0x%x\n", Length); #endif // // Get the context that we setup during DeviceAdd processing // devContext = CDFilterGetDeviceContext(WdfIoQueueGetDevice(Queue)); // // Setup the request for the next driver // WdfRequestFormatRequestUsingCurrentType(Request); // // Set the completion routine... // WdfRequestSetCompletionRoutine(Request, CDFilterReadComplete, NULL); // // And send it! // if (!WdfRequestSend(Request, devContext->TargetToSendRequestsTo, WDF_NO_SEND_OPTIONS)) { // // Oops! Something bad happened, complete the request // status = WdfRequestGetStatus(Request); #if DBG DbgPrint("WdfRequestSend failed - 0x%x\n", status); #endif WdfRequestComplete(Request, status); } return; }
// Bulk管道读操作 // VOID BulkRead(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_CONTEXT pContext = NULL; WDFUSBPIPE BulkInputPipe; WDFMEMORY hMem; WDFDEVICE hDevice = WdfIoQueueGetDevice(Queue); KDBG(DPFLTR_INFO_LEVEL, "[BulkRead] size: %d", Length); // 取管道 pContext = GetDeviceContext(hDevice); BulkInputPipe = GetBulkPipe(TRUE, hDevice); if(NULL == BulkInputPipe){ WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); return; } status = WdfRequestRetrieveOutputMemory(Request, &hMem); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfRequestRetrieveOutputMemory failed with status 0x%0.8x!!!", status); WdfRequestComplete(Request, status); return; } // 和写一样,仍然是对Request对象的重利用 // 除了重利用外,也可以新建一个Request对象。新建的方法在本工程其他地方用得较多。 status = WdfUsbTargetPipeFormatRequestForRead(BulkInputPipe, Request, hMem, NULL); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfUsbTargetPipeFormatRequestForRead failed with status 0x%08x\n", status); WdfRequestComplete(Request, status); return; } WdfRequestSetCompletionRoutine(Request, BulkReadComplete, BulkInputPipe); if(FALSE == WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pContext->UsbBulkInPipe), NULL)) { status = WdfRequestGetStatus(Request); KDBG(DPFLTR_INFO_LEVEL, "WdfRequestSend failed with status 0x%08x\n", status); WdfRequestComplete(Request, status); } }
VOID ForwardRequestToIoTarget( _In_ WDFQUEUE queue, _In_ WDFREQUEST request, _In_ size_t length) { TraceEntry(); Trace(TRACE_LEVEL_INFORMATION, "%!FUNC! - Queue 0x%p, Request 0x%p Length %Iu", queue, request, length); auto device = WdfIoQueueGetDevice(queue); auto context = GetDeviceContext(device); if (length > context->MaxLengthInBytesForRWTransfers) { TraceError("%!FUNC! - Buffer Length to big %Iu, Max is %Iu. Status - %!STATUS!", length, context->MaxLengthInBytesForRWTransfers, STATUS_BUFFER_OVERFLOW); WdfRequestCompleteWithInformation(request, STATUS_BUFFER_OVERFLOW, NULL); return; } auto targetDevice = WdfDeviceGetIoTarget(device); WdfRequestFormatRequestUsingCurrentType(request); WDF_REQUEST_SEND_OPTIONS options; WDF_REQUEST_SEND_OPTIONS_INIT( &options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_ABS_TIMEOUT_IN_SEC(10)); auto sendSuccess = WdfRequestSend(request, targetDevice, &options); auto status = WdfRequestGetStatus(request); if (!sendSuccess || !NT_SUCCESS(status)) { TraceError("%!FUNC! - WdfRequestSend returned %d with status: %!STATUS!", sendSuccess, status); WdfRequestCompleteWithInformation(request, status, NULL); return; } WdfRequestComplete(request, status); }
VOID FilterForwardRequestWithCompletionRoutine( IN WDFREQUEST Request, IN WDFIOTARGET Target ) /*++ Routine Description: This routine forwards the request to a lower driver with a completion so that when the request is completed by the lower driver, it can regain control of the request and look at the result. --*/ { BOOLEAN ret; NTSTATUS status; // // The following funciton essentially copies the content of // current stack location of the underlying IRP to the next one. // WdfRequestFormatRequestUsingCurrentType(Request); WdfRequestSetCompletionRoutine(Request, FilterRequestCompletionRoutine, WDF_NO_CONTEXT); ret = WdfRequestSend(Request, Target, WDF_NO_SEND_OPTIONS); if (ret == FALSE) { status = WdfRequestGetStatus (Request); KdPrint( ("WdfRequestSend failed: 0x%x\n", status)); WdfRequestComplete(Request, status); } return; }
VOID MouFilter_DispatchPassThrough( __in WDFREQUEST Request, __in WDFIOTARGET Target ) /*++ Routine Description: Passes a request on to the lower driver. --*/ { // // Pass the IRP to the target // WDF_REQUEST_SEND_OPTIONS options; BOOLEAN ret; NTSTATUS status = STATUS_SUCCESS; // // We are not interested in post processing the IRP so // fire and forget. // WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); ret = WdfRequestSend(Request, Target, &options); if (ret == FALSE) { status = WdfRequestGetStatus (Request); DebugPrint( ("WdfRequestSend failed: 0x%x\n", status)); WdfRequestComplete(Request, status); } return; }
VOID MouFilter_DispatchPassThrough(_In_ WDFREQUEST Request, _In_ WDFIOTARGET Target) /*++ Routine Description: Passes a request on to the lower driver. --*/ { WDF_REQUEST_SEND_OPTIONS options; BOOLEAN ret; NTSTATUS status = STATUS_SUCCESS; WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); ret = WdfRequestSend(Request, Target, &options); if (ret == FALSE) { status = WdfRequestGetStatus (Request); DebugPrint( ("WdfRequestSend failed: 0x%x\n", status)); WdfRequestComplete(Request, status); } return; }
/*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of MAX_TRANSFER_SIZE. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ VOID ReadWriteBulkEndPoints(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG Length, IN WDF_REQUEST_TYPE RequestType) { PMDL newMdl = NULL; PMDL requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; WDF_REQUEST_SEND_OPTIONS sendOptions; PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - begins\n")); // First validate input parameters. deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { PSDrv_DbgPrint(1, ("Transfer length (%d) is bigger then MaximumTransferSize (%d)!\n", totalLength, deviceContext->MaximumTransferSize)); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { PSDrv_DbgPrint(1, ("RequestType has to be either Read or Write! (RequestType = %d)\n", RequestType)); status = STATUS_INVALID_PARAMETER; goto Exit; } // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { PSDrv_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt! (PipeType = %d)\n", pipeInfo.PipeType)); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if(RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; PSDrv_DbgPrint(3, ("This is a read operation...\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; PSDrv_DbgPrint(3, ("This is a write operation...\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // The transfer request is for totalLength. We can perform a max of MAX_TRANSFER_SIZE in each stage. if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID)virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { PSDrv_DbgPrint(1, ("IoAllocateMdl failed! (newMdl is NULL)\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // Map the portion of user-buffer described by an mdl to another mdl IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*)&urb); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfMemoryCreate for urbMemory failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Set REQUEST_CONTEXT parameters. rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; // Set the timeout if (fileContext->nTimeOut != 0) { WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(fileContext->nTimeOut)); PSDrv_DbgPrint(3, ("Pipe timeout is set to: %d\n", fileContext->nTimeOut)); if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), &sendOptions)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } else { if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - ends\n")); return; }
/*++ 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; }
NTSTATUS kmdf1394_SubmitIrpAsync ( IN WDFIOTARGET IoTarget, IN WDFREQUEST Request, IN WDFMEMORY Memory) /*++ Routine Description: Asynchronous request submission routine Arguments: IoTarget - I/O Target object Request - current request object Irb - 1394 I/O Request Block to submit Return Value: NTSTATUS value --*/ { NTSTATUS ntStatus = STATUS_SUCCESS; ENTER("kmdf1394_SubmitIrpAsync"); ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); ASSERT (Memory); if (!NT_SUCCESS (ntStatus)) { return ntStatus; } ntStatus = WdfIoTargetFormatRequestForInternalIoctlOthers ( IoTarget, Request, IOCTL_1394_CLASS, Memory, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS (ntStatus)) { TRACE( TL_ERROR, ("WdfIoTargetFormatRequestForInternalIoctlOthers failed " "with status %x\n", ntStatus)); return ntStatus; } if (FALSE == (WdfRequestSend (Request, IoTarget, NULL))) { ntStatus = WdfRequestGetStatus (Request); } EXIT("kmdf1394_SubmitIrpAsync", ntStatus); return ntStatus; } // kmdf1394_SubmitIrpAsync
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; }
NTSTATUS BthEchoSharedSendBrbAsync( _In_ WDFIOTARGET IoTarget, _In_ WDFREQUEST Request, _In_ PBRB Brb, _In_ size_t BrbSize, _In_ PFN_WDF_REQUEST_COMPLETION_ROUTINE ComplRoutine, _In_opt_ WDFCONTEXT Context ) /*++ Routine Description: This routine formats a request with brb and sends it asynchronously Arguments: IoTarget - Target to send the brb to Request - request object to be formatted with brb Brb - Brb to be sent BrbSize - size of the Brb data structure ComplRoutine - WDF completion routine for the request This must be specified because we are formatting the request and hence not using SEND_AND_FORGET flag Context - (optional) context to be passed in to the completion routine Return Value: Success implies that request was sent correctly and completion routine will be called for it, failure implies it was not sent and caller should complete the request Notes: This routine does not call WdfRequestReuse on the Request passed in. Caller must do so before passing in the request, if it is reusing the request. This routine does not complete the request in case of failure. Caller must complete the request in case of failure. --*/ { NTSTATUS status = BTH_ERROR_SUCCESS; WDF_OBJECT_ATTRIBUTES attributes; WDFMEMORY memoryArg1 = NULL; if (BrbSize <= 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, "BrbSize has invalid value: %I64d\n", BrbSize ); status = STATUS_INVALID_PARAMETER; goto exit; } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = Request; status = WdfMemoryCreatePreallocated( &attributes, Brb, BrbSize, &memoryArg1 ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, "Creating preallocted memory for Brb 0x%p failed, Request to be formatted 0x%p, " "Status code %!STATUS!\n", Brb, Request, status ); goto exit; } status = WdfIoTargetFormatRequestForInternalIoctlOthers( IoTarget, Request, IOCTL_INTERNAL_BTH_SUBMIT_BRB, memoryArg1, NULL, //OtherArg1Offset NULL, //OtherArg2 NULL, //OtherArg2Offset NULL, //OtherArg4 NULL //OtherArg4Offset ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, "Formatting request 0x%p with Brb 0x%p failed, Status code %!STATUS!\n", Request, Brb, status ); goto exit; } // // Set a CompletionRoutine callback function. // WdfRequestSetCompletionRoutine( Request, ComplRoutine, Context ); if (FALSE == WdfRequestSend( Request, IoTarget, NULL )) { status = WdfRequestGetStatus(Request); TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", Request, Brb, status ); goto exit; } exit: return status; }
VOID ReadWriteBulkEndPoints( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG Length, _In_ WDF_REQUEST_TYPE RequestType ) /*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or RP_MJ_WRITE request. This read/write is performed in stages of maximum transfer size. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ { size_t totalLength = Length; size_t stageLength = 0; NTSTATUS status; PVOID virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDFMEMORY reqMemory; WDFMEMORY_OFFSET offset; WDF_OBJECT_ATTRIBUTES objectAttribs; PDEVICE_CONTEXT deviceContext; PPIPE_CONTEXT pipeContext; ULONG maxTransferSize; UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } // // Get the pipe associate with this request. // fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); rwContext = GetRequestContext(Request); if (RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputBuffer(Request, Length, &virtualAddress, &totalLength); rwContext->Read = TRUE; } else { //Write status = WdfRequestRetrieveInputBuffer(Request, Length, &virtualAddress, &totalLength); rwContext->Read = FALSE; } if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputBuffer failed\n")); goto Exit; } // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (totalLength > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = totalLength; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreatePreallocated(&objectAttribs, virtualAddress, totalLength, &reqMemory); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfMemoryCreatePreallocated failed\n")); goto Exit; } offset.BufferOffset = 0; offset.BufferLength = stageLength; // // The framework format call validates to make sure that you are reading or // writing to the right pipe type, sets the appropriate transfer flags, // creates an URB and initializes the request. // if (RequestType == WdfRequestTypeRead) { UsbSamp_DbgPrint(3, ("Read operation\n")); status = WdfUsbTargetPipeFormatRequestForRead(pipe, Request, reqMemory, &offset); } else { UsbSamp_DbgPrint(3, ("Write operation\n")); status = WdfUsbTargetPipeFormatRequestForWrite(pipe, Request, reqMemory, &offset); } if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeFormatRequest failed 0x%x\n", status)); goto Exit; } #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); // // set REQUEST_CONTEXT parameters. // rwContext->Length = (ULONG)totalLength - (ULONG)stageLength; rwContext->Numxfer = 0; // // Send the request asynchronously. // if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { UsbSamp_DbgPrint(1, ("WdfRequestSend failed\n")); status = WdfRequestGetStatus(Request); goto Exit; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); return; }
VOID ReadWriteBulkEndPoints( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG Length, _In_ WDF_REQUEST_TYPE RequestType ) /*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of maximum transfer size. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ { PMDL newMdl=NULL, requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; ULONG maxTransferSize; PPIPE_CONTEXT pipeContext; UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } // // Get the pipe associate with this request. // fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if ((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { UsbSamp_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n")); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if (RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; UsbSamp_DbgPrint(3, ("Read operation\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed %x\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; UsbSamp_DbgPrint(3, ("Write operation\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (totalLength > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { UsbSamp_DbgPrint(1, ("Failed to alloc mem for mdl\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // // map the portion of user-buffer described by an mdl to another mdl // IoBuildPartialMdl(requestMdl, newMdl, (PVOID) virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfUsbTargetDeviceCreateUrb(deviceContext->WdfUsbTargetDevice, &objectAttribs, &urbMemory, &urb); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateUrb failed %x\n", status)); goto Exit; } #if (NTDDI_VERSION >= NTDDI_WIN8) if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && pipeContext->StreamConfigured == TRUE) { // // For super speed bulk pipe with streams, we specify one of its associated // usbd pipe handles to format an URB for sending or receiving data. // The usbd pipe handle is returned by the HCD via sucessful open-streams request // usbdPipeHandle = GetStreamPipeHandleFromBulkPipe(pipe); } else { usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); } #else usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); #endif UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL ); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // set REQUEST_CONTEXT parameters. // rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); NT_ASSERT(!NT_SUCCESS(status)); } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); return; }
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; }
VOID XferCtrl ( __in WDFQUEUE Queue, __in WDFREQUEST Request, __in size_t InputBufferLength, __in size_t OutputBufferLength) { NTSTATUS status; PDEVICE_CONTEXT deviceContext; PREQUEST_CONTEXT requestContext; WDFMEMORY transferMemory; PWDF_USB_CONTROL_SETUP_PACKET setupPacket; WDF_REQUEST_SEND_OPTIONS sendOptions; WDFMEMORY_OFFSET _transferOffset; PWDFMEMORY_OFFSET transferOffset = &_transferOffset; UNREFERENCED_PARAMETER(InputBufferLength); UNREFERENCED_PARAMETER(OutputBufferLength); deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); requestContext = GetRequestContext(Request); setupPacket = (PWDF_USB_CONTROL_SETUP_PACKET)&requestContext->IoControlRequest.control; USBDBG("bmDir=%s bmType=%s bmRecipient=%s bmReserved=%03u bRequest=%u wIndex=%u wValue=%u wLength=%u\n", GetBmRequestDirString(setupPacket->Packet.bm.Request.Dir), GetBmRequestTypeString(setupPacket->Packet.bm.Request.Type), GetBmRequestRecipientString(setupPacket->Packet.bm.Request.Recipient), setupPacket->Packet.bm.Request.Reserved, setupPacket->Packet.bRequest, setupPacket->Packet.wIndex.Value, setupPacket->Packet.wValue.Value, setupPacket->Packet.wLength); // If the device and config descriptor requests are not handled they will be the "true" // descriptors directly from the device. i.e. if the device has two unassociated interfaces // the composite layer will split it into two but each virtual device interface would show // both interface deacriptors. // if (setupPacket->Packet.bm.Request.Dir == BMREQUEST_DEVICE_TO_HOST && setupPacket->Packet.bm.Request.Type == BMREQUEST_STANDARD && setupPacket->Packet.bRequest == USB_REQUEST_GET_DESCRIPTOR) { UCHAR descriptorType = setupPacket->Packet.wValue.Bytes.HiByte; // UCHAR descriptorIndex = setupPacket->Packet.wValue.Bytes.LowByte; ULONG descriptorSize = 0; PVOID descriptorIn = NULL; PVOID outputBuffer = NULL; size_t outputBufferLength = 0; if (requestContext->IoControlCode == LIBUSB_IOCTL_GET_DESCRIPTOR) { switch(descriptorType) { case USB_DESCRIPTOR_TYPE_DEVICE: descriptorSize = sizeof(deviceContext->UsbDeviceDescriptor); descriptorIn = &deviceContext->UsbDeviceDescriptor; break; case USB_DESCRIPTOR_TYPE_CONFIGURATION: if (setupPacket->Packet.wValue.Bytes.LowByte == 0) { descriptorSize = deviceContext->ConfigurationDescriptorSize; descriptorIn = deviceContext->UsbConfigurationDescriptor; } else { // we only support the one for now. ;) WdfRequestCompleteWithInformation(Request, STATUS_NO_MORE_ENTRIES, 0); return; } break; } if (descriptorIn && descriptorSize) { // handle (or fail) this standard request here. status = WdfRequestRetrieveOutputBuffer(Request, 2, &outputBuffer, &outputBufferLength); if (NT_SUCCESS(status)) { descriptorSize = (ULONG)min(descriptorSize, outputBufferLength); RtlCopyMemory(outputBuffer, descriptorIn, descriptorSize); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, descriptorSize); return; } USBERR("WdfRequestRetrieveOutputBuffer failed. status=%Xh\n", status); WdfRequestCompleteWithInformation(Request, status, 0); return; } } } if (METHOD_FROM_CTL_CODE(requestContext->IoControlCode) == METHOD_BUFFERED && requestContext->RequestType == WdfRequestTypeWrite) { // support for some of the legacy LIBUSB_IOCTL codes which place the data input // buffer at the end of the libusb_request structure. status = WdfRequestRetrieveInputMemory(Request, &transferMemory); if (!NT_SUCCESS(status)) { USBERR("WdfRequestRetrieveInputMemory failed. status=%Xh\n", status); goto Exit; } if (requestContext->Length < sizeof(libusb_request)) { // this can never happen because the input buffer length is checked for // this by the default IoControl event. status = STATUS_BUFFER_TOO_SMALL; USBERR("input buffer length is less than sizeof(libusb_request) status=%Xh\n", status); goto Exit; } transferOffset->BufferOffset = sizeof(libusb_request); transferOffset->BufferLength = requestContext->Length - sizeof(libusb_request); if (transferOffset->BufferLength == 0) { // this is okay but no input data means transferOffset->BufferOffset is pointing // to invalid memory; because the length is also zero it is still most likely safe. transferOffset = NULL; transferMemory = NULL; } } else { // native control transfers are direct; data comes from/goes to the out buffer whether reading or writing. transferOffset = NULL; status = WdfRequestRetrieveOutputMemory(Request, &transferMemory); if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { USBERR("WdfRequestRetrieveOutputMemory failed. status=%Xh\n", status); goto Exit; } if (status == STATUS_BUFFER_TOO_SMALL) { // zero length transfer buffer, this is okay. transferMemory = NULL; USBMSG("zero-length transfer buffer\n"); } } status = WdfUsbTargetDeviceFormatRequestForControlTransfer( deviceContext->WdfUsbTargetDevice, Request, setupPacket, transferMemory, transferOffset); if (!NT_SUCCESS(status)) { USBERR("WdfUsbTargetDeviceFormatRequestForControlTransfer failed. status=%Xh\n", status); goto Exit; } WdfRequestSetCompletionRoutine(Request, XferCtrlComplete, NULL); WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, 0); status = SetRequestTimeout(requestContext, Request, &sendOptions); if (!NT_SUCCESS(status)) { USBERR("SetRequestTimeout failed. status=%Xh\n", status); goto Exit; } if (!WdfRequestSend(Request, WdfUsbTargetDeviceGetIoTarget(deviceContext->WdfUsbTargetDevice), &sendOptions)) { status = WdfRequestGetStatus(Request); USBERR("WdfRequestSend failed. status=%Xh\n", status); } else { USBMSGN("[Ok] status=%Xh", status); return; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } return; }
/////////////////////////////////////////////////////////////////////////////// // // BasicUsbEvtRead // // This routine is called by the framework when there is a // read request for us to process // // INPUTS: // // Queue - Our default queue // // Request - A read request // // Length - The length of the read operation // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL == PASSIVE_LEVEL, due to // our PASSIVE_LEVEL execution level contraint // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// VOID BasicUsbEvtRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length) { PBASICUSB_DEVICE_CONTEXT devContext; WDFMEMORY requestMemory; NTSTATUS status; WDF_REQUEST_PARAMETERS requestParams; WDF_REQUEST_SEND_OPTIONS sendOptions; UNREFERENCED_PARAMETER(Length); #if DBG DbgPrint("BasicUsbEvtRead\n"); #endif devContext = BasicUsbGetContextFromDevice( WdfIoQueueGetDevice(Queue) ); // // The purpose of this routine will be to convert the read that // we received from the user into a USB request and send it to // the underlying bus driver. // // // First thing to do is get the output memory associated // with the request (only because it's a required parameter // to WdfUsbTargetPipeFormatRequestForRead) // status = WdfRequestRetrieveOutputMemory(Request, &requestMemory); if(!NT_SUCCESS(status)){ #if DBG DbgPrint("WdfRequestRetrieveOutputMemory failed 0x%0x\n", status); #endif WdfRequestComplete(Request, status); return; } // // Take the user Read request and format it into a Bulk // IN request. // status = WdfUsbTargetPipeFormatRequestForRead(devContext->BulkInPipe, Request, requestMemory, NULL); if(!NT_SUCCESS(status)){ #if DBG DbgPrint("WdfUsbTargetPipeFormatRequestForRead failed 0x%0x\n", status); #endif WdfRequestComplete(Request, status); return; } // // We'd like to asynchronously send this newly formatted request // to the underlying bus driver. In order to do that, we *must* // supply a completion routine that calls WdfRequestComplete. // Failure to do so is not architecturally defined, which means // it ain't gonna work. // // Note that because we have modified the request, we are not // allowed to use the WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET // flag as a cheap shortcut, we MUST supply the completion // routine. // WdfRequestSetCompletionRoutine( Request, BasicUsbEvtRequestReadCompletionRoutine, NULL); // // Send the request! // if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(devContext->BulkInPipe), NULL)) { // // Bad news. The target didn't get the request, so get the // failure status and complete the request ourselves.. // status = WdfRequestGetStatus(Request); #if DBG DbgPrint("WdfRequestSend failed 0x%0x\n", status); #endif WdfRequestComplete(Request, status); return; } return; }
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; }
NTSTATUS ToastMon_PostWriteRequests( IN WDFIOTARGET IoTarget ) /*++ Routine Description: Called by the timer callback to send a write request to the target device. Return Value: NT Status code - only failure expected is STATUS_INSUFFICIENT_RESOURCES --*/ { WDFREQUEST request; NTSTATUS status; PTARGET_DEVICE_INFO targetInfo; WDFMEMORY memory; WDF_OBJECT_ATTRIBUTES attributes; targetInfo = GetTargetDeviceInfo(IoTarget); request = targetInfo->WriteRequest; // // Allocate memory for write. Ideally I should have allocated the memory upfront along // with the request because the sizeof the memory buffer is constant. // But for demonstration, I have choosen to allocate a memory // object everytime I send a request down and delete it when the request // is completed. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); status = WdfMemoryCreate( &attributes, NonPagedPool, DRIVER_TAG, WRITE_BUF_SIZE, &memory, NULL); // buffer pointer if (!NT_SUCCESS(status)) { KdPrint(("WdfMemoryCreate failed 0x%x\n", status)); return status; } status = WdfIoTargetFormatRequestForWrite( IoTarget, request, memory, NULL, // Buffer offset NULL); // OutputBufferOffset if (!NT_SUCCESS(status)) { KdPrint(("WdfIoTargetFormatRequestForWrite failed 0x%x\n", status)); return status; } WdfRequestSetCompletionRoutine(request, Toastmon_WriteRequestCompletionRoutine, targetInfo); // // Clear the WriteRequest field in the context to avoid // being reposted even before the reqeuest completes. // This will be reset in the complete routine when the request completes. // targetInfo->WriteRequest = NULL; if(WdfRequestSend(request, IoTarget, WDF_NO_SEND_OPTIONS) == FALSE) { status = WdfRequestGetStatus(request); KdPrint(("WdfRequestSend failed 0x%x\n", status)); targetInfo->WriteRequest = request; } return status; }
VOID OsrFxEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: Called by the framework when it receives Read or Write requests. Arguments: Queue - Default queue handle Request - Handle to the read/write request Lenght - Length of the data buffer associated with the request. 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: --*/ { NTSTATUS status; WDFUSBPIPE pipe; WDFMEMORY reqMemory; PDEVICE_CONTEXT pDeviceContext; UNREFERENCED_PARAMETER(Queue); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "-->OsrFxEvtIoWrite\n"); // // First validate input parameters. // if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", TEST_BOARD_TRANSFER_BUFFER_SIZE); status = STATUS_INVALID_PARAMETER; goto Exit; } pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); pipe = pDeviceContext->BulkWritePipe; status = WdfRequestRetrieveInputMemory(Request, &reqMemory); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestRetrieveInputBuffer failed\n"); goto Exit; } status = WdfUsbTargetPipeFormatRequestForWrite(pipe, Request, reqMemory, NULL); // Offset if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfUsbTargetPipeFormatRequest failed 0x%x\n", status); goto Exit; } WdfRequestSetCompletionRoutine( Request, EvtRequestWriteCompletionRoutine, pipe); // // Send the request asynchronously. // if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { // // Framework couldn't send the request for some reason. // TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestSend failed\n"); status = WdfRequestGetStatus(Request); goto Exit; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- OsrFxEvtIoWrite\n"); return; }
VOID OsrFxEvtIoRead( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t Length ) /*++ Routine Description: Called by the framework when it receives Read or Write requests. Arguments: Queue - Default queue handle Request - Handle to the read/write request Lenght - Length of the data buffer associated with the request. 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: --*/ { WDFUSBPIPE pipe; NTSTATUS status; WDFMEMORY reqMemory; PDEVICE_CONTEXT pDeviceContext; GUID activity = RequestToActivityId(Request); UNREFERENCED_PARAMETER(Queue); // // Log read start event, using IRP activity ID if available or request // handle otherwise. // EventWriteReadStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "-->OsrFxEvtIoRead\n"); // // First validate input parameters. // if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", TEST_BOARD_TRANSFER_BUFFER_SIZE); status = STATUS_INVALID_PARAMETER; goto Exit; } pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); pipe = pDeviceContext->BulkReadPipe; status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); goto Exit; } // // The format call validates to make sure that you are reading or // writing to the right pipe type, sets the appropriate transfer flags, // creates an URB and initializes the request. // status = WdfUsbTargetPipeFormatRequestForRead(pipe, Request, reqMemory, NULL // Offsets ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfUsbTargetPipeFormatRequestForRead failed 0x%x\n", status); goto Exit; } WdfRequestSetCompletionRoutine( Request, EvtRequestReadCompletionRoutine, pipe); // // Send the request asynchronously. // if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { // // Framework couldn't send the request for some reason. // TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestSend failed\n"); status = WdfRequestGetStatus(Request); goto Exit; } Exit: if (!NT_SUCCESS(status)) { // // log event read failed // EventWriteReadFail(&activity, WdfIoQueueGetDevice(Queue), status); WdfRequestCompleteWithInformation(Request, status, 0); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "<-- OsrFxEvtIoRead\n"); return; }
NTSTATUS BthEchoRepeatReaderSubmit( _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, _In_ PBTHECHO_REPEAT_READER RepeatReader ) /*++ Description: This routine submits the repeat reader. In case of failure it invoked contreader failed callback Arguments: DevCtxHdr - Device context header RepeatReader - Repeat reader to submit Return Value: NTSTATUS Status code. --*/ { NTSTATUS status, statusReuse; WDF_REQUEST_REUSE_PARAMS reuseParams; struct _BRB_L2CA_ACL_TRANSFER *brb = &RepeatReader->TransferBrb; DevCtxHdr->ProfileDrvInterface.BthReuseBrb((PBRB)brb, BRB_L2CA_ACL_TRANSFER); WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_UNSUCCESSFUL); statusReuse = WdfRequestReuse(RepeatReader->RequestPendingRead, &reuseParams); NT_ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); // // Check if we are stopping, if yes set StopEvent and exit. // // After this point request is eligible for cancellation, so if this // flag gets set after we check it, request will be cancelled for stopping // the repeat reader and next time around we will stop when we are invoked // again upon completion of cancelled request. // if (RepeatReader->Stopping) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, "Continuos reader 0x%p stopping", RepeatReader); KeSetEvent(&RepeatReader->StopEvent, 0, FALSE); status = STATUS_SUCCESS; goto exit; } // // Format request for L2CA IN transfer // status = BthEchoConnectionObjectFormatRequestForL2CaTransfer( RepeatReader->Connection, RepeatReader->RequestPendingRead, &brb, RepeatReader->MemoryPendingRead, ACL_TRANSFER_DIRECTION_IN | ACL_SHORT_TRANSFER_OK ); if (!NT_SUCCESS(status)) { goto exit; } // // Set a CompletionRoutine callback function. // WdfRequestSetCompletionRoutine( RepeatReader->RequestPendingRead, BthEchoRepeatReaderPendingReadCompletion, RepeatReader ); // // Clear the stop event before sending the request // This is relevant only on start of the repeat reader // (i.e. the first submission) // this event eventually gets set only when repeat reader stops // and not on every resubmission. // KeClearEvent(&RepeatReader->StopEvent); if (FALSE == WdfRequestSend( RepeatReader->RequestPendingRead, DevCtxHdr->IoTarget, NULL )) { status = WdfRequestGetStatus(RepeatReader->RequestPendingRead); TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", RepeatReader->RequestPendingRead, brb, status ); goto exit; } else { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, "Resubmited pending read with request 0x%p, Brb 0x%p", RepeatReader->RequestPendingRead, brb ); } exit: if (!NT_SUCCESS(status)) { // // Invoke the reader failed callback before setting the event // to ensure that the connection object is alive during this callback // RepeatReader->Connection->ContinuousReader.BthEchoConnectionObjectContReaderFailedCallback( RepeatReader->Connection->DevCtxHdr, RepeatReader->Connection ); // // If we failed to send pending read, set the event since // we will not get completion callback // KeSetEvent(&RepeatReader->StopEvent, 0, FALSE); } return status; }