911 lines
22 KiB
C
911 lines
22 KiB
C
/*++
|
|
|
|
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
|
|
|