/*++ Copyright (c) 1989 Microsoft Corporation Module Name: eisac.c Abstract: This module implements routines to get EISA configuration information. Author: Shie-Lin Tzong (shielint) 18-Jan-1992 Environment: 16-bit real mode. Revision History: --*/ #include "hwdetect.h" #include "string.h" #if defined(NEC_98) #else // PC98 typedef EISA_PORT_CONFIGURATION far *FPEISA_PORT_CONFIGURATION; extern CM_EISA_FUNCTION_INFORMATION FunctionInformation; VOID GetEisaConfigurationData ( FPVOID Buffer, FPULONG Size ) /*++ Routine Description: This routine collects all the eisa slot information, function information and stores it in the caller supplied Buffer and returns the size of the data. Arguments: Buffer - A pointer to a PVOID to recieve the address of configuration data. Size - a pointer to a ULONG to receive the size of the configuration data. Return Value: None. --*/ { UCHAR Slot=0; UCHAR Function=0, SlotFunctions = 0, ReturnCode; EISA_SLOT_INFORMATION SlotInformation; FPUCHAR ConfigurationData, CurrentData; FPEISA_SLOT_INFORMATION FarSlotInformation; ULONG TotalSize = DATA_HEADER_SIZE; BOOLEAN Overflowed = FALSE; HwGetEisaSlotInformation(&SlotInformation, Slot); TotalSize += sizeof(EISA_SLOT_INFORMATION); ConfigurationData = (FPVOID)HwAllocateHeap(TotalSize, FALSE); CurrentData = ConfigurationData + DATA_HEADER_SIZE; _fmemcpy(CurrentData, (FPVOID)&SlotInformation, sizeof(EISA_SLOT_INFORMATION)); FarSlotInformation = (FPEISA_SLOT_INFORMATION)CurrentData; while (SlotInformation.ReturnCode != EISA_INVALID_SLOT) { // // Ensure that the slot is not empty and collect all the function // information for the slot. // if (SlotInformation.ReturnCode != EISA_EMPTY_SLOT) { while (SlotInformation.NumberFunctions > Function) { ReturnCode = HwGetEisaFunctionInformation( &FunctionInformation, Slot, Function); Function++; // // if function call succeeds and the function contains usefull // information or this is the last function for the slot and // there is no function information collected for the slot, we // will save this function information to our heap. // if (!ReturnCode) { if (((FunctionInformation.FunctionFlags & 0x7f) != 0) || (SlotInformation.NumberFunctions == Function && SlotFunctions == 0)) { CurrentData = (FPVOID)HwAllocateHeap( sizeof(EISA_FUNCTION_INFORMATION), FALSE); if (CurrentData == NULL) { Overflowed = TRUE; break; } SlotFunctions++; TotalSize += sizeof(EISA_FUNCTION_INFORMATION); _fmemcpy(CurrentData, (FPVOID)&FunctionInformation, sizeof(EISA_FUNCTION_INFORMATION)); } } } FarSlotInformation->NumberFunctions = SlotFunctions; } if (Overflowed) { break; } Slot++; Function = 0; HwGetEisaSlotInformation(&SlotInformation, Slot); CurrentData = (FPVOID)HwAllocateHeap( sizeof(EISA_SLOT_INFORMATION), FALSE); if (CurrentData == NULL) { Overflowed = TRUE; break; } TotalSize += sizeof(EISA_SLOT_INFORMATION); _fmemcpy(CurrentData, (FPVOID)&SlotInformation, sizeof(EISA_SLOT_INFORMATION)); FarSlotInformation = (FPEISA_SLOT_INFORMATION)CurrentData; SlotFunctions = 0; } // // Free the last EISA_SLOT_INFORMATION space which contains the slot // information for IVALID SLOT // if (Overflowed != TRUE) { HwFreeHeap(sizeof(EISA_SLOT_INFORMATION)); TotalSize -= sizeof(EISA_SLOT_INFORMATION); } // // Check if we got any EISA information. If nothing, we release // the space for data header and return. // if (TotalSize == DATA_HEADER_SIZE) { HwFreeHeap(DATA_HEADER_SIZE); *(FPULONG)Buffer = (ULONG)0; *Size = (ULONG)0; } else { HwSetUpFreeFormDataHeader((FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData, 0, 0, 0, TotalSize - DATA_HEADER_SIZE ); *(FPULONG)Buffer = (ULONG)ConfigurationData; *Size = TotalSize; } } BOOLEAN HwEisaGetIrqFromPort ( USHORT Port, PUCHAR Irq, PUCHAR TriggerMethod ) /*++ Routine Description: This routine scans EISA configuration data to match the I/O port address. The IRQ information is returned from the matched EISA function information. Arguments: Port - The I/O port address to scan for. Irq - Supplies a pointer to a variable to receive the irq information. TriggerMethod - Supplies a pointer to a variable to receive the EISA interrupt trigger method. Return Value: TRUE - if the Irq information is found. Otherwise a value of FALSE is returned. --*/ { UCHAR Function, i, j; FPEISA_SLOT_INFORMATION SlotInformation; FPEISA_FUNCTION_INFORMATION Buffer; UCHAR FunctionFlags; ULONG SizeToScan = 0L; EISA_PORT_CONFIGURATION PortConfig; EISA_IRQ_DESCRIPTOR IrqConfig; SlotInformation = (FPEISA_SLOT_INFORMATION)HwEisaConfigurationData; // // Scan through all the EISA configuration data. // while (SizeToScan < HwEisaConfigurationSize) { if (SlotInformation->ReturnCode != EISA_EMPTY_SLOT) { // // Make sure this slot contains PORT_RANGE and IRQ information. // if ((SlotInformation->FunctionInformation & EISA_HAS_PORT_RANGE) && (SlotInformation->FunctionInformation & EISA_HAS_IRQ_ENTRY)) { Buffer = (FPEISA_FUNCTION_INFORMATION)(SlotInformation + 1); // // For each function of the slot, if it contains both the IRQ // and PORT information, we then check for its PORT address. // for (Function = 0; Function < SlotInformation->NumberFunctions; Function++) { FunctionFlags = Buffer->FunctionFlags; if ((FunctionFlags & EISA_HAS_IRQ_ENTRY) && (FunctionFlags & EISA_HAS_PORT_RANGE)) { for (i = 0; i < 20 ; i++ ) { PortConfig = Buffer->EisaPort[i]; if ((Port >= PortConfig.PortAddress) && (Port <= (PortConfig.PortAddress + PortConfig.Configuration.NumberPorts))) { // // If there is only one IRQ entry, that's the // one we want. (This is the normal case and // correct usage of EISA function data.) Otherwise, // we try to get the irq from the same index // number as port entry. (This is ALR's incorrect // way of packing functions into one function // data.) // IrqConfig = Buffer->EisaIrq[0].ConfigurationByte; if (IrqConfig.MoreEntries == 0) { *Irq = IrqConfig.Interrupt; *TriggerMethod = IrqConfig.LevelTriggered; return(TRUE); } else if (i >= 7) { return(FALSE); } for (j = 0; j <= i; j++) { if (j == i) { *Irq = IrqConfig.Interrupt; *TriggerMethod = IrqConfig.LevelTriggered; return(TRUE); } if (!IrqConfig.MoreEntries) { return(FALSE); } IrqConfig = Buffer->EisaIrq[j+1].ConfigurationByte; } return(FALSE); } if (!PortConfig.Configuration.MoreEntries) { break; } } } Buffer++; } } // // Move on to next slot // SizeToScan += sizeof(EISA_SLOT_INFORMATION) + sizeof(EISA_FUNCTION_INFORMATION) * SlotInformation->NumberFunctions; SlotInformation = (FPEISA_SLOT_INFORMATION)(HwEisaConfigurationData + SizeToScan); } else { // // This is a empty slot. We simply skip it. // SizeToScan += sizeof(EISA_SLOT_INFORMATION); SlotInformation++; } } return(FALSE); } #endif // PC98