/** @file Collect Sio information from Native EFI Drivers. Sio is floppy, parallel, serial, ... hardware Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "LegacyBiosInterface.h" /** Collect EFI Info about legacy devices through Super IO interface. @param SioPtr Pointer to SIO data. @retval EFI_SUCCESS When SIO data is got successfully. @retval EFI_NOT_FOUND When ISA IO interface is absent. **/ EFI_STATUS LegacyBiosBuildSioDataFromSio ( IN DEVICE_PRODUCER_DATA_HEADER *SioPtr ) { EFI_STATUS Status; DEVICE_PRODUCER_SERIAL *SioSerial; DEVICE_PRODUCER_PARALLEL *SioParallel; DEVICE_PRODUCER_FLOPPY *SioFloppy; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; UINTN ChildIndex; EFI_SIO_PROTOCOL *Sio; ACPI_RESOURCE_HEADER_PTR Resources; EFI_ACPI_IO_PORT_DESCRIPTOR *IoResource; EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIoResource; EFI_ACPI_DMA_DESCRIPTOR *DmaResource; EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *IrqResource; UINT16 Address; UINT8 Dma; UINT8 Irq; UINTN EntryCount; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_SERIAL_IO_PROTOCOL *SerialIo; EFI_DEVICE_PATH_PROTOCOL *DevicePath; ACPI_HID_DEVICE_PATH *Acpi; // // Get the list of ISA controllers in the system // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSioProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Collect legacy information from each of the ISA controllers in the system // for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSioProtocolGuid, (VOID **) &Sio); if (EFI_ERROR (Status)) { continue; } Address = MAX_UINT16; Dma = MAX_UINT8; Irq = MAX_UINT8; Status = Sio->GetResources (Sio, &Resources); if (!EFI_ERROR (Status)) { // // Get the base address information from ACPI resource descriptor. // while (Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) { switch (Resources.SmallHeader->Byte) { case ACPI_IO_PORT_DESCRIPTOR: IoResource = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; Address = IoResource->BaseAddressMin; break; case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR: FixedIoResource = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; Address = FixedIoResource->BaseAddress; break; case ACPI_DMA_DESCRIPTOR: DmaResource = (EFI_ACPI_DMA_DESCRIPTOR *) Resources.SmallHeader; Dma = (UINT8) LowBitSet32 (DmaResource->ChannelMask); break; case ACPI_IRQ_DESCRIPTOR: case ACPI_IRQ_NOFLAG_DESCRIPTOR: IrqResource = (EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *) Resources.SmallHeader; Irq = (UINT8) LowBitSet32 (IrqResource->Mask); break; default: break; } if (Resources.SmallHeader->Bits.Type == 0) { Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader + Resources.SmallHeader->Bits.Length + sizeof (*Resources.SmallHeader)); } else { Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader + Resources.LargeHeader->Length + sizeof (*Resources.LargeHeader)); } } } DEBUG ((DEBUG_INFO, "LegacySio: Address/Dma/Irq = %x/%d/%d\n", Address, Dma, Irq)); DevicePath = DevicePathFromHandle (HandleBuffer[Index]); if (DevicePath == NULL) { continue; } Acpi = NULL; while (!IsDevicePathEnd (DevicePath)) { Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; DevicePath = NextDevicePathNode (DevicePath); } if ((Acpi == NULL) || (DevicePathType (Acpi) != ACPI_DEVICE_PATH) || ((DevicePathSubType (Acpi) != ACPI_DP) && (DevicePathSubType (Acpi) != ACPI_EXTENDED_DP)) ) { continue; } // // See if this is an ISA serial port // // Ignore DMA resource since it is always returned NULL // if (Acpi->HID == EISA_PNP_ID (0x500) || Acpi->HID == EISA_PNP_ID (0x501)) { if (Acpi->UID < 4 && Address != MAX_UINT16 && Irq != MAX_UINT8) { // // Get the handle of the child device that has opened the Super I/O Protocol // Status = gBS->OpenProtocolInformation ( HandleBuffer[Index], &gEfiSioProtocolGuid, &OpenInfoBuffer, &EntryCount ); if (EFI_ERROR (Status)) { continue; } for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) { if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo); if (!EFI_ERROR (Status)) { SioSerial = &SioPtr->Serial[Acpi->UID]; SioSerial->Address = Address; SioSerial->Irq = Irq; SioSerial->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF; break; } } } FreePool (OpenInfoBuffer); } } // // See if this is an ISA parallel port // // Ignore DMA resource since it is always returned NULL, port // only used in output mode. // if (Acpi->HID == EISA_PNP_ID (0x400) || Acpi->HID == EISA_PNP_ID (0x401)) { if (Acpi->UID < 3 && Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) { SioParallel = &SioPtr->Parallel[Acpi->UID]; SioParallel->Address = Address; SioParallel->Irq = Irq; SioParallel->Dma = Dma; SioParallel->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY; } } // // See if this is an ISA floppy controller // if (Acpi->HID == EISA_PNP_ID (0x604)) { if (Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) { Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); if (!EFI_ERROR (Status)) { SioFloppy = &SioPtr->Floppy; SioFloppy->Address = Address; SioFloppy->Irq = Irq; SioFloppy->Dma = Dma; SioFloppy->NumberOfFloppy++; } } } // // See if this is a mouse // Always set mouse found so USB hot plug will work // // Ignore lower byte of HID. Pnp0fxx is any type of mouse. // // Hid = ResourceList->Device.HID & 0xff00ffff; // PnpId = EISA_PNP_ID(0x0f00); // if (Hid == PnpId) { // if (ResourceList->Device.UID == 1) { // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer); // if (!EFI_ERROR (Status)) { // SioPtr->MousePresent = 0x01; // // } // } // } // } FreePool (HandleBuffer); return EFI_SUCCESS; } /** Collect EFI Info about legacy devices through ISA IO interface. @param SioPtr Pointer to SIO data. @retval EFI_SUCCESS When SIO data is got successfully. @retval EFI_NOT_FOUND When ISA IO interface is absent. **/ EFI_STATUS LegacyBiosBuildSioDataFromIsaIo ( IN DEVICE_PRODUCER_DATA_HEADER *SioPtr ) { EFI_STATUS Status; DEVICE_PRODUCER_SERIAL *SioSerial; DEVICE_PRODUCER_PARALLEL *SioParallel; DEVICE_PRODUCER_FLOPPY *SioFloppy; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; UINTN ResourceIndex; UINTN ChildIndex; EFI_ISA_IO_PROTOCOL *IsaIo; EFI_ISA_ACPI_RESOURCE_LIST *ResourceList; EFI_ISA_ACPI_RESOURCE *IoResource; EFI_ISA_ACPI_RESOURCE *DmaResource; EFI_ISA_ACPI_RESOURCE *InterruptResource; UINTN EntryCount; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_SERIAL_IO_PROTOCOL *SerialIo; // // Get the list of ISA controllers in the system // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiIsaIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Collect legacy information from each of the ISA controllers in the system // for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo); if (EFI_ERROR (Status)) { continue; } ResourceList = IsaIo->ResourceList; if (ResourceList == NULL) { continue; } // // Collect the resource types neededto fill in the SIO data structure // IoResource = NULL; DmaResource = NULL; InterruptResource = NULL; for (ResourceIndex = 0; ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList; ResourceIndex++ ) { switch (ResourceList->ResourceItem[ResourceIndex].Type) { case EfiIsaAcpiResourceIo: IoResource = &ResourceList->ResourceItem[ResourceIndex]; break; case EfiIsaAcpiResourceMemory: break; case EfiIsaAcpiResourceDma: DmaResource = &ResourceList->ResourceItem[ResourceIndex]; break; case EfiIsaAcpiResourceInterrupt: InterruptResource = &ResourceList->ResourceItem[ResourceIndex]; break; default: break; } } // // See if this is an ISA serial port // // Ignore DMA resource since it is always returned NULL // if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) { if (ResourceList->Device.UID <= 3 && IoResource != NULL && InterruptResource != NULL ) { // // Get the handle of the child device that has opened the ISA I/O Protocol // Status = gBS->OpenProtocolInformation ( HandleBuffer[Index], &gEfiIsaIoProtocolGuid, &OpenInfoBuffer, &EntryCount ); if (EFI_ERROR (Status)) { continue; } // // We want resource for legacy even if no 32-bit driver installed // for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) { if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo); if (!EFI_ERROR (Status)) { SioSerial = &SioPtr->Serial[ResourceList->Device.UID]; SioSerial->Address = (UINT16) IoResource->StartRange; SioSerial->Irq = (UINT8) InterruptResource->StartRange; SioSerial->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF; break; } } } FreePool (OpenInfoBuffer); } } // // See if this is an ISA parallel port // // Ignore DMA resource since it is always returned NULL, port // only used in output mode. // if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) { if (ResourceList->Device.UID <= 2 && IoResource != NULL && InterruptResource != NULL && DmaResource != NULL ) { SioParallel = &SioPtr->Parallel[ResourceList->Device.UID]; SioParallel->Address = (UINT16) IoResource->StartRange; SioParallel->Irq = (UINT8) InterruptResource->StartRange; SioParallel->Dma = (UINT8) DmaResource->StartRange; SioParallel->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY; } } // // See if this is an ISA floppy controller // if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) { if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) { Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); if (!EFI_ERROR (Status)) { SioFloppy = &SioPtr->Floppy; SioFloppy->Address = (UINT16) IoResource->StartRange; SioFloppy->Irq = (UINT8) InterruptResource->StartRange; SioFloppy->Dma = (UINT8) DmaResource->StartRange; SioFloppy->NumberOfFloppy++; } } } // // See if this is a mouse // Always set mouse found so USB hot plug will work // // Ignore lower byte of HID. Pnp0fxx is any type of mouse. // // Hid = ResourceList->Device.HID & 0xff00ffff; // PnpId = EISA_PNP_ID(0x0f00); // if (Hid == PnpId) { // if (ResourceList->Device.UID == 1) { // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer); // if (!EFI_ERROR (Status)) { // SioPtr->MousePresent = 0x01; // // } // } // } // } FreePool (HandleBuffer); return EFI_SUCCESS; } /** Collect EFI Info about legacy devices. @param Private Legacy BIOS Instance data @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosBuildSioData ( IN LEGACY_BIOS_INSTANCE *Private ) { EFI_STATUS Status; DEVICE_PRODUCER_DATA_HEADER *SioPtr; EFI_HANDLE IsaBusController; UINTN HandleCount; EFI_HANDLE *HandleBuffer; // // Get the pointer to the SIO data structure // SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData; // // Zero the data in the SIO data structure // gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0); // // Find the ISA Bus Controller used for legacy // Status = Private->LegacyBiosPlatform->GetPlatformHandle ( Private->LegacyBiosPlatform, EfiGetPlatformIsaBusHandle, 0, &HandleBuffer, &HandleCount, NULL ); IsaBusController = HandleBuffer[0]; if (!EFI_ERROR (Status)) { // // Force ISA Bus Controller to produce all ISA devices // gBS->ConnectController (IsaBusController, NULL, NULL, TRUE); } Status = LegacyBiosBuildSioDataFromIsaIo (SioPtr); if (EFI_ERROR (Status)) { LegacyBiosBuildSioDataFromSio (SioPtr); } return EFI_SUCCESS; }