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