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