1/** @file 2 Collect Sio information from Native EFI Drivers. 3 Sio is floppy, parallel, serial, ... hardware 4 5Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 6 7This program and the accompanying materials 8are licensed and made available under the terms and conditions 9of the BSD License which accompanies this distribution. The 10full text of the license may be found at 11http://opensource.org/licenses/bsd-license.php 12 13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14WITHOUT 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**/ 29EFI_STATUS 30LegacyBiosBuildSioDataFromSio ( 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**/ 247EFI_STATUS 248LegacyBiosBuildSioDataFromIsaIo ( 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**/ 438EFI_STATUS 439LegacyBiosBuildSioData ( 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