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