]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c
686a32dac8de05856be5512e44df579977a82551
[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 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 }