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