Home | History | Annotate | Download | only in LegacyBiosDxe
      1 /** @file
      2   Collect Sio information from Native EFI Drivers.
      3   Sio is floppy, parallel, serial, ... hardware
      4 
      5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions
      9 of the BSD License which accompanies this distribution.  The
     10 full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "LegacyBiosInterface.h"
     19 
     20 /**
     21   Collect EFI Info about legacy devices through Super IO interface.
     22 
     23   @param  SioPtr       Pointer to SIO data.
     24 
     25   @retval EFI_SUCCESS   When SIO data is got successfully.
     26   @retval EFI_NOT_FOUND When ISA IO interface is absent.
     27 
     28 **/
     29 EFI_STATUS
     30 LegacyBiosBuildSioDataFromSio (
     31   IN DEVICE_PRODUCER_DATA_HEADER             *SioPtr
     32   )
     33 {
     34   EFI_STATUS                                 Status;
     35   DEVICE_PRODUCER_SERIAL                     *SioSerial;
     36   DEVICE_PRODUCER_PARALLEL                   *SioParallel;
     37   DEVICE_PRODUCER_FLOPPY                     *SioFloppy;
     38   UINTN                                      HandleCount;
     39   EFI_HANDLE                                 *HandleBuffer;
     40   UINTN                                      Index;
     41   UINTN                                      ChildIndex;
     42   EFI_SIO_PROTOCOL                           *Sio;
     43   ACPI_RESOURCE_HEADER_PTR                   Resources;
     44   EFI_ACPI_IO_PORT_DESCRIPTOR                *IoResource;
     45   EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIoResource;
     46   EFI_ACPI_DMA_DESCRIPTOR                    *DmaResource;
     47   EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR             *IrqResource;
     48   UINT16                                     Address;
     49   UINT8                                      Dma;
     50   UINT8                                      Irq;
     51   UINTN                                      EntryCount;
     52   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY        *OpenInfoBuffer;
     53   EFI_BLOCK_IO_PROTOCOL                      *BlockIo;
     54   EFI_SERIAL_IO_PROTOCOL                     *SerialIo;
     55   EFI_DEVICE_PATH_PROTOCOL                   *DevicePath;
     56   ACPI_HID_DEVICE_PATH                       *Acpi;
     57 
     58   //
     59   // Get the list of ISA controllers in the system
     60   //
     61   Status = gBS->LocateHandleBuffer (
     62                   ByProtocol,
     63                   &gEfiSioProtocolGuid,
     64                   NULL,
     65                   &HandleCount,
     66                   &HandleBuffer
     67                   );
     68   if (EFI_ERROR (Status)) {
     69     return EFI_NOT_FOUND;
     70   }
     71   //
     72   // Collect legacy information from each of the ISA controllers in the system
     73   //
     74   for (Index = 0; Index < HandleCount; Index++) {
     75     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSioProtocolGuid, (VOID **) &Sio);
     76     if (EFI_ERROR (Status)) {
     77       continue;
     78     }
     79 
     80     Address = MAX_UINT16;
     81     Dma     = MAX_UINT8;
     82     Irq     = MAX_UINT8;
     83     Status = Sio->GetResources (Sio, &Resources);
     84     if (!EFI_ERROR (Status)) {
     85       //
     86       // Get the base address information from ACPI resource descriptor.
     87       //
     88       while (Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
     89         switch (Resources.SmallHeader->Byte) {
     90         case ACPI_IO_PORT_DESCRIPTOR:
     91           IoResource = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
     92           Address = IoResource->BaseAddressMin;
     93           break;
     94 
     95         case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
     96           FixedIoResource = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
     97           Address = FixedIoResource->BaseAddress;
     98           break;
     99 
    100         case ACPI_DMA_DESCRIPTOR:
    101           DmaResource = (EFI_ACPI_DMA_DESCRIPTOR *) Resources.SmallHeader;
    102           Dma = (UINT8) LowBitSet32 (DmaResource->ChannelMask);
    103           break;
    104 
    105         case ACPI_IRQ_DESCRIPTOR:
    106         case ACPI_IRQ_NOFLAG_DESCRIPTOR:
    107           IrqResource = (EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *) Resources.SmallHeader;
    108           Irq = (UINT8) LowBitSet32 (IrqResource->Mask);
    109           break;
    110 
    111         default:
    112           break;
    113         }
    114 
    115         if (Resources.SmallHeader->Bits.Type == 0) {
    116           Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader
    117                                                                   + Resources.SmallHeader->Bits.Length
    118                                                                   + sizeof (*Resources.SmallHeader));
    119         } else {
    120           Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader
    121                                                                   + Resources.LargeHeader->Length
    122                                                                   + sizeof (*Resources.LargeHeader));
    123         }
    124       }
    125     }
    126 
    127     DEBUG ((EFI_D_INFO, "LegacySio: Address/Dma/Irq = %x/%d/%d\n", Address, Dma, Irq));
    128 
    129     DevicePath = DevicePathFromHandle (HandleBuffer[Index]);
    130     if (DevicePath == NULL) {
    131       continue;
    132     }
    133 
    134     Acpi = NULL;
    135     while (!IsDevicePathEnd (DevicePath)) {
    136       Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
    137       DevicePath = NextDevicePathNode (DevicePath);
    138     }
    139 
    140     if ((Acpi == NULL) || (DevicePathType (Acpi) != ACPI_DEVICE_PATH) ||
    141         ((DevicePathSubType (Acpi) != ACPI_DP) && (DevicePathSubType (Acpi) != ACPI_EXTENDED_DP))
    142         ) {
    143       continue;
    144     }
    145 
    146     //
    147     // See if this is an ISA serial port
    148     //
    149     // Ignore DMA resource since it is always returned NULL
    150     //
    151     if (Acpi->HID == EISA_PNP_ID (0x500) || Acpi->HID == EISA_PNP_ID (0x501)) {
    152 
    153       if (Acpi->UID < 4 && Address != MAX_UINT16 && Irq != MAX_UINT8) {
    154         //
    155         // Get the handle of the child device that has opened the Super I/O Protocol
    156         //
    157         Status = gBS->OpenProtocolInformation (
    158                         HandleBuffer[Index],
    159                         &gEfiSioProtocolGuid,
    160                         &OpenInfoBuffer,
    161                         &EntryCount
    162                         );
    163         if (EFI_ERROR (Status)) {
    164           continue;
    165         }
    166         for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
    167           if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
    168             Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo);
    169             if (!EFI_ERROR (Status)) {
    170               SioSerial           = &SioPtr->Serial[Acpi->UID];
    171               SioSerial->Address  = Address;
    172               SioSerial->Irq      = Irq;
    173               SioSerial->Mode     = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
    174               break;
    175             }
    176           }
    177         }
    178 
    179         FreePool (OpenInfoBuffer);
    180       }
    181     }
    182     //
    183     // See if this is an ISA parallel port
    184     //
    185     // Ignore DMA resource since it is always returned NULL, port
    186     // only used in output mode.
    187     //
    188     if (Acpi->HID == EISA_PNP_ID (0x400) || Acpi->HID == EISA_PNP_ID (0x401)) {
    189       if (Acpi->UID < 3 && Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) {
    190         SioParallel           = &SioPtr->Parallel[Acpi->UID];
    191         SioParallel->Address  = Address;
    192         SioParallel->Irq      = Irq;
    193         SioParallel->Dma      = Dma;
    194         SioParallel->Mode     = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
    195       }
    196     }
    197     //
    198     // See if this is an ISA floppy controller
    199     //
    200     if (Acpi->HID == EISA_PNP_ID (0x604)) {
    201       if (Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) {
    202         Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
    203         if (!EFI_ERROR (Status)) {
    204           SioFloppy           = &SioPtr->Floppy;
    205           SioFloppy->Address  = Address;
    206           SioFloppy->Irq      = Irq;
    207           SioFloppy->Dma      = Dma;
    208           SioFloppy->NumberOfFloppy++;
    209         }
    210       }
    211     }
    212     //
    213     // See if this is a mouse
    214     // Always set mouse found so USB hot plug will work
    215     //
    216     // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
    217     //
    218     //    Hid = ResourceList->Device.HID & 0xff00ffff;
    219     //    PnpId = EISA_PNP_ID(0x0f00);
    220     //    if (Hid == PnpId) {
    221     //      if (ResourceList->Device.UID == 1) {
    222     //        Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
    223     //      if (!EFI_ERROR (Status)) {
    224     //
    225     SioPtr->MousePresent = 0x01;
    226     //
    227     //        }
    228     //      }
    229     //    }
    230     //
    231   }
    232 
    233   FreePool (HandleBuffer);
    234   return EFI_SUCCESS;
    235 
    236 }
    237 
    238 /**
    239   Collect EFI Info about legacy devices through ISA IO interface.
    240 
    241   @param  SioPtr       Pointer to SIO data.
    242 
    243   @retval EFI_SUCCESS   When SIO data is got successfully.
    244   @retval EFI_NOT_FOUND When ISA IO interface is absent.
    245 
    246 **/
    247 EFI_STATUS
    248 LegacyBiosBuildSioDataFromIsaIo (
    249   IN DEVICE_PRODUCER_DATA_HEADER      *SioPtr
    250   )
    251 {
    252   EFI_STATUS                          Status;
    253   DEVICE_PRODUCER_SERIAL              *SioSerial;
    254   DEVICE_PRODUCER_PARALLEL            *SioParallel;
    255   DEVICE_PRODUCER_FLOPPY              *SioFloppy;
    256   UINTN                               HandleCount;
    257   EFI_HANDLE                          *HandleBuffer;
    258   UINTN                               Index;
    259   UINTN                               ResourceIndex;
    260   UINTN                               ChildIndex;
    261   EFI_ISA_IO_PROTOCOL                 *IsaIo;
    262   EFI_ISA_ACPI_RESOURCE_LIST          *ResourceList;
    263   EFI_ISA_ACPI_RESOURCE               *IoResource;
    264   EFI_ISA_ACPI_RESOURCE               *DmaResource;
    265   EFI_ISA_ACPI_RESOURCE               *InterruptResource;
    266   UINTN                               EntryCount;
    267   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
    268   EFI_BLOCK_IO_PROTOCOL               *BlockIo;
    269   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
    270 
    271   //
    272   // Get the list of ISA controllers in the system
    273   //
    274   Status = gBS->LocateHandleBuffer (
    275                   ByProtocol,
    276                   &gEfiIsaIoProtocolGuid,
    277                   NULL,
    278                   &HandleCount,
    279                   &HandleBuffer
    280                   );
    281   if (EFI_ERROR (Status)) {
    282     return EFI_NOT_FOUND;
    283   }
    284   //
    285   // Collect legacy information from each of the ISA controllers in the system
    286   //
    287   for (Index = 0; Index < HandleCount; Index++) {
    288 
    289     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo);
    290     if (EFI_ERROR (Status)) {
    291       continue;
    292     }
    293 
    294     ResourceList = IsaIo->ResourceList;
    295 
    296     if (ResourceList == NULL) {
    297       continue;
    298     }
    299     //
    300     // Collect the resource types neededto fill in the SIO data structure
    301     //
    302     IoResource        = NULL;
    303     DmaResource       = NULL;
    304     InterruptResource = NULL;
    305     for (ResourceIndex = 0;
    306          ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList;
    307          ResourceIndex++
    308         ) {
    309       switch (ResourceList->ResourceItem[ResourceIndex].Type) {
    310       case EfiIsaAcpiResourceIo:
    311         IoResource = &ResourceList->ResourceItem[ResourceIndex];
    312         break;
    313 
    314       case EfiIsaAcpiResourceMemory:
    315         break;
    316 
    317       case EfiIsaAcpiResourceDma:
    318         DmaResource = &ResourceList->ResourceItem[ResourceIndex];
    319         break;
    320 
    321       case EfiIsaAcpiResourceInterrupt:
    322         InterruptResource = &ResourceList->ResourceItem[ResourceIndex];
    323         break;
    324 
    325       default:
    326         break;
    327       }
    328     }
    329     //
    330     // See if this is an ISA serial port
    331     //
    332     // Ignore DMA resource since it is always returned NULL
    333     //
    334     if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) {
    335 
    336       if (ResourceList->Device.UID <= 3 &&
    337           IoResource != NULL &&
    338           InterruptResource != NULL
    339           ) {
    340         //
    341         // Get the handle of the child device that has opened the ISA I/O Protocol
    342         //
    343         Status = gBS->OpenProtocolInformation (
    344                         HandleBuffer[Index],
    345                         &gEfiIsaIoProtocolGuid,
    346                         &OpenInfoBuffer,
    347                         &EntryCount
    348                         );
    349         if (EFI_ERROR (Status)) {
    350           continue;
    351         }
    352         //
    353         // We want resource for legacy even if no 32-bit driver installed
    354         //
    355         for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
    356           if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
    357             Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo);
    358             if (!EFI_ERROR (Status)) {
    359               SioSerial           = &SioPtr->Serial[ResourceList->Device.UID];
    360               SioSerial->Address  = (UINT16) IoResource->StartRange;
    361               SioSerial->Irq      = (UINT8) InterruptResource->StartRange;
    362               SioSerial->Mode     = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
    363               break;
    364             }
    365           }
    366         }
    367 
    368         FreePool (OpenInfoBuffer);
    369       }
    370     }
    371     //
    372     // See if this is an ISA parallel port
    373     //
    374     // Ignore DMA resource since it is always returned NULL, port
    375     // only used in output mode.
    376     //
    377     if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) {
    378       if (ResourceList->Device.UID <= 2 &&
    379           IoResource != NULL &&
    380           InterruptResource != NULL &&
    381           DmaResource != NULL
    382           ) {
    383         SioParallel           = &SioPtr->Parallel[ResourceList->Device.UID];
    384         SioParallel->Address  = (UINT16) IoResource->StartRange;
    385         SioParallel->Irq      = (UINT8) InterruptResource->StartRange;
    386         SioParallel->Dma      = (UINT8) DmaResource->StartRange;
    387         SioParallel->Mode     = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
    388       }
    389     }
    390     //
    391     // See if this is an ISA floppy controller
    392     //
    393     if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) {
    394       if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) {
    395         Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
    396         if (!EFI_ERROR (Status)) {
    397           SioFloppy           = &SioPtr->Floppy;
    398           SioFloppy->Address  = (UINT16) IoResource->StartRange;
    399           SioFloppy->Irq      = (UINT8) InterruptResource->StartRange;
    400           SioFloppy->Dma      = (UINT8) DmaResource->StartRange;
    401           SioFloppy->NumberOfFloppy++;
    402         }
    403       }
    404     }
    405     //
    406     // See if this is a mouse
    407     // Always set mouse found so USB hot plug will work
    408     //
    409     // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
    410     //
    411     //    Hid = ResourceList->Device.HID & 0xff00ffff;
    412     //    PnpId = EISA_PNP_ID(0x0f00);
    413     //    if (Hid == PnpId) {
    414     //      if (ResourceList->Device.UID == 1) {
    415     //        Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
    416     //      if (!EFI_ERROR (Status)) {
    417     //
    418     SioPtr->MousePresent = 0x01;
    419     //
    420     //        }
    421     //      }
    422     //    }
    423     //
    424   }
    425 
    426   FreePool (HandleBuffer);
    427   return EFI_SUCCESS;
    428 }
    429 
    430 /**
    431   Collect EFI Info about legacy devices.
    432 
    433   @param  Private      Legacy BIOS Instance data
    434 
    435   @retval EFI_SUCCESS  It should always work.
    436 
    437 **/
    438 EFI_STATUS
    439 LegacyBiosBuildSioData (
    440   IN  LEGACY_BIOS_INSTANCE      *Private
    441   )
    442 {
    443   EFI_STATUS                          Status;
    444   DEVICE_PRODUCER_DATA_HEADER         *SioPtr;
    445   EFI_HANDLE                          IsaBusController;
    446   UINTN                               HandleCount;
    447   EFI_HANDLE                          *HandleBuffer;
    448 
    449   //
    450   // Get the pointer to the SIO data structure
    451   //
    452   SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData;
    453 
    454   //
    455   // Zero the data in the SIO data structure
    456   //
    457   gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0);
    458 
    459   //
    460   // Find the ISA Bus Controller used for legacy
    461   //
    462   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
    463                                           Private->LegacyBiosPlatform,
    464                                           EfiGetPlatformIsaBusHandle,
    465                                           0,
    466                                           &HandleBuffer,
    467                                           &HandleCount,
    468                                           NULL
    469                                           );
    470   IsaBusController = HandleBuffer[0];
    471   if (!EFI_ERROR (Status)) {
    472     //
    473     // Force ISA Bus Controller to produce all ISA devices
    474     //
    475     gBS->ConnectController (IsaBusController, NULL, NULL, TRUE);
    476   }
    477 
    478   Status = LegacyBiosBuildSioDataFromIsaIo (SioPtr);
    479   if (EFI_ERROR (Status)) {
    480     LegacyBiosBuildSioDataFromSio (SioPtr);
    481   }
    482 
    483   return EFI_SUCCESS;
    484 }
    485