• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
LegacyBiosBuildSioDataFromSio(IN DEVICE_PRODUCER_DATA_HEADER * SioPtr)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
LegacyBiosBuildSioDataFromIsaIo(IN DEVICE_PRODUCER_DATA_HEADER * SioPtr)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
LegacyBiosBuildSioData(IN LEGACY_BIOS_INSTANCE * Private)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