windows-nt/Source/XPSP1/NT/drivers/wdm/usb/usbd/device.c

911 lines
22 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
DEVICE.C
Abstract:
This module contains the code that implements various support functions
related to device configuration.
Environment:
kernel mode only
Notes:
Revision History:
10-29-95 : created
--*/
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include "usbdi.h" //public data structures
#include "hcdi.h"
#include "usbd.h" //private data strutures
#ifdef USBD_DRIVER // USBPORT supercedes most of USBD, so we will remove
// the obsolete code by compiling it only if
// USBD_DRIVER is set.
#define DEADMAN_TIMER
#define DEADMAN_TIMEOUT 5000 //timeout in ms
//use a 5 second timeout
typedef struct _USBD_TIMEOUT_CONTEXT {
PIRP Irp;
KTIMER TimeoutTimer;
KDPC TimeoutDpc;
KSPIN_LOCK TimeoutSpin;
KEVENT Event;
BOOLEAN Complete;
} USBD_TIMEOUT_CONTEXT, *PUSBD_TIMEOUT_CONTEXT;
#ifdef PAGE_CODE
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, USBD_SubmitSynchronousURB)
#pragma alloc_text(PAGE, USBD_SendCommand)
#pragma alloc_text(PAGE, USBD_OpenEndpoint)
#pragma alloc_text(PAGE, USBD_CloseEndpoint)
#pragma alloc_text(PAGE, USBD_FreeUsbAddress)
#pragma alloc_text(PAGE, USBD_AllocateUsbAddress)
#pragma alloc_text(PAGE, USBD_GetEndpointState)
#endif
#endif
#ifdef DEADMAN_TIMER
VOID
USBD_SyncUrbTimeoutDPC(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext -
SystemArgument1 - not used.
SystemArgument2 - not used.
Return Value:
None.
--*/
{
PUSBD_TIMEOUT_CONTEXT usbdTimeoutContext = DeferredContext;
BOOLEAN complete;
#if DBG
BOOLEAN status;
#endif
KIRQL irql;
KeAcquireSpinLock(&usbdTimeoutContext->TimeoutSpin, &irql);
complete = usbdTimeoutContext->Complete;
KeReleaseSpinLock(&usbdTimeoutContext->TimeoutSpin, irql);
if (!complete) {
#if DBG
status =
#endif
IoCancelIrp(usbdTimeoutContext->Irp);
#if DBG
USBD_ASSERT(status == TRUE);
#endif
}
//OK to free it
KeSetEvent(&usbdTimeoutContext->Event, 1, FALSE);
}
NTSTATUS
USBD_SyncIrp_Complete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PUSBD_TIMEOUT_CONTEXT usbdTimeoutContext = Context;
KIRQL irql;
BOOLEAN cancelled;
NTSTATUS ntStatus;
KeAcquireSpinLock(&usbdTimeoutContext->TimeoutSpin, &irql);
usbdTimeoutContext->Complete = TRUE;
cancelled = KeCancelTimer(&usbdTimeoutContext->TimeoutTimer);
KeReleaseSpinLock(&usbdTimeoutContext->TimeoutSpin, irql);
// see if the timer was in the queue, if it was then it is safe to free
// it
if (cancelled) {
// safe to free it
KeSetEvent(&usbdTimeoutContext->Event, 1, FALSE);
}
ntStatus = Irp->IoStatus.Status;
return ntStatus;
}
#endif /* DEADMAN_TIMER */
NTSTATUS
USBD_SubmitSynchronousURB(
IN PURB Urb,
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_DEVICE_DATA DeviceData
)
/*++
Routine Description:
Submit a Urb to HCD synchronously
Arguments:
Urb - Urb to submit
DeviceObject USBD device object
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS, status;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
#ifdef DEADMAN_TIMER
BOOLEAN haveTimer = FALSE;
PUSBD_TIMEOUT_CONTEXT usbdTimeoutContext;
#endif /* DEADMAN_TIMER */
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_SubmitSynchronousURB\n"));
ASSERT_DEVICE(DeviceData);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
HCD_DEVICE_OBJECT(DeviceObject),
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
if (NULL == irp) {
USBD_KdBreak(("USBD_SubmitSynchronousURB build Irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Call the hc driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->Parameters.Others.Argument1 = Urb;
#ifdef DEADMAN_TIMER
usbdTimeoutContext = GETHEAP(NonPagedPool,
sizeof(*usbdTimeoutContext));
if (usbdTimeoutContext) {
LARGE_INTEGER dueTime;
usbdTimeoutContext->Irp = irp;
usbdTimeoutContext->Complete = FALSE;
KeInitializeEvent(&usbdTimeoutContext->Event, NotificationEvent, FALSE);
KeInitializeSpinLock(&usbdTimeoutContext->TimeoutSpin);
KeInitializeTimer(&usbdTimeoutContext->TimeoutTimer);
KeInitializeDpc(&usbdTimeoutContext->TimeoutDpc,
USBD_SyncUrbTimeoutDPC,
usbdTimeoutContext);
dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
KeSetTimer(&usbdTimeoutContext->TimeoutTimer,
dueTime,
&usbdTimeoutContext->TimeoutDpc);
haveTimer = TRUE;
IoSetCompletionRoutine(irp,
USBD_SyncIrp_Complete,
// always pass FDO to completion routine
usbdTimeoutContext,
TRUE,
TRUE,
TRUE);
}
#endif
//
// initialize flags field
// for internal request
//
Urb->UrbHeader.UsbdFlags = 0;
//
// Init the Irp field for transfers
//
switch(Urb->UrbHeader.Function) {
case URB_FUNCTION_CONTROL_TRANSFER:
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
HC_URB(Urb)->HcdUrbCommonTransfer.hca.HcdIrp = irp;
if (HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL == NULL &&
HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferLength != 0) {
if ((HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL =
IoAllocateMdl(HC_URB(Urb)->HcdUrbCommonTransfer.TransferBuffer,
HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferLength,
FALSE,
FALSE,
NULL)) == NULL)
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
else {
Urb->UrbHeader.UsbdFlags |= USBD_REQUEST_MDL_ALLOCATED;
MmBuildMdlForNonPagedPool(HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL);
}
}
break;
}
USBD_KdPrint(3, ("'USBD_SubmitSynchronousURB: calling HCD with URB\n"));
if (NT_SUCCESS(ntStatus)) {
// set the renter bit on the URB function code
Urb->UrbHeader.Function |= HCD_NO_USBD_CALL;
ntStatus = IoCallDriver(HCD_DEVICE_OBJECT(DeviceObject),
irp);
}
USBD_KdPrint(3, ("'ntStatus from IoCallDriver = 0x%x\n", ntStatus));
status = STATUS_SUCCESS;
if (ntStatus == STATUS_PENDING) {
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = ioStatus.Status;
} else {
ioStatus.Status = ntStatus;
}
#ifdef DEADMAN_TIMER
// the completion routine should have canceled the timer
// so we should never find it in the queue
//
// remove our timeoutDPC from the queue
//
if (haveTimer) {
USBD_ASSERT(KeCancelTimer(&usbdTimeoutContext->TimeoutTimer) == FALSE);
KeWaitForSingleObject(&usbdTimeoutContext->Event,
Suspended,
KernelMode,
FALSE,
NULL);
RETHEAP(usbdTimeoutContext);
}
#endif
// NOTE:
// mapping is handled by completion routine
// called by HCD
USBD_KdPrint(3, ("'urb status = 0x%x ntStatus = 0x%x\n", Urb->UrbHeader.Status, ntStatus));
return ntStatus;
}
NTSTATUS
USBD_SendCommand(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN USHORT RequestCode,
IN USHORT WValue,
IN USHORT WIndex,
IN USHORT WLength,
IN PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG BytesReturned,
OUT USBD_STATUS *UsbStatus
)
/*++
Routine Description:
Send a standard USB command on the default pipe.
Arguments:
DeviceData - ptr to USBD device structure the command will be sent to
DeviceObject -
RequestCode -
WValue - wValue for setup packet
WIndex - wIndex for setup packet
WLength - wLength for setup packet
Buffer - Input/Output Buffer for command
BufferLength - Length of Input/Output buffer.
BytesReturned - pointer to ulong to copy number of bytes
returned (optional)
UsbStatus - USBD status code returned in the URB.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PHCD_URB urb = NULL;
PUSBD_PIPE defaultPipe;
PUSB_STANDARD_SETUP_PACKET setupPacket;
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_SendCommand\n"));
ASSERT_DEVICE(DeviceData);
if (!DeviceData || DeviceData->Sig != SIG_DEVICE) {
USBD_Warning(NULL,
"Bad DeviceData passed to USBD_SendCommand, fail!\n",
FALSE);
return STATUS_INVALID_PARAMETER;
}
defaultPipe = &(DeviceData->DefaultPipe);
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
if (deviceExtension->DeviceHackFlags &
USBD_DEVHACK_SLOW_ENUMERATION) {
//
// if noncomplience switch is on in the
// registry we'll pause here to give the
// device a chance to respond.
//
LARGE_INTEGER deltaTime;
deltaTime.QuadPart = 100 * -10000;
(VOID) KeDelayExecutionThread(KernelMode,
FALSE,
&deltaTime);
}
urb = GETHEAP(NonPagedPool,
sizeof(struct _URB_CONTROL_TRANSFER));
if (!urb) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
setupPacket = (PUSB_STANDARD_SETUP_PACKET)
urb->HcdUrbCommonTransfer.Extension.u.SetupPacket;
setupPacket->RequestCode = RequestCode;
setupPacket->wValue = WValue;
setupPacket->wIndex = WIndex;
setupPacket->wLength = WLength;
if (!USBD_ValidatePipe(defaultPipe) ||
!defaultPipe->HcdEndpoint) {
USBD_Warning(DeviceData,
"Bad DefaultPipe or Endpoint in USBD_SendCommand, fail!\n",
FALSE);
ntStatus = STATUS_INVALID_PARAMETER;
goto USBD_SendCommand_done;
}
urb->HcdUrbCommonTransfer.hca.HcdEndpoint = defaultPipe->HcdEndpoint;
urb->HcdUrbCommonTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK;
// USBD is responsible for setting the transfer direction
//
// TRANSFER direction is implied in the command
if (RequestCode & USB_DEVICE_TO_HOST)
USBD_SET_TRANSFER_DIRECTION_IN(urb->HcdUrbCommonTransfer.TransferFlags);
else
USBD_SET_TRANSFER_DIRECTION_OUT(urb->HcdUrbCommonTransfer.TransferFlags);
urb->HcdUrbCommonTransfer.TransferBufferLength = BufferLength;
urb->HcdUrbCommonTransfer.TransferBuffer = Buffer;
urb->HcdUrbCommonTransfer.TransferBufferMDL = NULL;
urb->HcdUrbCommonTransfer.UrbLink = NULL;
USBD_KdPrint(3, ("'SendCommand cmd = 0x%x buffer = 0x%x length = 0x%x direction = 0x%x\n",
setupPacket->RequestCode,
urb->HcdUrbCommonTransfer.TransferBuffer,
urb->HcdUrbCommonTransfer.TransferBufferLength,
urb->HcdUrbCommonTransfer.TransferFlags
));
ntStatus = USBD_SubmitSynchronousURB((PURB)urb, DeviceObject, DeviceData);
if (BytesReturned) {
*BytesReturned = urb->HcdUrbCommonTransfer.TransferBufferLength;
}
if (UsbStatus) {
*UsbStatus = urb->HcdUrbCommonTransfer.Status;
}
USBD_SendCommand_done:
// free the transfer URB
RETHEAP(urb);
}
USBD_KdPrint(3, ("'exit USBD_SendCommand 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_OpenEndpoint(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUSBD_PIPE PipeHandle,
OUT USBD_STATUS *UsbStatus,
BOOLEAN IsDefaultPipe
)
/*++
Routine Description:
open an endpoint on a USB device.
Arguments:
DeviceData - data describes the device this endpoint is on.
DeviceObject - USBD device object.
PipeHandle - USBD PipeHandle to associate with the endpoint.
on input MaxTransferSize initialize to the largest
transfer that will be sent on this endpoint,
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PHCD_URB urb;
PUSBD_EXTENSION deviceExtension;
extern UCHAR ForceDoubleBuffer;
extern UCHAR ForceFastIso;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_OpenEndpoint\n"));
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
ASSERT_DEVICE(DeviceData);
USBD_ASSERT(PIPE_CLOSED(PipeHandle) == TRUE);
urb = GETHEAP(NonPagedPool,
sizeof(struct _URB_HCD_OPEN_ENDPOINT));
if (!urb) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
urb->UrbHeader.Length = sizeof(struct _URB_HCD_OPEN_ENDPOINT);
urb->UrbHeader.Function = URB_FUNCTION_HCD_OPEN_ENDPOINT;
urb->HcdUrbOpenEndpoint.EndpointDescriptor = &PipeHandle->EndpointDescriptor;
urb->HcdUrbOpenEndpoint.DeviceAddress = DeviceData->DeviceAddress;
urb->HcdUrbOpenEndpoint.HcdEndpointFlags = 0;
if (DeviceData->LowSpeed == TRUE) {
urb->HcdUrbOpenEndpoint.HcdEndpointFlags |= USBD_EP_FLAG_LOWSPEED;
}
// default pipe and iso pipes never halt
if (IsDefaultPipe ||
(PipeHandle->EndpointDescriptor.bmAttributes &
USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
urb->HcdUrbOpenEndpoint.HcdEndpointFlags |= USBD_EP_FLAG_NEVERHALT;
}
if (ForceDoubleBuffer &&
((PipeHandle->EndpointDescriptor.bmAttributes &
USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)) {
PipeHandle->UsbdPipeFlags |= USBD_PF_DOUBLE_BUFFER;
USBD_KdPrint(1, (">>Forcing Double Buffer -- Bulk <<\n"));
}
if (ForceFastIso &&
((PipeHandle->EndpointDescriptor.bmAttributes &
USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS)) {
PipeHandle->UsbdPipeFlags |= USBD_PF_ENABLE_RT_THREAD_ACCESS;
USBD_KdPrint(1, (">>Forcing Fast Iso <<\n"));
}
urb->HcdUrbOpenEndpoint.MaxTransferSize =
PipeHandle->MaxTransferSize;
// check client option flags
if (PipeHandle->UsbdPipeFlags & USBD_PF_DOUBLE_BUFFER) {
USBD_KdPrint(1, (">>Setting Double Buffer Flag<<\n"));
urb->HcdUrbOpenEndpoint.HcdEndpointFlags |=
USBD_EP_FLAG_DOUBLE_BUFFER;
}
if (PipeHandle->UsbdPipeFlags & USBD_PF_ENABLE_RT_THREAD_ACCESS) {
USBD_KdPrint(1, (">>Setting Fast ISO Flag<<\n"));
urb->HcdUrbOpenEndpoint.HcdEndpointFlags |=
USBD_EP_FLAG_FAST_ISO;
}
if (PipeHandle->UsbdPipeFlags & USBD_PF_MAP_ADD_TRANSFERS) {
USBD_KdPrint(1, (">>Setting Map Add Flag<<\n"));
urb->HcdUrbOpenEndpoint.HcdEndpointFlags |=
USBD_EP_FLAG_MAP_ADD_IO;
}
//
// Serialize Open Endpoint requests
//
ntStatus = USBD_SubmitSynchronousURB((PURB) urb, DeviceObject,
DeviceData);
if (NT_SUCCESS(ntStatus)) {
PipeHandle->HcdEndpoint = urb->HcdUrbOpenEndpoint.HcdEndpoint;
PipeHandle->ScheduleOffset = urb->HcdUrbOpenEndpoint.ScheduleOffset;
PipeHandle->Sig = SIG_PIPE;
}
if (UsbStatus) {
*UsbStatus = urb->UrbHeader.Status;
}
RETHEAP(urb);
}
USBD_KdPrint(3, ("'exit USBD_OpenEndpoint 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_CloseEndpoint(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE PipeHandle,
IN OUT USBD_STATUS *UsbStatus
)
/*++
Routine Description:
Close an Endpoint
Arguments:
DeviceData - ptr to USBD device data structure.
DeviceObject - USBD device object.
PipeHandle - USBD pipe handle associated with the endpoint.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PHCD_URB urb;
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_CloseEndpoint\n"));
ASSERT_DEVICE(DeviceData);
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
urb = GETHEAP(NonPagedPool,
sizeof(struct _URB_HCD_CLOSE_ENDPOINT));
if (!urb) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
urb->UrbHeader.Length = sizeof(struct _URB_HCD_CLOSE_ENDPOINT);
urb->UrbHeader.Function = URB_FUNCTION_HCD_CLOSE_ENDPOINT;
urb->HcdUrbCloseEndpoint.HcdEndpoint = PipeHandle->HcdEndpoint;
//
// Serialize Close Endpoint requests
//
ntStatus = USBD_SubmitSynchronousURB((PURB) urb, DeviceObject,
DeviceData);
if (UsbStatus) {
*UsbStatus = urb->UrbHeader.Status;
}
RETHEAP(urb);
}
USBD_KdPrint(3, ("'exit USBD_CloseEndpoint 0x%x\n", ntStatus));
return ntStatus;
}
VOID
USBD_FreeUsbAddress(
IN PDEVICE_OBJECT DeviceObject,
IN USHORT DeviceAddress
)
/*++
Routine Description:
Arguments:
Return Value:
Valid USB address (1..127) to use for this device,
returns 0 if no device address available.
--*/
{
PUSBD_EXTENSION deviceExtension;
USHORT address = 0, i, j;
ULONG bit;
PAGED_CODE();
// we should never see a free to device address 0
USBD_ASSERT(DeviceAddress != 0);
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
for (j=0; j<4; j++) {
bit = 1;
for (i=0; i<32; i++) {
address = (USHORT)(j*32+i);
if (address == DeviceAddress) {
deviceExtension->AddressList[j] &= ~bit;
goto USBD_FreeUsbAddress_Done;
}
bit = bit<<1;
}
}
USBD_FreeUsbAddress_Done:
USBD_KdPrint(3, ("'USBD free Address %d\n", address));
}
USHORT
USBD_AllocateUsbAddress(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
Valid USB address (1..127) to use for this device,
returns 0 if no device address available.
--*/
{
PUSBD_EXTENSION deviceExtension;
USHORT address = 0, i, j;
ULONG bit;
PAGED_CODE();
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
for (j=0; j<4; j++) {
bit = 1;
for (i=0; i<32; i++) {
if (!(deviceExtension->AddressList[j] & bit)) {
deviceExtension->AddressList[j] |= bit;
address = (USHORT)(j*32+i);
goto USBD_AllocateUsbAddress_Done;
}
bit = bit<<1;
}
}
USBD_AllocateUsbAddress_Done:
USBD_KdPrint(3, ("'USBD assigning Address %d\n", address));
return address;
}
NTSTATUS
USBD_GetEndpointState(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE PipeHandle,
OUT USBD_STATUS *UsbStatus,
OUT PULONG EndpointState
)
/*++
Routine Description:
open an endpoint on a USB device.
Arguments:
DeviceData - data describes the device this endpoint is on.
DeviceObject - USBD device object.
PipeHandle - USBD PipeHandle to associate with the endpoint.
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PHCD_URB urb;
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_GetEndpointState\n"));
ASSERT_DEVICE(DeviceData);
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
USBD_ASSERT(PIPE_CLOSED(PipeHandle) == FALSE);
urb = GETHEAP(NonPagedPool,
sizeof(struct _URB_HCD_OPEN_ENDPOINT));
if (!urb) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
urb->UrbHeader.Length = sizeof(struct _URB_HCD_OPEN_ENDPOINT);
urb->UrbHeader.Function = URB_FUNCTION_HCD_GET_ENDPOINT_STATE;
urb->HcdUrbEndpointState.HcdEndpoint = PipeHandle->HcdEndpoint;
urb->HcdUrbEndpointState.HcdEndpointState = 0;
// Serialize Open Endpoint requests
//
ntStatus = USBD_SubmitSynchronousURB((PURB) urb,
DeviceObject,
DeviceData);
if (UsbStatus) {
*UsbStatus = urb->UrbHeader.Status;
}
*EndpointState = urb->HcdUrbEndpointState.HcdEndpointState;
RETHEAP(urb);
}
USBD_KdPrint(3, ("'exit USBD_GetEndpointState 0x%x\n", ntStatus));
return ntStatus;
}
#endif // USBD_DRIVER