/*++ Copyright (c) 1997-2000 Microsoft Corporation Module Name: interface.c Abstract: IRP_MN_QUERY_INTERFACE lives here. Author: Peter Johnston (peterj) 31-Mar-1997 Revision History: --*/ #include "pcip.h" NTSTATUS PciGetBusStandardInterface( IN PDEVICE_OBJECT Pdo, OUT PBUS_INTERFACE_STANDARD BusInterface ); extern PCI_INTERFACE ArbiterInterfaceBusNumber; extern PCI_INTERFACE ArbiterInterfaceMemory; extern PCI_INTERFACE ArbiterInterfaceIo; extern PCI_INTERFACE TranslatorInterfaceInterrupt; extern PCI_INTERFACE TranslatorInterfaceMemory; extern PCI_INTERFACE TranslatorInterfaceIo; extern PCI_INTERFACE BusHandlerInterface; extern PCI_INTERFACE PciRoutingInterface; extern PCI_INTERFACE PciCardbusPrivateInterface; extern PCI_INTERFACE PciLegacyDeviceDetectionInterface; extern PCI_INTERFACE PciPmeInterface; extern PCI_INTERFACE PciDevicePresentInterface; extern PCI_INTERFACE PciNativeIdeInterface; PPCI_INTERFACE PciInterfaces[] = { &ArbiterInterfaceBusNumber, &ArbiterInterfaceMemory, &ArbiterInterfaceIo, &BusHandlerInterface, &PciRoutingInterface, &PciCardbusPrivateInterface, &PciLegacyDeviceDetectionInterface, &PciPmeInterface, &PciDevicePresentInterface, &PciNativeIdeInterface, NULL }; // // These are the interfaces we supply only if nobody underneath // us (the HAL) does. // PPCI_INTERFACE PciInterfacesLastResort[] = { &TranslatorInterfaceInterrupt, NULL }; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, PciQueryInterface) #pragma alloc_text(PAGE, PciGetBusStandardInterface) #endif NTSTATUS PciGetBusStandardInterface( IN PDEVICE_OBJECT Pdo, OUT PBUS_INTERFACE_STANDARD BusInterface ) /*++ Routine Description: This routine gets the bus iterface standard information from the PDO. Arguments: Pdo - Physical device object to query for this information. BusInterface - Supplies a pointer for the retrived information. Return Value: NT status. --*/ { KEVENT event; NTSTATUS status; PIRP irp; IO_STATUS_BLOCK ioStatusBlock; PIO_STACK_LOCATION irpStack; PciDebugPrint( PciDbgObnoxious, "PCI - PciGetBusStandardInterface entered.\n" ); KeInitializeEvent( &event, NotificationEvent, FALSE ); irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, Pdo, NULL, 0, NULL, &event, &ioStatusBlock ); if (irp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } irpStack = IoGetNextIrpStackLocation( irp ); irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE; irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD; irpStack->Parameters.QueryInterface.Size = sizeof( BUS_INTERFACE_STANDARD ); irpStack->Parameters.QueryInterface.Version = 1; irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface; irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; // // Initialize the status to error in case the ACPI driver decides not to // set it correctly. // irp->IoStatus.Status = STATUS_NOT_SUPPORTED; status = IoCallDriver( Pdo, irp ); if (!NT_SUCCESS( status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciGetBusStandardInterface IoCallDriver returned %08x.\n", status ); return status; } if (status == STATUS_PENDING) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); } PciDebugPrint( PciDbgVerbose, "PCI - PciGetBusStandardInterface returning status %08x.\n", ioStatusBlock.Status ); return ioStatusBlock.Status; } NTSTATUS PciQueryInterface( IN PVOID DeviceExtension, IN PGUID InterfaceType, IN USHORT Size, IN USHORT Version, IN PVOID InterfaceSpecificData, IN OUT PINTERFACE InterfaceReturn, IN BOOLEAN LastChance ) { PPCI_INTERFACE *interfaceEntry; PPCI_INTERFACE interface; PPCI_INTERFACE *interfaceTable; BOOLEAN isPdo; ULONG index; NTSTATUS status; #if DBG UNICODE_STRING guidString; status = RtlStringFromGUID(InterfaceType, &guidString); if (NT_SUCCESS(status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface TYPE = %wZ\n", &guidString ); RtlFreeUnicodeString(&guidString); PciDebugPrint( PciDbgObnoxious, " Size = %d, Version = %d, InterfaceData = %x, LastChance = %s\n", Size, Version, InterfaceSpecificData, LastChance ? "TRUE" : "FALSE" ); } #endif isPdo = ((PPCI_PDO_EXTENSION)DeviceExtension)->ExtensionType == PciPdoExtensionType; // // Try to locate the requested interface in the PCI driver's set // of exported interfaces. // // Note - we do not allow last chance interfaces (ie mock translators) for // machines where we assign bus numbers // if (LastChance) { interfaceTable = PciInterfacesLastResort; } else { interfaceTable = PciInterfaces; } for (interfaceEntry = interfaceTable; *interfaceEntry; interfaceEntry++) { interface = *interfaceEntry; #if 0 status = RtlStringFromGUID(interface->InterfaceType, &guidString); if (NT_SUCCESS(status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface looking at guid = %wZ\n", &guidString ); RtlFreeUnicodeString(&guidString); } #endif // // Check if this interface is allowed to be used from this // device object type. // if (isPdo) { if ((interface->Flags & PCIIF_PDO) == 0) { // // This interface cannot be used from a PDO. // #if DBG status = RtlStringFromGUID(interface->InterfaceType, &guidString); if (NT_SUCCESS(status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface: guid = %wZ only for PDOs\n", &guidString ); RtlFreeUnicodeString(&guidString); } #endif continue; } } else { // // Allowable from FDO? // if ((interface->Flags & PCIIF_FDO) == 0) { // // No. // #if DBG status = RtlStringFromGUID(interface->InterfaceType, &guidString); if (NT_SUCCESS(status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface: guid = %wZ only for FDOs\n", &guidString ); RtlFreeUnicodeString(&guidString); } #endif continue; } // // Allowable only at root? // if (interface->Flags & PCIIF_ROOT) { PPCI_FDO_EXTENSION FdoExtension = (PPCI_FDO_EXTENSION)DeviceExtension; if (!PCI_IS_ROOT_FDO(FdoExtension)) { #if DBG status = RtlStringFromGUID(interface->InterfaceType, &guidString); if (NT_SUCCESS(status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface: guid = %wZ only for ROOT\n", &guidString ); RtlFreeUnicodeString(&guidString); } #endif continue; } } } #if DBG status = RtlStringFromGUID(interface->InterfaceType, &guidString); if (NT_SUCCESS(status)) { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface looking at guid = %wZ\n", &guidString ); RtlFreeUnicodeString(&guidString); } #endif // // Check for the appropriate GUID then verify version numbers // and size. // if ((PciCompareGuid(InterfaceType, interface->InterfaceType)) && (Version >= interface->MinVersion) && (Version <= interface->MaxVersion) && (Size >= interface->MinSize) ) { // // We have a possible hit. Check to see if the interface // itself agrees. // status = interface->Constructor( DeviceExtension, interface, InterfaceSpecificData, Version, Size, InterfaceReturn ); if (NT_SUCCESS(status)) { // // We found and allocated an interface, reference it // and get out of the loop. // InterfaceReturn->InterfaceReference(InterfaceReturn->Context); PciDebugPrint( PciDbgObnoxious, "PCI - PciQueryInterface returning SUCCESS\n" ); return status; #if DBG } else { PciDebugPrint( PciDbgVerbose, "PCI - PciQueryInterface - Contructor %08lx = %08lx\n", interface->Constructor, status ); #endif } } } // // Failed to find the requested interface. // PciDebugPrint( PciDbgObnoxious, "PCI - PciQueryInterface FAILED TO FIND INTERFACE\n" ); return STATUS_NOT_SUPPORTED; }