]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
00f0ea767cdbce2632960746b5a02d7bfa6dd58c
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaBusDxe / IsaBus.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation<BR>
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 IsaBus.c
15
16 Abstract:
17
18 Discovers all the ISA Controllers and their resources by using the ISA PnP
19 Protocol, produces an instance of the ISA I/O Protocol for every ISA
20 Controller found, loads and initializes all ISA Device Drivers, matches ISA
21 Device Drivers with their respective ISA Controllers in a deterministic
22 manner, and informs a ISA Device Driver when it is to start managing an ISA
23 Controller.
24
25 Revision History:
26
27 --*/
28
29 #include "InternalIsaBus.h"
30
31 //
32 // ISA Bus Driver Global Variables
33 //
34 EFI_DRIVER_BINDING_PROTOCOL gIsaBusControllerDriver = {
35 IsaBusControllerDriverSupported,
36 IsaBusControllerDriverStart,
37 IsaBusControllerDriverStop,
38 0xa,
39 NULL,
40 NULL
41 };
42
43 /**
44 The user Entry Point for module IsaBus. The user code starts with this function.
45
46 @param[in] ImageHandle The firmware allocated handle for the EFI image.
47 @param[in] SystemTable A pointer to the EFI System Table.
48
49 @retval EFI_SUCCESS The entry point is executed successfully.
50 @retval other Some error occurs when executing this entry point.
51
52 **/
53 EFI_STATUS
54 EFIAPI
55 InitializeIsaBus(
56 IN EFI_HANDLE ImageHandle,
57 IN EFI_SYSTEM_TABLE *SystemTable
58 )
59 {
60 EFI_STATUS Status;
61
62 //
63 // Install driver model protocol(s).
64 //
65 Status = EfiLibInstallAllDriverProtocols (
66 ImageHandle,
67 SystemTable,
68 &gIsaBusControllerDriver,
69 ImageHandle,
70 &gIsaBusComponentName,
71 NULL,
72 NULL
73 );
74 ASSERT_EFI_ERROR (Status);
75
76
77 return Status;
78 }
79
80
81 EFI_STATUS
82 EFIAPI
83 IsaBusControllerDriverSupported (
84 IN EFI_DRIVER_BINDING_PROTOCOL * This,
85 IN EFI_HANDLE Controller,
86 IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
87 )
88 /*++
89
90 Routine Description:
91
92 This function checks to see if a controller can be managed by the ISA Bus
93 Driver. This is done by checking to see if the controller supports the
94 EFI_PCI_IO_PROTOCOL protocol, and then looking at the PCI Configuration
95 Header to see if the device is a PCI to ISA bridge. The class code of
96 PCI to ISA bridge: Base class 06h, Sub class 01h Interface 00h
97
98 Arguments:
99
100 This - The EFI_DRIVER_BINDING_PROTOCOL instance.
101 Controller - The handle of the device to check.
102 RemainingDevicePath - A pointer to the remaining portion of a device path.
103
104 Returns:
105
106 EFI_SUCCESS - The device is supported by this driver.
107 EFI_UNSUPPORTED - The device is not supported by this driver.
108
109 --*/
110 {
111 EFI_STATUS Status;
112 EFI_ISA_ACPI_PROTOCOL *IsaAcpi;
113
114 //
115 // If RemainingDevicePath is not NULL, it should verify that the first device
116 // path node in RemainingDevicePath is an ACPI Device path node
117 //
118 if (RemainingDevicePath != NULL) {
119 if (RemainingDevicePath->Type != ACPI_DEVICE_PATH) {
120 return EFI_UNSUPPORTED;
121 } else if (RemainingDevicePath->SubType == ACPI_DP) {
122 if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_HID_DEVICE_PATH)) {
123 return EFI_UNSUPPORTED;
124 }
125 } else if (RemainingDevicePath->SubType == ACPI_EXTENDED_DP) {
126 if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_EXTENDED_HID_DEVICE_PATH)) {
127 return EFI_UNSUPPORTED;
128 }
129 } else {
130 return EFI_UNSUPPORTED;
131 }
132 }
133 //
134 // Test the existence of DEVICE_PATH protocol
135 //
136 Status = gBS->OpenProtocol (
137 Controller,
138 &gEfiDevicePathProtocolGuid,
139 NULL,
140 This->DriverBindingHandle,
141 Controller,
142 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
143 );
144 if (EFI_ERROR (Status)) {
145 return Status;
146 }
147 //
148 // Get the Isa Acpi protocol
149 //
150 Status = gBS->OpenProtocol (
151 Controller,
152 &gEfiIsaAcpiProtocolGuid,
153 (VOID **) &IsaAcpi,
154 This->DriverBindingHandle,
155 Controller,
156 EFI_OPEN_PROTOCOL_BY_DRIVER
157 );
158 if (Status == EFI_ALREADY_STARTED) {
159 return EFI_SUCCESS;
160 }
161
162 if (EFI_ERROR (Status)) {
163 return Status;
164 }
165
166 gBS->CloseProtocol (
167 Controller,
168 &gEfiIsaAcpiProtocolGuid,
169 This->DriverBindingHandle,
170 Controller
171 );
172
173 return Status;
174 }
175
176 EFI_STATUS
177 EFIAPI
178 IsaBusControllerDriverStart (
179 IN EFI_DRIVER_BINDING_PROTOCOL * This,
180 IN EFI_HANDLE Controller,
181 IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
182 )
183 /*++
184
185 Routine Description:
186
187 This function tells the ISA Bus Driver to start managing a PCI to ISA
188 Bridge controller.
189
190 Arguments:
191
192 This - The EFI_DRIVER_BINDING_PROTOCOL instance.
193 Controller - A handle to the device being started.
194 RemainingDevicePath - A pointer to the remaining portion of a device path.
195
196 Returns:
197
198 EFI_SUCCESS - The device was started.
199 EFI_UNSUPPORTED - The device is not supported.
200 EFI_DEVICE_ERROR - The device could not be started due to a device error.
201 EFI_ALREADY_STARTED - The device has already been started.
202 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
203 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
204 resources.
205
206 --*/
207 {
208 EFI_STATUS Status;
209 EFI_PCI_IO_PROTOCOL *PciIo;
210 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
211 EFI_ISA_ACPI_PROTOCOL *IsaAcpi;
212 EFI_ISA_ACPI_DEVICE_ID *IsaDevice;
213 EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
214 EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
215
216 //
217 // Local variables declaration for StatusCode reporting
218 //
219 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData;
220 EFI_DEVICE_PATH_PROTOCOL *DevicePathData;
221
222 //
223 // Initialize status code structure
224 //
225 AllocFailExtendedData.DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA);
226 AllocFailExtendedData.DataHeader.Size = sizeof (EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA);
227 CopyMem (
228 &AllocFailExtendedData.DataHeader.Type,
229 &gEfiStatusCodeSpecificDataGuid,
230 sizeof (EFI_GUID)
231 );
232
233 //
234 // Open Device Path Protocol
235 //
236 Status = gBS->OpenProtocol (
237 Controller,
238 &gEfiDevicePathProtocolGuid,
239 (VOID **) &ParentDevicePath,
240 This->DriverBindingHandle,
241 Controller,
242 EFI_OPEN_PROTOCOL_BY_DRIVER
243 );
244 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
245 return Status;
246 }
247 //
248 // Open Pci IO Protocol
249 //
250 Status = gBS->OpenProtocol (
251 Controller,
252 &gEfiPciIoProtocolGuid,
253 (VOID **) &PciIo,
254 This->DriverBindingHandle,
255 Controller,
256 EFI_OPEN_PROTOCOL_GET_PROTOCOL
257 );
258 if (EFI_ERROR (Status)) {
259 //
260 // Close opened protocol
261 //
262 gBS->CloseProtocol (
263 Controller,
264 &gEfiDevicePathProtocolGuid,
265 This->DriverBindingHandle,
266 Controller
267 );
268 return Status;
269 }
270 //
271 // Open ISA Acpi Protocol
272 //
273 Status = gBS->OpenProtocol (
274 Controller,
275 &gEfiIsaAcpiProtocolGuid,
276 (VOID **) &IsaAcpi,
277 This->DriverBindingHandle,
278 Controller,
279 EFI_OPEN_PROTOCOL_BY_DRIVER
280 );
281 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
282 //
283 // Close opened protocol
284 //
285 gBS->CloseProtocol (
286 Controller,
287 &gEfiDevicePathProtocolGuid,
288 This->DriverBindingHandle,
289 Controller
290 );
291 gBS->CloseProtocol (
292 Controller,
293 &gEfiPciIoProtocolGuid,
294 This->DriverBindingHandle,
295 Controller
296 );
297 return Status;
298 }
299 //
300 // The IsaBus driver will use memory below 16M, which is not tested yet,
301 // so call CompatibleRangeTest to test them. Since memory below 1M should
302 // be reserved to CSM, and 15M~16M might be reserved for Isa hole, test 1M
303 // ~15M here
304 //
305 Status = gBS->LocateProtocol (
306 &gEfiGenericMemTestProtocolGuid,
307 NULL,
308 (VOID **) &GenMemoryTest
309 );
310
311 if (!EFI_ERROR (Status)) {
312 Status = GenMemoryTest->CompatibleRangeTest (
313 GenMemoryTest,
314 0x100000,
315 0xE00000
316 );
317 }
318 //
319 // Report Status Code here since we will initialize the host controller
320 //
321 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
322 EFI_PROGRESS_CODE,
323 (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
324 ParentDevicePath
325 );
326
327 //
328 // first init ISA interface
329 //
330 IsaAcpi->InterfaceInit (IsaAcpi);
331
332 //
333 // Report Status Code here since we will enable the host controller
334 //
335 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
336 EFI_PROGRESS_CODE,
337 (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
338 ParentDevicePath
339 );
340
341 //
342 // Create each ISA device handle in this ISA bus
343 //
344 IsaDevice = NULL;
345 do {
346 Status = IsaAcpi->DeviceEnumerate (IsaAcpi, &IsaDevice);
347 if (EFI_ERROR (Status)) {
348 break;
349 }
350 //
351 // Get current resource of this ISA device
352 //
353 ResourceList = NULL;
354 Status = IsaAcpi->GetCurResource (IsaAcpi, IsaDevice, &ResourceList);
355 if (EFI_ERROR (Status)) {
356 continue;
357 }
358
359 //
360 // Create handle for this ISA device
361 //
362 Status = IsaCreateDevice (
363 This,
364 Controller,
365 PciIo,
366 ParentDevicePath,
367 ResourceList,
368 &DevicePathData
369 //&AllocFailExtendedData.DevicePath
370 );
371
372 if (EFI_ERROR (Status)) {
373 continue;
374 }
375 //
376 // Initialize ISA device
377 //
378 IsaAcpi->InitDevice (IsaAcpi, IsaDevice);
379
380 //
381 // Set resources for this ISA device
382 //
383 Status = IsaAcpi->SetResource (IsaAcpi, IsaDevice, ResourceList);
384
385 //
386 // Report Status Code here when failed to resource conflicts
387 //
388 if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
389 //
390 // It's hard to tell which resource conflicts
391 //
392 AllocFailExtendedData.Bar = 0;
393 AllocFailExtendedData.ReqRes = NULL;
394 AllocFailExtendedData.AllocRes = NULL;
395 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
396 EFI_ERROR_CODE,
397 (EFI_IO_BUS_LPC | EFI_IOB_EC_RESOURCE_CONFLICT),
398 DevicePathData
399 );
400
401 }
402 //
403 // Set power for this ISA device
404 //
405 IsaAcpi->SetPower (IsaAcpi, IsaDevice, TRUE);
406
407 //
408 // Enable this ISA device
409 //
410 IsaAcpi->EnableDevice (IsaAcpi, IsaDevice, TRUE);
411
412 } while (TRUE);
413
414 return EFI_SUCCESS;
415 }
416
417 EFI_STATUS
418 EFIAPI
419 IsaBusControllerDriverStop (
420 IN EFI_DRIVER_BINDING_PROTOCOL * This,
421 IN EFI_HANDLE Controller,
422 IN UINTN NumberOfChildren,
423 IN EFI_HANDLE * ChildHandleBuffer OPTIONAL
424 )
425 /*++
426
427 Routine Description:
428
429 This function tells the ISA Bus Driver to stop managing a PCI to ISA
430 Bridge controller.
431
432 Arguments:
433
434 This - The EFI_DRIVER_BINDING_PROTOCOL instance.
435 Controller - A handle to the device being stopped.
436 NumberOfChindren - The number of child device handles in ChildHandleBuffer.
437 ChildHandleBuffer - An array of child handles to be freed.
438
439
440 Returns:
441
442 EFI_SUCCESS - The device was stopped.
443 EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
444 EFI_NOT_STARTED - The device has not been started.
445 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
446 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
447 resources.
448
449 --*/
450 {
451 EFI_STATUS Status;
452 UINTN Index;
453 BOOLEAN AllChildrenStopped;
454 ISA_IO_DEVICE *IsaIoDevice;
455 EFI_ISA_IO_PROTOCOL *IsaIo;
456
457 if (NumberOfChildren == 0) {
458 //
459 // Close the bus driver
460 //
461 Status = gBS->CloseProtocol (
462 Controller,
463 &gEfiPciIoProtocolGuid,
464 This->DriverBindingHandle,
465 Controller
466 );
467 if (EFI_ERROR (Status)) {
468 return Status;
469 }
470
471 Status = gBS->CloseProtocol (
472 Controller,
473 &gEfiDevicePathProtocolGuid,
474 This->DriverBindingHandle,
475 Controller
476 );
477 if (EFI_ERROR (Status)) {
478 return Status;
479 }
480
481 Status = gBS->CloseProtocol (
482 Controller,
483 &gEfiIsaAcpiProtocolGuid,
484 This->DriverBindingHandle,
485 Controller
486 );
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 return EFI_SUCCESS;
492 }
493 //
494 // Complete all outstanding transactions to Controller.
495 // Don't allow any new transaction to Controller to be started.
496 //
497 //
498 // Stop all the children
499 // Find all the ISA devices that were discovered on this PCI to ISA Bridge
500 // with the Start() function.
501 //
502 AllChildrenStopped = TRUE;
503
504 for (Index = 0; Index < NumberOfChildren; Index++) {
505
506 Status = gBS->OpenProtocol (
507 ChildHandleBuffer[Index],
508 &gEfiIsaIoProtocolGuid,
509 (VOID **) &IsaIo,
510 This->DriverBindingHandle,
511 Controller,
512 EFI_OPEN_PROTOCOL_GET_PROTOCOL
513 );
514 if (!EFI_ERROR (Status)) {
515
516 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);
517
518 Status = gBS->UninstallMultipleProtocolInterfaces (
519 ChildHandleBuffer[Index],
520 &gEfiDevicePathProtocolGuid,
521 IsaIoDevice->DevicePath,
522 &gEfiIsaIoProtocolGuid,
523 &IsaIoDevice->IsaIo,
524 NULL
525 );
526
527 if (!EFI_ERROR (Status)) {
528 //
529 // Close the child handle
530 //
531 Status = gBS->CloseProtocol (
532 Controller,
533 &gEfiPciIoProtocolGuid,
534 This->DriverBindingHandle,
535 ChildHandleBuffer[Index]
536 );
537
538 gBS->FreePool (IsaIoDevice->DevicePath);
539 gBS->FreePool (IsaIoDevice);
540 }
541 }
542
543 if (EFI_ERROR (Status)) {
544 AllChildrenStopped = FALSE;
545 }
546 }
547
548 if (!AllChildrenStopped) {
549 return EFI_DEVICE_ERROR;
550 }
551
552 return EFI_SUCCESS;
553 }
554 //
555 // Internal Function
556 //
557 EFI_STATUS
558 IsaCreateDevice (
559 IN EFI_DRIVER_BINDING_PROTOCOL *This,
560 IN EFI_HANDLE Controller,
561 IN EFI_PCI_IO_PROTOCOL *PciIo,
562 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
563 IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList,
564 OUT EFI_DEVICE_PATH_PROTOCOL **ChildDevicePath
565 )
566 /*++
567
568 Routine Description:
569
570 Create ISA device found by IsaPnpProtocol
571
572 Arguments:
573
574 This - The EFI_DRIVER_BINDING_PROTOCOL instance.
575 Controller - The handle of ISA bus controller(PCI to ISA bridge)
576 PciIo - The Pointer to the PCI protocol
577 ParentDevicePath - Device path of the ISA bus controller
578 IsaDeviceResourceList - The resource list of the ISA device
579 ChildDevicePath - The pointer to the child device.
580
581 Returns:
582
583 EFI_SUCCESS - Create the child device.
584 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
585 resources.
586 EFI_DEVICE_ERROR - Can not create child device.
587
588 --*/
589 {
590 EFI_STATUS Status;
591 ISA_IO_DEVICE *IsaIoDevice;
592 EFI_DEV_PATH Node;
593
594 //
595 // Initialize the PCI_IO_DEVICE structure
596 //
597 IsaIoDevice = AllocateZeroPool (sizeof (ISA_IO_DEVICE));
598 if (IsaIoDevice == NULL) {
599 return EFI_OUT_OF_RESOURCES;
600 }
601
602 IsaIoDevice->Signature = ISA_IO_DEVICE_SIGNATURE;
603 IsaIoDevice->Handle = NULL;
604 IsaIoDevice->PciIo = PciIo;
605
606 //
607 // Initialize the ISA I/O instance structure
608 //
609 Status = InitializeIsaIoInstance (IsaIoDevice, IsaDeviceResourceList);
610 if (EFI_ERROR (Status)) {
611 gBS->FreePool (IsaIoDevice);
612 return Status;
613 }
614 //
615 // Build the child device path
616 //
617 Node.DevPath.Type = ACPI_DEVICE_PATH;
618 Node.DevPath.SubType = ACPI_DP;
619 SetDevicePathNodeLength (&Node.DevPath, sizeof (ACPI_HID_DEVICE_PATH));
620 Node.Acpi.HID = IsaDeviceResourceList->Device.HID;
621 Node.Acpi.UID = IsaDeviceResourceList->Device.UID;
622
623 IsaIoDevice->DevicePath = AppendDevicePathNode (
624 ParentDevicePath,
625 &Node.DevPath
626 );
627
628 if (IsaIoDevice->DevicePath == NULL) {
629 Status = EFI_DEVICE_ERROR;
630 goto Done;
631 }
632
633 *ChildDevicePath = IsaIoDevice->DevicePath;
634
635 //
636 // Create a child handle and attach the DevicePath,
637 // PCI I/O, and Controller State
638 //
639 Status = gBS->InstallMultipleProtocolInterfaces (
640 &IsaIoDevice->Handle,
641 &gEfiDevicePathProtocolGuid,
642 IsaIoDevice->DevicePath,
643 &gEfiIsaIoProtocolGuid,
644 &IsaIoDevice->IsaIo,
645 NULL
646 );
647 if (EFI_ERROR (Status)) {
648 goto Done;
649 }
650
651 Status = gBS->OpenProtocol (
652 Controller,
653 &gEfiPciIoProtocolGuid,
654 (VOID **) &PciIo,
655 This->DriverBindingHandle,
656 IsaIoDevice->Handle,
657 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
658 );
659 if (EFI_ERROR (Status)) {
660 gBS->UninstallMultipleProtocolInterfaces (
661 IsaIoDevice->Handle,
662 &gEfiDevicePathProtocolGuid,
663 IsaIoDevice->DevicePath,
664 &gEfiIsaIoProtocolGuid,
665 &IsaIoDevice->IsaIo,
666 NULL
667 );
668 }
669
670 Done:
671
672 if (EFI_ERROR (Status)) {
673 if (IsaIoDevice->DevicePath != NULL) {
674 gBS->FreePool (IsaIoDevice->DevicePath);
675 }
676
677 gBS->FreePool (IsaIoDevice);
678 }
679
680 return Status;
681 }