/*++

Copyright (c) 1995  Microsoft Corporation

Module Name:

    busif.c

Abstract:

    Exports PnP services thru a bus interface, this eleminates
    any dependency of usbhub on usbd.sys with regard to the 'port'
    driver support.

    Old services have been renamed ServiceNameX and a dummy entrypoint
    added



Environment:

    kernel mode only

Notes:



Revision History:

    10-29-95 : created

--*/

#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"


//#include "usbdi.h"       //public data structures
#include "usbdi.h"
#include "hcdi.h"

#include "usb200.h"
#include "usbd.h"        //private data strutures
#include <initguid.h>
#include "hubbusif.h"    // hub service bus interface
#include "usbbusif.h"    // hub service bus interface


#ifdef USBD_DRIVER      // USBPORT supercedes most of USBD, so we will remove
                        // the obsolete code by compiling it only if
                        // USBD_DRIVER is set.


NTSTATUS
USBD_RestoreDeviceX(
    IN OUT PUSBD_DEVICE_DATA OldDeviceData,
    IN OUT PUSBD_DEVICE_DATA NewDeviceData,
    IN PDEVICE_OBJECT DeviceObject
    );

NTSTATUS
USBD_CreateDeviceX(
    IN OUT PUSBD_DEVICE_DATA *DeviceData,
    IN PDEVICE_OBJECT DeviceObject,
    IN BOOLEAN DeviceIsLowSpeed,
    IN ULONG MaxPacketSize_Endpoint0,
    IN OUT PULONG DeviceHackFlags
    );

NTSTATUS
USBD_RemoveDeviceX(
    IN PUSBD_DEVICE_DATA DeviceData,
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR Flags
    );

NTSTATUS
USBD_InitializeDeviceX(
    IN PUSBD_DEVICE_DATA DeviceData,
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
    IN ULONG DeviceDescriptorLength,
    IN OUT PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
    IN ULONG ConfigDescriptorLength
    );


NTSTATUS
USBD_BusCreateDevice(
    IN PVOID BusContext,
    IN OUT PUSB_DEVICE_HANDLE *DeviceHandle,
    IN PUSB_DEVICE_HANDLE HubDevicehandle,
    IN USHORT PortStatus,
    IN USHORT PortNumber
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/
{
    NTSTATUS ntStatus;
    BOOLEAN isLowSpeed;
    PDEVICE_OBJECT rootHubPdo;
    ULONG hackFlags;
    PUSBD_DEVICE_DATA deviceData;

    rootHubPdo = BusContext;

    isLowSpeed = (PortStatus & USB_PORT_STATUS_LOW_SPEED) ? TRUE : FALSE;
    
    ntStatus = USBD_CreateDeviceX(
            &deviceData,
            rootHubPdo,
            isLowSpeed,
            0,  // max packet size override, it turns out we 
                // never use this
            &hackFlags);

    *DeviceHandle = deviceData;

    return ntStatus;  
}


NTSTATUS
USBD_BusInitializeDevice(
    IN PVOID BusContext,
    IN OUT PUSB_DEVICE_HANDLE DeviceHandle
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/
{
    NTSTATUS ntStatus;
    PDEVICE_OBJECT rootHubPdo;

    rootHubPdo = BusContext;

    ntStatus = USBD_InitializeDeviceX(DeviceHandle,
                                      rootHubPdo,
                                      NULL,
                                      0,
                                      NULL,
                                      0);

    return ntStatus;                                      
}


NTSTATUS
USBD_BusRemoveDevice(
    IN PVOID BusContext,
    IN OUT PUSB_DEVICE_HANDLE DeviceHandle,
    IN ULONG Flags
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus;
    PDEVICE_OBJECT rootHubPdo;

    rootHubPdo = BusContext;

    // note old remove device only supports 8 flags
    
    ntStatus = USBD_RemoveDeviceX(
            DeviceHandle,
            rootHubPdo,
            (UCHAR) Flags);

    return ntStatus;                
}    


NTSTATUS
USBD_BusGetUsbDescriptors(
    IN PVOID BusContext,
    IN OUT PUSB_DEVICE_HANDLE DeviceHandle,
    IN OUT PUCHAR DeviceDescriptorBuffer,
    IN OUT PULONG DeviceDescriptorBufferLength,
    IN OUT PUCHAR ConfigDescriptorBuffer,
    IN OUT PULONG ConfigDescriptorBufferLength
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_OBJECT rootHubPdo;
    PUSBD_DEVICE_DATA deviceData = DeviceHandle;

    rootHubPdo = BusContext;

    // use the cached device descriptor
    if (DeviceDescriptorBuffer && *DeviceDescriptorBufferLength) {
        RtlCopyMemory(DeviceDescriptorBuffer,
                      &deviceData->DeviceDescriptor,
                      *DeviceDescriptorBufferLength);
        *DeviceDescriptorBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);                    
    }

    // Fetch the config descriptor.  If all that is desired is the 9 byte
    // config descriptor header, just return the cached config descriptor
    // header so that we don't send back to back requests for just the 9 byte
    // header to the device.  That seems to confuse some devices, some usb
    // audio devices in particular when enumerating on OHCI host controllers.
    //
    if (ConfigDescriptorBuffer &&
        *ConfigDescriptorBufferLength == sizeof(USB_CONFIGURATION_DESCRIPTOR))
    {
        RtlCopyMemory(ConfigDescriptorBuffer,
                      &deviceData->ConfigDescriptor,
                      sizeof(USB_CONFIGURATION_DESCRIPTOR));
    }
    else if (ConfigDescriptorBuffer && *ConfigDescriptorBufferLength) {
    
        ULONG bytesReturned;
        
        ntStatus = 
            USBD_SendCommand(deviceData,
                            rootHubPdo,
                            STANDARD_COMMAND_GET_DESCRIPTOR,
                            USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(
                                USB_CONFIGURATION_DESCRIPTOR_TYPE, 0),
                            0,
                            (USHORT) *ConfigDescriptorBufferLength,
                            (PUCHAR) ConfigDescriptorBuffer,
                            *ConfigDescriptorBufferLength,
                            &bytesReturned,
                            NULL);
                            
        if (NT_SUCCESS(ntStatus) &&
            bytesReturned < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
            // truncated config descriptor returned
            USBD_KdPrint(0, 
("'WARNING: Truncated Config Descriptor returned - get JD\n"));
             
            ntStatus = STATUS_DEVICE_DATA_ERROR;
        }
    }

    return ntStatus;
}    


NTSTATUS
USBD_BusRestoreDevice(
    IN PVOID BusContext,
    IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
    IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus;
    PDEVICE_OBJECT rootHubPdo;

    rootHubPdo = BusContext;

    ntStatus = USBD_RestoreDeviceX(OldDeviceHandle,
                                   NewDeviceHandle,
                                   rootHubPdo);
                                   
    return ntStatus; 
}    


NTSTATUS
USBD_BusGetUsbDeviceHackFlags(
    IN PVOID BusContext,
    IN PUSB_DEVICE_HANDLE DeviceHandle,
    IN OUT PULONG HackFlags
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_OBJECT rootHubPdo;
    PUSBD_DEVICE_DATA deviceData = DeviceHandle;

    rootHubPdo = BusContext;

    TEST_TRAP();        
    return ntStatus; 
}    


NTSTATUS
USBD_BusGetUsbPortHackFlags(
    IN PVOID BusContext,
    IN OUT PULONG HackFlags
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_OBJECT rootHubPdo;
    PUSBD_EXTENSION deviceExtensionUsbd;

    rootHubPdo = BusContext;
    *HackFlags = 0;
    
    deviceExtensionUsbd = ((PUSBD_EXTENSION)rootHubPdo->DeviceExtension)->TrueDeviceExtension;
    if (deviceExtensionUsbd->DiagnosticMode) {
        *HackFlags |= USBD_DEVHACK_SET_DIAG_ID;
    }
    
    return ntStatus; 
}    


VOID
USBD_BusInterfaceReference(
    IN PVOID BusContext
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
}    


VOID
USBD_BusInterfaceDereference(
    IN PVOID BusContext
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
}    


NTSTATUS
USBD_BusQueryBusTime(
    IN PVOID BusContext,
    IN PULONG CurrentFrame
    )
/*++

Routine Description:

    returns the current USB frame

Arguments:

Return Value:

    NT status code.

--*/    
{
    PUSBD_EXTENSION deviceExtensionUsbd;
    PDEVICE_OBJECT rootHubPdo = BusContext;

    deviceExtensionUsbd = rootHubPdo->DeviceExtension;
    deviceExtensionUsbd = deviceExtensionUsbd->TrueDeviceExtension;

    return deviceExtensionUsbd->HcdGetCurrentFrame(
                deviceExtensionUsbd->HcdDeviceObject,
                CurrentFrame);
}    

VOID 
USBD_GetUSBDIVersion(
        PUSBD_VERSION_INFORMATION VersionInformation
        );  
        
VOID
USBD_BusGetUSBDIVersion(
    IN PVOID BusContext,
    IN OUT PUSBD_VERSION_INFORMATION VersionInformation,
    IN OUT PULONG HcdCapabilities
    )
/*++

Routine Description:

    returns the current USB frame

Arguments:

Return Value:

    NT status code.

--*/    
{
    PUSBD_EXTENSION deviceExtensionUsbd;
    PDEVICE_OBJECT rootHubPdo = BusContext;

    deviceExtensionUsbd = rootHubPdo->DeviceExtension;
    deviceExtensionUsbd = deviceExtensionUsbd->TrueDeviceExtension;

    USBD_GetUSBDIVersion(VersionInformation);
    
    *HcdCapabilities = 0;
    
    if (deviceExtensionUsbd->HcdSubmitIsoUrb != NULL) {
        *HcdCapabilities = USB_HCD_CAPS_SUPPORTS_RT_THREADS;
    }                
}    


NTSTATUS
USBD_BusSubmitIsoOutUrb(
    IN PVOID BusContext,
    IN OUT PURB Urb            
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    PUSBD_EXTENSION deviceExtensionUsbd;
    PDEVICE_OBJECT rootHubPdo = BusContext;
    NTSTATUS ntStatus;
//    PUSBD_DEVICE_DATA deviceData;
    PUSBD_PIPE pipeHandle;

    pipeHandle =  (PUSBD_PIPE)Urb->UrbIsochronousTransfer.PipeHandle;  
    
    ASSERT_PIPE(pipeHandle);
    deviceExtensionUsbd = rootHubPdo->DeviceExtension;
    deviceExtensionUsbd = deviceExtensionUsbd->TrueDeviceExtension;

    ((PHCD_URB)Urb)->HcdUrbCommonTransfer.hca.HcdEndpoint = 
        pipeHandle->HcdEndpoint;    

    if (pipeHandle->EndpointDescriptor.bEndpointAddress & 
        USB_ENDPOINT_DIRECTION_MASK) {
        USBD_SET_TRANSFER_DIRECTION_IN(((PHCD_URB)Urb)->HcdUrbCommonTransfer.TransferFlags);
    } else {
        USBD_SET_TRANSFER_DIRECTION_OUT(((PHCD_URB)Urb)->HcdUrbCommonTransfer.TransferFlags);
    }            

    if (deviceExtensionUsbd->HcdSubmitIsoUrb == NULL) {
        // fast iso interface not supported by HCD
        TEST_TRAP();        
        ntStatus = STATUS_NOT_SUPPORTED;
    } else {
        ntStatus = deviceExtensionUsbd->HcdSubmitIsoUrb(
            deviceExtensionUsbd->HcdDeviceObject,
            Urb);
    }

    return ntStatus;
}    


NTSTATUS
USBD_BusQueryDeviceInformation(
    IN PVOID BusContext,
    IN PUSB_DEVICE_HANDLE DeviceHandle,
    IN OUT PVOID DeviceInformationBuffer,
    IN ULONG DeviceInformationBufferLength,
    IN OUT PULONG LengthOfDataCopied
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    ULONG need;
    PUSBD_CONFIG configHandle;
    ULONG i,j,k;
    PUSB_DEVICE_INFORMATION_0 level_0 = DeviceInformationBuffer;
    PUSB_LEVEL_INFORMATION levelInfo = DeviceInformationBuffer;
    ULONG numberOfPipes = 0;
    PUSBD_DEVICE_DATA deviceData = DeviceHandle;


    // bugbug 
    // need more validation here
    
    PAGED_CODE();
    
    *LengthOfDataCopied = 0;   
    
    if (DeviceInformationBufferLength < sizeof(*levelInfo)) {
        return STATUS_BUFFER_TOO_SMALL;            
    }

    if (levelInfo->InformationLevel > 0) {
        // usbd only supports level 0
        return STATUS_NOT_SUPPORTED;                     
    }

    // figure out how much room we need
    configHandle = deviceData->ConfigurationHandle;
    if (configHandle) {
    
        // count the pipes in each interface
        for (i=0;
             i< configHandle->ConfigurationDescriptor->bNumInterfaces;
             i++) {
            numberOfPipes +=
                configHandle->InterfaceHandle[i]->
                    InterfaceInformation->NumberOfPipes;
        }
        
    }
    
    need = (numberOfPipes-1) * sizeof(USB_PIPE_INFORMATION_0) +
            sizeof(USB_DEVICE_INFORMATION_0);


    if (DeviceInformationBufferLength < need) {
        // report how much space if possible
        levelInfo->ActualLength = need;
        *LengthOfDataCopied = sizeof(*levelInfo);
        return STATUS_BUFFER_TOO_SMALL;
    }    

    RtlZeroMemory(level_0, need);
    
    // 
    // enough room, fill in the buffer
    //

    level_0->InformationLevel = 0;
    level_0->ActualLength = need;        
    level_0->DeviceAddress = deviceData->DeviceAddress;
    level_0->DeviceDescriptor = deviceData->DeviceDescriptor;
    
    if (deviceData->LowSpeed) {
        level_0->DeviceSpeed = UsbLowSpeed;
    } else {
        level_0->DeviceSpeed = UsbFullSpeed;
    }

//    if (DeviceData->xxx) {
        level_0->DeviceType = Usb11Device;
//    } else {
//        level_0->DeviceSpeed = UsbFullSpeed;
//    }

//    level_0->PortNumber = xxx;
    level_0->NumberOfOpenPipes = numberOfPipes;
    level_0->CurrentConfigurationValue = 0;
    // get the pipe information
    if (configHandle) {
    
        level_0->CurrentConfigurationValue =
            configHandle->ConfigurationDescriptor->bConfigurationValue;

        j=0;
        for (i=0;
             i<configHandle->ConfigurationDescriptor->bNumInterfaces;
             i++) {

            PUSBD_INTERFACE interfaceHandle =
                configHandle->InterfaceHandle[i];

            for (k=0;
                 k<interfaceHandle->InterfaceInformation->NumberOfPipes;
                 k++, j++) {
                 
                    ASSERT(j < numberOfPipes);
                    
                    level_0->PipeList[j].ScheduleOffset = 
                        interfaceHandle->PipeHandle[k].ScheduleOffset;
                    RtlCopyMemory(&level_0->PipeList[j].
                                    EndpointDescriptor,
                                  &interfaceHandle->PipeHandle[k].
                                    EndpointDescriptor,
                                  sizeof(USB_ENDPOINT_DESCRIPTOR));
        
            }
        }
    }

    *LengthOfDataCopied = need;

    // dump the level data returned
    USBD_KdPrint(1, ("  USBD level 0 Device Information:\n"));
    USBD_KdPrint(1, ("  InformationLevel %d\n", 
        level_0->InformationLevel));
//    USBD_KdPrint(1, ("  DeviceDescriptor %d\n", 
//        level_0->InformationLevel));
    USBD_KdPrint(1, ("  ActualLength %d\n", 
        level_0->ActualLength));
    USBD_KdPrint(1, ("  DeviceSpeed %d\n", 
        level_0->DeviceSpeed));                
    USBD_KdPrint(1, ("  PortNumber %d\n", 
        level_0->PortNumber));
    USBD_KdPrint(1, ("  CurrentConfigurationValue %d\n", 
        level_0->CurrentConfigurationValue));
    USBD_KdPrint(1, ("  DeviceAddress %d\n", 
        level_0->DeviceAddress));
    USBD_KdPrint(1, ("  NumberOfOpenPipes %d\n", 
        level_0->NumberOfOpenPipes));
        
    for (i=0; i< level_0->NumberOfOpenPipes; i++) {         
        USBD_KdPrint(1, ("  ScheduleOffset[%d] %d\n", i,
            level_0->PipeList[i].ScheduleOffset));
        USBD_KdPrint(1, ("  MaxPacket %d\n", 
            level_0->PipeList[i].EndpointDescriptor.wMaxPacketSize));
        USBD_KdPrint(1, ("  Interval %d\n", 
            level_0->PipeList[i].EndpointDescriptor.bInterval));            
//        USBD_KdPrint(1, ("' \n", level_0->));
//        USBD_KdPrint(1, ("' \n", level_0->));
    }
    
    return STATUS_SUCCESS;
}    


NTSTATUS
USBD_BusQueryBusInformation(
    IN PVOID BusContext,
    IN ULONG Level,
    IN OUT PVOID BusInformationBuffer,
    IN OUT PULONG BusInformationBufferLength,
    OUT PULONG BusInformationActulaLength
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;
    PUSB_BUS_INFORMATION_LEVEL_0 level_0;
    PUSB_BUS_INFORMATION_LEVEL_1 level_1;
    PDEVICE_OBJECT rootHubPdo = BusContext;
    PUSBD_EXTENSION deviceExtensionUsbd;
    ULONG len, need;
    
    deviceExtensionUsbd = rootHubPdo->DeviceExtension;
    deviceExtensionUsbd = deviceExtensionUsbd->TrueDeviceExtension;

    switch (Level) {
    case 0:
        level_0 =  BusInformationBuffer;
        if (BusInformationActulaLength != NULL) {
            *BusInformationActulaLength = sizeof(*level_0);
        }
        
        if (*BusInformationBufferLength >= sizeof(*level_0)) {
            *BusInformationBufferLength = sizeof(*level_0);

            level_0->TotalBandwidth = 12000; // 12 Mbits
            level_0->ConsumedBandwidth =
                deviceExtensionUsbd->HcdGetConsumedBW(
                    deviceExtensionUsbd->HcdDeviceObject);
            
            ntStatus = STATUS_SUCCESS;
        } else {
            ntStatus = STATUS_BUFFER_TOO_SMALL;
        }
        
        break;

    case 1:
        level_1 =  BusInformationBuffer;

        need = sizeof(*level_1) + 
             deviceExtensionUsbd->DeviceLinkUnicodeString.Length;
        
        if (BusInformationActulaLength != NULL) {
            *BusInformationActulaLength = need;
        }
        
        if (*BusInformationBufferLength >= need) {
            *BusInformationBufferLength = need;

            level_1->TotalBandwidth = 12000; // 12 Mbits
            level_1->ConsumedBandwidth =
                deviceExtensionUsbd->HcdGetConsumedBW(
                    deviceExtensionUsbd->HcdDeviceObject);
                    
            level_1->ControllerNameLength =
                deviceExtensionUsbd->DeviceLinkUnicodeString.Length;

            len = deviceExtensionUsbd->DeviceLinkUnicodeString.Length;

            if (len > sizeof(level_1->ControllerNameUnicodeString)) {
                len =  sizeof(level_1->ControllerNameUnicodeString);
            }
            
            RtlCopyMemory(&level_1->ControllerNameUnicodeString[0],
                          deviceExtensionUsbd->DeviceLinkUnicodeString.Buffer,
                          len);
                
            ntStatus = STATUS_SUCCESS;
        } else {
            ntStatus = STATUS_BUFFER_TOO_SMALL;
        }
        
        break;        
    }
    
    return ntStatus; 
}    


NTSTATUS
USBD_BusGetBusInformation(
    IN PVOID BusContext,
    IN ULONG Level,
    IN PUSB_DEVICE_HANDLE DeviceHandle,
    IN OUT PVOID DeviceInformationBuffer,
    IN OUT PULONG DeviceInformationBufferLength
    )
/*++

Routine Description:

Arguments:

Return Value:

    NT status code.

--*/    
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    TEST_TRAP();        
    return ntStatus; 
}    



NTSTATUS
USBD_GetBusInterfaceHub(
    IN PDEVICE_OBJECT RootHubPdo,
    IN PIRP Irp
    )
/*++

Routine Description:

    Return the Hub Bus Interface to the caller

Arguments:

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION irpStack;
    NTSTATUS ntStatus;
    USHORT requestedSize, requestedVersion;
    
    PAGED_CODE();

    irpStack = IoGetCurrentIrpStackLocation(Irp);

    requestedSize = irpStack->Parameters.QueryInterface.Size;
    requestedVersion = irpStack->Parameters.QueryInterface.Version;

    // assume success
    ntStatus = STATUS_SUCCESS;


    if (requestedVersion >= USB_BUSIF_HUB_VERSION_0) {
    
        PUSB_BUS_INTERFACE_HUB_V0 busInterface0;
        
        busInterface0 = (PUSB_BUS_INTERFACE_HUB_V0) 
            irpStack->Parameters.QueryInterface.Interface;

        busInterface0->BusContext = 
            RootHubPdo;                
        busInterface0->InterfaceReference = 
            USBD_BusInterfaceReference;        
        busInterface0->InterfaceDereference =
            USBD_BusInterfaceDereference;

        busInterface0->Size = sizeof(USB_BUS_INTERFACE_HUB_V0);
        busInterface0->Version = USB_BUSIF_HUB_VERSION_0;
    }

    if (requestedVersion >= USB_BUSIF_HUB_VERSION_1) {
    
        PUSB_BUS_INTERFACE_HUB_V1 busInterface1;
        
        busInterface1 = (PUSB_BUS_INTERFACE_HUB_V1)
            irpStack->Parameters.QueryInterface.Interface;

        busInterface1->CreateUsbDevice =
            USBD_BusCreateDevice;
        busInterface1->InitializeUsbDevice =
            USBD_BusInitializeDevice;
        busInterface1->GetUsbDescriptors =
            USBD_BusGetUsbDescriptors;
        busInterface1->RemoveUsbDevice =
            USBD_BusRemoveDevice;
        busInterface1->RestoreUsbDevice =
            USBD_BusRestoreDevice;
        busInterface1->GetPortHackFlags =     
            USBD_BusGetUsbPortHackFlags;
        busInterface1->QueryDeviceInformation =  
            USBD_BusQueryDeviceInformation;

        busInterface1->Size = sizeof(USB_BUS_INTERFACE_HUB_V1);
        busInterface1->Version = USB_BUSIF_HUB_VERSION_1;
    }
        
    return ntStatus;
}


NTSTATUS
USBD_GetBusInterfaceUSBDI(
    IN PDEVICE_OBJECT RootHubPdo,
    IN PIRP Irp
    )
/*++

Routine Description:

    Return the Hub Bus Interface to the caller

Arguments:

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION irpStack;
    NTSTATUS ntStatus;
    USHORT requestedSize, requestedVersion;
    
    PAGED_CODE();

    irpStack = IoGetCurrentIrpStackLocation(Irp);

    requestedSize = irpStack->Parameters.QueryInterface.Size;
    requestedVersion = irpStack->Parameters.QueryInterface.Version;

    // assume success
    ntStatus = STATUS_SUCCESS;

    if (requestedVersion >= USB_BUSIF_USBDI_VERSION_0) {
    
        PUSB_BUS_INTERFACE_USBDI_V0 busInterface0;
        
        busInterface0 = (PUSB_BUS_INTERFACE_USBDI_V0) 
            irpStack->Parameters.QueryInterface.Interface;

        busInterface0->BusContext = 
            RootHubPdo;                
        busInterface0->InterfaceReference = 
            USBD_BusInterfaceReference;        
        busInterface0->InterfaceDereference =
            USBD_BusInterfaceDereference;

        busInterface0->GetUSBDIVersion = 
            USBD_BusGetUSBDIVersion;
        busInterface0->QueryBusTime = 
            USBD_BusQueryBusTime;            
        busInterface0->SubmitIsoOutUrb = 
            USBD_BusSubmitIsoOutUrb;
        busInterface0->QueryBusInformation = 
            USBD_BusQueryBusInformation;
            

        busInterface0->Size = sizeof(USB_BUS_INTERFACE_USBDI_V0);
        busInterface0->Version = USB_BUSIF_USBDI_VERSION_0;
    }

    return ntStatus;
}


NTSTATUS
USBD_GetBusInterface(
    IN PDEVICE_OBJECT RootHubPdo,
    IN PIRP Irp
    )
/*++

Routine Description:

    Return the Hub Bus Interface to the caller

Arguments:

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION irpStack;
    NTSTATUS ntStatus;
    USHORT requestedSize, requestedVersion;
    
    PAGED_CODE();

    irpStack = IoGetCurrentIrpStackLocation(Irp);

    requestedSize = irpStack->Parameters.QueryInterface.Size;
    requestedVersion = irpStack->Parameters.QueryInterface.Version;

//    USBPORT_KdPrint((1, "'USBPORT_GetBusInterface - Requested version = %d\n",
//            requestedVersion));
//    USBPORT_KdPrint((1, "'USBPORT_GetBusInterface - Requested size = %d\n",
//            requestedSize));  
//    USBPORT_KdPrint((1, "'USBPORT_GetBusInterface - interface data = %x\n",
//            irpStack->Parameters.QueryInterface.InterfaceSpecificData));              
            
            
    // Initialize ntStatus as IRP status, because we're not supposed to
    // touch the IRP status for interfaces that we do not support.
    // (USBD_PdoPnP sets IRP status to ntStatus on exit.)
    ntStatus = Irp->IoStatus.Status;

    // validate version, size and GUID
    if (RtlCompareMemory(irpStack->Parameters.QueryInterface.InterfaceType,
                         &USB_BUS_INTERFACE_HUB_GUID,
                         sizeof(GUID)) == sizeof(GUID)) {

        ntStatus = USBD_GetBusInterfaceHub(RootHubPdo,
                                           Irp);

    } else if (RtlCompareMemory(irpStack->Parameters.QueryInterface.InterfaceType,
                         &USB_BUS_INTERFACE_USBDI_GUID,
                         sizeof(GUID)) == sizeof(GUID)) {

        ntStatus = USBD_GetBusInterfaceUSBDI(RootHubPdo,
                                             Irp);

    }

    return ntStatus;
}

#endif      // USBD_DRIVER