| /** @file | |
| Collect Sio information from Native EFI Drivers. | |
| Sio is floppy, parallel, serial, ... hardware | |
| Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions | |
| of the BSD License which accompanies this distribution. The | |
| full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #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 ((EFI_D_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; | |
| } |