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