NS_IMETHODIMP RequestContextService::GetRequestContextFromLoadGroup(nsILoadGroup *aLoadGroup, nsIRequestContext **rc) { nsresult rv; uint64_t rcID; rv = aLoadGroup->GetRequestContextID(&rcID); if (NS_FAILED(rv)) { return rv; } return GetRequestContext(rcID, rc); }
/*++ Routine Description: This callback is invoked on every inflight request when the device is suspended or removed. Since our inflight read and write requests are actually pending in the target device, we will just acknowledge its presence. Until we acknowledge, complete, or requeue the requests framework will wait before allowing the device suspend or remove to proceed. When the underlying USB stack gets the request to suspend or remove, it will fail all the pending requests. Arguments: Return Value: None --*/ VOID PSDrvEvtIoStop(__in WDFQUEUE Queue, __in WDFREQUEST Request, __in ULONG ActionFlags) { PREQUEST_CONTEXT reqContext; UNREFERENCED_PARAMETER(Queue); reqContext=GetRequestContext(Request); if (ActionFlags & WdfRequestStopActionSuspend ) { WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue } else if(ActionFlags & WdfRequestStopActionPurge) { WdfRequestCancelSentRequest(Request); } return; }
/* EvtIoStop Invoked for every inflight pipe write request. The callback executes when: 1) libusbK will stop the queue because of queue policy changes. 2) The system requests stand-by 3) The device is removed */ VOID Queue_OnStop( __in WDFQUEUE Queue, __in WDFREQUEST Request, __in ULONG ActionFlags) { PQUEUE_CONTEXT queueContext; PREQUEST_CONTEXT requestContext; if (Request == NULL || Queue == NULL) { USBERRN("Invalid wdf object."); return; } if ((queueContext = GetQueueContext(Queue)) == NULL) { USBERRN("Invalid queue context."); return; } if ((requestContext = GetRequestContext(Request)) == NULL) { USBERRN("Invalid request context."); return; } // None of the libusbK transfer functions set EvtRequestCancel, hence this should never happen. if (ActionFlags & WdfRequestStopRequestCancelable) { USBERRN("WdfRequestStopRequestCancelable! pipeID=%02Xh", queueContext->Info.EndpointAddress); WdfVerifierDbgBreakPoint(); return; } if (ActionFlags & WdfRequestStopActionSuspend) { USBDBGN("StopAcknowledge for ActionSuspend. pipeID=%02Xh request=%p timeout=%d", queueContext->Info.EndpointAddress, Request, requestContext->Timeout); WdfRequestStopAcknowledge(Request, FALSE); } else if(ActionFlags & WdfRequestStopActionPurge) { USBDBGN("CancelSentRequest for ActionPurge. pipeID=%02Xh request=%p timeout=%d", queueContext->Info.EndpointAddress, Request, requestContext->Timeout); WdfRequestCancelSentRequest(Request); } }
/* EvtIoResume Invoked for pipe write requests which were "StopAcknowledge" in EvtIoStop. This callback exucutes after the device has re-entered D0(working). */ VOID Queue_OnResume(WDFQUEUE Queue, WDFREQUEST Request) { PQUEUE_CONTEXT queueContext; PREQUEST_CONTEXT requestContext; NTSTATUS status = STATUS_SUCCESS; if (Request == NULL || Queue == NULL) { USBERRN("Invalid wdf object."); return; } if ((queueContext = GetQueueContext(Queue)) == NULL) { USBERRN("Invalid queue context."); return; } if ((requestContext = GetRequestContext(Request)) == NULL) { USBERRN("Invalid request context."); return; } mXfer_HandlePipeResetScenarios(status, queueContext, requestContext); }
VOID PipeQueue_OnIoControl(__in WDFQUEUE Queue, __in WDFREQUEST Request, __in size_t OutputBufferLength, __in size_t InputBufferLength, __in ULONG IoControlCode) { NTSTATUS status; ULONG length = 0; PREQUEST_CONTEXT requestContext = GetRequestContext(Request); PQUEUE_CONTEXT queueContext = NULL; VALIDATE_REQUEST_CONTEXT(requestContext, status); if (!NT_SUCCESS(status)) goto Done; if ((queueContext = GetQueueContext(Queue)) == NULL) { status = STATUS_INVALID_DEVICE_REQUEST; USBERRN("Invalid queue context"); goto Done; } switch(IoControlCode) { case LIBUSB_IOCTL_ISOCHRONOUS_READ: case LIBUSB_IOCTL_ISOCHRONOUS_WRITE: case LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE: case LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ: switch (queueContext->Info.PipeType) { case WdfUsbPipeTypeIsochronous: if (USB_ENDPOINT_DIRECTION_IN(queueContext->Info.EndpointAddress)) { XferIsoRead(Queue, Request); return; } XferIsoWrite(Queue, Request); return; case WdfUsbPipeTypeBulk: case WdfUsbPipeTypeInterrupt: if(requestContext->Policies.RawIO) { if (USB_ENDPOINT_DIRECTION_IN(queueContext->Info.EndpointAddress)) Xfer_ReadBulkRaw(Queue, Request); else Xfer_WriteBulkRaw(Queue, Request); } else { if (USB_ENDPOINT_DIRECTION_IN(queueContext->Info.EndpointAddress)) Xfer_ReadBulk(Queue, Request); else Xfer_WriteBulk(Queue, Request); } return; default: status = STATUS_INVALID_PARAMETER; USBERRN("Invalid PipeType=%s\n", GetPipeTypeString(queueContext->Info.PipeType)); break; } case LIBUSBK_IOCTL_ISOEX_READ: case LIBUSBK_IOCTL_ISOEX_WRITE: if (queueContext->Info.PipeType == WdfUsbPipeTypeIsochronous) { XferIsoEx(Queue, Request); return; } status = STATUS_INVALID_PARAMETER; USBERRN("Invalid PipeType=%s\n", GetPipeTypeString(queueContext->Info.PipeType)); break; /* case LIBUSBK_IOCTL_AUTOISOEX_READ: case LIBUSBK_IOCTL_AUTOISOEX_WRITE: if (queueContext->Info.PipeType == WdfUsbPipeTypeIsochronous) { XferAutoIsoEx(Queue, Request); return; } status = STATUS_INVALID_PARAMETER; USBERRN("Invalid PipeType=%s\n", GetPipeTypeString(queueContext->Info.PipeType)); break; */ case LIBUSB_IOCTL_SET_FEATURE: case LIBUSB_IOCTL_CLEAR_FEATURE: case LIBUSB_IOCTL_GET_DESCRIPTOR: case LIBUSB_IOCTL_SET_DESCRIPTOR: case LIBUSB_IOCTL_VENDOR_WRITE: case LIBUSB_IOCTL_VENDOR_READ: case LIBUSB_IOCTL_CONTROL_READ: case LIBUSB_IOCTL_CONTROL_WRITE: XferCtrl(Queue, Request, InputBufferLength, OutputBufferLength); return; default: USBERR("unknown IoControlCode %Xh (function=%04Xh)\n", IoControlCode, FUNCTION_FROM_CTL_CODE(IoControlCode)); status = STATUS_INVALID_DEVICE_REQUEST; WdfRequestCompleteWithInformation(Request, status, 0); return; } Done: WdfRequestCompleteWithInformation(Request, status, length); return; }
static VOID UsbChief_ReadEndPoint(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG totalLength) { PMDL newMdl=NULL, requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG stageLength = 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; UsbChief_DbgPrint(DEBUG_RW, ("UsbChief_DispatchReadWrite - begins\n")); deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); rwContext = GetRequestContext(Request); status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)){ UsbChief_DbgPrint(0, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); goto Exit; } virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); if (totalLength > MAX_TRANSFER_SIZE) stageLength = MAX_TRANSFER_SIZE; else stageLength = totalLength; newMdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); if (!newMdl) { UsbChief_DbgPrint(0, ("Failed to alloc mem for mdl\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } 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)) { UsbChief_DbgPrint(0, ("Failed to alloc mem for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL ); if (!NT_SUCCESS(status)) { UsbChief_DbgPrint(0, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, UsbChief_ReadCompletion, NULL); 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); ASSERT(!NT_SUCCESS(status)); } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } }
VOID NdisprotSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_BUFFER_LIST pNetBufferList, IN ULONG SendCompleteFlags ) /*++ Routine Description: NDIS entry point called to signify completion of a packet send. We pick up and complete the Write IRP corresponding to this packet. Arguments: ProtocolBindingContext - pointer to open context pNetBufferList - NetBufferList that completed send SendCompleteFlags - Specifies if the caller is at DISPATCH level Return Value: None --*/ { PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST CurrNetBufferList = NULL; PNET_BUFFER_LIST NextNetBufferList; NDIS_STATUS CompletionStatus; BOOLEAN DispatchLevel; WDFREQUEST request; PREQUEST_CONTEXT reqContext; pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext; NPROT_STRUCT_ASSERT(pOpenContext, oc); DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags); for (CurrNetBufferList = pNetBufferList; CurrNetBufferList != NULL; CurrNetBufferList = NextNetBufferList) { NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList); request = NPROT_REQUEST_FROM_SEND_NBL(CurrNetBufferList); reqContext = GetRequestContext(request); CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList); DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d " "completed with status %x\n", CurrNetBufferList, request, reqContext->Length, CompletionStatus)); // // We are done with the NDIS_PACKET: // NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel); CurrNetBufferList = NULL; if (CompletionStatus == NDIS_STATUS_SUCCESS) { WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, reqContext->Length); } else { WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); pOpenContext->PendedSendCount--; if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING)) && (pOpenContext->PendedSendCount == 0)) { NPROT_ASSERT(pOpenContext->ClosingEvent != NULL); NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent); pOpenContext->ClosingEvent = NULL; } NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP } }
VOID AmccPciEvtIoDefault( __in WDFQUEUE Queue, __in WDFREQUEST Request ) /*++ Routine Description: Start the IRP on the device. This driver allows only one I/O to be active on the adapter at any one time. If multiple I/Os are sent to the driver, they will be queued and completed as they complete on the adapter (one IRP per interrupt). Arguments: Queue - Default queue handle Request - Handle to the write request Parameters - Contains current stack location information from the IRP Return Value: None --*/ { PAMCC_DEVICE_EXTENSION devExt; REQUEST_CONTEXT * transfer; NTSTATUS status; size_t length; WDF_DMA_DIRECTION direction; WDFDMATRANSACTION dmaTransaction; WDF_REQUEST_PARAMETERS params; WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters( Request, ¶ms ); // // Get the device extension. // devExt = AmccPciGetDevExt(WdfIoQueueGetDevice( Queue )); // // Validate and gather parameters. // switch (params.Type) { case WdfRequestTypeRead: length = params.Parameters.Read.Length; direction = WdfDmaDirectionReadFromDevice; break; case WdfRequestTypeWrite: length = params.Parameters.Write.Length; direction = WdfDmaDirectionWriteToDevice; break; default: TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO, "Request type not Read or Write\n"); WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO, "Request %p: %s %d bytes", Request, (direction)?"Write":"Read", (ULONG)length); // // The length must be non-zero. // if (length == 0) { TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO, "Zero transfer length input to read/write"); WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } transfer = GetRequestContext(Request); // // Create new DmaRequst to conduct this DMA transaction. // status = WdfDmaTransactionCreate( devExt->DmaEnabler, WDF_NO_OBJECT_ATTRIBUTES, &dmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "WdfDmaRequestCreate failed: %X", status); WdfRequestComplete(Request, status); return; } // // Create new DmaTransaction. // status = WdfDmaTransactionInitializeUsingRequest( dmaTransaction, Request, AmccPciProgramDma, direction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "WdfDmaRequestInitializeWithRequest failed: %X", status); WdfObjectDelete(dmaTransaction); WdfRequestComplete(Request, status); return; } // // Fill transfer context structure // transfer->Request = Request; transfer->DmaTransaction = dmaTransaction; // // Save the current Request as the "in-progress" request. // devExt->CurrentRequest = Request; // // Execute this dmaTransaction transaction. // status = WdfDmaTransactionExecute( dmaTransaction, WDF_NO_CONTEXT); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "WdfDmaTransactionExecute failed: %X", status); WdfObjectDelete(dmaTransaction); WdfRequestComplete(Request, status); return; } 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; }
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 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; }
net::URLRequestContextGetter *BrowserContextQt::GetMediaRequestContext() { return GetRequestContext(); }
net::URLRequestContextGetter *BrowserContextQt::GetRequestContextForRenderProcess(int) { return GetRequestContext(); }
net::URLRequestContextGetter *BrowserContextQt::GetMediaRequestContextForStoragePartition(const base::FilePath&, bool) { return GetRequestContext(); }
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; }
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 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 --*/ { size_t totalLength = Length; size_t stageLength = 0; NTSTATUS status; PVOID virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDFMEMORY reqMemory; WDFMEMORY_OFFSET offset; WDF_OBJECT_ATTRIBUTES objectAttribs; PDEVICE_CONTEXT deviceContext; kJtag_DbgPrint(3, ("kJtag_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { kJtag_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { kJtag_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; 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)){ kJtag_DbgPrint(1, ("WdfRequestRetrieveInputBuffer failed\n")); goto Exit; } // // If the totalLength exceeds MAX_TRANSFER_SIZE, we will break // that into multiple transfer of size no more than MAX_TRANSFER_SIZE // in each stage. // if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = totalLength; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreatePreallocated(&objectAttribs, virtualAddress, totalLength, &reqMemory); if(!NT_SUCCESS(status)){ kJtag_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) { kJtag_DbgPrint(3, ("Read operation\n")); status = WdfUsbTargetPipeFormatRequestForRead(pipe, Request, reqMemory, &offset); } else { kJtag_DbgPrint(3, ("Write operation\n")); status = WdfUsbTargetPipeFormatRequestForWrite(pipe, Request, reqMemory, &offset); } if (!NT_SUCCESS(status)) { kJtag_DbgPrint(1, ("WdfUsbTargetPipeFormatRequest failed 0x%x\n", status)); goto Exit; } WdfRequestSetCompletionRoutine( Request, ReadWriteCompletion, NULL); // // set REQUEST_CONTEXT parameters. // rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; // // Send the request asynchronously. // if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { kJtag_DbgPrint(1, ("WdfRequestSend failed\n")); status = WdfRequestGetStatus(Request); goto Exit; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } kJtag_DbgPrint(3, ("kJtag_DispatchReadWrite - ends\n")); return; }
VOID Xfer_ReadBulk ( __in WDFQUEUE Queue, __in WDFREQUEST Request) { NTSTATUS status; PREQUEST_CONTEXT requestContext = NULL; PQUEUE_CONTEXT queueContext = NULL; PDEVICE_CONTEXT deviceContext; ULONG remainingLength; ULONG stageLength = 0; ULONG remainderLength = 0; WDF_REQUEST_SEND_OPTIONS sendOptions; PUCHAR transferBuffer; deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); requestContext = GetRequestContext(Request); VALIDATE_REQUEST_CONTEXT(requestContext, status); if (!NT_SUCCESS(status)) goto Exit; if ((queueContext = GetQueueContext(Queue)) == NULL) { status = STATUS_INVALID_DEVICE_REQUEST; USBERRN("Invalid queue context"); goto Exit; } queueContext->Xfer.Transferred = 0; queueContext->Xfer.Length = requestContext->Length; if (!queueContext->OverMem) { status = STATUS_INVALID_DEVICE_REQUEST; USBERRN("Invalid queue context:OverMem"); goto Exit; } if (!queueContext->Info.MaximumPacketSize) { status = STATUS_INVALID_BUFFER_SIZE; USBERRN("PipeID=%02Xh MaximumPacketSize=0", queueContext->Info.EndpointAddress); goto Exit; } // handle pipe reset scenarios: ResetPipeOnResume, AutoClearStall mXfer_HandlePipeResetScenarios(status, queueContext, requestContext); // Handle special case scenario where read length = 0 if (!queueContext->Xfer.Length) { // if AllowPartialReads complete successfully for 0 bytes status = requestContext->Policies.AllowPartialReads ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE; goto Exit; } // Init queue user memory status = GetTransferMemory(Request, requestContext->ActualRequestType, &queueContext->Xfer.UserMem); if (!NT_SUCCESS(status)) { USBERR("GetTransferMemory failed. Status=%08Xh\n", status); goto Exit; } queueContext->Xfer.UserOfs.BufferOffset = 0; queueContext->Xfer.UserOfs.BufferLength = queueContext->Xfer.Length; // Check if there are bytes left over from a previous transfer. if (queueContext->OverOfs.BufferLength > 0) { // Copy partial read bytes bytes into UserMem remainingLength = queueContext->Xfer.Length - queueContext->Xfer.Transferred; stageLength = (ULONG)queueContext->OverOfs.BufferLength > remainingLength ? remainingLength : (ULONG)queueContext->OverOfs.BufferLength; transferBuffer = &queueContext->OverBuf[queueContext->OverOfs.BufferOffset]; mXfer_CopyPartialReadToUserMemory(status, queueContext, transferBuffer, stageLength, goto Exit); USBDBGN("PipeID=%02Xh Transferred %u bytes from a previous partial read.", queueContext->Info.EndpointAddress, queueContext->Xfer.Transferred); if (queueContext->Xfer.Transferred >= queueContext->Xfer.Length) { if (requestContext->Policies.AutoFlush) { // discard any extra partial read bytes queueContext->OverOfs.BufferLength = 0; queueContext->OverOfs.BufferOffset = 0; } USBMSGN("PipeID=%02Xh DoneReason: Transferred==Requested. Transferred=%u", queueContext->Info.EndpointAddress, queueContext->Xfer.Transferred); status = STATUS_SUCCESS; goto Exit; } /* It would seem if IgnoreShortPackets=FALSE we would complete the request here. However, WinUSB does not handle it this way and will still submit the request. */ #if 0 else if (!requestContext->Policies.IgnoreShortPackets) { USBMSGN("PipeID=%02Xh DoneReason: IgnoreShortPackets=FALSE. Transferred=%u", queueContext->Info.EndpointAddress, queueContext->Xfer.Transferred); status = STATUS_SUCCESS; goto Exit; } #endif }
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; }
/*++ 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 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 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 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; }
VOID AmccPciEvtInterruptDpc( __in WDFINTERRUPT WdfInterrupt, __in WDFOBJECT WdfDevice ) /*++ Routine Description: DPC callback for ISR. Arguments: WdfInterrupt - Handle to the framework interrupt object WdfDevice - Associated device object. Return Value: --*/ { PAMCC_DEVICE_EXTENSION devExt; WDFREQUEST request; REQUEST_CONTEXT * transfer; NTSTATUS status; size_t transferred; BOOLEAN transactionComplete; UNREFERENCED_PARAMETER( WdfInterrupt ); devExt = AmccPciGetDevExt(WdfDevice); // // Retreive request and transfer. // request = devExt->CurrentRequest; transfer = GetRequestContext(request); // // Check to see if the request is cancelled by the system. While // we are DMAing a large buffer into multiple transaction, // there is good possibilty for the request to get cancelled because // the originator of the request exited or cancelled the I/O explicitly. // if(WdfRequestIsCanceled(request)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "Aborted DMA transaction 0x%p", request); WdfObjectDelete( transfer->DmaTransaction ); devExt->CurrentRequest = NULL; WdfRequestComplete(request, STATUS_CANCELLED); return; } // // The boolean transactionComplete indicates whether the transaction has // exited the transfer state, e.g. no further transfers are scheduled. // // If transactionComplete == FALSE, then the next DMA transfer has been // scheduled, e.g. the next interrrupt will drive the ISR again. // // If transactionComplete == TRUE, then status indicates the reason; // SUCCESS is the nomative case, while non-SUCCESS indicates the // DMA transaction failed for "status" reason. // transactionComplete = WdfDmaTransactionDmaCompleted( transfer->DmaTransaction, &status ); if (transactionComplete) { ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED); // // No more data: request is complete // TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO, "Request %p completed: status %X", request, status); // // Get the final bytes transferred count. // transferred = WdfDmaTransactionGetBytesTransferred( transfer->DmaTransaction ); TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO, "Bytes transfered %d", (int) transferred ); // // Delete this DmaTransaction transaction. // WdfObjectDelete( transfer->DmaTransaction ); // // Clean-up for this request. // devExt->CurrentRequest = NULL; // // Complete this IO request. // WdfRequestCompleteWithInformation( request, status, (NT_SUCCESS(status)) ? transferred : 0 ); } }
VOID PipeQueue_OnWrite(__in WDFQUEUE Queue, __in WDFREQUEST Request, __in size_t InputBufferLength) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_CONTEXT deviceContext; PREQUEST_CONTEXT requestContext; PQUEUE_CONTEXT queueContext = NULL; UNREFERENCED_PARAMETER(InputBufferLength); deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); requestContext = GetRequestContext(Request); VALIDATE_REQUEST_CONTEXT(requestContext, status); if (!NT_SUCCESS(status)) goto Done; if ((queueContext = GetQueueContext(Queue)) == NULL) { status = STATUS_INVALID_DEVICE_REQUEST; USBERRN("Invalid queue context"); goto Done; } if (!queueContext->PipeHandle) { USBERR("null pipe handle\n"); status = STATUS_INVALID_HANDLE; goto Done; } switch(queueContext->Info.PipeType) { case WdfUsbPipeTypeIsochronous: if (USB_ENDPOINT_DIRECTION_OUT(queueContext->Info.EndpointAddress)) { XferIsoWrite(Queue, Request); return; } break; case WdfUsbPipeTypeBulk: case WdfUsbPipeTypeInterrupt: if (USB_ENDPOINT_DIRECTION_IN(queueContext->Info.EndpointAddress)) { status = STATUS_INVALID_DEVICE_REQUEST; USBERRN("Cannot write to an IN pipe."); goto Done; } if(requestContext->Policies.RawIO) Xfer_WriteBulkRaw(Queue, Request); else Xfer_WriteBulk(Queue, Request); } status = STATUS_INVALID_DEVICE_REQUEST; USBERRN("PipeID=%02Xh Invalid request", queueContext->Info.EndpointAddress); Done: WdfRequestCompleteWithInformation(Request, status, 0); }
__drv_sameIRQL NTSTATUS BthEchoCliOpenRemoteConnection( __in PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, __in WDFFILEOBJECT FileObject, __in WDFREQUEST Request ) /*++ Description: This routine is invoked by BthEchoCliEvtDeviceFileCreate. In this routine we send down open channel BRB. This routine allocates open channel BRB. If the request is sent down successfully completion routine needs to free this BRB. Arguments: __in PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx - __in WDFFILEOBJECT FileObject - __in WDFREQUEST Request - Return Value: NTSTATUS Status code. --*/ { NTSTATUS status; WDFOBJECT connectionObject; struct _BRB_L2CA_OPEN_CHANNEL *brb = NULL; PBTHECHO_CONNECTION connection = NULL; PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, "Connect request"); // // Create the connection object that would store information // about the open channel // // Set file object as the parent for this connection object // status = BthEchoConnectionObjectCreate( &DevCtx->Header, FileObject, //parent &connectionObject ); if (!NT_SUCCESS(status)) { goto exit; } connection = GetConnectionObjectContext(connectionObject); connection->ConnectionState = ConnectionStateConnecting; // // Get the BRB from request context and initialize it as // BRB_L2CA_OPEN_CHANNEL BRB // brb = (struct _BRB_L2CA_OPEN_CHANNEL *)GetRequestContext(Request); DevCtx->Header.ProfileDrvInterface.BthReuseBrb( (PBRB)brb, BRB_L2CA_OPEN_CHANNEL ); brb->Hdr.ClientContext[0] = connection; brb->BtAddress = DevCtx->ServerBthAddress; brb->Psm = fileCtx->ServerPsm; brb->ChannelFlags = CF_ROLE_EITHER; brb->ConfigOut.Flags = 0; brb->ConfigIn.Flags = 0; brb->ConfigOut.Flags |= CFG_MTU; brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU; brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU; brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU; brb->ConfigIn.Flags = CFG_MTU; brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max; brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min; brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max; // // Get notificaiton about remote disconnect // brb->CallbackFlags = CALLBACK_DISCONNECT; brb->Callback = &BthEchoCliIndicationCallback; brb->CallbackContext = connection; brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device); brb->IncomingQueueDepth = 50; status = BthEchoSharedSendBrbAsync( DevCtx->Header.IoTarget, Request, (PBRB) brb, sizeof(*brb), BthEchoCliRemoteConnectCompletion, brb //Context ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, "Sending brb for opening connection failed, returning status code %!STATUS!\n", status); goto exit; } exit: if(!NT_SUCCESS(status)) { if (connection) { // // Set the right state to facilitate debugging // connection->ConnectionState = ConnectionStateConnectFailed; } // // In case of failure of this routine we will fail // Create which will delete file object and since connection object // is child of the file object, it will be deleted too // } return status; }
static VOID UsbChief_ReadCompletion(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; ULONG bytesRead; UNREFERENCED_PARAMETER(Context); rwContext = GetRequestContext(Request); pipe = (WDFUSBPIPE)Target; status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)){ UsbChief_QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); goto End; } urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL); bytesRead = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; rwContext->Numxfer += bytesRead; if (rwContext->Length == 0) { WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } if (rwContext->Length > MAX_TRANSFER_SIZE) stageLength = MAX_TRANSFER_SIZE; else stageLength = rwContext->Length; UsbChief_DbgPrint(DEBUG_RW, ("Stage next Read transfer... %d bytes remaing\n", rwContext->Length)); MmPrepareMdlForReuse(rwContext->Mdl); status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)){ UsbChief_DbgPrint(0, ("WdfRequestRetrieveOutputWdmMdl for Read failed %x\n", status)); goto End; } IoBuildPartialMdl(requestMdl, rwContext->Mdl, (PVOID) rwContext->VirtualAddress, stageLength); urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength; rwContext->VirtualAddress += stageLength; rwContext->Length -= stageLength; status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, rwContext->UrbMemory, NULL); if (!NT_SUCCESS(status)) { UsbChief_DbgPrint(0, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } WdfRequestSetCompletionRoutine(Request, UsbChief_ReadCompletion, NULL); if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { UsbChief_DbgPrint(0, ("WdfRequestSend for Read failed\n")); status = WdfRequestGetStatus(Request); goto End; } return; End: IoFreeMdl(rwContext->Mdl); UsbChief_DbgPrint(DEBUG_RW, ("Read request completed with status 0x%x\n", status)); WdfRequestComplete(Request, status); }