]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/SioBusDxe/SioBusDxe.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / SioBusDxe / SioBusDxe.c
1 /** @file
2 The SioBusDxe driver is used to create child devices on the ISA bus and
3 installs the Super I/O protocols on them.
4
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "SioBusDxe.h"
12
13 //
14 // SioBus Driver Binding Protocol
15 //
16 EFI_DRIVER_BINDING_PROTOCOL gSioBusDriverBinding = {
17 SioBusDriverBindingSupported,
18 SioBusDriverBindingStart,
19 SioBusDriverBindingStop,
20 0x10,
21 NULL,
22 NULL
23 };
24
25 /**
26 Tests to see if this driver supports a given controller. If a child device is
27 provided, it further tests to see if this driver supports creating a handle
28 for the specified child device.
29
30 This function checks to see if the driver specified by This supports the
31 device specified by ControllerHandle. Drivers will typically use the device
32 path attached to ControllerHandle and/or the services from the bus I/O
33 abstraction attached to ControllerHandle to determine if the driver supports
34 ControllerHandle. This function may be called many times during platform
35 initialization. In order to reduce boot times, the tests performed by this
36 function must be very small, and take as little time as possible to execute.
37 This function must not change the state of any hardware devices, and this
38 function must be aware that the device specified by ControllerHandle may
39 already be managed by the same driver or a different driver. This function
40 must match its calls to AllocatePages() with FreePages(), AllocatePool() with
41 FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
42 may have been previously started by the same driver, if a protocol is already
43 in the opened state, then it must not be closed with CloseProtocol(). This is
44 required to guarantee the state of ControllerHandle is not modified by this
45 function.
46
47 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
48 instance.
49 @param[in] ControllerHandle The handle of the controller to test. This
50 handle must support a protocol interface
51 that supplies an I/O abstraction to the
52 driver.
53 @param[in] RemainingDevicePath A pointer to the remaining portion of a
54 device path. This parameter is ignored by
55 device drivers, and is optional for bus
56 drivers. For bus drivers, if this parameter
57 is not NULL, then the bus driver must
58 determine if the bus controller specified by
59 ControllerHandle and the child controller
60 specified by RemainingDevicePath are both
61 supported by this bus driver.
62
63 @retval EFI_SUCCESS The device specified by ControllerHandle and
64 RemainingDevicePath is supported by the
65 driver specified by This.
66 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
67 RemainingDevicePath is already being managed
68 by the driver specified by This.
69 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
70 RemainingDevicePath is already being managed
71 by a different driver or an application that
72 requires exclusive access.
73 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
74 RemainingDevicePath is not supported by the
75 driver specified by This.
76
77 **/
78 EFI_STATUS
79 EFIAPI
80 SioBusDriverBindingSupported (
81 IN EFI_DRIVER_BINDING_PROTOCOL *This,
82 IN EFI_HANDLE Controller,
83 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
84 )
85 {
86 EFI_STATUS Status;
87 EFI_PCI_IO_PROTOCOL *PciIo;
88 PCI_TYPE00 Pci;
89 UINTN SegmentNumber;
90 UINTN BusNumber;
91 UINTN DeviceNumber;
92 UINTN FunctionNumber;
93
94 //
95 // Get PciIo protocol instance
96 //
97 Status = gBS->OpenProtocol (
98 Controller,
99 &gEfiPciIoProtocolGuid,
100 (VOID **)&PciIo,
101 This->DriverBindingHandle,
102 Controller,
103 EFI_OPEN_PROTOCOL_BY_DRIVER
104 );
105 if (EFI_ERROR (Status)) {
106 return Status;
107 }
108
109 Status = PciIo->Pci.Read (
110 PciIo,
111 EfiPciIoWidthUint32,
112 0,
113 sizeof (Pci) / sizeof (UINT32),
114 &Pci
115 );
116
117 if (!EFI_ERROR (Status)) {
118 Status = EFI_UNSUPPORTED;
119 if ((Pci.Hdr.Command & 0x03) == 0x03) {
120 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
121 //
122 // See if this is a standard PCI to ISA Bridge from the Base Code and
123 // Class Code
124 //
125 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA) {
126 Status = EFI_SUCCESS;
127 }
128
129 //
130 // See if this is an Intel PCI to ISA bridge in Positive Decode Mode
131 //
132 if ((Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) &&
133 (Pci.Hdr.VendorId == 0x8086))
134 {
135 //
136 // See if this is on Function #0 to avoid false positives on
137 // PCI_CLASS_BRIDGE_OTHER that has the same value as
138 // PCI_CLASS_BRIDGE_ISA_PDECODE
139 //
140 Status = PciIo->GetLocation (
141 PciIo,
142 &SegmentNumber,
143 &BusNumber,
144 &DeviceNumber,
145 &FunctionNumber
146 );
147 if (!EFI_ERROR (Status) && (FunctionNumber == 0)) {
148 Status = EFI_SUCCESS;
149 } else {
150 Status = EFI_UNSUPPORTED;
151 }
152 }
153 }
154 }
155 }
156
157 gBS->CloseProtocol (
158 Controller,
159 &gEfiPciIoProtocolGuid,
160 This->DriverBindingHandle,
161 Controller
162 );
163
164 return Status;
165 }
166
167 /**
168 Starts a device controller or a bus controller.
169
170 The Start() function is designed to be invoked from the EFI boot service
171 ConnectController(). As a result, much of the error checking on the
172 parameters to Start() has been moved into this common boot service. It is
173 legal to call Start() from other locations, but the following calling
174 restrictions must be followed or the system behavior will not be
175 deterministic.
176 1. ControllerHandle must be a valid EFI_HANDLE.
177 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
178 naturally aligned EFI_DEVICE_PATH_PROTOCOL.
179 3. Prior to calling Start(), the Supported() function for the driver
180 specified by This must have been called with the same calling parameters,
181 and Supported() must have returned EFI_SUCCESS.
182
183 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
184 instance.
185 @param[in] ControllerHandle The handle of the controller to start. This
186 handle must support a protocol interface
187 that supplies an I/O abstraction to the
188 driver.
189 @param[in] RemainingDevicePath A pointer to the remaining portion of a
190 device path. This parameter is ignored by
191 device drivers, and is optional for bus
192 drivers. For a bus driver, if this parameter
193 is NULL, then handles for all the children
194 of Controller are created by this driver. If
195 this parameter is not NULL and the first
196 Device Path Node is not the End of Device
197 Path Node, then only the handle for the
198 child device specified by the first Device
199 Path Node of RemainingDevicePath is created
200 by this driver. If the first Device Path
201 Node of RemainingDevicePath is the End of
202 Device Path Node, no child handle is created
203 by this driver.
204
205 @retval EFI_SUCCESS The device was started.
206 @retval EFI_DEVICE_ERROR The device could not be started due to a
207 device error.
208 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
209 lack of resources.
210 @retval Others The driver failded to start the device.
211
212 **/
213 EFI_STATUS
214 EFIAPI
215 SioBusDriverBindingStart (
216 IN EFI_DRIVER_BINDING_PROTOCOL *This,
217 IN EFI_HANDLE Controller,
218 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
219 )
220 {
221 EFI_STATUS Status;
222 EFI_PCI_IO_PROTOCOL *PciIo;
223 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
224 UINT64 Supports;
225 UINT64 OriginalAttributes;
226 UINT64 Attributes;
227 BOOLEAN Enabled;
228 SIO_BUS_DRIVER_PRIVATE_DATA *Private;
229 UINT32 ChildDeviceNumber;
230
231 Enabled = FALSE;
232 Supports = 0;
233 OriginalAttributes = 0;
234 Private = NULL;
235
236 //
237 // Open the PCI I/O Protocol Interface
238 //
239 PciIo = NULL;
240 Status = gBS->OpenProtocol (
241 Controller,
242 &gEfiPciIoProtocolGuid,
243 (VOID **)&PciIo,
244 This->DriverBindingHandle,
245 Controller,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
247 );
248 if (EFI_ERROR (Status)) {
249 return Status;
250 }
251
252 //
253 // Open Device Path Protocol
254 //
255 Status = gBS->OpenProtocol (
256 Controller,
257 &gEfiDevicePathProtocolGuid,
258 (VOID **)&ParentDevicePath,
259 This->DriverBindingHandle,
260 Controller,
261 EFI_OPEN_PROTOCOL_BY_DRIVER
262 );
263 if (EFI_ERROR (Status)) {
264 gBS->CloseProtocol (
265 Controller,
266 &gEfiPciIoProtocolGuid,
267 This->DriverBindingHandle,
268 Controller
269 );
270 return Status;
271 }
272
273 //
274 // Get supported PCI attributes
275 //
276 Status = PciIo->Attributes (
277 PciIo,
278 EfiPciIoAttributeOperationSupported,
279 0,
280 &Supports
281 );
282 if (EFI_ERROR (Status)) {
283 goto Done;
284 }
285
286 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_ISA_IO |
287 EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
288 if ((Supports == 0) ||
289 (Supports == (EFI_PCI_IO_ATTRIBUTE_ISA_IO |
290 EFI_PCI_IO_ATTRIBUTE_ISA_IO_16)))
291 {
292 Status = EFI_UNSUPPORTED;
293 goto Done;
294 }
295
296 Status = PciIo->Attributes (
297 PciIo,
298 EfiPciIoAttributeOperationGet,
299 0,
300 &OriginalAttributes
301 );
302 if (EFI_ERROR (Status)) {
303 goto Done;
304 }
305
306 Attributes = EFI_PCI_DEVICE_ENABLE |
307 Supports |
308 EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
309 Status = PciIo->Attributes (
310 PciIo,
311 EfiPciIoAttributeOperationEnable,
312 Attributes,
313 NULL
314 );
315 if (EFI_ERROR (Status)) {
316 goto Done;
317 }
318
319 Enabled = TRUE;
320
321 //
322 // Store the OriginalAttributes for the restore in BindingStop()
323 //
324 Private = AllocateZeroPool (sizeof (SIO_BUS_DRIVER_PRIVATE_DATA));
325 if (Private == NULL) {
326 Status = EFI_OUT_OF_RESOURCES;
327 goto Done;
328 }
329
330 Private->PciIo = PciIo;
331 Private->OriginalAttributes = OriginalAttributes;
332
333 Status = gBS->InstallProtocolInterface (
334 &Controller,
335 &gEfiCallerIdGuid,
336 EFI_NATIVE_INTERFACE,
337 Private
338 );
339 if (EFI_ERROR (Status)) {
340 goto Done;
341 }
342
343 //
344 // Report status code for the start of general controller initialization
345 //
346 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
347 EFI_PROGRESS_CODE,
348 (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
349 ParentDevicePath
350 );
351
352 //
353 // Report status code for the start of enabling devices on the bus
354 //
355 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
356 EFI_PROGRESS_CODE,
357 (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
358 ParentDevicePath
359 );
360
361 //
362 // Create all the children upon the first entrance
363 //
364 ChildDeviceNumber = SioCreateAllChildDevices (
365 This,
366 Controller,
367 PciIo,
368 ParentDevicePath
369 );
370 if (ChildDeviceNumber == 0) {
371 Status = EFI_DEVICE_ERROR;
372 }
373
374 Done:
375 if (EFI_ERROR (Status)) {
376 if ((PciIo != NULL) && Enabled) {
377 PciIo->Attributes (
378 PciIo,
379 EfiPciIoAttributeOperationSet,
380 OriginalAttributes,
381 NULL
382 );
383 }
384
385 gBS->CloseProtocol (
386 Controller,
387 &gEfiDevicePathProtocolGuid,
388 This->DriverBindingHandle,
389 Controller
390 );
391
392 gBS->CloseProtocol (
393 Controller,
394 &gEfiPciIoProtocolGuid,
395 This->DriverBindingHandle,
396 Controller
397 );
398
399 if (Private != NULL) {
400 gBS->UninstallMultipleProtocolInterfaces (
401 Controller,
402 &gEfiCallerIdGuid,
403 Private,
404 NULL
405 );
406 FreePool (Private);
407 }
408
409 return Status;
410 }
411
412 return EFI_SUCCESS;
413 }
414
415 /**
416 Stops a device controller or a bus controller.
417
418 The Stop() function is designed to be invoked from the EFI boot service
419 DisconnectController(). As a result, much of the error checking on the
420 parameters to Stop() has been moved into this common boot service. It is
421 legal to call Stop() from other locations, but the following calling
422 restrictions must be followed or the system behavior will not be
423 deterministic.
424 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
425 call to this same driver's Start() function.
426 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
427 valid EFI_HANDLE. In addition, all of these handles must have been created
428 in this driver's Start() function, and the Start() function must have
429 called OpenProtocol() on ControllerHandle with an Attribute of
430 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
431
432 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
433 instance.
434 @param[in] ControllerHandle A handle to the device being stopped. The
435 handle must support a bus specific I/O
436 protocol for the driver to use to stop the
437 device.
438 @param[in] NumberOfChildren The number of child device handles in
439 ChildHandleBuffer.
440 @param[in] ChildHandleBuffer An array of child handles to be freed. May be
441 NULL if NumberOfChildren is 0.
442
443 @retval EFI_SUCCESS The device was stopped.
444 @retval EFI_DEVICE_ERROR The device could not be stopped due to a
445 device error.
446
447 **/
448 EFI_STATUS
449 EFIAPI
450 SioBusDriverBindingStop (
451 IN EFI_DRIVER_BINDING_PROTOCOL *This,
452 IN EFI_HANDLE Controller,
453 IN UINTN NumberOfChildren,
454 IN EFI_HANDLE *ChildHandleBuffer
455 )
456 {
457 EFI_STATUS Status;
458 SIO_BUS_DRIVER_PRIVATE_DATA *Private;
459 UINTN Index;
460 BOOLEAN AllChildrenStopped;
461 EFI_SIO_PROTOCOL *Sio;
462 SIO_DEV *SioDevice;
463 EFI_PCI_IO_PROTOCOL *PciIo;
464
465 if (NumberOfChildren == 0) {
466 //
467 // Restore PCI attributes
468 //
469 Status = gBS->OpenProtocol (
470 Controller,
471 &gEfiCallerIdGuid,
472 (VOID **)&Private,
473 This->DriverBindingHandle,
474 Controller,
475 EFI_OPEN_PROTOCOL_GET_PROTOCOL
476 );
477 if (EFI_ERROR (Status)) {
478 return Status;
479 }
480
481 Status = Private->PciIo->Attributes (
482 Private->PciIo,
483 EfiPciIoAttributeOperationSet,
484 Private->OriginalAttributes,
485 NULL
486 );
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 gBS->UninstallProtocolInterface (
492 Controller,
493 &gEfiCallerIdGuid,
494 Private
495 );
496 FreePool (Private);
497
498 //
499 // Close the bus driver
500 //
501 Status = gBS->CloseProtocol (
502 Controller,
503 &gEfiDevicePathProtocolGuid,
504 This->DriverBindingHandle,
505 Controller
506 );
507 if (EFI_ERROR (Status)) {
508 return Status;
509 }
510
511 Status = gBS->CloseProtocol (
512 Controller,
513 &gEfiPciIoProtocolGuid,
514 This->DriverBindingHandle,
515 Controller
516 );
517 if (EFI_ERROR (Status)) {
518 return Status;
519 }
520
521 return EFI_SUCCESS;
522 }
523
524 //
525 // Stop all the children
526 //
527 AllChildrenStopped = TRUE;
528
529 for (Index = 0; Index < NumberOfChildren; Index++) {
530 Status = gBS->OpenProtocol (
531 ChildHandleBuffer[Index],
532 &gEfiSioProtocolGuid,
533 (VOID **)&Sio,
534 This->DriverBindingHandle,
535 Controller,
536 EFI_OPEN_PROTOCOL_GET_PROTOCOL
537 );
538 if (!EFI_ERROR (Status)) {
539 SioDevice = SIO_DEV_FROM_SIO (Sio);
540
541 //
542 // Close the child handle
543 //
544 Status = gBS->CloseProtocol (
545 Controller,
546 &gEfiPciIoProtocolGuid,
547 This->DriverBindingHandle,
548 ChildHandleBuffer[Index]
549 );
550 Status = gBS->UninstallMultipleProtocolInterfaces (
551 ChildHandleBuffer[Index],
552 &gEfiDevicePathProtocolGuid,
553 SioDevice->DevicePath,
554 &gEfiSioProtocolGuid,
555 &SioDevice->Sio,
556 NULL
557 );
558
559 if (!EFI_ERROR (Status)) {
560 FreePool (SioDevice->DevicePath);
561 FreePool (SioDevice);
562 } else {
563 //
564 // Re-open PCI IO Protocol on behalf of the child device
565 // because of failure of destroying the child device handle
566 //
567 gBS->OpenProtocol (
568 Controller,
569 &gEfiPciIoProtocolGuid,
570 (VOID **)&PciIo,
571 This->DriverBindingHandle,
572 ChildHandleBuffer[Index],
573 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
574 );
575 }
576 }
577
578 if (EFI_ERROR (Status)) {
579 AllChildrenStopped = FALSE;
580 }
581 }
582
583 if (!AllChildrenStopped) {
584 return EFI_DEVICE_ERROR;
585 }
586
587 return EFI_SUCCESS;
588 }
589
590 /**
591 The entry point for the SioBusDxe driver.
592
593 @param[in] ImageHandle The firmware allocated handle for the EFI image.
594 @param[in] SystemTable A pointer to the EFI System Table.
595
596 @retval EFI_SUCCESS The entry point is executed successfully.
597 @retval other Some error occurs when executing this entry point.
598
599 **/
600 EFI_STATUS
601 EFIAPI
602 SioBusDxeDriverEntryPoint (
603 IN EFI_HANDLE ImageHandle,
604 IN EFI_SYSTEM_TABLE *SystemTable
605 )
606 {
607 //
608 // Install driver model protocol(s).
609 //
610 return EfiLibInstallDriverBindingComponentName2 (
611 ImageHandle,
612 SystemTable,
613 &gSioBusDriverBinding,
614 ImageHandle,
615 &gSioBusComponentName,
616 &gSioBusComponentName2
617 );
618 }