Ejemplo n.º 1
0
NTSTATUS
WaitForUsbDeviceArrivalNotification(PDEVICE_OBJECT DeviceObject)
{
    PURB Urb;
    PIRP Irp;
    NTSTATUS Status;
    PIO_STACK_LOCATION Stack = NULL;
    PHUB_DEVICE_EXTENSION DeviceExtension;

    DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

    Urb = &DeviceExtension->Urb;

    RtlZeroMemory(Urb, sizeof(URB));

    /* Send URB to the miniports Status Change Endpoint SCE */
    UsbBuildInterruptOrBulkTransferRequest(Urb,
                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                           DeviceExtension->PipeHandle,
                                           &DeviceExtension->PortStatus,
                                           NULL,
                                           sizeof(ULONG) * 2,
                                           USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
                                           NULL);

    Urb->UrbHeader.UsbdDeviceHandle = DeviceExtension->RootHubUsbDevice;

    Irp = IoAllocateIrp(DeviceExtension->RootHubPdo->StackSize, FALSE);

    if (Irp == NULL)
    {
        DPRINT("Usbhub: IoBuildDeviceIoControlRequest() failed\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }


    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
    Irp->IoStatus.Information = 0;
    Irp->Flags = 0;
    Irp->UserBuffer = NULL;

    Stack = IoGetCurrentIrpStackLocation(Irp);
    Stack->DeviceObject = DeviceExtension->RootHubPdo;

    Stack = IoGetNextIrpStackLocation(Irp);
    Stack->DeviceObject = DeviceExtension->RootHubPdo;
    Stack->Parameters.Others.Argument1 = Urb;
    Stack->Parameters.Others.Argument2 = NULL;
    Stack->MajorFunction =  IRP_MJ_INTERNAL_DEVICE_CONTROL;
    Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;

    //IoSetCompletionRoutineEx(DeviceExtension->RootHubPdo, Irp, (PIO_COMPLETION_ROUTINE)DeviceArrivalCompletion, DeviceObject, TRUE, TRUE, TRUE);
    IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)DeviceArrivalCompletion, DeviceObject, TRUE, TRUE, TRUE);

    Status = IoCallDriver(DeviceExtension->RootHubPdo, Irp);
    DPRINT1("SCE request status %x\n", Status);

    return STATUS_PENDING;
}
Ejemplo n.º 2
0
VOID
USBSTOR_SendCSW(
    PIRP_CONTEXT Context,
    PIRP Irp)
{
    PIO_STACK_LOCATION IoStack;

    //
    // get next irp stack location
    //
    IoStack = IoGetNextIrpStackLocation(Irp);

    //
    // now initialize the urb for sending the csw
    //
    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                           Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
                                           Context->csw,
                                           NULL,
                                           512, //FIXME
                                           USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
                                           NULL);

    //
    // initialize stack location
    //
    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
    Irp->IoStatus.Status = STATUS_SUCCESS;


    //
    // setup completion routine
    //
    IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);

    //
    // call driver
    //
    IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
}
Ejemplo n.º 3
0
//Bulk or Interrupt transfer (asynchronous)
NTSTATUS UsbDev::UsbBulkOrInterruptTransfer(
	PIRP pIrp,
	PURB pUrb,
	PUSBD_PIPE_INFORMATION	pPipeInfo,
	BOOL Rw,
	PVOID TransferBuffer,
	PMDL TransferBufferMDL,
	ULONG TransferBufferLength,
	PVOID BulkOrInterruptCompletion,
	PVOID BulkOrInterruptContext
	)
{
	NTSTATUS	ntStatus;
	PIO_STACK_LOCATION	pStack;
	
	if(pIrp && pUrb && pPipeInfo && (TransferBuffer || TransferBufferMDL) && BulkOrInterruptCompletion && BulkOrInterruptContext)
	{// pIrp != NULL && pUrb != NULL
		pStack=IoGetNextIrpStackLocation(pIrp);
		pStack->Parameters.Others.Argument1 = pUrb;	
		pStack->Parameters.DeviceIoControl.IoControlCode=IOCTL_INTERNAL_USB_SUBMIT_URB;
		pStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;	
		UsbBuildInterruptOrBulkTransferRequest(pUrb,
											   sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
											   pPipeInfo->PipeHandle,
											   TransferBuffer,
											   TransferBufferMDL,
											   TransferBufferLength,
											   ((Rw ? USBD_TRANSFER_DIRECTION_IN : 0) | USBD_SHORT_TRANSFER_OK),
											   NULL);
		IoSetCompletionRoutine(pIrp,(PIO_COMPLETION_ROUTINE)BulkOrInterruptCompletion,BulkOrInterruptContext,TRUE,TRUE,TRUE);
		ntStatus = IoCallDriver(m_pLdo,pIrp);
	}// pIrp != NULL && pUrb != NULL
	else
	{// pIrp == NULL || pUrb == NULL
		ntStatus = STATUS_INVALID_PARAMETER;//((NTSTATUS)0xC000000DL)
	}// pIrp == NULL || pUrb == NULL

	return ntStatus;
}
Ejemplo n.º 4
0
/*++
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;
}
Ejemplo n.º 5
0
NTSTATUS
USBSTOR_SendRequest(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP OriginalRequest,
    IN UCHAR CommandLength,
    IN PUCHAR Command,
    IN ULONG TransferDataLength,
    IN PUCHAR TransferData,
    IN ULONG RetryCount)
{
    PIRP_CONTEXT Context;
    PPDO_DEVICE_EXTENSION PDODeviceExtension;
    PFDO_DEVICE_EXTENSION FDODeviceExtension;
    PIRP Irp;
    PUCHAR MdlVirtualAddress;

    //
    // first allocate irp context
    //
    Context = USBSTOR_AllocateIrpContext();
    if (!Context)
    {
        //
        // no memory
        //
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // get PDO device extension
    //
    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

    //
    // get FDO device extension
    //
    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;

    //
    // now build the cbw
    //
    USBSTOR_BuildCBW((ULONG)Context->cbw,
                     TransferDataLength,
                     PDODeviceExtension->LUN,
                     CommandLength,
                     Command,
                     Context->cbw);

    DPRINT("CBW %p\n", Context->cbw);
    DumpCBW((PUCHAR)Context->cbw);

    //
    // now initialize the urb
    //
    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                           FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
                                           Context->cbw,
                                           NULL,
                                           sizeof(CBW),
                                           USBD_TRANSFER_DIRECTION_OUT,
                                           NULL);

    //
    // initialize rest of context
    //
    Context->Irp = OriginalRequest;
    Context->TransferData = TransferData;
    Context->TransferDataLength = TransferDataLength;
    Context->FDODeviceExtension = FDODeviceExtension;
    Context->PDODeviceExtension = PDODeviceExtension;
    Context->RetryCount = RetryCount;

    //
    // is there transfer data
    //
    if (Context->TransferDataLength)
    {
        //
        // check if the original request already does have an mdl associated
        //
        if (OriginalRequest)
        {
            if ((OriginalRequest->MdlAddress != NULL) &&
                (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
            {
                //
                // Sanity check that the Mdl does describe the TransferData for read/write
                //
                if (CommandLength == UFI_READ_WRITE_CMD_LEN)
                {
                    MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);

                    //
                    // is there an offset
                    //
                    if (MdlVirtualAddress != Context->TransferData)
                    {
                        //
                        // lets build an mdl
                        //
                        Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
                        if (!Context->TransferBufferMDL)
                        {
                            //
                            // failed to allocate MDL
                            //
                            return STATUS_INSUFFICIENT_RESOURCES;
                        }

                        //
                        // now build the partial mdl
                        //
                        IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
                    }
                }

                if (!Context->TransferBufferMDL)
                {
                    //
                    // I/O paging request
                    //
                    Context->TransferBufferMDL = OriginalRequest->MdlAddress;
                }
            }
            else
            {
                //
                // allocate mdl for buffer, buffer must be allocated from NonPagedPool
                //
                Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
                if (!Context->TransferBufferMDL)
                {
                    //
                    // failed to allocate MDL
                    //
                    return STATUS_INSUFFICIENT_RESOURCES;
                }

                //
                // build mdl for nonpaged pool
                //
                MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
            }
        }
        else
        {
            //
            // allocate mdl for buffer, buffer must be allocated from NonPagedPool
            //
            Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
            if (!Context->TransferBufferMDL)
            {
                //
                // failed to allocate MDL
                //
                return STATUS_INSUFFICIENT_RESOURCES;
            }

            //
            // build mdl for nonpaged pool
            //
            MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
        }
    }

    //
    // now allocate the request
    //
    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
    if (!Irp)
    {
        FreeItem(Context->cbw);
        FreeItem(Context);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    if (OriginalRequest)
    {
        //
        // mark orignal irp as pending
        //
        IoMarkIrpPending(OriginalRequest);
    }

    //
    // send request
    //
    USBSTOR_SendCBW(Context, Irp);

    //
    // done
    //
    return STATUS_PENDING;
}
Ejemplo n.º 6
0
NTSTATUS
NTAPI
USBSTOR_CBWCompletionRoutine(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Ctx)
{
    PIRP_CONTEXT Context;
    PIO_STACK_LOCATION IoStack;
    UCHAR Code;
    USBD_PIPE_HANDLE PipeHandle;

    DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);

    //
    // access context
    //
    Context = (PIRP_CONTEXT)Ctx;

    //
    // get next stack location
    //
    IoStack = IoGetNextIrpStackLocation(Irp);

    //
    // is there data to be submitted
    //
    if (Context->TransferDataLength)
    {
        //
        // get command code
        //
        Code = Context->cbw->CommandBlock[0];

        if (Code == SCSIOP_WRITE)
        {
            //
            // write request use bulk out pipe
            //
            PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
        }
        else
        {
            //
            // default bulk in pipe
            //
            PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
        }

        //
        // now initialize the urb for sending data
        //
        UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
                                               sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                               PipeHandle,
                                               NULL,
                                               Context->TransferBufferMDL,
                                               Context->TransferDataLength,
                                               ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
                                               NULL);

        //
        // setup completion routine
        //
        IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
    }
    else
    {
        //
        // now initialize the urb for sending the csw
        //

        UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
                                               sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                               Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
                                               Context->csw,
                                               NULL,
                                               512, //FIXME
                                               USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
                                               NULL);

        //
        // setup completion routine
        //
        IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
    }

    //
    // initialize stack location
    //
    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
    Irp->IoStatus.Status = STATUS_SUCCESS;

    //
    // call driver
    //
    IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);

    return STATUS_MORE_PROCESSING_REQUIRED;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
NTSTATUS
NICPostInterruptRequest(
    PMP_ADAPTER Adapter,
    PNOTICB    pNotiCB
    )
/*++

Routine Description:

    This routine sends a read IRP to the target device to get
    the incoming network packet from the device.
        
Arguments:

    Adapter    - pointer to the MP_ADAPTER structure
    pRCB    -  Pointer to the RCB block that contains the IRP.


Return Value:

    NT status code

--*/
{
    PIRP            irp = pNotiCB->Irp;
    PIO_STACK_LOCATION  nextStack;
    PDEVICE_OBJECT   TargetDeviceObject = Adapter->NextDeviceObject;
	PMP_USBPIPE   usbpipe;
	USHORT            siz;
	PURB              urb=pNotiCB->Urb;

    DEBUGP(MP_TRACE, ("--> NICPostInterruptRequest\n"));

    // 
    // Obtain a pointer to the stack location of the first driver that will be
    // invoked.  This is where the function codes and the parameters are set.
    // 
	usbpipe=Adapter->UsbPipeForNIC;
	siz = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
	UsbBuildInterruptOrBulkTransferRequest
		(
		urb, 
		siz,
		usbpipe->InterfaceData->Pipes[usbpipe->InterruptPipe].PipeHandle,
		(PVOID)pNotiCB->pData,
		NULL,
		usbpipe->interrupt_max,
		USBD_SHORT_TRANSFER_OK,
		NULL
		);




	nextStack = IoGetNextIrpStackLocation( irp );
	nextStack->Parameters.Others.Argument1 = urb;
	nextStack->Parameters.DeviceIoControl.IoControlCode =
		IOCTL_INTERNAL_USB_SUBMIT_URB;
	nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        

    pNotiCB->IrpLock = IRPLOCK_CANCELABLE;    
    pNotiCB->Ref = 1;

    IoSetCompletionRoutine(irp,
                   InterruptPipeCompletion,
                   pNotiCB,
                   TRUE,
                   TRUE,
                   TRUE);
    //
    // We are making an asynchronous request, so we don't really care
    // about the return status of IoCallDriver.
    //
    (void) IoCallDriver(TargetDeviceObject, irp);

    DEBUGP(MP_TRACE, ("<-- NICPostInterruptRequest\n"));

    return STATUS_SUCCESS;
}
NTSTATUS OnWriteComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT ctx)
{   
    PIO_STACK_LOCATION stack;
    NTSTATUS           status;
    ULONG              length;
    KIRQL              OldIrql;
    ULONG              count;
    
    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

    status = Irp->IoStatus.Status;
    
    if(NT_SUCCESS(status) && ctx->remain && !Irp->Cancel)
    {
        /* we have more to transfer */
        length = ctx->remain;
        if(length > pdx->maxtransfer)
            length = pdx->maxtransfer;
        
        UsbBuildInterruptOrBulkTransferRequest(&ctx->urb,
                                               sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
                                               pdx->houtpipe,
                                               ctx->data,
                                               NULL,
                                               length,
                                               (USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK),
                                               NULL);

        ctx->data += length;
        ctx->remain -= length;
        
        stack = IoGetNextIrpStackLocation(Irp);
        stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        stack->Parameters.Others.Argument1 = (PVOID)&ctx->urb;
        stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;

        IoSetCompletionRoutine(Irp, 
                               (PIO_COMPLETION_ROUTINE)OnWriteComplete,
                               (PVOID) ctx,
                               TRUE,
                               TRUE,
                               TRUE);

        IoCallDriver(pdx->LowerDeviceObject, Irp);

        return STATUS_MORE_PROCESSING_REQUIRED;
    }
    
    if(NT_SUCCESS(status)) 
    {
        Irp->IoStatus.Information = ctx->total;
    } 
    else 
    {
        KdPrint((DRIVERNAME " - finished with error!\n"));
    }
    
    ExFreePool(ctx);

    StartNextPacket    ( &pdx->dqWrite, fdo    );
    IoReleaseRemoveLock( &pdx->RemoveLock, Irp );
    
    return STATUS_SUCCESS;
}
NTSTATUS StartPolling(PDEVICE_EXTENSION pdx)
{
    PIO_STACK_LOCATION stack;
    KIRQL              OldIrql;
    NTSTATUS           status;

    ASSERT(pdx->PollingIrp);

    KeAcquireSpinLock(&pdx->PollLock, &OldIrql);
    
    if(pdx->PollPending)
    {
        KeReleaseSpinLock(&pdx->PollLock, OldIrql);
        return STATUS_SUCCESS;
    }

    KeReleaseSpinLock(&pdx->PollLock, OldIrql);

    status = IoAcquireRemoveLock(&pdx->RemoveLock, pdx->PollingIrp);
    
    if(!NT_SUCCESS(status))
    {
        KeAcquireSpinLock(&pdx->PollLock, &OldIrql);
        pdx->PollPending = FALSE;
        KeReleaseSpinLock(&pdx->PollLock, OldIrql);
        
        return status;
    }
  
    // safe to do since we passed in FALSE for the second parameter
    // of IoAllocateIrp
    IoInitializeIrp(pdx->PollingIrp, sizeof(IRP), pdx->LowerDeviceObject->StackSize);

    IoSetCompletionRoutine(
                            pdx->PollingIrp,
                            (PIO_COMPLETION_ROUTINE) OnPollComplete,
                            pdx,
                            TRUE,
                            TRUE,
                            TRUE
                          );

    stack = IoGetNextIrpStackLocation(pdx->PollingIrp);

    memset(&pdx->PollingUrb, 0, sizeof(URB));
    
    UsbBuildInterruptOrBulkTransferRequest(
                                            &pdx->PollingUrb,
                                            sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
                                            pdx->hinpipe,
                                            &pdx->PollingBuffer[0],
                                            NULL,
                                            POLLING_BUFFER_SIZE,
                                            (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK),
                                            NULL
                                          );

    stack->MajorFunction                            = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
    stack->Parameters.Others.Argument1              = &pdx->PollingUrb;

    pdx->PollPending = TRUE;
    
    return IoCallDriver(pdx->LowerDeviceObject, pdx->PollingIrp);
}
VOID StartIo( PDEVICE_OBJECT fdo, PIRP Irp )
{
    PIO_STACK_LOCATION stack;
    PRWCONTEXT         ctx;
    ULONG              length, i;
    KIRQL              OldIrql;    
    NTSTATUS           status;

    if((Irp == NULL) || (Irp->AssociatedIrp.SystemBuffer == NULL))
    {
        CompleteRequest(Irp, STATUS_INVALID_PARAMETER, 0);
        return;        
    }
    
    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

    status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);

    if(!NT_SUCCESS(status))
    {
        CompleteRequest(Irp, status, 0);
        return;
    }

    stack = IoGetCurrentIrpStackLocation(Irp);

    if(stack->MajorFunction == IRP_MJ_WRITE)
    {
        // start a write operation 
        ctx = (PRWCONTEXT) ExAllocatePoolWithTag(NonPagedPool, sizeof(RWCONTEXT), SPOT_TAG);
    
        if(ctx == NULL)
        {
            KdPrint((DRIVERNAME " - Could not allocate transfer context\n"));
            
            StartNextPacket    ( &pdx->dqWrite, fdo                    );
            CompleteRequest    ( Irp, STATUS_INSUFFICIENT_RESOURCES, 0 );
            IoReleaseRemoveLock( &pdx->RemoveLock, Irp                 );
            
            return;
        }

        RtlZeroMemory(ctx, sizeof(RWCONTEXT));

        ctx->total = ctx->remain = stack->Parameters.Write.Length;
        ctx->data  = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
        
        length = ctx->remain;
        if(length > pdx->maxtransfer)
            length = pdx->maxtransfer;

        UsbBuildInterruptOrBulkTransferRequest(&ctx->urb,
                                               sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
                                               pdx->houtpipe,
                                               ctx->data,
                                               NULL,
                                               length,
                                               (USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK),
                                               NULL);

        ctx->data += length;
        ctx->remain -= length;
        
        stack = IoGetNextIrpStackLocation(Irp);
        stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        stack->Parameters.Others.Argument1 = (PVOID)&ctx->urb;
        stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;

        IoSetCompletionRoutine(Irp, 
                               (PIO_COMPLETION_ROUTINE)OnWriteComplete,
                               (PVOID) ctx,
                               TRUE,
                               TRUE,
                               TRUE);

        IoCallDriver(pdx->LowerDeviceObject, Irp);
    }
    else 
    {
        // flush 
        KdPrint((DRIVERNAME " - Flushed!\n"));
        
        StartNextPacket    ( &pdx->dqWrite, fdo     );
        CompleteRequest    ( Irp, STATUS_SUCCESS, 0 );
        IoReleaseRemoveLock( &pdx->RemoveLock, Irp  );
    }

    return;
}
Ejemplo n.º 12
0
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);
		}
	}
}
NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite(
    WDFREQUEST request,
    PMDL transfer_mdl,
    ULONG length,
    bool is_read,
    ULONG time_out,
    bool is_ioctl) {
  ASSERT_IRQL_LOW_OR_DISPATCH();

  ASSERT(IsPipeAttached());
  if (!IsPipeAttached()) {
    WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
    return STATUS_INVALID_DEVICE_STATE;
  }

  // Quick access check. Might be redundant though...
  ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe()));
  if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) {
    WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    return STATUS_ACCESS_DENIED;
  }

  // Set URB flags
  ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ?
                                                USBD_TRANSFER_DIRECTION_IN :
                                                USBD_TRANSFER_DIRECTION_OUT);

  // Calculate transfer length for this stage.
  ULONG stage_len =
    (length > GetTransferGranularity()) ? GetTransferGranularity() : length;

  // Get virtual address that we're gonna use in the transfer.
  // We rely here on the fact that we're in the context of the calling thread.
  void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl);

  // Allocate our private MDL for this address which we will use for the transfer
  PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL);
  ASSERT(NULL != new_mdl);
  if (NULL == new_mdl) {
    WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Map the portion of user buffer that we're going to transfer at this stage
  // to our mdl.
  IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len);

  // Allocate memory for URB and associate it with this request
  WDF_OBJECT_ATTRIBUTES mem_attrib;
  WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib);
  mem_attrib.ParentObject = request;

  WDFMEMORY urb_mem = NULL;
  PURB urb = NULL;
  NTSTATUS status =
    WdfMemoryCreate(&mem_attrib,
                    NonPagedPool,
                    GANDR_POOL_TAG_BULKRW_URB,
                    sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                    &urb_mem,
                    reinterpret_cast<PVOID*>(&urb));
  ASSERT(NT_SUCCESS(status) && (NULL != urb));
  if (!NT_SUCCESS(status)) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Get USB pipe handle for our pipe and initialize transfer request for it
  USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe();
  ASSERT(NULL != usbd_pipe_hndl);
  if (NULL == usbd_pipe_hndl) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
    return STATUS_INTERNAL_ERROR;
  }

  // Initialize URB with request information
  UsbBuildInterruptOrBulkTransferRequest(
    urb,
    sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
    usbd_pipe_hndl,
    NULL,
    new_mdl,
    stage_len,
    urb_flags,
    NULL);

  // Build transfer request
  status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(),
                                               request,
                                               urb_mem,
                                               NULL);
  ASSERT(NT_SUCCESS(status));
  if (!NT_SUCCESS(status)) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, status);
    return status;
  }

  // Initialize our request context.
  AndroidUsbWdfRequestContext* context =
    GetAndroidUsbWdfRequestContext(request);
  ASSERT(NULL != context);
  if (NULL == context) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
    return STATUS_INTERNAL_ERROR;
  }

  context->object_type = AndroidUsbWdfObjectTypeRequest;
  context->urb_mem = urb_mem;
  context->transfer_mdl = transfer_mdl;
  context->mdl = new_mdl;
  context->length = length;
  context->transfer_size = stage_len;
  context->num_xfer = 0;
  context->virtual_address = virtual_address;
  context->is_read = is_read;
  context->initial_time_out = time_out;
  context->is_ioctl = is_ioctl;

  // Set our completion routine
  WdfRequestSetCompletionRoutine(request,
                                 CommonReadWriteCompletionEntry,
                                 this);

  // Init send options (our timeout goes here)
  WDF_REQUEST_SEND_OPTIONS send_options;
  if (0 != time_out) {
    WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT);
    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out));
  }

  // Timestamp first WdfRequestSend
  KeQuerySystemTime(&context->sent_at);

  // Send request asynchronously.
  if (WdfRequestSend(request, wdf_pipe_io_target(),
                     (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) {
    return STATUS_SUCCESS;
  }

  // Something went wrong here
  status = WdfRequestGetStatus(request);
  ASSERT(!NT_SUCCESS(status));
  GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X",
           is_read, status);
  WdfRequestCompleteWithInformation(request, status, 0);

  return status;
}