www.pudn.com > usbfx2lk_v1.1.zip > usbfx2lk_usb.cpp


/////////////////////////////////////////////////////////////////////////////// 
// 
//    (C) Copyright 2005 OSR Open Systems Resources, Inc. 
//    All Rights Reserved 
// 
//    This sofware is supplied for instructional purposes only. 
// 
//    OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty 
//    for this software.  THIS SOFTWARE IS PROVIDED  "AS IS" WITHOUT WARRANTY 
//    OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 
//    THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR 
//    PURPOSE.  THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS 
//    WITH YOU.  OSR's entire liability and your exclusive remedy shall not 
//    exceed the price paid for this material.  In no event shall OSR or its 
//    suppliers be liable for any damages whatsoever (including, without 
//    limitation, damages for loss of business profit, business interruption, 
//    loss of business information, or any other pecuniary loss) arising out 
//    of the use or inability to use this software, even if OSR has been 
//    advised of the possibility of such damages.  Because some states/ 
//    jurisdictions do not allow the exclusion or limitation of liability for 
//    consequential or incidental damages, the above limitation may not apply 
//    to you. 
// 
//    OSR Open Systems Resources, Inc. 
//    105 Route 101A Suite 19 
//    Amherst, NH 03031  (603) 595-6500 FAX: (603) 595-6503 
//    email bugs to: bugs@osr.com 
// 
// 
//    MODULE: 
// 
//      USBFx2LK_PnP.cpp 
// 
//    ABSTRACT: 
// 
//      This file contains the routines that handle Plug and Play processing for the  
//      OSR USB FX2 Learning Kit Device 
// 
//    AUTHOR(S): 
// 
//      OSR Open Systems Resources, Inc. 
//  
/////////////////////////////////////////////////////////////////////////////// 
#include "usbfx2lk.h" 
 
#ifdef WPP_TRACING 
// 
// Include the necessary tmh file - this is  
//  just a matter of course if you're using WPP tracing. 
// 
extern "C" { 
#include "usbfx2lk_usb.tmh" 
} 
#endif 
 
// 
// Forward Definitions 
// 
NTSTATUS SubmitUrb(PUSBFX2LK_EXT DevExt,PURB Urb); 
NTSTATUS ConfigureUsbDevice(PUSBFX2LK_EXT DevExt); 
NTSTATUS SelectUsbInterfaces(PUSBFX2LK_EXT DevExt, 
                             PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor); 
VOID DetermineDeviceSpeed(PUSBFX2LK_EXT DevExt); 
#ifndef IoForwardIrpSynchronously 
NTSTATUS DetermineDeviceSpeedCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); 
#endif //IoForwardIrpSynchronously 
NTSTATUS AsynchronousUrbRequestCompletion(IN PDEVICE_OBJECT DeviceObject, 
                                          IN PIRP Irp, IN PVOID Context); 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// ReadandSelectUsbDescriptors 
// 
//  This routine is called by OsrStartDevice to Read and Select the USB 
//  descriptors that will be used to talk to the usb device. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS ReadandSelectUsbDescriptors(PUSBFX2LK_EXT DevExt) 
{ 
    PURB                   urb = NULL; 
    NTSTATUS               status; 
    PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL; 
     
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ReadandSelectUsbDescriptors: Enter\n")); 
 
    // 
    // Allocate a URB. 
    // 
    urb = (PURB) ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),'bruO'); 
 
    if(urb) { 
 
        // 
        // Allocate a USB_DEVICE_DESCRIPTOR to receive the device descriptor from our device. 
        // 
        deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR) ExAllocatePoolWithTag(NonPagedPool,  
                                                        sizeof(USB_DEVICE_DESCRIPTOR), 'dduO'); 
 
        if(deviceDescriptor) { 
 
            // 
            // Format the Urb for the request to get the USB_DEVICE_DESCRIPTOR 
            // 
            UsbBuildGetDescriptorRequest( 
                    urb,  
                    (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), 
                    USB_DEVICE_DESCRIPTOR_TYPE,  
                    0,  
                    0,  
                    deviceDescriptor,  
                    NULL,  
                    sizeof(USB_DEVICE_DESCRIPTOR),  
                    NULL); 
 
            // 
            // Submit the URB to the Device 
            // 
            status = SubmitUrb(DevExt,urb); 
 
            // 
            // If the request is successful, then configure the device 
            // 
            if(NT_SUCCESS(status)) { 
 
                ASSERT(deviceDescriptor->bNumConfigurations); 
 
                // 
                // Save away the device descriptor 
                // 
                DevExt->UsbDeviceDescriptor = deviceDescriptor; 
 
                status = ConfigureUsbDevice(DevExt);     
 
            } else { 
 
                // 
                // No descriptor info? Clean up. 
                // 
                ExFreePool(deviceDescriptor); 
 
            } 
               
            // 
            // Free the URB  
            // 
            ExFreePool(urb); 
 
        } else { 
 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("ReadandSelectUsbDescriptors: Failed to allocate memory for deviceDescriptor\n")); 
            ExFreePool(urb); 
            status = STATUS_INSUFFICIENT_RESOURCES; 
        } 
    } else { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("ReadandSelectUsbDescriptors: Failed to allocate memory for urb\n")); 
        status = STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ReadandSelectUsbDescriptors: Exit\n")); 
 
    return status; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// ConfigureUsbDevice 
// 
//  This routine is called by ReadandSelectUsbDescriptors to read the USB  
//  configuration descriptor that will be used to talk to the usb device. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS ConfigureUsbDevice(PUSBFX2LK_EXT DevExt) 
{ 
    PURB                          urb = NULL; 
    ULONG                         size = sizeof(USB_CONFIGURATION_DESCRIPTOR); 
    NTSTATUS                      status; 
    PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ConfigureUsbDevice: Enter\n")); 
 
    // 
    // Allocate memory for a URB. 
    // 
    urb = (PURB) ExAllocatePoolWithTag(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),'bruO'); 
 
    if(urb) { 
 
        // 
        // Allocate memory for the default sized configuration descriptor. 
        // 
        configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePoolWithTag(NonPagedPool, size,'dcuO'); 
 
        if(configurationDescriptor) { 
 
            // 
            // Format the URB for the request. 
            // 
            UsbBuildGetDescriptorRequest( 
                    urb,  
                    (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), 
                    USB_CONFIGURATION_DESCRIPTOR_TYPE,  
                    0,  
                    0,  
                    configurationDescriptor, 
                    NULL,  
                    sizeof(USB_CONFIGURATION_DESCRIPTOR),  
                    NULL); 
 
            // 
            // Submit the request to the USB Device. 
            // 
            status = SubmitUrb(DevExt,urb); 
 
            // 
            // If the request is not successful, go and cleanup from the error. 
            // 
            if(!NT_SUCCESS(status)) { 
 
                OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                    ("ConfigureUsbDevice: UsbBuildGetDescriptorRequest failed\n")); 
                goto ConfigureDevice_Exit; 
            } 
        } else { 
 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("ConfigureUsbDevice: Failed to allocate mem for config Descriptor\n")); 
            status = STATUS_INSUFFICIENT_RESOURCES; 
            goto ConfigureDevice_Exit; 
        } 
 
        // 
        // Okay, the request was successful.   Look at the returned length in the configuration 
        // descriptor and use it to allocate a configuration descriptor that is big enough 
        // to receive the full configuration from the device. 
        // 
        size = configurationDescriptor->wTotalLength; 
 
        // 
        // Free the existing configuration descriptor. 
        // 
        ExFreePool(configurationDescriptor); 
 
        // 
        // Allocate the correct sized descriptor. 
        // 
        configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePoolWithTag(NonPagedPool, size,'dcuO'); 
 
        if(configurationDescriptor) { 
 
            // 
            // Format the urb to get the full configuration descriptor. 
            // 
            UsbBuildGetDescriptorRequest( 
                    urb,  
                    (USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), 
                    USB_CONFIGURATION_DESCRIPTOR_TYPE, 
                    0,  
                    0,  
                    configurationDescriptor,  
                    NULL,  
                    size,  
                    NULL); 
 
            // 
            // Submit the request to the device. 
            // 
            status = SubmitUrb(DevExt,urb); 
 
            // 
            // If the request is not successful, clean up after the error. 
            // 
            if(!NT_SUCCESS(status)) { 
 
                OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                    ("ConfigureUsbDevice: Failed to read configuration descriptor\n")); 
                goto ConfigureDevice_Exit; 
            } 
        } else { 
 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("ConfigureUsbDevice: Failed to alloc mem for config Descriptor\n")); 
            status = STATUS_INSUFFICIENT_RESOURCES; 
            goto ConfigureDevice_Exit; 
        } 
    } else { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("ConfigureUsbDevice: Failed to allocate memory for urb\n")); 
        status = STATUS_INSUFFICIENT_RESOURCES; 
        goto ConfigureDevice_Exit; 
    } 
 
    // 
    // Check to make sure that a configuration descriptor was allocated. 
    // 
    if(configurationDescriptor) { 
 
        // 
        // Save a copy of configurationDescriptor in deviceExtension 
        // remember to free it later. 
        // 
        DevExt->UsbConfigurationDescriptor = configurationDescriptor; 
 
        // 
        // Determine if the USB configuration is cabable of supporting  
        // remote wake. 
        // 
        if(configurationDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { 
            // 
            // This configuration supports remote wakeup 
            // 
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO, 
                ("ConfigureUsbDevice: Remote Wakeup Enabled.\n")); 
            DevExt->WaitWakeEnable = TRUE; 
 
        } else { 
 
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO, 
                ("ConfigureUsbDevice: Remote Wakeup Disabled.\n")); 
            DevExt->WaitWakeEnable = FALSE; 
        } 
 
        // 
        // Select the interface(s) that we are going to use to communicate with the device. 
        // 
        status = SelectUsbInterfaces(DevExt, configurationDescriptor); 
 
        // 
        // And also determine the speed at which the device is running 
        // 
        DetermineDeviceSpeed(DevExt); 
 
    } else { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO, 
            ("ConfigureUsbDevice: Failed to allocate configuration descriptor.\n")); 
        DevExt->UsbConfigurationDescriptor = NULL; 
    } 
 
    // 
    // Cleanup memory and exit. 
    // 
ConfigureDevice_Exit: 
 
    if(urb) { 
 
        ExFreePool(urb); 
    } 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ConfigureUsbDevice: Exit\n")); 
 
    return status; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SelectUsbInterfaces 
// 
//  This routine is called by ConfigureUsbDevice to read the USB  
//  select the interfaces that will be used to talk to the usb device. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
//      ConfigurationDescriptor - Address of the Configuration Descriptor 
//                                  selected. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
//      The OSR FX2 Learning Kit device running the OSR standard firmware only 
//      offers one USB Interface. 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SelectUsbInterfaces(PUSBFX2LK_EXT DevExt, 
                             PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) 
{ 
    LONG                        numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces; 
    LONG                        interfaceNumber = 0; 
    LONG                        interfaceindex = 0; 
    ULONG                       i; 
    PURB                        urb = NULL; 
    NTSTATUS                    status; 
    PUSB_INTERFACE_DESCRIPTOR   interfaceDescriptor = NULL; 
    PUSBD_INTERFACE_LIST_ENTRY  interfaceList = NULL;  
    PUSBD_INTERFACE_LIST_ENTRY  tmp = NULL; 
    PUSBD_INTERFACE_INFORMATION Interface = NULL; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SelectUsbInterfaces: Enter\n")); 
 
    // 
    //  Allocate memory for the devices supported interfaces. 
    // 
    interfaceList = (PUSBD_INTERFACE_LIST_ENTRY) ExAllocatePoolWithTag(NonPagedPool,  
                        sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1),'eliU'); 
 
    // 
    // Confirm memory was allocated. 
    // 
    if(!interfaceList) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("SelectUsbInterfaces: Failed to allocate mem for interfaceList\n")); 
        return STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    tmp = interfaceList; 
 
 
    // 
    // Parse the received USB interfaces selecting one that matches our input criteria. 
    // Fortunately, we are not fussy and will take any interface found, which for our  
    // device is the only one we return. 
    //  
    while(interfaceNumber < numberOfInterfaces) { 
 
        // 
        // A driver would call USBD_ParseConfigurationDescriptorEx in order 
        // to select a interface that meets the input criteria of driver. 
        // This would work well, if the a device had different interfaces.   
        // Unfortunately, our device only has one interface, so this will  
        // select it. 
        // 
        interfaceDescriptor = USBD_ParseConfigurationDescriptorEx( 
                                            ConfigurationDescriptor,  
                                            ConfigurationDescriptor, 
                                            interfaceindex, 
                                            0, -1, -1, -1); 
 
        if(interfaceDescriptor) { 
 
            // 
            // An interface met our criteria, save the information 
            // in our interface list. 
            // 
            interfaceList->InterfaceDescriptor = interfaceDescriptor; 
            interfaceList->Interface = NULL; 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("--------- Interface %d\n",interfaceNumber)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbLength = %d\n",interfaceList->InterfaceDescriptor->bLength)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbDescriptorType = %d\n",interfaceList->InterfaceDescriptor->bDescriptorType)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceNumber = %d\n",interfaceList->InterfaceDescriptor->bInterfaceNumber)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbAlternateSetting = %d\n",interfaceList->InterfaceDescriptor->bAlternateSetting)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbNumEndpoints = %d\n",interfaceList->InterfaceDescriptor->bNumEndpoints)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceClass = %d\n",interfaceList->InterfaceDescriptor->bInterfaceClass)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceSubClass = %d\n",interfaceList->InterfaceDescriptor->bInterfaceSubClass)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceProtocol = %d\n",interfaceList->InterfaceDescriptor->bInterfaceProtocol)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tiInterface = %d\n\n",interfaceList->InterfaceDescriptor->iInterface)); 
            interfaceList++; 
            interfaceNumber++; 
 
        } 
 
        interfaceindex++; 
    } 
 
    // 
    // Format a URB that will be used to select the input configuration 
    // that will be used to interface to the device. 
    // 
    interfaceList->InterfaceDescriptor = NULL; 
    interfaceList->Interface = NULL; 
 
    urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp); 
 
    // 
    // Make sure that a URB was allocated. 
    // 
    if(urb) { 
 
        // 
        // Set our pipe information into the interface pipes list. 
        // This tells our device our we will use the pipe. 
        // 
        Interface = &urb->UrbSelectConfiguration.Interface; 
 
        for(i=0; iNumberOfPipes; i++) { 
 
            // 
            // Set the transfer size and any pipe flags we use 
            // USBD sets the rest of the Interface struct members 
            // 
 
            Interface->Pipes[i].MaximumTransferSize =  
                                USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; 
        } 
 
        // 
        // Submit the urb to the device. 
        // 
        status = SubmitUrb(DevExt, urb); 
 
        if(NT_SUCCESS(status)) { 
 
            // 
            // save a copy of interface information in the device extension. 
            // 
            DevExt->UsbInterface = (PUSBD_INTERFACE_INFORMATION) ExAllocatePoolWithTag(NonPagedPool, 
                                                                        Interface->Length,'eliU'); 
 
            if(DevExt->UsbInterface) { 
                 
                RtlCopyMemory(DevExt->UsbInterface, 
                              Interface, 
                              Interface->Length); 
            } else { 
 
                status = STATUS_INSUFFICIENT_RESOURCES; 
                OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("SelectUsbInterfaces: memory alloc for UsbInterface failed\n")); 
                goto SelectUsbInterfacesExit; 
            } 
 
            // 
            // Dump the interface to the debugger 
            // 
 
            Interface = &urb->UrbSelectConfiguration.Interface; 
 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("---------\n")); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("NumberOfPipes 0x%x\n",  
                                 Interface->NumberOfPipes)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Length 0x%x\n",  
                                 Interface->Length)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Alt Setting 0x%x\n",  
                                 Interface->AlternateSetting)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Interface Number 0x%x\n",  
                                 Interface->InterfaceNumber)); 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Class, subclass, protocol 0x%x 0x%x 0x%x\n", 
                                 Interface->Class, 
                                 Interface->SubClass, 
                                 Interface->Protocol)); 
 
            // 
            // Initialize the PipeContext 
            // Dump the pipe info 
            // 
            if(Interface->NumberOfPipes) { 
                DevExt->PipeContext = (PUSBFX2LK_PIPE_CONTEXT) ExAllocatePoolWithTag(NonPagedPool, 
                                                Interface->NumberOfPipes * 
                                                sizeof(USBFX2LK_PIPE_CONTEXT),'xtcP'); 
 
                if(DevExt->PipeContext) { 
                 
                    for(i=0; iNumberOfPipes; i++) { 
 
                        RtlCopyMemory(&DevExt->PipeContext[i].PipeInformation, 
                                      &Interface->Pipes[i],sizeof(USBD_PIPE_INFORMATION)); 
 
                        // 
                        // Setup our convenience pointer 
                        // 
                        if (Interface->Pipes[i].PipeType == UsbdPipeTypeBulk) { 
 
                            if (USBD_PIPE_DIRECTION_IN(&Interface->Pipes[i])) { 
 
                                // 
                                // This is the bulk IN pipe. Make sure we only 
                                //  have one 
                                // 
                                ASSERT(DevExt->BulkInPipe == NULL); 
 
                                DevExt->BulkInPipe = &DevExt->PipeContext[i]; 
 
                            } else { 
 
                                // 
                                // This is the bulk OUT pipe. Make sure we only 
                                //  have one 
                                // 
                                ASSERT(DevExt->BulkOutPipe == NULL); 
 
                                DevExt->BulkOutPipe = &DevExt->PipeContext[i]; 
 
                            } 
 
                        } else { 
 
                            // 
                            // Our device has two bulk pipes and one iso pipe, 
                            //  we shouldn't get any other pipe besides iso here 
                            //  
                            ASSERT(Interface->Pipes[i].PipeType == UsbdPipeTypeInterrupt); 
 
                            // 
                            // And we only have one 
                            // 
                            ASSERT(DevExt->InterruptPipe == NULL); 
 
                            DevExt->InterruptPipe = &DevExt->PipeContext[i]; 
 
                        } 
 
                    } 
 
                    DevExt->NumberOfPipes = Interface->NumberOfPipes; 
 
                } else { 
                     
                    status = STATUS_INSUFFICIENT_RESOURCES; 
                    OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                        ("SelectUsbInterfaces: memory alloc for UsbInterface failed\n")); 
                    goto SelectUsbInterfacesExit; 
                } 
            } 
 
            for(i=0; iNumberOfPipes; i++) { 
 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("---------\n")); 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("PipeType 0x%x\n",  
                                     Interface->Pipes[i].PipeType)); 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("EndpointAddress 0x%x\n",  
                                     Interface->Pipes[i].EndpointAddress)); 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("MaxPacketSize 0x%x\n",  
                                    Interface->Pipes[i].MaximumPacketSize)); 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Interval 0x%x\n",  
                                     Interface->Pipes[i].Interval)); 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Handle %p\n",  
                                     Interface->Pipes[i].PipeHandle)); 
                OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("MaximumTransferSize 0x%x\n",  
                                    Interface->Pipes[i].MaximumTransferSize)); 
            } 
 
            OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("---------\n")); 
        } else { 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("Failed to select an interface\n")); 
        } 
    } else { 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("SelectUsbInterfaces: USBD_CreateConfigurationRequestEx failed\n")); 
        status = STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    // 
    // Clean up after ourselves and exit. 
    // 
SelectUsbInterfacesExit: 
 
    if(tmp) { 
        ExFreePool(tmp); 
    } 
 
    if(urb) { 
        ExFreePool(urb); 
    } 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SelectUsbInterfaces: Exit\n")); 
 
    return status; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// DeconfigureUsbDevice 
// 
//  This routine is called to release the Usb Device and deconfigure the 
//  descriptors. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS DeconfigureUsbDevice(PUSBFX2LK_EXT DevExt) 
{ 
    PURB     urb; 
    ULONG    size = sizeof(struct _URB_SELECT_CONFIGURATION);; 
    NTSTATUS status; 
     
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DeconfigureUsbDevice: Enter\n")); 
 
    urb = (PURB) ExAllocatePoolWithTag(NonPagedPool, size,'csuO'); 
 
    if(urb) { 
 
        UsbBuildSelectConfigurationRequest(urb, (USHORT)size, NULL); 
 
        status = SubmitUrb(DevExt,urb); 
 
        if(!NT_SUCCESS(status)) { 
 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("DeconfigureUsbDevice: Failed to deconfigure device %08.8x %s\n", 
                status,OsrNtStatusToString(status))); 
        } 
 
        ExFreePool(urb); 
 
    } else { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("DeconfigureUsbDevice: Failed to allocate urb\n")); 
        status = STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DeconfigureUsbDevice: Exit\n")); 
 
    return status; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// DetermineDeviceSpeed 
// 
//  This routine is called by ConfigureUsbDevice to determine if the device 
//  is running at low or high speed. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
// 
//  OUTPUTS: 
// 
//      When finished, the RunningAtHighSpeed member of the  
//       device extension is set to either TRUE or FALSE 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
//   We need to determine if the device is running at high speed by querying  
//    for the USB_BUS_INTERFACE_USBDI_V1 interface.  One slight problem here,  
//    USB 2.0 support wasn't added to Windows 2000 until SP4 and so the latest  
//    DDK is a bit behind. If you were to believe the DDK documentation and  
//    headers, you would think that this interface is not supported at ALL in  
//    Windows 2000.  However, this exchange in  
//    microsoft.public.development.device.drivers in July 2004 says otherwise: 
//   
//////////////////////////////////////////////////////////////////////////// 
//   
//    Subject: Availability of USB_BUS_INTERFACE_USBDI_V1 in Windows 2000 Sp4 ? 
//     
//    Hello, 
//     
//    Since Windows 2000 Service PAck4 has support for USB 2.0 Enhanced USB 
//    Host Controller , I was wondering if it has support for 
//    USB_BUS_INTERFACE_USBDI_V1 structure , since i want to use its member 
//    ( PUSB_BUSIFFN_IS_DEVICE_HIGH_SPEED IsDeviceHighSpeed ) . 
//    MSDN says that this is supported only on WinXP onwards but i am 
//    thinking why should this not be available when Enhanced USB Host 
//    Controller driver is available on W2k sp4 
//     
//    could anybody please clarify this? 
//     
//    thanks in advance 
//    Taha 
//     
//////////////////////////////////////////////////////////////////////////// 
//    	 
//    Eliyas Yakub [MSFT] 	  Jul 12, 10:41 am     show options 
//    From: "Eliyas Yakub [MSFT]"  
//    Date: Mon, 12 Jul 2004 10:41:52 -0700 
//     
//    Looking at the code USBPORT code, I can definitely say it's available. I 
//    will bring this to our doc team's attention. Thanks. 
//     
//    -Eliyas 
//   
//////////////////////////////////////////////////////////////////////////// 
//   
//   Since the support in the DDK isn't there, we simply 
//    added our own vendor specific command to determine if 
//    we're running at full or high speed. If you don't have 
//    this amount of flexibility with your device, you would  
//    need to cut and paste the appropriate definitions out  
//    of USBBUSIF.H in the Windows XP or Server 2003 build environment 
//    with the caveat of it not being officially documented or  
//    supported 
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID DetermineDeviceSpeed(PUSBFX2LK_EXT DevExt)  
{ 
 
    DevExt->RunningAtHighSpeed = FALSE; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeed: Enter\n")); 
 
#ifdef W2K 
 
    NTSTATUS status; 
    URB urb; 
    ULONG transferFlags; 
 
    // 
    // See the Notes section above, we've created 
    //  a custom command to determine this while 
    //  running on Win2K 
    // 
    RtlZeroMemory(&urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 
 
    // 
    // Build the vendor request with the appropriate  
    //  flags and command 
    // 
    UsbBuildVendorRequest(&urb, 
                          URB_FUNCTION_VENDOR_DEVICE, 
                          sizeof(struct  _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                          (USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN), 
                          0, 
                          USBFX2LK_IS_HIGH_SPEED, 
                          0, 
                          0, 
                          &DevExt->RunningAtHighSpeed, 
                          NULL, 
                          sizeof(BOOLEAN), 
                          NULL); 
 
    // 
    // Make the request active on the device 
    // 
    status = SubmitUrb(DevExt, &urb); 
 
    if(!NT_SUCCESS(status)) { 
         
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("DetermineDeviceSpeed: Failed to query speed - 0x%x (%s)\n", 
                status,OsrNtStatusToString(status))); 
 
    } else { 
 
        OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO, 
            ("DetermineDeviceSpeed: Device is running at %s speed.\n", 
            DevExt->RunningAtHighSpeed ? "HIGH" : "FULL")); 
    } 
 
#else 
 
    NTSTATUS status; 
    PIRP irp; 
    KEVENT event; 
    PIO_STACK_LOCATION ioNextStack; 
    USB_BUS_INTERFACE_USBDI_V1 usbInterface; 
 
    // 
    // The way we determine our device speed on 
    //  XP and later is by sending an IRP_MJ_PNP/ 
    //  IRP_MN_QUERY_INTERFACE IRP for the  
    //  USB_BUS_INTERFACE_USBDI_GUID interface. 
    // 
 
    // 
    // Allocate an IRP with an appropriate number 
    //  of stack locations for this request 
    // 
    irp = IoAllocateIrp(DevExt->DeviceToSendIrpsTo->StackSize, 
                        FALSE); 
 
    if(!irp) { 
 
        // 
        // Can't allocate an IRP so we can't determine if 
        //  we're at high speed. 
        // 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("DetermineDeviceSpeed: Failed to allocate an IRP. Defaulting to full speed\n")); 
        return; 
    } 
 
    // 
    // Assume failure. 
    // 
    irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 
 
    // 
    // Initialize the IRP that we will be waiting on for the  
    //  IRP to complete 
    // 
    KeInitializeEvent(&event, NotificationEvent, FALSE); 
 
    // 
    // Get a pointer to the NEXT irp stack location.  
    //  Because we are the ones who allocated the IRP, 
    //  we do not have a current IRP stack location.  
    //  Also, since we are passing the IRP down to the  
    //  next lower driver, we want to modify the next  
    //  stack location 
    // 
    ioNextStack = IoGetNextIrpStackLocation(irp); 
 
    // 
    // This is a PNP/QUERY_INTERFACE request 
    // 
    ioNextStack->MajorFunction = IRP_MJ_PNP; 
    ioNextStack->MinorFunction = IRP_MN_QUERY_INTERFACE; 
 
    // 
    // Setup the QUERY_INTERFACE stack location parameters 
    // 
 
    // 
    // Indicate which interface we're querying for 
    // 
    ioNextStack->Parameters.QueryInterface.InterfaceType =  
                                        &USB_BUS_INTERFACE_USBDI_GUID; 
 
    // 
    // Indicate which version of the interface we are querying 
    // 
    ioNextStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_1; 
 
    // 
    // Setup the buffer for the returned interface 
    // 
    ioNextStack->Parameters.QueryInterface.Interface = (PINTERFACE)&usbInterface; 
 
 
    // 
    // Set up the size of the buffer 
    // 
    ioNextStack->Parameters.QueryInterface.Size =  
                                    sizeof(USB_BUS_INTERFACE_USBDI_V1); 
 
 
#ifdef IoForwardIrpSynchronously 
    // 
    // Pass the IRP down to the lower driver 
    // 
    if(IoForwardIrpSynchronously(DevExt->DeviceToSendIrpsTo,irp)) { 
        status = Irp->IoStatus.Status; 
    } else { 
        status = STATUS_UNSUCCESSFUL; 
    } 
 
#else //IoForwardIrpSynchronously 
 
    // 
    // Setup a completion routine, passing the event as the  
    //  context parameter. When the completion routine runs, it 
    //  will set the event and stop completion processing by  
    //  returning STATUS_MORE_PROCESSING_REQUIRED. 
    // 
    IoSetCompletionRoutine(irp, 
                           DetermineDeviceSpeedCompletionRoutine, 
                           &event, 
                           TRUE, 
                           TRUE, 
                           TRUE); 
 
    // 
    // Pass the IRP down to the lower driver 
    // 
    status = IoCallDriver(DevExt->DeviceToSendIrpsTo, irp); 
 
    if(status == STATUS_PENDING) { 
 
        // 
        // If the IRP was pended, then we must wait for the  
        //  event to be signalled by our completion routine 
        // 
        (VOID)OsrWaitForSingleObject(&event); 
 
        // 
        // Retrieve the real completion status from the 
        //  IRP 
        // 
        status = irp->IoStatus.Status; 
    } 
#endif //IoForwardIrpSynchronously 
    // 
    // DId the call succeed? 
    // 
    if(NT_SUCCESS(status)) { 
 
        // 
        // We should have a valid IsDeviceHighSpeed routine to 
        //  call through the interface 
        // 
        ASSERT(usbInterface.IsDeviceHighSpeed); 
 
        // 
        // Call the routine and see what we are running at 
        // 
        DevExt->RunningAtHighSpeed = usbInterface.IsDeviceHighSpeed(usbInterface.BusContext); 
 
 
        OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO, 
            ("DetermineDeviceSpeed: Device is running at %s speed.\n", 
            DevExt->RunningAtHighSpeed ? "HIGH" : "FULL")); 
 
    } else { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("DetermineDeviceSpeed: Failed to query interface - 0x%x (%s)\n", 
            status,OsrNtStatusToString(status))); 
 
    } 
 
    // 
    // Delete the Irp that we allocated. 
    // 
    IoFreeIrp(irp); 
 
#endif 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeed: Exit\n")); 
 
    return; 
} 
 
#ifndef IoForwardIrpSynchronously 
/////////////////////////////////////////////////////////////////////////////// 
// 
// DetermineDeviceSpeedCompletionRoutine 
// 
//  This routine is a completion routine used to signal the completion 
//  of the IRP sent down by DetermineDeviceSpeed. It's only job is to  
//  set the event passed in as the context parameter and stop the processing 
//  of the IRP. 
// 
// 
//  INPUTS: 
// 
//      DeviceObject  -  Address of the Devices Device Extension. 
//      Irp           -  Address of the QUERY_INTERFACE IRP sent down by  
//                       DetermineDeviceSpeed 
//      Context       -  A pointer to a KEVENT 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      STATUS_MORE_PROCESSING_REQUIRED to stop completion processing of the IRP 
// 
//  IRQL: 
// 
//      IRQL <= DISPATCH_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS DetermineDeviceSpeedCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) 
{     
     
    PKEVENT event = (PKEVENT)Context; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeedCompletionRoutine: Enter\n")); 
 
    UNREFERENCED_PARAMETER(DeviceObject); 
    UNREFERENCED_PARAMETER(Irp); 
 
    // 
    // Set the event 
    // 
    KeSetEvent(event, EVENT_INCREMENT, FALSE); 
 
    // 
    // And stop completion processing of the IRP 
    //  
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeedCompletionRoutine: Exit\n")); 
 
    return STATUS_MORE_PROCESSING_REQUIRED; 
 
} 
#endif //IoForwardIrpSynchronously 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitUrb 
// 
//  This routine is called to synchronously submit the Input Urb to the USB 
//  device. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
//      Urb      -  Address of the USB to be delivered. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitUrb(PUSBFX2LK_EXT DevExt,PURB Urb) 
{ 
    PIRP               irp = NULL; 
    KEVENT             event; 
    NTSTATUS           status; 
    IO_STATUS_BLOCK    ioStatus; 
    PIO_STACK_LOCATION nextStack; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitUrb: Enter\n")); 
 
    // 
    // Initialize the Event that will be waited on if the underlying 
    // driver returns STATUS_PENDING 
    // 
    KeInitializeEvent(&event, NotificationEvent, FALSE); 
 
    // 
    // Build the Irp to be used to submit the URB. 
    // 
    irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,  
                                        DevExt->DeviceToSendIrpsTo, 
                                        NULL,  
                                        0,  
                                        NULL,  
                                        0,  
                                        TRUE,  
                                        &event,  
                                        &ioStatus); 
 
    if(!irp) { 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
            ("SubmitUrb: IoBuildDeviceIoControlRequest failed\n")); 
        return STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
 
    // 
    // Put the URB to be submitted into the Others part of the next stack location. 
    // This urb will be passed to the USB Bus Driver for submission to our USB 
    // device. 
    // 
    nextStack = IoGetNextIrpStackLocation(irp); 
    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 
    nextStack->Parameters.Others.Argument1 = Urb; 
 
    // 
    // Increment the number of outstanding requests. 
    // 
    OsrIncrementOutstandingIoCount(DevExt,__FILE__,__LINE__); 
 
    // 
    // Submit the Irp to the driver. 
    // 
    status = IoCallDriver(DevExt->DeviceToSendIrpsTo,irp); 
 
    // 
    // Wait for a response if not already completed. 
    // 
    if(status == STATUS_PENDING) { 
         
        (VOID)OsrWaitForSingleObject(&event); 
 
        // 
        //  Get the completion status 
        // 
        status = ioStatus.Status; 
    } 
 
    // 
    // Decrement the number of outstanding requests. 
    // 
    OsrDecrementOutstandingIoCount(DevExt,__FILE__,__LINE__); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitUrb: Exit\n")); 
 
    return status; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitIrpAndUrbAsync 
// 
//  This routine is called to asynchronously submit the Input IRP and Urb to  
//  the USB device. 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  Address of the Devices Device Extension. 
//      IRP     -  Address of the IRP to setup for the URB transfer 
//                 and submit to the device 
//      Urb     -  Address of the USB to be delivered. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      Arbitrary Context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitIrpAndUrbAsync(PUSBFX2LK_EXT DevExt, PIRP Irp, PURB Urb) 
{ 
    PIO_STACK_LOCATION nextStack; 
    NTSTATUS status; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB, 
                            ("SubmitIrpAndUrbAsync: Enter\n")); 
 
    // 
    // We need to submit this request as a USB request,  
    //  so we'll get the next IRP stack location and set 
    //  it up as a USB interrupt transfer. 
    // 
    nextStack = IoGetNextIrpStackLocation(Irp); 
 
    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 
    nextStack->Parameters.DeviceIoControl.IoControlCode =  
                                               IOCTL_INTERNAL_USB_SUBMIT_URB; 
 
    nextStack->Parameters.Others.Argument1 = Urb; 
 
    // 
    // Setup our completion routine that will free the URB 
    // 
    IoSetCompletionRoutine(Irp, AsynchronousUrbRequestCompletion, 
                           Urb, TRUE, TRUE, TRUE); 
 
 
    // 
    // We're submitting this URB to the device and it may  
    //  complete at an arbitrary point in the future, so  
    //  we need to mark it pending 
    // 
    IoMarkIrpPending(Irp); 
 
    // 
    // While we have the Irp in our queue, store the address of the URB 
    // in the DriverContext[1] field of the Irp.   We do this so that  
    // if the Irp is canceled while in our queue, we have enough information  
    // to do the correct cleanup. 
    // 
    Irp->Tail.Overlay.DriverContext[1] = Urb; 
 
    // 
    // Queue the using the appropriate cancel safe queue routin 
    // 
#ifdef W2K3 
     
    // 
    // IoCsqInsertIrpEx returns whatever we return from OsrCsqInsertIoIrpEx,  
    //  which for us is STATUS_SUCCESS. 
    // 
    status = IoCsqInsertIrpEx(&DevExt->CancelSafeIoQueue,Irp,NULL,DevExt); 
    ASSERT(status == STATUS_SUCCESS); 
 
#else // W2K3 
    IoCsqInsertIrp(&DevExt->CancelSafeIoQueue,Irp,NULL); 
#endif // W2K3 
 
 
    // 
    // We have queued this IRP onto our internal queue.  
    //  Now call our helper routine ProcessNextIrpInQueue 
    //  to pass this request (or possibly another request 
    //  that was running parallel and beat us to the queue) 
    //  to the host controller.  
    // 
    // ProcessNextIrpInQueue will pass the request on to the 
    //  host if we are in an applicable PnP state otherwise the 
    //  request will just stay in the queue. 
    // 
    ProcessNextIrpInQueue(DevExt);     
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB, 
            ("SubmitIrpAndUrbAsync: Exit\n")); 
 
    return STATUS_PENDING; 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitResetPipe 
// 
//      Resets the passed in pipe 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_RESET_PIPE 
//                  IRP. 
// 
//      Pipe    -  The USBFX2_PIPE_ENUM for the pipe to reset 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitResetPipe(PUSBFX2LK_EXT DevExt, PIRP Irp, USBFX2_PIPE_ENUM Pipe) 
{ 
    NTSTATUS status; 
    PURB resetUrb; 
    PUSBFX2LK_PIPE_CONTEXT pipeContext = NULL; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ResetPipe: Enter\n")); 
 
    // 
    // Find the pipe context for the pipe that we're resetting 
    // 
    switch(Pipe) { 
 
        case USBFx2BulkInPipe: 
            pipeContext = DevExt->BulkInPipe; 
            break; 
 
        case USBFx2BulkOutPipe: 
            pipeContext = DevExt->BulkOutPipe; 
            break; 
         
        case USBFx2InterruptPipe: 
            pipeContext = DevExt->InterruptPipe; 
            break; 
 
        default: 
            // 
            // Bogus pipe 
            // 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("ResetPipe: Exit Invalid Pipe\n")); 
            Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
            Irp->IoStatus.Information = 0; 
            IoCompleteRequest(Irp, IO_NO_INCREMENT); 
            return STATUS_INVALID_PARAMETER; 
    } 
 
    // 
    // We'd better have a pipe at this point,  
    //  otherwise our device configuration failed 
    // 
    ASSERT(pipeContext); 
 
    // 
    // Allocate our reset URB 
    // 
    resetUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_PIPE_REQUEST), 
                                    'PRxF'); 
 
    if (!resetUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("ResetPipe: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
 
    // 
    // Setup the URB_FUNCTION_RESET_PIPE URB appropriately 
    // 
    resetUrb->UrbHeader.Length          = sizeof(struct _URB_PIPE_REQUEST); 
    resetUrb->UrbHeader.Function        = URB_FUNCTION_RESET_PIPE; 
    resetUrb->UrbPipeRequest.PipeHandle = pipeContext->PipeInformation.PipeHandle; 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, resetUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ResetPipe: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitGetBarGraphState 
// 
//  This routine gets the state of the bar graph on the board 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY 
//                  IRP. User's buffer has already been validated 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitGetBarGraphState(PUSBFX2LK_EXT DevExt, PIRP Irp) 
{ 
    NTSTATUS status; 
    PURB getBarGraphUrb; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetBarGraphState: Enter\n")); 
 
    // 
    // Allocate our get bar graph URB 
    // 
    getBarGraphUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                                    'BGxF'); 
 
    if (!getBarGraphUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("GetBarGraphState: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
    RtlZeroMemory(getBarGraphUrb, 
                  sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 
 
 
    // 
    // Build the vendor request with the appropriate  
    //  flags and command 
    // 
    //  We're getting data from the device, 
    //  to we need to set the USBD_TRANSFER_DIRECTION_IN flag 
    //  
    UsbBuildVendorRequest(getBarGraphUrb, 
                          URB_FUNCTION_VENDOR_DEVICE, 
                          sizeof(struct  _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                          USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN, 
                          0, 
                          USBFX2LK_READ_BARGRAPH_DISPLAY, 
                          0, 
                          0, 
                          Irp->AssociatedIrp.SystemBuffer, 
                          NULL, 
                          sizeof(BAR_GRAPH_STATE), 
                          NULL); 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, getBarGraphUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetBarGraphState: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
     
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitSetBarGraphState 
// 
//  This routine sets the state of the bar graph on the board 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY 
//                  IRP. User's buffer has already been validated 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitSetBarGraphState(PUSBFX2LK_EXT DevExt, PIRP Irp) 
{ 
 
    NTSTATUS status; 
    PURB setBarGraphUrb; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetBarGraphState: Enter\n")); 
 
    // 
    // Allocate our set bar graph URB 
    // 
    setBarGraphUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                                    'BSxF'); 
 
    if (!setBarGraphUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("SetBarGraphState: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
    RtlZeroMemory(setBarGraphUrb, 
                  sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 
 
 
    // 
    // Build the vendor request with the appropriate  
    //  flags and command 
    // 
    //  We're getting data from the device, 
    //  to we need to set the USBD_TRANSFER_DIRECTION_IN flag 
    //  
    UsbBuildVendorRequest(setBarGraphUrb, 
                          URB_FUNCTION_VENDOR_DEVICE, 
                          sizeof(struct  _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                          USBD_SHORT_TRANSFER_OK, 
                          0, 
                          USBFX2LK_SET_BARGRAPH_DISPLAY, 
                          0, 
                          0, 
                          Irp->AssociatedIrp.SystemBuffer, 
                          NULL, 
                          sizeof(BAR_GRAPH_STATE), 
                          NULL); 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, setBarGraphUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetBarGraphState: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitGetSevenSegmentState 
// 
//  This routine gets or sets the state of the 7 segment display  on the board 
// 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY 
//                  IRP. User's buffer has already been validated 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
///////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitGetSevenSegmentState(PUSBFX2LK_EXT DevExt, PIRP Irp) 
{ 
    NTSTATUS status; 
    PURB getSevenSegmentUrb; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSevenSegmentState: Enter\n")); 
 
    // 
    // Allocate our get seven segment URB 
    // 
    getSevenSegmentUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                                    'SGxF'); 
 
    if (!getSevenSegmentUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("GetSevenSegmentState: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
    RtlZeroMemory(getSevenSegmentUrb, 
                  sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 
 
 
    // 
    // Build the vendor request with the appropriate  
    //  flags and command 
    // 
    //  We're getting data from the device, 
    //  to we need to set the USBD_TRANSFER_DIRECTION_IN flag 
    //  
    UsbBuildVendorRequest(getSevenSegmentUrb, 
                          URB_FUNCTION_VENDOR_DEVICE, 
                          sizeof(struct  _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                          USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN, 
                          0, 
                          USBFX2LK_READ_7SEGMENT_DISPLAY, 
                          0, 
                          0, 
                          Irp->AssociatedIrp.SystemBuffer, 
                          NULL, 
                          sizeof(UCHAR), 
                          NULL); 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, getSevenSegmentUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSevenSegmentState: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitSetSevenSegmentState 
// 
//  This routine sets the state of the 7 segment display  on the board 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY 
//                  IRP. User's buffer has already been validated 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitSetSevenSegmentState(PUSBFX2LK_EXT DevExt, PIRP Irp) 
{ 
    NTSTATUS status; 
    PURB setSevenSegmentUrb; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetSevenSegmentState: Enter\n")); 
 
    // 
    // Allocate our set seven segment URB 
    // 
    setSevenSegmentUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                                    'SSxF'); 
 
    if (!setSevenSegmentUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("SetSevenSegmentState: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
    RtlZeroMemory(setSevenSegmentUrb, 
                  sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 
 
 
    // 
    // Build the vendor request with the appropriate  
    //  flags and command 
    // 
    //  We're getting data from the device, 
    //  to we need to set the USBD_TRANSFER_DIRECTION_IN flag 
    //  
    UsbBuildVendorRequest(setSevenSegmentUrb, 
                          URB_FUNCTION_VENDOR_DEVICE, 
                          sizeof(struct  _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                          USBD_SHORT_TRANSFER_OK, 
                          0, 
                          USBFX2LK_SET_7SEGMENT_DISPLAY, 
                          0, 
                          0, 
                          Irp->AssociatedIrp.SystemBuffer, 
                          NULL, 
                          sizeof(UCHAR), 
                          NULL); 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, setSevenSegmentUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetSevenSegmentState: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// SubmitGetSwitchState 
// 
//  This routine gets the state of the switches on the board 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_READ_SWITCHES 
//                  IRP. User's buffer has already been validated 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitGetSwitchState(PUSBFX2LK_EXT DevExt, PIRP Irp) 
{ 
 
    NTSTATUS status; 
    PURB getSwitchUrb; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSwitchState: Enter\n")); 
 
    // 
    // Allocate our get seven segment URB 
    // 
    getSwitchUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                                    'WGxF'); 
 
    if (!getSwitchUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("GetSwitchState: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
    RtlZeroMemory(getSwitchUrb, 
                  sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 
 
 
    // 
    // Build the vendor request with the appropriate  
    //  flags and command 
    // 
    //  We're getting data from the device, 
    //  to we need to set the USBD_TRANSFER_DIRECTION_IN flag 
    //  
    UsbBuildVendorRequest(getSwitchUrb, 
                          URB_FUNCTION_VENDOR_DEVICE, 
                          sizeof(struct  _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 
                          USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN, 
                          0, 
                          USBFX2LK_READ_SWITCHES, 
                          0, 
                          0, 
                          Irp->AssociatedIrp.SystemBuffer, 
                          NULL, 
                          sizeof(SWITCH_STATE), 
                          NULL); 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, getSwitchUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSwitchState: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// GetDeviceDescriptor 
// 
//      Returns the USB device descriptor for the device 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//  OUTPUTS: 
// 
//      DeviceDescriptor - If successful, contains the USB device descriptor 
//                         for the device 
// 
//      BytesTransferred - The actual amount of data transferred by this  
//                         operation 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS GetDeviceDescriptor(PUSBFX2LK_EXT DevExt, PUSB_DEVICE_DESCRIPTOR DeviceDescriptor, 
                             PULONG BytesTransferred) 
{ 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetDeviceDescriptor: Enter\n")); 
 
    // 
    // We've already saved the device descriptor away  
    //  so we just need to copy it out of the device  
    //  extension 
    // 
    RtlCopyMemory(DeviceDescriptor, DevExt->UsbDeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); 
 
    // 
    // Indicate the amount of data that was actually  
    //  transferred 
    // 
    *BytesTransferred = sizeof(USB_DEVICE_DESCRIPTOR); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetDeviceDescriptor: Exit\n")); 
 
    return STATUS_SUCCESS; 
 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// GetConfigurationDescriptor 
// 
//      Returns the USB configuration descriptor for the device 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//  OUTPUTS: 
// 
//      ConfigDescriptor - If successful, contains the USB configuration descriptor 
//                         for the device 
// 
//      BytesTransferred - The actual amount of data transferred by this  
//                         operation 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS GetConfigurationDescriptor(PUSBFX2LK_EXT DevExt, 
                                    PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, 
                                    PULONG BytesTransferred) 
{ 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetConfigurationDescriptor: Enter\n")); 
 
    // 
    // We've already saved the config descriptor away  
    //  so we just need to copy it out of the device  
    //  extension 
    // 
    RtlCopyMemory(ConfigDescriptor, DevExt->UsbConfigurationDescriptor, 
                                    sizeof(USB_CONFIGURATION_DESCRIPTOR)); 
 
    // 
    // Indicate the amount of data that was actually  
    //  transferred 
    // 
    *BytesTransferred = sizeof(USB_CONFIGURATION_DESCRIPTOR); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetConfigurationDescriptor: Exit\n")); 
 
    return STATUS_SUCCESS; 
 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// GetInterfaceInformation 
// 
//      Returns the USB interface information for the device 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//  OUTPUTS: 
// 
//      InterfaceDescriptor - If successful, contains the USB Interface Information 
//                         for the device 
// 
//      BytesTransferred - The actual amount of data transferred by this  
//                         operation 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS GetInterfaceInformation(PUSBFX2LK_EXT DevExt, 
                                 PUSBD_INTERFACE_INFORMATION InterfaceDescriptor, 
                                 PULONG BytesTransferred) 
{ 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetInterfaceInformation: Enter\n")); 
 
    // 
    // We've already saved the interface information away so we just need to copy  
    // it out of the device extension 
    // 
    RtlCopyMemory(InterfaceDescriptor, DevExt->UsbInterface, DevExt->UsbInterface->Length); 
 
    *BytesTransferred = DevExt->UsbInterface->Length; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetInterfaceInformation: Exit\n")); 
 
    return STATUS_SUCCESS; 
 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// GetPipeInformation 
// 
//      Returns information about the passed in Pipe 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Pipe    -  The USBFX2_PIPE_ENUM for the pipe to reset 
// 
//  OUTPUTS: 
// 
//      PipeInformation - If successful, contains information about the  
//                        passed in pipe 
// 
//      BytesTransferred - The actual amount of data transferred by this  
//                         operation 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS GetPipeInformation(PUSBFX2LK_EXT DevExt, USBFX2_PIPE_ENUM Pipe,  
                            PUSBD_PIPE_INFORMATION PipeInformation, 
                            PULONG BytesTransferred) 
{ 
    PUSBFX2LK_PIPE_CONTEXT pipeContext; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetPipeInformation: Enter\n")); 
 
    // 
    // Find the pipe context for the pipe that we're resetting 
    // 
    switch(Pipe) { 
 
        case USBFx2BulkInPipe: 
 
            pipeContext = DevExt->BulkInPipe; 
            break; 
 
        case USBFx2BulkOutPipe: 
 
            pipeContext = DevExt->BulkOutPipe; 
            break; 
         
        case USBFx2InterruptPipe: 
 
            pipeContext = DevExt->InterruptPipe; 
            break; 
 
        default: 
 
            // 
            // Bogus pipe 
            // 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("GetPipeInformation: Exit Invalid Pipe\n")); 
            // 
            // Failure case, indicate that no data was transferred.  
            // 
            *BytesTransferred = 0; 
            return STATUS_INVALID_PARAMETER; 
 
    } 
 
    // 
    // We'd better have a pipe at this point,  
    //  otherwise our device configuration failed 
    // 
    ASSERT(pipeContext); 
 
    // 
    // Just copy the pipe info out of the pipe context 
    // 
    RtlCopyMemory(PipeInformation, &pipeContext->PipeInformation, sizeof(USBD_PIPE_INFORMATION)); 
 
    // 
    // Indicate the amount of data that was actually  
    //  transferred 
    // 
    *BytesTransferred = sizeof(USBD_PIPE_INFORMATION); 
 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetPipeInformation: Exit\n")); 
 
    return STATUS_SUCCESS; 
 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// GetUserInterruptRequest 
// 
//      Queries the interrupt pipe on the USBFX2LK board 
// 
//  INPUTS: 
// 
//      DevExt  -  One of our device extensions 
// 
//      Irp     -  Pointer to an IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE 
//                  IRP. User's buffer has already been validated 
// 
//  OUTPUTS: 
// 
//      BytesReturned - Number of bytes actually transferred 
// 
//  RETURNS: 
// 
//      An appropriate NTSTATUS value 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User context 
// 
//  NOTES: 
//   
//      Routine assumes that the output data buffer in the IRP is 
//      valid for this request. Must be checked by caller. 
// 
//      Called relinquishes ownership of the IRP when calling this 
//      routine, IRP must NOT be touched by caller after this routine 
//      returns 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS SubmitInterruptDataRequest(PUSBFX2LK_EXT DevExt, PIRP Irp) 
{ 
    PUCHAR interruptData; 
    PURB interruptUrb; 
    NTSTATUS status; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitInterruptDataRequest: Enter\n")); 
 
    // 
    // This is a METHOD_BUFFERED request 
    // 
    interruptData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer; 
 
    // 
    // Initialize the data 
    // 
    *interruptData = 0; 
 
    // 
    // Allocate our interrupt URB 
    // 
    interruptUrb =  
        (PURB)ExAllocatePoolWithTag(NonPagedPool, 
                                    sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 
                                    'IGxF'); 
 
    if (!interruptUrb) { 
 
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB, 
                ("SubmitInterruptDataRequest: Failed to allocate memory, Exiting.\n")); 
 
        // 
        // We need to complete the IRP ourselves 
        // 
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 
        Irp->IoStatus.Information = 0; 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
        return STATUS_INSUFFICIENT_RESOURCES; 
 
    } 
 
    RtlZeroMemory(interruptUrb,  
                  sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER)); 
 
    // 
    // Build the interrupt buffer 
    // 
    UsbBuildInterruptOrBulkTransferRequest( 
                                    interruptUrb, 
                                    sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 
                                    DevExt->InterruptPipe->PipeInformation.PipeHandle, 
                                    interruptData, 
                                    NULL, 
                                    sizeof(UCHAR), 
                                    (USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN), 
                                    NULL); 
 
    status = SubmitIrpAndUrbAsync(DevExt, Irp, interruptUrb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitInterruptDataRequest: Exit\n")); 
 
    // 
    // Return whatever status SubmitIrpAndUrbAsync returned 
    // 
    return status; 
     
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// AsynchronousUrbRequestCompletion 
// 
//  Generic completion routine for USB requests.  
// 
// 
//  INPUTS: 
// 
//      DeviceObject  -  Our Device Object 
//      Irp           -  Address of completing Irp 
//      Context       -  A PURB 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      STATUS_SUCCESS 
// 
//  IRQL: 
// 
//      IRQL <= DISPATCH_LEVEL 
// 
//  CONTEXT: 
// 
//      Any 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS AsynchronousUrbRequestCompletion(IN PDEVICE_OBJECT DeviceObject, 
                                          IN PIRP Irp, IN PVOID Context) 
{ 
    PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension; 
    PURB urb = (PURB)Context; 
 
    UNREFERENCED_PARAMETER(DeviceObject); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB, 
                ("AsynchronousUrbRequestCompletion: Entered.\n")); 
 
    // 
    // If successful, indicate how much interrupt data was 
    //  transferred. We get this out of the interrupt URB 
    //  that was submitted to the device 
    // 
    if(NT_SUCCESS(Irp->IoStatus.Status)) { 
 
        // 
        // Determine where the bytes transferred field  
        //  for this URB is based on the function type. 
        // 
        switch (urb->UrbHeader.Function) { 
 
        case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: 
         
            Irp->IoStatus.Information  
                      = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; 
            break; 
 
        case URB_FUNCTION_CONTROL_TRANSFER: 
 
            Irp->IoStatus.Information  
                      = urb->UrbControlVendorClassRequest.TransferBufferLength; 
            break; 
 
        default: 
 
            // 
            // Uknown type, no data 
            // 
            Irp->IoStatus.Information = 0; 
            break; 
 
        } 
 
    } 
 
    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_USB, 
          ("AsynchronousUrbRequestCompletion: Completion status - 0x%x (%s). "\ 
                                                  "Bytes Transferred - 0x%p\n", 
               Irp->IoStatus.Status,OsrNtStatusToString(Irp->IoStatus.Status), 
               (PVOID)Irp->IoStatus.Information)); 
 
 
    // 
    // That's one less operation outstanding on the device 
    //  
    OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__); 
 
    // 
    // Free the URB  
    // 
    ExFreePool(urb); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB, 
                ("AsynchronousUrbRequestCompletion: Exited.\n")); 
 
    // 
    // Tell the I/O Mgr that he can continue Irp Completion 
    // 
    return STATUS_SUCCESS; 
}