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