/***************************************************************************** Company : Shree Ganesha Inc. File Name : SkyWalker1Usb.cpp Author : Date : Purpose : This File Holds all the USB Device access related declarations Revision History: =============================================================================== DATE VERSION AUTHOR REMARK =============================================================================== XXth April,2009 01 Initial Version *****************************************************************************/ /* Include the Library and Other header file */ //#include #include "SkyWalker1Main.h" //Header for the Tuner related definitions /* End of Inclusion the Library and Other header file */ /* Macro Definitions */ #define USB_MEMORY_TAG 'MBSU' /* End of Global & Static variables Declaration */ /* External Variable Declaration */ /* End of External Variable Declaration */ /* Declare Enumerations here */ /* End of Enumeration declaration */ /* Function Prototypes */ NTSTATUS ReadandSelectDescriptors( IN PKSDEVICE pKSDeviceObject ); NTSTATUS ConfigureDevice(IN PKSDEVICE pKSDeviceObject); NTSTATUS SelectInterfaces( IN PKSDEVICE pKSDeviceObject, IN PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor); NTSTATUS UsbReadWriteCompletion( IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket, IN PVOID pContext ); NTSTATUS ResetUsbPipe( IN PKSDEVICE pKSDeviceObject, IN PUSBD_PIPE_INFORMATION pPipeInformation); NTSTATUS ResetUsbDevice(IN PKSDEVICE pKSDeviceObject); NTSTATUS GetUsbPortStatus( IN PKSDEVICE pKSDeviceObject, IN OUT PULONG pulPortStatus); NTSTATUS ResetUsbParentPort( IN PKSDEVICE pKSDeviceObject ); NTSTATUS SendURBToBusDriver(IN PKSDEVICE pKSDeviceObject, IN PURB pUSBRequestBlock ); NTSTATUS AbortUsbPipes(IN PKSDEVICE pKSDeviceObject); LONG IncrementPendingIoCount(IN OUT CSkyWalker1Device * pDevice); LONG DecrementPendingIoCount(IN OUT CSkyWalker1Device * pDevice); //Debugging related Functions VOID PrintDeviceDescriptor( PUSB_DEVICE_DESCRIPTOR pDeviceDescriptor); VOID PrintConfigurationDescriptor(IN PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor); VOID PrintInterfaceDescriptor(IN PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor); VOID PrintPipeInformation(PUSBD_PIPE_INFORMATION pPipeInformation); /* End of Function prototype definitions */ /***************************************************************************** Function : InitializeUsbDevice Description : Function to used to Initialize the USB Interface of the Tuner IN PARAM : Pointer to Device Object which needs to be Initialized Irp to start the device IRP_MN_START OUT PARAM : Status of the Device Initialization STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Device initialized Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS InitializeUsbDevice(IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { NTSTATUS ntInitStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = NULL; KIRQL kOldIrql; PrintFunctionEntry(__FUNCTION__); pDevice = reinterpret_cast(pKSDeviceObject->Context); //We cannot touch the device (send it any non pnp irps) until a //start device has been passed down to the lower drivers. //first pass the Irp down ntInitStatus = PassDownIRPAndWaitForCompletion( pKSDeviceObject->NextDeviceObject, pIoRequestPacket, TRUE); if(!NT_SUCCESS(ntInitStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Lower Driver did not start !!!,Stopping Device Start\n")); goto FinishStartDevice; } //Lower Device Initialized , Start the Device Now // //Read the device descriptor, configuration descriptor //and select the interface descriptors // ntInitStatus = ReadandSelectDescriptors(pKSDeviceObject); if(!NT_SUCCESS(ntInitStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("ReadandSelectDescriptors failed\n")); goto FinishStartDevice; } KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); SET_NEW_PNP_STATE(pDevice, Working); pDevice->QueueState = AllowRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); /* //initialize wait wake outstanding flag to false. //and issue a wait wake. deviceExtension->FlagWWOutstanding = 0; deviceExtension->FlagWWCancel = 0; deviceExtension->WaitWakeIrp = NULL; if(deviceExtension->WaitWakeEnable) { IssueWaitWake(deviceExtension); } ProcessQueuedRequests(deviceExtension); */ FinishStartDevice: PrintFunctionExit(__FUNCTION__,ntInitStatus); return ntInitStatus; } /***************************************************************************** Function : ReadandSelectDescriptors Description : Function to used to Read Device Descriptor IN PARAM : Pointer to KS Device Object OUT PARAM : Status of the Device Descriptor Read STATUS_SUCCESS on Successful execution else Error PreCondition : NONE PostCondtion : Device Descriptor Read Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ReadandSelectDescriptors( IN PKSDEVICE pKSDeviceObject ) { URB USBRequestBlock; NTSTATUS ntStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); //1. Read the device descriptor UsbBuildGetDescriptorRequest( &USBRequestBlock, (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, &pDevice->USBDeviceDescriptor, NULL, sizeof(pDevice->USBDeviceDescriptor), NULL); ntStatus = SendURBToBusDriver( pKSDeviceObject, &USBRequestBlock); if (!NT_SUCCESS(ntStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Error Trying to Read Device Descriptor\n")); goto CompleteReadAndSetup; } PrintDeviceDescriptor(&pDevice->USBDeviceDescriptor); //Device Descriptor read successfully thus, Read and select configuration ntStatus = ConfigureDevice(pKSDeviceObject); CompleteReadAndSetup: PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : ConfigureDevice Description : This helper routine reads the configuration descriptor for the device in couple of steps. IN PARAM : Pointer to KS Device Object OUT PARAM : Status of the Configuration Descriptor Read STATUS_SUCCESS on Successful execution else Error PreCondition : NONE PostCondtion : Configuration Descriptor Read Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ConfigureDevice(IN PKSDEVICE pKSDeviceObject) { URB USBRequestBlock; NTSTATUS ntConfigureStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor = NULL; PrintFunctionEntry(__FUNCTION__); SkyWalkerDebugPrint(EXTREME_LEVEL,("Total Number of Configurations = %d\n", pDevice->USBDeviceDescriptor.bNumConfigurations)); //Read the first configuration descriptor //This requires two steps: //1. Read the fixed sized configuration desciptor (CD) //2. Read the CD with all embedded interface and endpoint descriptors UsbBuildGetDescriptorRequest( &USBRequestBlock, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, &ConfigurationDescriptor, NULL, sizeof(ConfigurationDescriptor), NULL); ntConfigureStatus = SendURBToBusDriver( pKSDeviceObject, &USBRequestBlock); if (!NT_SUCCESS(ntConfigureStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Error Trying to Read Fixed Size Configuration Descriptor\n")); goto CompleteDeviceConfigure; } ULONG ulConfigurationDesciptorSize = ConfigurationDescriptor.wTotalLength; SkyWalkerDebugPrint(EXTREME_LEVEL, ("Configuration Descriptor Size = %lu \n",ulConfigurationDesciptorSize)); pConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePoolWithTag( NonPagedPool, ulConfigurationDesciptorSize, USB_MEMORY_TAG); if (!pConfigurationDescriptor) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Unable to allocate %lu bytes for Configuration Descriptor\n", ulConfigurationDesciptorSize)); ntConfigureStatus = STATUS_INSUFFICIENT_RESOURCES; goto CompleteDeviceConfigure; } UsbBuildGetDescriptorRequest( &USBRequestBlock, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, pConfigurationDescriptor, NULL, ulConfigurationDesciptorSize, NULL); ntConfigureStatus = SendURBToBusDriver( pKSDeviceObject, &USBRequestBlock); if (!NT_SUCCESS(ntConfigureStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Error Trying to Read Actual Configuration Descriptor\n")); goto CompleteDeviceConfigure; } PrintConfigurationDescriptor(&ConfigurationDescriptor); ntConfigureStatus = SelectInterfaces(pKSDeviceObject, pConfigurationDescriptor); CompleteDeviceConfigure: if(pConfigurationDescriptor) { ExFreePoolWithTag(pConfigurationDescriptor,USB_MEMORY_TAG); } PrintFunctionExit(__FUNCTION__,ntConfigureStatus); return ntConfigureStatus; } /***************************************************************************** Function : SelectInterfaces Description : This helper routine selects the configuration IN PARAM : Pointer to KS Device Object Configuration Descriptor OUT PARAM : Status of the Configuration Descriptor Selection STATUS_SUCCESS on Successful execution else Error PreCondition : NONE PostCondtion : Configuration Descriptor Selection Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS SelectInterfaces( IN PKSDEVICE pKSDeviceObject, IN PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor) { NTSTATUS ntSelectStatus = STATUS_SUCCESS; URB USBRequestBlock; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor = NULL; PUSBD_INTERFACE_INFORMATION pInterfaceInformation = NULL; LONG lNumberOfInterfaces = pConfigurationDescriptor->bNumInterfaces; LONG lInterfaceNumber = 0L; LONG lInterfaceIndex = 0L; ULONG ulPipeIndex = 0L; //The Device needs to be configured by sending a URB that specifies the configuration to use //if device driver fails to configure the device then the I/O manager subsequently unloads //the Driver from memory //Search for the Configuration descriptor in the list of all configuration and obtain a pointer //to the interface pInterfaceDescriptor = USBD_ParseConfigurationDescriptorEx( pConfigurationDescriptor, //Address of the Configuration Descriptor Structure pConfigurationDescriptor, //Adress within the First Structure from where search should begin -1, -1, -1, -1, -1); if (!pInterfaceDescriptor) { SkyWalkerDebugPrint(ENTRY_LEVEL,("No Interface available for the Device\n")); ntSelectStatus = STATUS_DEVICE_CONFIGURATION_ERROR; goto FinishSelectInterface; } //Create a URB that can be sent to the host controller driver (HCD) to set the Device //in the configured state USBD_INTERFACE_LIST_ENTRY Interfaces[2] = { {pInterfaceDescriptor, NULL}, {NULL, NULL}, }; PURB pConfigSelectURB = USBD_CreateConfigurationRequestEx(pConfigurationDescriptor, Interfaces); if (!pConfigSelectURB) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Unable to Create Configuration Request\n")); ntSelectStatus = STATUS_INSUFFICIENT_RESOURCES; goto FinishSelectInterface; } //Get the Interface supported by selected configuration pInterfaceInformation = &pConfigSelectURB->UrbSelectConfiguration.Interface; for(ulPipeIndex=0; ulPipeIndexNumberOfPipes; ulPipeIndex++) { //Perform pipe initialization here set the transfer size and any pipe flags we use //USBD sets the rest of the Interface struct members //pInterfaceInformation->Pipes[ulPipeIndex].MaximumTransferSize = USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; } ntSelectStatus = SendURBToBusDriver(pKSDeviceObject,pConfigSelectURB); if (!NT_SUCCESS(ntSelectStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Error Trying to Select Configuration\n")); goto FinishSelectInterface; } PrintInterfaceDescriptor(pInterfaceDescriptor); for(ulPipeIndex=0; ulPipeIndexNumberOfPipes; ulPipeIndex++) { SkyWalkerDebugPrint(EXTREME_LEVEL,("--------------------------\n")); PrintPipeInformation(&pInterfaceInformation->Pipes[ulPipeIndex]); SkyWalkerDebugPrint(EXTREME_LEVEL,("--------------------------\n")); //Setting the Pipes if(pInterfaceInformation->Pipes[ulPipeIndex].EndpointAddress == 0x82) { RtlCopyMemory( &pDevice->ReadPipe, &pInterfaceInformation->Pipes[ulPipeIndex], sizeof(pDevice->ReadPipe)); } else { RtlCopyMemory( &pDevice->WritePipe, &pInterfaceInformation->Pipes[ulPipeIndex], sizeof(pDevice->WritePipe)); } } FinishSelectInterface: if(pConfigSelectURB) { ExFreePool(pConfigSelectURB); } PrintFunctionExit(__FUNCTION__,ntSelectStatus); return ntSelectStatus; } /***************************************************************************** Function : QueryStopUsbDevice Description : Function to used to Service PnP IRPs of Minor Type IRP_MN_QUERY_STOP_DEVICE IN PARAM : Pointer to Device Object whose stop query has come Device Stop Query Irp with Minor Code IRP_MN_QUERY_STOP_DEVICE OUT PARAM : Status of the Stop Query Processing STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Device can be stopped or not is returned Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS QueryStopUsbDevice(IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; NTSTATUS ntQueryStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); //If we can stop the device, we need to set the QueueState to //HoldRequests so further requests will be queued. KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); SET_NEW_PNP_STATE(pDevice, PendingStop); pDevice->QueueState = HoldRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); //wait for the existing ones to be finished. //first, decrement this operation DecrementPendingIoCount(pDevice); KeWaitForSingleObject(&pDevice->EvDeviceStopOk, Executive, KernelMode, FALSE, NULL); PrintFunctionExit(__FUNCTION__,ntQueryStatus); return ntQueryStatus; } /***************************************************************************** Function : DecrementPendingIoCount Description : This routine decrements the outstanding I/O count This is typically invoked after the dispatch routine has finished processing the irp. IN PARAM : Device Pointer OUT PARAM : Io Pending Count PreCondition : NONE PostCondtion : Pending IO Count is Decremented and same is returned to the caller Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ LONG DecrementPendingIoCount(IN OUT CSkyWalker1Device * pDevice) { LONG ulResult = 0; KIRQL kOldIrql; PrintFunctionEntry(__FUNCTION__); KeAcquireSpinLock(&pDevice->kIoCountLock, &kOldIrql); ulResult = InterlockedDecrement((PLONG)&pDevice->ulOutStandingIoCount); if(ulResult == 1) { SkyWalkerDebugPrint(EXTREME_LEVEL,("Device can be Stopped\n")); KeSetEvent(&pDevice->EvDeviceStopOk, IO_NO_INCREMENT, FALSE); } if(ulResult == 0) { SkyWalkerDebugPrint(EXTREME_LEVEL,("Device can be Removed\n")); KeSetEvent(&pDevice->EvDeviceRemoveOk,IO_NO_INCREMENT, FALSE); } KeReleaseSpinLock(&pDevice->kIoCountLock, kOldIrql); SkyWalkerDebugPrint(EXTREME_LEVEL, ("%s::%d\n",__FUNCTION__,ulResult)); PrintFunctionExit(__FUNCTION__,STATUS_SUCCESS); return ulResult; } /***************************************************************************** Function : IncrementPendingIoCount Description : This routine increments the outstanding I/O count This is typically invoked before the dispatch routine to process new Irp is called IN PARAM : Device Pointer OUT PARAM : Io Pending Count PreCondition : NONE PostCondtion : Pending IO Count is Incremented and same is returned to the caller Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ LONG IncrementPendingIoCount(IN OUT CSkyWalker1Device * pDevice) { LONG ulResult = 0; KIRQL kOldIrql; PrintFunctionEntry(__FUNCTION__); KeAcquireSpinLock(&pDevice->kIoCountLock, &kOldIrql); ulResult = InterlockedIncrement((PLONG)&pDevice->ulOutStandingIoCount); //when OutStandingIO bumps from 1 to 2, clear the StopEvent if(ulResult == 2) { KeClearEvent(&pDevice->EvDeviceStopOk); } KeReleaseSpinLock(&pDevice->kIoCountLock, kOldIrql); SkyWalkerDebugPrint(EXTREME_LEVEL, ("%s::%d\n",__FUNCTION__,ulResult)); PrintFunctionExit(__FUNCTION__,STATUS_SUCCESS); return ulResult; } /***************************************************************************** Function : CancelStopUsbDevice Description : Function to used to Service PnP IRPs of Minor Type IRP_MN_CANCEL_STOP_DEVICE IN PARAM : Pointer to Device Object whose Cancel stop request has come Device Stop Cancel Irp with Minor Code IRP_MN_CANCEL_STOP_DEVICE OUT PARAM : Status of the Device Stop Cancel Processing STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Device Stop is cancelled Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS CancelStopUsbDevice(IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; KEVENT Evevent; NTSTATUS ntStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); //First check to see whether you have received cancel-stop //without first receiving a query-stop. This could happen if someone //above us fails a query-stop and passes down the subsequent //cancel-stop. if(pDevice->UsbDeviceState == PendingStop ) { if(NT_SUCCESS(ntStatus)) { KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); RESTORE_PREVIOUS_PNP_STATE(pDevice); pDevice->QueueState = AllowRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); //ProcessQueuedRequests(deviceExtension); } } else { //spurious Irp // //If the device is already in an active state when the driver //receives this IRP, a function driver simply sets status to //success and passes the IRP to the next driver. For such a //cancel-stop IRP, a function driver need not set a completion //routine. } PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : DeconfigureUsbDevice Description : This routine is invoked when the device is removed or stopped. This routine de-configures the usb device. IN PARAM : Pointer to KS Device Object OUT PARAM : Status of the Device Deinitialization STATUS_SUCCESS on Successful execution else Error PreCondition : NONE PostCondtion : USB Device Uninitialized Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS DeconfigureUsbDevice(IN PKSDEVICE pKSDeviceObject) { NTSTATUS ntUnInitStatus = STATUS_SUCCESS; URB USBRequestBlock; PrintFunctionEntry(__FUNCTION__); UsbBuildSelectConfigurationRequest(&USBRequestBlock, sizeof(_URB_SELECT_CONFIGURATION), NULL); ntUnInitStatus = SendURBToBusDriver(pKSDeviceObject,&USBRequestBlock); if (!NT_SUCCESS(ntUnInitStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Error Trying to Deconfigure the Device\n")); } PrintFunctionExit(__FUNCTION__,ntUnInitStatus); return ntUnInitStatus; } /***************************************************************************** Function : StopUsbDevice Description : This routine is invoked when the device is stopped. This routine services Irp of minor type IRP_MN_STOP_DEVICE IN PARAM : Pointer to KS Device Object STOP DEVICE Irp OUT PARAM : Status of the Device Stop STATUS_SUCCESS on Successful execution else Error PreCondition : NONE PostCondtion : USB Device Stopped Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS StopUsbDevice(IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; NTSTATUS ntDeviceStopStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = NULL; PrintFunctionEntry(__FUNCTION__); //initialize variables pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; //if(WinXpOrBetter == deviceExtension->WdmVersion) { // if(deviceExtension->SSEnable) { // // // //Cancel the timer so that the DPCs are no longer fired. // //Thus, we are making judicious usage of our resources. // //we do not need DPCs because the device is stopping. // //The timers are re-initialized while handling the start // //device irp. // // // KeCancelTimer(&deviceExtension->Timer); // // // //after the device is stopped, it can be surprise removed. // //we set this to 0, so that we do not attempt to cancel // //the timer while handling surprise remove or remove irps. // //when we get the start device request, this flag will be // //reinitialized. // // // deviceExtension->SSEnable = 0; // // // //make sure that if a DPC was fired before we called cancel timer, // //then the DPC and work-time have run to their completion // // // KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent, // Executive, // KernelMode, // FALSE, // NULL); // // // //make sure that the selective suspend request has been completed. // // // KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, // Executive, // KernelMode, // FALSE, // NULL); // } //} // //after the stop Irp is sent to the lower driver object, //the driver must not send any more Irps down that touch //the device until another Start has occurred. // /* if(deviceExtension->WaitWakeEnable) { CancelWaitWake(deviceExtension); }*/ KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); SET_NEW_PNP_STATE(pDevice, Stopped); KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); ntDeviceStopStatus = DeconfigureUsbDevice(pKSDeviceObject); PrintFunctionExit(__FUNCTION__,ntDeviceStopStatus); return ntDeviceStopStatus; } /***************************************************************************** Function : ReadWriteUsbDevice Description : Dispatch routine for read and write. This routine creates a BULKUSB_RW_CONTEXT for a read/write. This read/write is performed in stages of MAX_BULK_PACKET_SIZE. once a stage of transfer is complete, then the irp is circulated again, until the requested length of tranfer is performed. IN PARAM : Pointer to Device Object Device Register to/From which Write/ Read is to be performed Transfer Buffer Length of the Transfer Buffer True if Read from else False for Write to device OUT PARAM : Status of Read / Write request sending to Device STATUS_PENDING on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Read/ Write Request submitted to Device Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ReadWriteUsbDevice(IN PKSDEVICE pKSDeviceObject, IN ULONG ulStreamIndex, IN ULONG ulPacketIndex, IN PUCHAR pucTransferBuffer, IN ULONG ulTransferLength, IN BOOLEAN bRead) { NTSTATUS ntReadWriteStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; ULONG ulURBFlags = 0; ULONG ulStageTransferLength = 0; PURB pUSBRequestBlock = NULL; PUSBD_PIPE_INFORMATION pPipeInformation = NULL; PIO_STACK_LOCATION pNextStackLocation = NULL; PBULKUSB_RW_CONTEXT pReadWriteContext = NULL; PIRP pUsbIoRequestPacket = NULL; PrintFunctionEntry(__FUNCTION__); //Acquire device Remove lock here if(pDevice->UsbDeviceState != Working) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Invalid device state\n")); ntReadWriteStatus = STATUS_INVALID_DEVICE_STATE; goto FinishDeviceReadWrite; } if(!IS_VALID(pucTransferBuffer)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Invalid Transfer Buffer Passed\n")); ntReadWriteStatus = STATUS_INVALID_PARAMETER; goto FinishDeviceReadWrite; } if(ulTransferLength > MAX_BULK_TRANSFER_SIZE) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Tansfer Length (%lu) > MAX_BULK_TRANSFER_SIZE (%lu)\n", ulTransferLength, MAX_BULK_TRANSFER_SIZE)); ntReadWriteStatus = STATUS_INVALID_PARAMETER; goto FinishDeviceReadWrite; } if(ulTransferLength == 0) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Transfer data length = 0\n")); ntReadWriteStatus = STATUS_SUCCESS; goto FinishDeviceReadWrite; } ulURBFlags = USBD_SHORT_TRANSFER_OK; if(bRead) { ulURBFlags |= USBD_TRANSFER_DIRECTION_IN; SkyWalkerDebugPrint(EXTREME_LEVEL,("Read Operation\n")); pPipeInformation = &pDevice->ReadPipe; } else { ulURBFlags |= USBD_TRANSFER_DIRECTION_OUT; SkyWalkerDebugPrint(EXTREME_LEVEL,("Write Operation\n")); pPipeInformation = &pDevice->WritePipe; } DbgPrint("Pipe Information = %p\n",pPipeInformation); //the transfer request is for TransferLength. //we can perform a max of Packet Size //in each stage. if(ulTransferLength > MAX_BULK_PACKET_SIZE) { ulStageTransferLength = MAX_BULK_PACKET_SIZE; } else { ulStageTransferLength = ulTransferLength; } //Allocate IRP for the USB Transfer pUsbIoRequestPacket = IoAllocateIrp(pKSDeviceObject->NextDeviceObject->StackSize, FALSE); if(!IS_VALID(pUsbIoRequestPacket)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Failed to Allocate Memory for the USB Irp\n")); ntReadWriteStatus = STATUS_INSUFFICIENT_RESOURCES; goto FinishDeviceReadWrite; } ULONG ulStreamOffset = PACKET_PER_FRAME * ulStreamIndex; pDevice->pUsbStreamIrp[ulPacketIndex + ulStreamOffset] = pUsbIoRequestPacket; pUSBRequestBlock = (PURB)ExAllocatePoolWithTag( NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), USB_MEMORY_TAG); if(!IS_VALID(pUSBRequestBlock)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Failed to Allocate Memory for the Bulk / Interrupt URB\n")); ntReadWriteStatus = STATUS_INSUFFICIENT_RESOURCES; goto FinishDeviceReadWrite; } RtlZeroMemory(pUSBRequestBlock, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER)); UsbBuildInterruptOrBulkTransferRequest( pUSBRequestBlock, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), pPipeInformation->PipeHandle, pucTransferBuffer, NULL, ulStageTransferLength, ulURBFlags, NULL); pReadWriteContext = (PBULKUSB_RW_CONTEXT)ExAllocatePoolWithTag( NonPagedPool, sizeof(BULKUSB_RW_CONTEXT), USB_MEMORY_TAG); if(!IS_VALID(pReadWriteContext)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Failed to Allocate Memory for the Read Write Context\n")); ntReadWriteStatus = STATUS_INSUFFICIENT_RESOURCES; goto FinishDeviceReadWrite; } //set BULKUSB_RW_CONTEXT parameters. pReadWriteContext->pUSBRequestBlock = pUSBRequestBlock; pReadWriteContext->pTransferBuffer = pucTransferBuffer + ulStageTransferLength; pReadWriteContext->ulRemainingByteTransfer = ulTransferLength - ulStageTransferLength ; pReadWriteContext->ulCompletedByteTransfer = 0L; pReadWriteContext->pDevice = pDevice; pReadWriteContext->ulStreamIndex = ulStreamIndex; //use the original read/write irp as an internal device control irp pNextStackLocation = IoGetNextIrpStackLocation(pUsbIoRequestPacket); pNextStackLocation->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; pNextStackLocation->Parameters.Others.Argument1 = (PVOID)pUSBRequestBlock ; pNextStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; IoSetCompletionRoutine(pUsbIoRequestPacket, (PIO_COMPLETION_ROUTINE)UsbReadWriteCompletion, pReadWriteContext, TRUE, TRUE, TRUE); SkyWalkerDebugPrint(EXTREME_LEVEL,("USB Transfer Details for Stream %lu Packet %lu\n", ulStreamIndex, ulPacketIndex)); SkyWalkerDebugPrint(EXTREME_LEVEL,("ulStageTransferLength = %lu\n",ulStageTransferLength)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->ulCompletedByteTransfer = %lu\n",pReadWriteContext->ulCompletedByteTransfer)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->ulRemainingByteTransfer = %lu\n",pReadWriteContext->ulRemainingByteTransfer)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("bRead = %02d\n",bRead)); //since we return STATUS_PENDING call IoMarkIrpPending. //This is the boiler plate code. //This may cause extra overhead of an APC for the Irp completion //but this is the correct thing to do. IoMarkIrpPending(pUsbIoRequestPacket); IncrementPendingIoCount(pDevice); ntReadWriteStatus = IoCallDriver( pKSDeviceObject->NextDeviceObject, pUsbIoRequestPacket); if(!NT_SUCCESS(ntReadWriteStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("IoCallDriver Failed with status %X\n", ntReadWriteStatus)); //if the device was yanked out, then the pipeInformation //field is invalid. //similarly if the request was cancelled, then we need not //invoked reset pipe/device. KIRQL CurrentIrql = KeGetCurrentIrql(); if((ntReadWriteStatus != STATUS_CANCELLED) && (ntReadWriteStatus != STATUS_DEVICE_NOT_CONNECTED)) { if(CurrentIrql < DISPATCH_LEVEL) { ntReadWriteStatus = ResetUsbPipe(pKSDeviceObject,pPipeInformation); if(!NT_SUCCESS(ntReadWriteStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Reset USB Pipe Failed\n")); ntReadWriteStatus = ResetUsbDevice(pKSDeviceObject); } } } else { SkyWalkerDebugPrint(ENTRY_LEVEL, ("ntReadWriteStatus is STATUS_CANCELLED or " "STATUS_DEVICE_NOT_CONNECTED\n")); } //Freeing up the resources allocated in this routine goto FinishDeviceReadWrite; } PrintFunctionExit(__FUNCTION__,STATUS_PENDING); return STATUS_PENDING; FinishDeviceReadWrite: if(IS_VALID(pUSBRequestBlock)) { ExFreePoolWithTag(pUSBRequestBlock,USB_MEMORY_TAG); pUSBRequestBlock = NULL; } if(IS_VALID(pReadWriteContext)) { ExFreePoolWithTag(pReadWriteContext,USB_MEMORY_TAG); pReadWriteContext = NULL; } if(IS_VALID(pUsbIoRequestPacket)) { IoFreeIrp(pUsbIoRequestPacket); pUsbIoRequestPacket = NULL; } PrintFunctionExit(__FUNCTION__,ntReadWriteStatus); return ntReadWriteStatus; } /***************************************************************************** Function : UsbReadWriteCompletion 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. In this case return STATUS_MORE_PROCESSING_REQUIRED. if the irp completes in error, free all memory allocs and return the status. IN PARAM : Pointer to Device Object Io Request Packet Context OUT PARAM : Status of Read / Write request Completion STATUS_MORE_PROCESSING_REQUIRED always PreCondition : NONE PostCondtion : On Success Read/ Write Request Completed Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS UsbReadWriteCompletion( IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket, IN PVOID pContext ) { ULONG ulStageTransferLength = 0; NTSTATUS ntReadWriteCompleteStatus = pIoRequestPacket->IoStatus.Status; PIO_STACK_LOCATION pNextStackLocation; PBULKUSB_RW_CONTEXT pReadWriteContext = (PBULKUSB_RW_CONTEXT)pContext; CSkyWalker1Device * pDevice = pReadWriteContext->pDevice; ULONG ulStreamIndex = 0L; PrintFunctionEntry(__FUNCTION__); //successfully performed a stageLength of transfer. //check if we need to recirculate the irp. if(NT_SUCCESS(ntReadWriteCompleteStatus)) { if(pReadWriteContext) { pReadWriteContext->ulCompletedByteTransfer += pReadWriteContext->pUSBRequestBlock->UrbBulkOrInterruptTransfer.TransferBufferLength; if((pReadWriteContext->ulRemainingByteTransfer)&& (!pIoRequestPacket->Cancel)) { //another stage transfer SkyWalkerDebugPrint(EXTREME_LEVEL, ("Another stage transfer...\n")); //the transfer request is for TransferLength. //we can perform a max of MAX_BULK_PACKET_SIZE //in each stage. if(pReadWriteContext->ulRemainingByteTransfer > MAX_BULK_PACKET_SIZE) { ulStageTransferLength = MAX_BULK_PACKET_SIZE; } else { ulStageTransferLength = pReadWriteContext->ulRemainingByteTransfer; } //Reinitialize the urb pReadWriteContext->pUSBRequestBlock->UrbBulkOrInterruptTransfer.TransferBufferLength = ulStageTransferLength; pReadWriteContext->pUSBRequestBlock->UrbBulkOrInterruptTransfer.TransferBuffer = pReadWriteContext->pTransferBuffer; pReadWriteContext->pTransferBuffer += ulStageTransferLength; pReadWriteContext->ulRemainingByteTransfer -= ulStageTransferLength ; //use the original read/write irp as an internal device control irp pNextStackLocation = IoGetNextIrpStackLocation(pIoRequestPacket); pNextStackLocation->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; pNextStackLocation->Parameters.Others.Argument1 = (PVOID)pReadWriteContext->pUSBRequestBlock ; pNextStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; IoSetCompletionRoutine(pIoRequestPacket, (PIO_COMPLETION_ROUTINE)UsbReadWriteCompletion, pReadWriteContext, TRUE, TRUE, TRUE); SkyWalkerDebugPrint(EXTREME_LEVEL,("USB Transfer Details for Stream %lu\n", pReadWriteContext->ulStreamIndex)); SkyWalkerDebugPrint(EXTREME_LEVEL,("ulStageTransferLength = %lu\n",ulStageTransferLength)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->ulCompletedByteTransfer = %lu\n",pReadWriteContext->ulCompletedByteTransfer)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->ulRemainingByteTransfer = %lu\n",pReadWriteContext->ulRemainingByteTransfer)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pIoRequestPacket = 0x%p\n",pIoRequestPacket)); ntReadWriteCompleteStatus = IoCallDriver( pDevice->m_pKSDevice->NextDeviceObject, pIoRequestPacket); return STATUS_MORE_PROCESSING_REQUIRED; } else { InterlockedExchangeAdd((LONG*)&pDevice->m_NumberOfBytesRead[pReadWriteContext->ulStreamIndex], pReadWriteContext->ulCompletedByteTransfer); ulStreamIndex = pReadWriteContext->ulStreamIndex; //This is the last transfer //SkyWalkerDebugPrint(ENTRY_LEVEL,("Valid Synthesis Buffer\n")); // //This is not needed as anyways the IRP is going to Free soon //pIoRequestPacket->IoStatus.Information = pReadWriteContext->ulCompletedByteTransfer; ////Set the Frame Read Event here // //if(pReadWriteContext->ulCompletedByteTransfer == pDevice->m_SampleSize) //{ // pDevice->m_SynthesisDataValid = 1; //} } } } else { SkyWalkerDebugPrint(ENTRY_LEVEL, ("ReadWriteCompletion Failed \n")); } if(pReadWriteContext) { //Dump pReadWriteContext SkyWalkerDebugPrint(EXTREME_LEVEL,("Completed Stream = %lu",pReadWriteContext->ulStreamIndex)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->pUSBRequestBlock = 0x%p\n", pReadWriteContext->pUSBRequestBlock)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->ulRemainingByteTransfer = %lu\n", pReadWriteContext->ulRemainingByteTransfer)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->ulCompletedByteTransfer = %lu\n", pReadWriteContext->ulCompletedByteTransfer)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pReadWriteContext->pDevice = 0x%p\n", pReadWriteContext->pDevice)); SkyWalkerDebugPrint(EXTREME_LEVEL,("Actual Byte Transfer = %lu", pReadWriteContext->pUSBRequestBlock-> UrbBulkOrInterruptTransfer.TransferBufferLength)); DecrementPendingIoCount(pDevice); if(IS_VALID(pReadWriteContext->pUSBRequestBlock)) { ExFreePoolWithTag(pReadWriteContext->pUSBRequestBlock,USB_MEMORY_TAG); pReadWriteContext->pUSBRequestBlock = NULL; } if(IS_VALID(pReadWriteContext)) { ExFreePoolWithTag(pReadWriteContext,USB_MEMORY_TAG); pReadWriteContext = NULL; } if(IS_VALID(pIoRequestPacket)) { IoFreeIrp(pIoRequestPacket); pIoRequestPacket = NULL; } } SkyWalkerDebugPrint(EXTREME_LEVEL,("Calling ProcessStream \n")); //TS is read, Process the stream pDevice->ProcessStream(ulStreamIndex); PrintFunctionExit(__FUNCTION__,STATUS_MORE_PROCESSING_REQUIRED); //This is the only status that can be returned from the Asynchronous //IRP created by Driver return STATUS_MORE_PROCESSING_REQUIRED; } /***************************************************************************** Function : ControlUsbDevice Description : This Function is used to send the Vendor requests to the Device IN PARAM : Pointer to Device Object Vendor Request Value corresponding to Request Index for the Request (Used with Request) Transfer Buffer for Read/Write size of the Transfer Buffer True if Read from else False for Write to device OUT PARAM : Status of Vendor Request Execution STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Vendor Request Command Executed Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ControlUsbDevice( IN PKSDEVICE pKSDeviceObject, IN UCHAR ucRequest, IN USHORT usValue, IN USHORT usIndex, IN PUCHAR pucTransferBuffer, IN ULONG ulTransferLength, IN BOOLEAN bRead) { NTSTATUS ntControlStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; PURB pUSBRequestBlock = NULL; ULONG ulURBFlags = 0L; PrintFunctionEntry(__FUNCTION__); if(pDevice->UsbDeviceState != Working) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Invalid device state\n")); ntControlStatus = STATUS_INVALID_DEVICE_STATE; goto ExitControlDevice; } ulURBFlags = USBD_SHORT_TRANSFER_OK; if(bRead) { ulURBFlags |= USBD_TRANSFER_DIRECTION_IN; //Requst data from Device SkyWalkerDebugPrint(EXTREME_LEVEL,("Read Operation\n")); } else { ulURBFlags |= USBD_TRANSFER_DIRECTION_OUT; SkyWalkerDebugPrint(EXTREME_LEVEL,("Write Operation\n")); } pUSBRequestBlock = (PURB)ExAllocatePoolWithTag( NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), USB_MEMORY_TAG); if(!IS_VALID(pUSBRequestBlock)) { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Failed to Allocate Memory for the Vendor URB\n")); ntControlStatus = STATUS_INSUFFICIENT_RESOURCES; goto ExitControlDevice; } UsbBuildVendorRequest( pUSBRequestBlock,//Pointer to an URB that //is to be formatted as a vendor or class //request. URB_FUNCTION_VENDOR_DEVICE, //Function sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), //Length of URB in Bytes ulURBFlags, //Zero, One or Combination of //USBD_TRANSFER_DIRECTION_IN & USBD_SHORT_TRANSFER_OK 0, //Reserved ucRequest, //USB/Vendor Specific Request Code usValue, //Value Specific to Request usIndex, //Device Defined identifier else Zero pucTransferBuffer,//Pointer to Resident Buffer for Transfer or NULL NULL, //Pointer to MDL for Transfer or NULL ulTransferLength,//Length in Bytes of Buffer specified NULL //NULL Always ); ntControlStatus = SendURBToBusDriver(pKSDeviceObject,pUSBRequestBlock); if(!NT_SUCCESS(ntControlStatus)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Sending Vendor Request Failed\n")); } ExFreePool(pUSBRequestBlock); ExitControlDevice: PrintFunctionExit(__FUNCTION__,ntControlStatus); return ntControlStatus; } /***************************************************************************** Function : SendURBToBusDriver Description : Function to used to Send the URB to the USB Bus Driver (USBD.sys) IN PARAM : Pointer to Device Object to which URB is to be sent Pointer to the URB to be sent OUT PARAM : Status of the URB Send operation STATUS_SUCCESS on Successful execution STATUS_INVALID_PARAMETER in case of Error STATUS_INSUFFICIENT_RESOURCES in case IRP could not be created else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success URB sent to the Bus Driver Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS SendURBToBusDriver(IN PKSDEVICE pKSDeviceObject, IN PURB pUSBRequestBlock ) { NTSTATUS ntIrpProcessingStatus = STATUS_SUCCESS; USBD_STATUS UsbStatus; PIRP pIoRequestPacket = NULL; KEVENT kIrpCompleted; IO_STATUS_BLOCK IoStatusBlock; PIO_STACK_LOCATION pNextIoStackLocation = NULL; PDEVICE_OBJECT pRootDeviceObject = pKSDeviceObject->NextDeviceObject; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); if((!IS_VALID(pRootDeviceObject)) || (!(IS_VALID(pUSBRequestBlock)))) { SkyWalkerDebugPrint(ENTRY_LEVEL,("pRootDeviceObject = 0x%p, pUSBRequestBlock = 0x%p\n",pRootDeviceObject,pUSBRequestBlock)); ntIrpProcessingStatus = STATUS_INVALID_PARAMETER; goto CompleteURBSend; } //Initialize Kernel Event which should be trigerred after completion //of the Device IO Control request KeInitializeEvent(&kIrpCompleted, //PKEVENT NotificationEvent, //Type FALSE); //State //Create Internal Device Io Control Request pIoRequestPacket = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_SUBMIT_URB , pRootDeviceObject, //Device to which the request to be sent NULL, 0, NULL, 0, TRUE, //TRUE for IRM_MJ_INTERNAL_DEVICE_CONTROL, IRP_MJ_SCSI &kIrpCompleted, //Event should be trigerred when the IRP completes &IoStatusBlock); //The Status Block should be set when the Io request Completes //If could not create the IRP return with the INSUFFICIENT RESOURCES if(pIoRequestPacket == NULL) { ntIrpProcessingStatus = STATUS_INSUFFICIENT_RESOURCES; goto CompleteURBSend; } pNextIoStackLocation = IoGetNextIrpStackLocation(pIoRequestPacket); pNextIoStackLocation->Parameters.Others.Argument1 = pUSBRequestBlock; IncrementPendingIoCount(pDevice); //Call the Next Driver ntIrpProcessingStatus = IoCallDriver(pRootDeviceObject,pIoRequestPacket); if(ntIrpProcessingStatus == STATUS_PENDING) { LARGE_INTEGER Timeout; Timeout.QuadPart = (LONGLONG) 2 /*sec*/* 1000 /*msec*/ * 1000 /*usec*/ * (-10)/*Conv. Factor*/; //for(int nRetry = 0; ((nRetry < 3) && (ntIrpProcessingStatus != STATUS_SUCCESS)) ; nRetry++) { //IRP is yet to be processed thus STATUS_PENDING is returned from the Lower Device Driver (USBD.sys) ntIrpProcessingStatus = KeWaitForSingleObject(&kIrpCompleted, //PKEVENT Executive, //Wait Reason has to be Executive KernelMode, //Must be kernel mode so //that Stack will not Paged out FALSE, //No Alert NULL//&Timeout //Wait for 2 sec max ); SkyWalkerDebugPrint(EXTREME_LEVEL,("KeWaitForSingleObject returned with status = %s(0x%X)\n", NTStatusToString(ntIrpProcessingStatus),ntIrpProcessingStatus)); //SkyWalkerDebugPrint(EXTREME_LEVEL,("nRetry = %d\n",nRetry)); } ntIrpProcessingStatus = IoStatusBlock.Status; UsbStatus = URB_STATUS(pUSBRequestBlock); SkyWalkerDebugPrint(EXTREME_LEVEL,("URB STATUS = 0x%X\n",UsbStatus)); } DecrementPendingIoCount(pDevice); CompleteURBSend: PrintFunctionExit(__FUNCTION__,ntIrpProcessingStatus); return ntIrpProcessingStatus; } /***************************************************************************** Function : QueryRemoveUsbDevice Description : Function to used to Service PnP IRPs of Minor Type IRP_MN_QUERY_REMOVE_DEVICE IN PARAM : Pointer to Device Object whose Remove Query has come Device Remove Query Irp with Minor Code IRP_MN_QUERY_REMOVE_DEVICE OUT PARAM : Status of the Device Remove Query Processing STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Device can be removed is conveyed to the caller Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS QueryRemoveUsbDevice( IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; NTSTATUS ntQueryStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); // //If we can allow removal of the device, we should set the QueueState //to HoldRequests so further requests will be queued. This is required //so that we can process queued up requests in cancel-remove just in //case somebody else in the stack fails the query-remove. KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); SET_NEW_PNP_STATE(pDevice, PendingRemove); pDevice->QueueState = HoldRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); //wait for the existing ones to be finished. //first, decrement this operation DecrementPendingIoCount(pDevice); KeWaitForSingleObject(&pDevice->EvDeviceStopOk, Executive, KernelMode, FALSE, NULL); PrintFunctionExit(__FUNCTION__,ntQueryStatus); return ntQueryStatus; } /***************************************************************************** Function : CancelRemoveUsbDevice Description : Function to used to Service PnP IRPs of Minor Type IRP_MN_CANCEL_REMOVE_DEVICE IN PARAM : Pointer to Device Object whose Remove request has been cancelled Device Remove Cancel Irp with Minor Code IRP_MN_CANCEL_REMOVE_DEVICE OUT PARAM : Status of the Device Remove Cancel Irp Processing STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Device Remove cancel request is processed Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS CancelRemoveUsbDevice(IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; KEVENT Evevent; NTSTATUS ntStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); //We need to reset the QueueState flag to ProcessRequest, //since the device resume its normal activities. // //First check to see whether you have received cancel-stop //without first receiving a query-stop. This could happen if someone //above us fails a query-stop and passes down the subsequent //cancel-stop. if(pDevice->UsbDeviceState == PendingRemove ) { ntStatus = PassDownIRPAndWaitForCompletion(pKSDeviceObject->NextDeviceObject, pIoRequestPacket, true); if(NT_SUCCESS(ntStatus)) { KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); RESTORE_PREVIOUS_PNP_STATE(pDevice); pDevice->QueueState = AllowRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); //ProcessQueuedRequests(deviceExtension); } } else { /* spurious cancel Remove If the device is already started when the driver receives this IRP, the driver simply sets status to success and passes the IRP to the next driver. For such a cancel-remove IRP, a function driver need not set a completion routine. The device may not be in the remove-pending state, because, for example, the driver failed the previous IRP_MN_QUERY_REMOVE_DEVICE.*/ } PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : SurpriseUsbDeviceRemoval Description : Function to used to Service PnP IRPs of Minor Type IRP_MN_SURPRISE_REMOVAL IN PARAM : Pointer to Device Object which is removed surprisingly Device Remove Cancel Irp with Minor Code IRP_MN_SURPRISE_REMOVAL OUT PARAM : Status of the Spurious Device Removal Processing STATUS_SUCCESS Always PreCondition : NONE PostCondtion : On Success Surprised Device Remove is processed Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS SurpriseUsbDeviceRemoval(IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; KEVENT Evevent; NTSTATUS ntStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); // //1. fail pending requests //2. return device and memory resources //3. disable interfaces // //if(deviceExtension->WaitWakeEnable) { // // CancelWaitWake(deviceExtension); //} //if(WinXpOrBetter == deviceExtension->WdmVersion) { // if(deviceExtension->SSEnable) { // // // //Cancel the timer so that the DPCs are no longer fired. // //we do not need DPCs because the device has been surprise // //removed // // // // KeCancelTimer(&deviceExtension->Timer); // deviceExtension->SSEnable = 0; // // // //make sure that if a DPC was fired before we called cancel timer, // //then the DPC and work-time have run to their completion // // // KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent, // Executive, // KernelMode, // FALSE, // NULL); // // // //make sure that the selective suspend request has been completed. // // // KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, // Executive, // KernelMode, // FALSE, // NULL); // } //} KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); SET_NEW_PNP_STATE(pDevice, SurpriseRemoved); pDevice->QueueState = FailRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); //ProcessQueuedRequests(deviceExtension); AbortUsbPipes(pKSDeviceObject); PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : AbortUsbPipes Description : This function sends an abort pipe request for pipes. IN PARAM : Pointer to Device Object OUT PARAM : Status of the Pipe Abort STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Pipe are aborted Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS AbortUsbPipes(IN PKSDEVICE pKSDeviceObject) { PURB pUsbRequestBlock = NULL; ULONG ulPipeIndex = 0; NTSTATUS ntStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PUSBD_PIPE_INFORMATION pPipeInformation = &pDevice->ReadPipe; PrintFunctionEntry(__FUNCTION__); for(ulPipeIndex = 0; ulPipeIndex < 2; ulPipeIndex++) { //if(pPipeInformation->PipeOpen) { SkyWalkerDebugPrint(EXTREME_LEVEL, ("Aborting Pipe 0x%X\n",pPipeInformation->EndpointAddress)); pUsbRequestBlock = (PURB) ExAllocatePoolWithTag( NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), USB_MEMORY_TAG); if(pUsbRequestBlock) { pUsbRequestBlock->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST); pUsbRequestBlock->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE; pUsbRequestBlock->UrbPipeRequest.PipeHandle = pPipeInformation->PipeHandle; ntStatus = SendURBToBusDriver(pKSDeviceObject,pUsbRequestBlock); ExFreePool(pUsbRequestBlock); } else { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Failed to Allocate memory for URB during Pipe Abort\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto FinishAbortPipe; } if(NT_SUCCESS(ntStatus)) { //pPipeInformation->PipeOpen = FALSE; } pPipeInformation = &pDevice->WritePipe; } } FinishAbortPipe: PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : RemoveUsbDevice Description : Function to used to Service PnP IRPs of Minor Type IRP_MN_REMOVE_DEVICE IN PARAM : Pointer to Device Object whose remove request has come Device Remove Cancel Irp with Minor Code IRP_MN_REMOVE_DEVICE OUT PARAM : Status of the Device Removal STATUS_SUCCESS Always PreCondition : NONE PostCondtion : On Success Device Remove request is processed Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS RemoveUsbDevice( IN PKSDEVICE pKSDeviceObject, IN PIRP pIoRequestPacket) { KIRQL kOldIrql; KEVENT Evevent; NTSTATUS ntStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; ULONG ulRequestCount = 0L; PrintFunctionEntry(__FUNCTION__); // //The Plug & Play system has dictated the removal of this device. We //have no choice but to detach and delete the device object. //(If we wanted to express an interest in preventing this removal, //we should have failed the query remove IRP). // if(pDevice->UsbDeviceState != SurpriseRemoved ) { // //we are here after QUERY_REMOVE // KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); pDevice->QueueState = FailRequests; KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); //if(deviceExtension->WaitWakeEnable) { // // CancelWaitWake(deviceExtension); //} //if(WinXpOrBetter == deviceExtension->WdmVersion) { // if(deviceExtension->SSEnable) { // // // //Cancel the timer so that the DPCs are no longer fired. // //we do not need DPCs because the device has been removed // // // KeCancelTimer(&deviceExtension->Timer); // deviceExtension->SSEnable = 0; // // // //make sure that if a DPC was fired before we called cancel timer, // //then the DPC and work-time have run to their completion // // // KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent, // Executive, // KernelMode, // FALSE, // NULL); // // // //make sure that the selective suspend request has been completed. // // // KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, // Executive, // KernelMode, // FALSE, // NULL); // } //} //ProcessQueuedRequests(deviceExtension); AbortUsbPipes(pKSDeviceObject); } KeAcquireSpinLock(&pDevice->DeviceStateLock, &kOldIrql); SET_NEW_PNP_STATE(pDevice, Removed); KeReleaseSpinLock(&pDevice->DeviceStateLock, kOldIrql); // //need 2 decrements // ulRequestCount = DecrementPendingIoCount(pDevice); ulRequestCount = DecrementPendingIoCount(pDevice); KeWaitForSingleObject(&pDevice->EvDeviceRemoveOk, Executive, KernelMode, FALSE, NULL); PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : ResetUsbPipe Description : This routine synchronously submits a URB_FUNCTION_RESET_PIPE request down the stack. IN PARAM : Pointer to Device Object Pipe to be reseted OUT PARAM : Status of the Reset Usb Pipe Request STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Usb Pipe is reseted Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ResetUsbPipe( IN PKSDEVICE pKSDeviceObject, IN PUSBD_PIPE_INFORMATION pPipeInformation) { PURB pUsbRequestBlock = NULL; NTSTATUS ntResetStatus = STATUS_SUCCESS; CSkyWalker1Device * pDevice = (CSkyWalker1Device *)pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); SkyWalkerDebugPrint(EXTREME_LEVEL,("Pipe to Reset = 0x%X",pPipeInformation->EndpointAddress)); SkyWalkerDebugPrint(EXTREME_LEVEL,("Pipe Handle = 0x%p",pPipeInformation->PipeHandle)); pUsbRequestBlock = (PURB) ExAllocatePoolWithTag( NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), USB_MEMORY_TAG); if(pUsbRequestBlock) { pUsbRequestBlock->UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST); pUsbRequestBlock->UrbHeader.Function = URB_FUNCTION_RESET_PIPE; pUsbRequestBlock->UrbPipeRequest.PipeHandle = pPipeInformation->PipeHandle; SkyWalkerDebugPrint(EXTREME_LEVEL,("Sending the Pipe Reset Command\n")); ntResetStatus = SendURBToBusDriver(pKSDeviceObject, pUsbRequestBlock); ExFreePool(pUsbRequestBlock); } else { SkyWalkerDebugPrint(ENTRY_LEVEL,("Failed to allocate URB Memory during Pipe Reset\n")); ntResetStatus = STATUS_INSUFFICIENT_RESOURCES; } if(NT_SUCCESS(ntResetStatus)) { SkyWalkerDebugPrint(EXTREME_LEVEL, ("Successfully Reseted the Usb Pipe\n")); ntResetStatus = STATUS_SUCCESS; } else { SkyWalkerDebugPrint(ENTRY_LEVEL, ("Failed to reset the Usb Pipe\n")); } PrintFunctionExit(__FUNCTION__,ntResetStatus); return ntResetStatus; } /***************************************************************************** Function : ResetUsbDevice Description : This routine checks the current status of the Usb Port If Device is connected but not enabled then it resets the Usb Port IN PARAM : Pointer to Device Object OUT PARAM : Status of the Reset Usb Device Request STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Usb Device is reseted Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ResetUsbDevice(IN PKSDEVICE pKSDeviceObject) { NTSTATUS ntResetStatus = STATUS_SUCCESS; ULONG ulPortStatus = 0; PrintFunctionEntry(__FUNCTION__); ntResetStatus = GetUsbPortStatus(pKSDeviceObject, &ulPortStatus); if((NT_SUCCESS(ntResetStatus)) && (!(ulPortStatus & USBD_PORT_ENABLED)) && (ulPortStatus & USBD_PORT_CONNECTED)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Resetting the Parent Port\n")); ntResetStatus = ResetUsbParentPort(pKSDeviceObject); } PrintFunctionExit(__FUNCTION__,ntResetStatus); return ntResetStatus; } /***************************************************************************** Function : GetUsbPortStatus Description : This routine retrives the Usb Port Status as Enabled / Disabled and Connected / Not Connected IN PARAM : Pointer to Device Object Port Status OUT PARAM : Status of the USB Port Status Request STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Usb Port status is retrived Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS GetUsbPortStatus( IN PKSDEVICE pKSDeviceObject, IN OUT PULONG pulPortStatus) { NTSTATUS ntStatus = STATUS_SUCCESS; KEVENT EvRequestComplete; PIRP pIoRequestPacket = NULL; IO_STATUS_BLOCK IoStatus; PIO_STACK_LOCATION pNextStackLocation = NULL; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); *pulPortStatus = 0; //Initialize the Event to be triggerred after completion of Device Io Control request KeInitializeEvent(&EvRequestComplete, NotificationEvent, FALSE); pIoRequestPacket = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_GET_PORT_STATUS, pKSDeviceObject->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &EvRequestComplete, &IoStatus); if(!IS_VALID(pIoRequestPacket)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Memory Allocation during Get Port Status Failed\n")); goto FinishGetPortStatus; return STATUS_INSUFFICIENT_RESOURCES; } pNextStackLocation = IoGetNextIrpStackLocation(pIoRequestPacket); pNextStackLocation->Parameters.Others.Argument1 = pulPortStatus; ntStatus = IoCallDriver(pKSDeviceObject->NextDeviceObject, pIoRequestPacket); if(ntStatus == STATUS_PENDING) { KeWaitForSingleObject(&EvRequestComplete, Executive, KernelMode, FALSE, NULL); } else { IoStatus.Status = ntStatus; } ntStatus = IoStatus.Status; SkyWalkerDebugPrint(EXTREME_LEVEL,("Port Status = %lu (",*pulPortStatus)); SkyWalkerDebugPrint(EXTREME_LEVEL,("%s, ",(((*pulPortStatus) & USBD_PORT_ENABLED)? "Enabled" : "Disabled"))); SkyWalkerDebugPrint(EXTREME_LEVEL,("%s)\n",(((*pulPortStatus) & USBD_PORT_CONNECTED)? "Connected" : "Not Connected"))); FinishGetPortStatus: PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } /***************************************************************************** Function : ResetUsbParentPort Description : This routine sends an IOCTL_INTERNAL_USB_RESET_PORT synchronously down the stack. IN PARAM : Pointer to Device Object OUT PARAM : Status of the Reset USB Port Request STATUS_SUCCESS on Successful execution else Error from the Bus Driver PreCondition : NONE PostCondtion : On Success Usb Port is reseted Logic : NONE Assumption : NONE Revision History: *****************************************************************************/ NTSTATUS ResetUsbParentPort( IN PKSDEVICE pKSDeviceObject ) { NTSTATUS ntStatus = STATUS_SUCCESS; KEVENT EvRequestComplete; PIRP pIoRequestPacket = NULL; IO_STATUS_BLOCK IoStatus; PIO_STACK_LOCATION pNextStackLocation = NULL; CSkyWalker1Device * pDevice = (CSkyWalker1Device *) pKSDeviceObject->Context; PrintFunctionEntry(__FUNCTION__); //Initialize the Event to be triggerred after completion of Device Io Control request KeInitializeEvent(&EvRequestComplete, NotificationEvent, FALSE); pIoRequestPacket = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_RESET_PORT, pKSDeviceObject->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &EvRequestComplete, &IoStatus); if(!IS_VALID(pIoRequestPacket)) { SkyWalkerDebugPrint(ENTRY_LEVEL,("Memory Allocation during Reset Parent Device Failed\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto FinishResetDevice; } pNextStackLocation = IoGetNextIrpStackLocation(pIoRequestPacket); ntStatus = IoCallDriver(pKSDeviceObject->NextDeviceObject, pIoRequestPacket); if(ntStatus == STATUS_PENDING) { KeWaitForSingleObject(&EvRequestComplete, Executive, KernelMode, FALSE, NULL); } else { IoStatus.Status = ntStatus; } ntStatus = IoStatus.Status; FinishResetDevice: PrintFunctionExit(__FUNCTION__,ntStatus); return ntStatus; } //Print Device Descriptor VOID PrintDeviceDescriptor(IN PUSB_DEVICE_DESCRIPTOR pDeviceDescriptor) { SkyWalkerDebugPrint(INTERMEDIATE_LEVEL, (__FUNCTION__"\n")); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bLength= %02d\n", pDeviceDescriptor->bLength)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bDescriptorType= %02d\n", pDeviceDescriptor->bDescriptorType)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bcdUSB= 0x%X\n", pDeviceDescriptor->bcdUSB)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bDeviceClass= 0x%02X\n", pDeviceDescriptor->bDeviceClass)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bDeviceSubClass= 0x%02X\n", pDeviceDescriptor->bDeviceSubClass)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bDeviceProtocol= 0x%02X\n", pDeviceDescriptor->bDeviceProtocol)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bMaxPacketSize0= %02d\n", pDeviceDescriptor->bMaxPacketSize0)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->idVendor= 0x%X\n", pDeviceDescriptor->idVendor)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->idProduct= 0x%X\n", pDeviceDescriptor->idProduct)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bcdDevice= 0x%X\n", pDeviceDescriptor->bcdDevice)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->iManufacturer= %02d\n", pDeviceDescriptor->iManufacturer)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->iProduct= %02d\n", pDeviceDescriptor->iProduct)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->iSerialNumber= %02d\n", pDeviceDescriptor->iSerialNumber)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pDeviceDescriptor->bNumConfigurations= %02d\n", pDeviceDescriptor->bNumConfigurations)); } //Print Configuration Descriptor VOID PrintConfigurationDescriptor(IN PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor) { SkyWalkerDebugPrint(INTERMEDIATE_LEVEL, (__FUNCTION__"\n")); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->bLength= %02d\n", pConfigurationDescriptor->bLength)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->bDescriptorType= %02d\n", pConfigurationDescriptor->bDescriptorType)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->wTotalLength= %d\n", pConfigurationDescriptor->wTotalLength)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->bNumInterfaces= %02d\n", pConfigurationDescriptor->bNumInterfaces)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->bConfigurationValue= %02d\n", pConfigurationDescriptor->bConfigurationValue)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->iConfiguration= %02d\n", pConfigurationDescriptor->iConfiguration)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->bmAttributes= 0x%02X\n", pConfigurationDescriptor->bmAttributes)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pConfigurationDescriptor->MaxPower= %02d\n", pConfigurationDescriptor->MaxPower)); } //Print Interface Descriptor VOID PrintInterfaceDescriptor(IN PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor) { SkyWalkerDebugPrint(INTERMEDIATE_LEVEL, (__FUNCTION__"\n")); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bLength= %02d\n", pInterfaceDescriptor->bLength)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bDescriptorType= %02d\n", pInterfaceDescriptor->bDescriptorType)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bInterfaceNumber= %02d\n", pInterfaceDescriptor->bInterfaceNumber)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bAlternateSetting= %02d\n", pInterfaceDescriptor->bAlternateSetting)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bNumEndpoints= %02d\n", pInterfaceDescriptor->bNumEndpoints)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bInterfaceClass= 0x%02X\n", pInterfaceDescriptor->bInterfaceClass)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bInterfaceSubClass= 0x%02X\n", pInterfaceDescriptor->bInterfaceSubClass)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->bInterfaceProtocol= 0x%02X\n", pInterfaceDescriptor->bInterfaceProtocol)); SkyWalkerDebugPrint(EXTREME_LEVEL, ("pInterfaceDescriptor->iInterface= %02d\n", pInterfaceDescriptor->iInterface)); } //Print Pipe Information VOID PrintPipeInformation(PUSBD_PIPE_INFORMATION pPipeInformation) { SkyWalkerDebugPrint(EXTREME_LEVEL,("pPipeInformation->PipeType = 0x%X\n", pPipeInformation->PipeType)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pPipeInformation->EndpointAddress = 0x%X\n", pPipeInformation->EndpointAddress)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pPipeInformation->MaximumPacketSize = 0x%X\n", pPipeInformation->MaximumPacketSize)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pPipeInformation->Interval = 0x%X\n", pPipeInformation->Interval)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pPipeInformation->PipeHandle = 0x%p\n", pPipeInformation->PipeHandle)); SkyWalkerDebugPrint(EXTREME_LEVEL,("pPipeInformation->MaximumTransferSize = 0x%X\n", pPipeInformation->MaximumTransferSize)); }