/*++ Copyright (c) 1994 Microsoft Corporation Module Name: intrface.c Abstract: This module contains the external interfaces of the pcmcia driver Author: Neil Sandlin (neilsa) 3-Mar-1999 Environment: Kernel mode Revision History : --*/ #include "pch.h" // // Internal References // ULONG PcmciaReadCardMemory( IN PDEVICE_OBJECT Pdo, IN ULONG WhichSpace, OUT PUCHAR Buffer, IN ULONG Offset, IN ULONG Length ); ULONG PcmciaWriteCardMemory( IN PDEVICE_OBJECT Pdo, IN ULONG WhichSpace, IN PUCHAR Buffer, IN ULONG Offset, IN ULONG Length ); NTSTATUS PcmciaMfEnumerateChild( IN PPDO_EXTENSION PdoExtension, IN ULONG Index, OUT PMF_DEVICE_INFO ChildInfo ); BOOLEAN PcmciaModifyMemoryWindow( IN PDEVICE_OBJECT Pdo, IN ULONGLONG HostBase, IN ULONGLONG CardBase, IN BOOLEAN Enable, IN ULONG WindowSize OPTIONAL, IN UCHAR AccessSpeed OPTIONAL, IN UCHAR BusWidth OPTIONAL, IN BOOLEAN IsAttributeMemory OPTIONAL ); BOOLEAN PcmciaSetVpp( IN PDEVICE_OBJECT Pdo, IN UCHAR VppLevel ); BOOLEAN PcmciaIsWriteProtected( IN PDEVICE_OBJECT Pdo ); BOOLEAN PcmciaTranslateBusAddress( IN PVOID Context, IN PHYSICAL_ADDRESS BusAddress, IN ULONG Length, IN OUT PULONG AddressSpace, OUT PPHYSICAL_ADDRESS TranslatedAddress ); PDMA_ADAPTER PcmciaGetDmaAdapter( IN PVOID Context, IN struct _DEVICE_DESCRIPTION *DeviceDescriptor, OUT PULONG NumberOfMapRegisters ); VOID PcmciaNop( IN PVOID Context ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, PcmciaPdoQueryInterface) #pragma alloc_text(PAGE, PcmciaMfEnumerateChild) #pragma alloc_text(PAGE, PcmciaNop) #pragma alloc_text(PAGE, PcmciaGetInterface) #pragma alloc_text(PAGE, PcmciaUpdateInterruptLine) #endif NTSTATUS PcmciaPdoQueryInterface( IN PDEVICE_OBJECT Pdo, IN OUT PIRP Irp ) /*++ Routine Description: Fills in the interface requested Interfaces supported are: GUID_PCMCIA_INTERFACE_STANDARD: This returns a pointer to a PCMCIA_INTERFACE_STANDARD structure. These interfaces are exported solely for flash memory card support as a means for flash memory card drivers to slide memory windows, set Vpp levels etc. GUID_TRANSLATOR_INTERFACE_STANDARD: This returns an interrupt translator for 16-bit pc-cards which is used by PnP for translating raw IRQs. We simply return the Hal implemented translator, since PCMCIA does not need any specific translation. We do not return a translator if this is for a cardbus card GUID_PCMCIA_BUS_INTERFACE_STANDARD: This returns a pointer to a PCMCIA_BUS_INTERFACE_STANDARD structure. This contains entry points to set/get PCMCIA config data for the pc-card GUID_MF_ENUMERATION_INTERFACE For 16-bit multifunction pc-cards returns a pointer to MF_ENUMERATION_INTERFACE structure which contains entry points to enumerate multifunction children of the pc-card Completes the Passed in IRP before returning Arguments Pdo - Pointer to the device object Irp - Pointer to the io request packet Return Value STATUS_SUCCESS STATUS_INSUFFICIENT_RESOURCES - if supplied interface size is not big enough to accomodate the interface STATUS_INVALID_PARAMETER_1 - if the requested interface is not supported by this driver --*/ { PIO_STACK_LOCATION irpStack; PPCMCIA_INTERFACE_STANDARD pcmciaInterfaceStandard; GUID *interfaceType; PPDO_EXTENSION pdoExtension; PFDO_EXTENSION fdoExtension; PSOCKET socket; NTSTATUS status; PAGED_CODE(); irpStack = IoGetCurrentIrpStackLocation(Irp); interfaceType = (GUID *) irpStack->Parameters.QueryInterface.InterfaceType; pdoExtension = Pdo->DeviceExtension; socket = pdoExtension->Socket; fdoExtension = socket->DeviceExtension; if (Is16BitCard(pdoExtension) && CompareGuid(interfaceType, (PVOID) &GUID_PCMCIA_INTERFACE_STANDARD)) { if (irpStack->Parameters.QueryInterface.Size < sizeof(PCMCIA_INTERFACE_STANDARD)) { return STATUS_INVALID_PARAMETER; } // // Ignore the version for the present // pcmciaInterfaceStandard = (PPCMCIA_INTERFACE_STANDARD) irpStack->Parameters.QueryInterface.Interface; RtlZeroMemory(pcmciaInterfaceStandard, sizeof (PCMCIA_INTERFACE_STANDARD)); pcmciaInterfaceStandard->Size = sizeof(PCMCIA_INTERFACE_STANDARD); pcmciaInterfaceStandard->Version = 1; pcmciaInterfaceStandard->Context = Pdo; // // Fill in the exported functions // socket = pdoExtension->Socket; ASSERT (socket != NULL); pcmciaInterfaceStandard->InterfaceReference = (PINTERFACE_REFERENCE) PcmciaNop; pcmciaInterfaceStandard->InterfaceDereference = (PINTERFACE_DEREFERENCE) PcmciaNop; pcmciaInterfaceStandard->ModifyMemoryWindow = PcmciaModifyMemoryWindow; pcmciaInterfaceStandard->SetVpp = PcmciaSetVpp; pcmciaInterfaceStandard->IsWriteProtected = PcmciaIsWriteProtected; Irp->IoStatus.Status = status = STATUS_SUCCESS;; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else if (CompareGuid(interfaceType, (PVOID) &GUID_TRANSLATOR_INTERFACE_STANDARD) && ((ULONG_PTR)irpStack->Parameters.QueryInterface.InterfaceSpecificData == CmResourceTypeInterrupt)) { if ((Is16BitCard(pdoExtension) && !IsSocketFlagSet(pdoExtension->Socket, SOCKET_CB_ROUTE_R2_TO_PCI)) && // // Eject a translator only if the controller is PCI enumerated // (i.e. we are enumerated by PCI - so we eject a PCI-Isa translator) // (CardBusExtension(fdoExtension) || PciPcmciaBridgeExtension(fdoExtension))) { PTRANSLATOR_INTERFACE translator; ULONG busNumber; // // We need a translator for this PDO (16-bit pc-card) which uses // ISA resources. // status = HalGetInterruptTranslator( PCIBus, 0, Isa, irpStack->Parameters.QueryInterface.Size, irpStack->Parameters.QueryInterface.Version, (PTRANSLATOR_INTERFACE) irpStack->Parameters.QueryInterface.Interface, &busNumber ); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { // // Translator interface not supported for this card/controller // if (pdoExtension->LowerDevice != NULL) { PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp); } else { status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } } } else if (IsDeviceMultifunction(pdoExtension) && CompareGuid(interfaceType, (PVOID)&GUID_MF_ENUMERATION_INTERFACE)) { // // Multifunction enumeration interface // PMF_ENUMERATION_INTERFACE mfEnum; mfEnum = (PMF_ENUMERATION_INTERFACE) irpStack->Parameters.QueryInterface.Interface; mfEnum->Context = pdoExtension; mfEnum->InterfaceReference = PcmciaNop; mfEnum->InterfaceDereference = PcmciaNop; mfEnum->EnumerateChild = (PMF_ENUMERATE_CHILD) PcmciaMfEnumerateChild; status = Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else if (CompareGuid(interfaceType, (PVOID)&GUID_PCMCIA_BUS_INTERFACE_STANDARD)) { PPCMCIA_BUS_INTERFACE_STANDARD busInterface; busInterface = (PPCMCIA_BUS_INTERFACE_STANDARD) irpStack->Parameters.QueryInterface.Interface; busInterface->Context = Pdo; busInterface->InterfaceReference = PcmciaNop; busInterface->InterfaceDereference = PcmciaNop; busInterface->ReadConfig = PcmciaReadCardMemory; busInterface->WriteConfig = PcmciaWriteCardMemory; status = Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else if (Is16BitCard(pdoExtension) && CompareGuid(interfaceType, (PVOID) &GUID_BUS_INTERFACE_STANDARD)) { PBUS_INTERFACE_STANDARD busInterface = (PBUS_INTERFACE_STANDARD)irpStack->Parameters.QueryInterface.Interface; busInterface->Size = sizeof( BUS_INTERFACE_STANDARD ); busInterface->Version = 1; busInterface->Context = Pdo; busInterface->InterfaceReference = PcmciaNop; busInterface->InterfaceDereference = PcmciaNop; busInterface->TranslateBusAddress = PcmciaTranslateBusAddress; busInterface->GetDmaAdapter = PcmciaGetDmaAdapter; busInterface->GetBusData = PcmciaReadCardMemory; busInterface->SetBusData = PcmciaWriteCardMemory; status = Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { // // Query Interface type not supported // if (pdoExtension->LowerDevice != NULL) { PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp); } else { status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } } return status; } ULONG PcmciaReadCardMemory( IN PDEVICE_OBJECT Pdo, IN ULONG WhichSpace, OUT PUCHAR Buffer, IN ULONG Offset, IN ULONG Length ) /*++ Routine Description: Stub for reading card memory which is exported via PCMCIA_BUS_INTERFACE_STANDARD. This just calls the PcmciaReadWriteCardMemory which does the real work Note: this has to be non-paged since it can be called by clients at DISPATCH_LEVEL Arguments: Pdo - Device object representing the PC-CARD whose config memory needs to be read WhichSpace - Indicates which memory space needs to be mapped: one of PCCARD_COMMON_MEMORY_SPACE PCCARD_ATTRIBUTE_MEMORY_SPACE PCCARD_PCI_CONFIGURATION_MEMORY_SPACE (only for cardbus cards) Buffer - Caller supplied buffer into which the memory contents are copied Offset - Offset of the attribute memory at which we copy Length - Number of bytes of attribute memory to be copied Return value: Count of bytes read --*/ { DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x read card memory\n", Pdo)); return NT_SUCCESS(PcmciaReadWriteCardMemory(Pdo, WhichSpace, Buffer, Offset, Length, TRUE)) ? Length : 0; } ULONG PcmciaWriteCardMemory( IN PDEVICE_OBJECT Pdo, IN ULONG WhichSpace, IN PUCHAR Buffer, IN ULONG Offset, IN ULONG Length ) /*++ Routine Description: Stub for writing to card memory which is exported via PCMCIA_BUS_INTERFACE_STANDARD. This just calls PcmciaReadWriteCardMemory which does the real work Note: this has to be non-paged since it can be called by clients at DISPATCH_LEVEL Arguments: Pdo - Device object representing the PC-CARD whose config memory needs to be written to WhichSpace - Indicates which memory space needs to be mapped: one of PCCARD_COMMON_MEMORY_SPACE PCCARD_ATTRIBUTE_MEMORY_SPACE PCCARD_PCI_CONFIGURATION_MEMORY_SPACE (only for cardbus cards) Buffer - Caller supplied buffer out of which the memory contents are copied Offset - Offset of the attribute memory at which we copy Length - Number of bytes of buffer to be copied Return value: Count of bytes written --*/ { DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x write card memory\n", Pdo)); return NT_SUCCESS(PcmciaReadWriteCardMemory(Pdo, WhichSpace, Buffer, Offset, Length, FALSE)) ? Length : 0; } BOOLEAN PcmciaModifyMemoryWindow( IN PDEVICE_OBJECT Pdo, IN ULONGLONG HostBase, IN ULONGLONG CardBase, IN BOOLEAN Enable, IN ULONG WindowSize OPTIONAL, IN UCHAR AccessSpeed OPTIONAL, IN UCHAR BusWidth OPTIONAL, IN BOOLEAN IsAttributeMemory OPTIONAL ) /*++ Routine Description: Part of the interfaces originally developed to support flash memory cards. This routine enables the caller to 'slide' the supplied host memory window across the given (16-bit)pc-card's card memory. i.e. the host memory window will be modified to map the pc-card at a new card memory offset Arguments: Pdo - Pointer to the device object for the PC-Card HostBase - Host memory window base to be mapped CardBase - Mandatory if Enable is TRUE New card memory offset to map the host memory window to Enable - If this is FALSE - all the remaining arguments are ignored and the host window will simply be disabled WindowSize - Specifies the size of the host memory window to be mapped. Note this must be at the proper alignment and must be less than or equal to the originally allocated window size for the host base. If this is zero, the originally allocated window size will be used. AccessSpeed - Mandatory if Enable is TRUE Specifies the new access speed for the pc-card. (AccessSpeed should be encoded as per the pc-card standard, card/socket services spec) BusWidth - Mandatory if Enable is TRUE One of PCMCIA_MEMORY_8BIT_ACCESS or PCMCIA_MEMORY_16BIT_ACCESS IsAttributeMemory - Mandatory if Enable is TRUE Specifies if the window should be mapped to the pc-card's attribute or common memory Return Value: TRUE - Memory window was enabled/disabled as requested FALSE - If not --*/ { PPDO_EXTENSION pdoExtension; PSOCKET socket; pdoExtension = Pdo->DeviceExtension; socket = pdoExtension->Socket; DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x modify memory window\n", Pdo)); if (socket->SocketFnPtr->PCBModifyMemoryWindow == NULL) { return FALSE; } else { return (*(socket->SocketFnPtr->PCBModifyMemoryWindow))(Pdo, HostBase, CardBase, Enable, WindowSize, AccessSpeed, BusWidth, IsAttributeMemory); } } BOOLEAN PcmciaSetVpp( IN PDEVICE_OBJECT Pdo, IN UCHAR VppLevel ) /*++ Routine Description Part of the interfaces originally developed to support flash memory cards. Sets VPP1 to the required setting Arguments Pdo - Pointer to device object for the PC-Card Vpp - Desired Vpp setting. This is currently one of PCMCIA_VPP_12V (12 volts) PCMCIA_VPP_0V (disable VPP) PCMCIA_VPP_IS_VCC (route VCC to VPP) Return TRUE - if successful FALSE - if not. This will be returned if the PC-Card is not already powered up --*/ { PPDO_EXTENSION pdoExtension; PSOCKET socket; pdoExtension = Pdo->DeviceExtension; socket = pdoExtension->Socket; DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x set vpp\n", Pdo)); if (socket->SocketFnPtr->PCBSetVpp == NULL) { return FALSE; } else { return (*(socket->SocketFnPtr->PCBSetVpp))(Pdo, VppLevel); } } BOOLEAN PcmciaIsWriteProtected( IN PDEVICE_OBJECT Pdo ) /*++ Routine Description: Part of the interfaces originally developed to support flash memory cards. Returns the status of the write protected pin for the given PC-Card Arguments: Pdo - Pointer to the device object for the PC-Card Return Value: TRUE - if the PC-Card is write-protected FALSE - if not --*/ { PPDO_EXTENSION pdoExtension; PSOCKET socket; pdoExtension = Pdo->DeviceExtension; socket = pdoExtension->Socket; DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x is write protected \n", Pdo)); if (socket->SocketFnPtr->PCBIsWriteProtected == NULL) { return FALSE; } else { return (*(socket->SocketFnPtr->PCBIsWriteProtected))(Pdo); } } BOOLEAN PcmciaTranslateBusAddress( IN PVOID Context, IN PHYSICAL_ADDRESS BusAddress, IN ULONG Length, IN OUT PULONG AddressSpace, OUT PPHYSICAL_ADDRESS TranslatedAddress ) /*++ Routine Description This function is used to translate bus addresses from legacy drivers. Arguments Context - Supplies a pointer to the interface context. This is actually the PDO for the root bus. BusAddress - Supplies the orginal address to be translated. Length - Supplies the length of the range to be translated. AddressSpace - Points to the location of of the address space type such as memory or I/O port. This value is updated by the translation. TranslatedAddress - Returns the translated address. Return Value Returns a boolean indicating if the operations was a success. --*/ { return HalTranslateBusAddress(Isa, 0, BusAddress, AddressSpace, TranslatedAddress); } PDMA_ADAPTER PcmciaGetDmaAdapter( IN PVOID Context, IN struct _DEVICE_DESCRIPTION *DeviceDescriptor, OUT PULONG NumberOfMapRegisters ) /*++ Routine Description Passes IoGetDmaAdapter calls to the parent. Arguments Context - Supplies a pointer to the interface context. This is actually the PDO. DeviceDescriptor - Supplies the device descriptor used to allocate the dma adapter object. NubmerOfMapRegisters - Returns the maximum number of map registers a device can allocate at one time. Return Value Returns a DMA adapter or NULL. --*/ { PDEVICE_OBJECT Pdo = Context; PPDO_EXTENSION pdoExtension; PFDO_EXTENSION fdoExtension; pdoExtension = Pdo->DeviceExtension; if (!pdoExtension || !pdoExtension->Socket || !pdoExtension->Socket->DeviceExtension) { return NULL; } // // Get the parent FDO extension // fdoExtension = pdoExtension->Socket->DeviceExtension; // // Pass the call on to the parent // return IoGetDmaAdapter(fdoExtension->Pdo, DeviceDescriptor, NumberOfMapRegisters); } VOID PcmciaNop( IN PVOID Context ) /*++ Routine Description Does nothing Arguments none Return Value none --*/ { PAGED_CODE(); UNREFERENCED_PARAMETER(Context); } NTSTATUS PcmciaMfEnumerateChild( IN PPDO_EXTENSION PdoExtension, IN ULONG Index, OUT PMF_DEVICE_INFO ChildInfo ) /*++ Routine Description Returns required enumeration information for the multifunction children of the given pc-card. This fills in the required info. for the child indicated, returing STATUS_NO_MORE_ENTRIES when there are no more children to be enumerated Arguments PdoExtension - Pointer to the device extension for the multifunction parent pc-card Index - Zero based index for the child to be enumerated ChildInfo - Caller allocated buffer in which the info about the child is returned. We may allocate additional buffers for each field in the supplied structure. This will be freed by the caller when no longer needed Return value STATUS_SUCCESS - supplied child info filled in & returned STATUS_NO_MORE_ENTRIES - No child of the given index exists. Caller is assumed to iteratively call this routine with index incremented from 0 upwards till this status value is returned STATUS_NO_SUCH_DEVICE - if the pc-card no longer exists --*/ { PSOCKET socket; PSOCKET_DATA socketData; PCONFIG_ENTRY configEntry, mfConfigEntry; ULONG i, currentIndex, count; NTSTATUS status; UCHAR iRes; PUCHAR idString; ANSI_STRING ansiString; PAGED_CODE(); DebugPrint((PCMCIA_DEBUG_INTERFACE, "PcmciaMfEnumerateChild: parent ext %x child index %x\n", PdoExtension, Index )); try { if (IsDeviceDeleted(PdoExtension) || IsDeviceLogicallyRemoved(PdoExtension)) { // // This pdo is deleted or marked to be deleted // status = STATUS_NO_SUCH_DEVICE; leave; } socket = PdoExtension->Socket; ASSERT (socket != NULL); RtlZeroMemory(ChildInfo, sizeof(MF_DEVICE_INFO)); if (Index >= socket->NumberOfFunctions) { // // info requested for a child which doesn't exist // status = STATUS_NO_MORE_ENTRIES; leave; } // // Fill in the name field // This is of the form ChildXX // where XX is the number of the function // Examples: Child00, Child01 etc. // idString = (PUCHAR) ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH); if (!idString) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } sprintf(idString, "Child%02x", Index); RtlInitAnsiString(&ansiString, idString); status = RtlAnsiStringToUnicodeString(&ChildInfo->Name, &ansiString, TRUE); ExFreePool(idString); if (!NT_SUCCESS(status)) { leave; } // // Get compatible ids // status = PcmciaGetCompatibleIds(PdoExtension->DeviceObject, Index, &ChildInfo->CompatibleID); if (!NT_SUCCESS(status)) { leave; } // // Get hardware ids // status = PcmciaGetHardwareIds(PdoExtension->DeviceObject, Index, &ChildInfo->HardwareID); if (!NT_SUCCESS(status)) { leave; } // // Fill in the resource map stuff // // Locate the socket data structure corresponding to this function for (socketData = PdoExtension->SocketData, i=0; (socketData != NULL) && (i != Index); socketData=socketData->Next, i++); if (!socketData) { // // this condition should never be encountered // ASSERT (FALSE); status = STATUS_NO_MORE_ENTRIES; leave; } if (!(socketData->NumberOfConfigEntries > 0)) { // // No resource map required // status = STATUS_SUCCESS; leave; } count = (socketData->MfNeedsIrq ? 1 : 0) + socketData->MfIoPortCount + socketData->MfMemoryCount; if (count == 0) { ASSERT(FALSE); // // No resource map required // status = STATUS_SUCCESS; leave; } // // Allocate resource map // ChildInfo->ResourceMap = ExAllocatePool(PagedPool, sizeof(MF_RESOURCE_MAP) + (count-1) * sizeof(UCHAR)); if (!ChildInfo->ResourceMap) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } ChildInfo->ResourceMap->Count = count; // // Compute the resource map indices // The config entry *already* contains fields (MfIrqResourceMapIndex, MfIoPortResourceMapIndex etc.) // which indicate the relative index of the resource requested for this function within the resource type. // We calculate the absolute index by adding up the number of instances of each resource type requested, // preceding the current resource type, to this relative index. // currentIndex = 0; // // Fill the irq map if there's one // if (socketData->MfNeedsIrq) { ChildInfo->ResourceMap->Resources[currentIndex++] = socketData->MfIrqResourceMapIndex; } // // Fill the i/o port map if there's one // if (socketData->MfIoPortCount) { for (iRes=0; iResMfIoPortCount; iRes++) { ChildInfo->ResourceMap->Resources[currentIndex++] = socketData->MfIoPortResourceMapIndex + iRes; } } // // Fill the memory request map if there's one // if (socketData->MfMemoryCount) { for (iRes=0; iResMfMemoryCount; iRes++) { ChildInfo->ResourceMap->Resources[currentIndex++] = socketData->MfMemoryResourceMapIndex + iRes; } } status = STATUS_SUCCESS; } finally { if (!NT_SUCCESS(status)) { // // Free up all the allocated buffers // if (ChildInfo->Name.Buffer) { ExFreePool(ChildInfo->Name.Buffer); } if (ChildInfo->CompatibleID.Buffer) { ExFreePool(ChildInfo->CompatibleID.Buffer); } if (ChildInfo->HardwareID.Buffer) { ExFreePool(ChildInfo->HardwareID.Buffer); } if (ChildInfo->ResourceMap) { ExFreePool(ChildInfo->ResourceMap); } if (ChildInfo->VaryingResourceMap) { ExFreePool(ChildInfo->ResourceMap); } } } return status; } NTSTATUS PcmciaGetInterface( IN PDEVICE_OBJECT DeviceObject, IN CONST GUID *pGuid, IN USHORT sizeofInterface, OUT PINTERFACE pInterface ) /* Routine Description Gets the interface exported by PCI for enumerating 32-bit cardbus cards, which appear as regular PCI devices. This interface will be used to respond during subsequent enumeration requests from PnP to invoke PCI to enumerate the cards. Arguments Pdo - Pointer to physical device object for the cardbus controller PciCardBusInterface - Pointer to the PCI-Cardbus interface will be returned in this variable Return Value Status */ { KEVENT event; PIRP irp; NTSTATUS status; IO_STATUS_BLOCK statusBlock; PIO_STACK_LOCATION irpSp; PAGED_CODE(); KeInitializeEvent (&event, NotificationEvent, FALSE); irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, DeviceObject, NULL, 0, 0, &event, &statusBlock ); irp->IoStatus.Status = STATUS_NOT_SUPPORTED ; irp->IoStatus.Information = 0; irpSp = IoGetNextIrpStackLocation(irp); irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE; irpSp->Parameters.QueryInterface.InterfaceType= pGuid; irpSp->Parameters.QueryInterface.Size = sizeofInterface; irpSp->Parameters.QueryInterface.Version = 1; irpSp->Parameters.QueryInterface.Interface = pInterface; status = IoCallDriver(DeviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = statusBlock.Status; } if (!NT_SUCCESS(status)) { DebugPrint((PCMCIA_DEBUG_INFO, "GetInterface failed with status %x\n", status)); } return status; } NTSTATUS PcmciaUpdateInterruptLine( IN PPDO_EXTENSION PdoExtension, IN PFDO_EXTENSION FdoExtension ) /* Routine Description This routine uses the PCI Irq Routing interface to update the raw interrupt line of a cardbus card. This is done in order to allow cardbus cards to run on non-acpi machines without pci irq routing, as long as the bios supplies the interrupt for the cardbus controller. Arguments PdoExtension - Pointer to the extension for the cardbus card FdoExtension - Pointer to the extension for the cardbus controller Return Value Status */ { PAGED_CODE(); if (!IsDeviceFlagSet(FdoExtension, PCMCIA_INT_ROUTE_INTERFACE)) { return STATUS_UNSUCCESSFUL; } if (FdoExtension->Configuration.Interrupt.u.Interrupt.Vector == 0) { return STATUS_UNSUCCESSFUL; } (FdoExtension->PciIntRouteInterface.UpdateInterruptLine)(PdoExtension->PciPdo, (UCHAR) FdoExtension->Configuration.Interrupt.u.Interrupt.Vector); return STATUS_SUCCESS; }