3 Implement the Driver Binding Protocol and the Component Name 2 Protocol for
4 the Virtio GPU hybrid driver.
6 Copyright (C) 2016, Red Hat, Inc.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/DevicePathLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/PrintLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/UefiLib.h>
17 #include <Protocol/ComponentName2.h>
18 #include <Protocol/DevicePath.h>
19 #include <Protocol/DriverBinding.h>
20 #include <Protocol/PciIo.h>
22 #include "VirtioGpu.h"
25 // The device path node that describes the Video Output Device Attributes for
26 // the single head (UEFI child handle) that we support.
28 // The ACPI_DISPLAY_ADR() macro corresponds to Table B-2, section "B.4.2 _DOD"
29 // in the ACPI 3.0b spec, or more recently, to Table B-379, section "B.3.2
30 // _DOD" in the ACPI 6.0 spec.
32 STATIC CONST ACPI_ADR_DEVICE_PATH mAcpiAdr
= {
34 ACPI_DEVICE_PATH
, // Type
35 ACPI_ADR_DP
, // SubType
36 { sizeof mAcpiAdr
, 0 }, // Length
40 1, // DeviceIdScheme: use the ACPI
41 // bit-field definitions
46 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL
, // Type
53 // Component Name 2 Protocol implementation.
55 STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
56 { "en", L
"Virtio GPU Driver" },
63 VirtioGpuGetDriverName (
64 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
66 OUT CHAR16
**DriverName
69 return LookupUnicodeString2 (
71 This
->SupportedLanguages
,
74 FALSE
/* Iso639Language */
81 VirtioGpuGetControllerName (
82 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
83 IN EFI_HANDLE ControllerHandle
,
84 IN EFI_HANDLE ChildHandle OPTIONAL
,
86 OUT CHAR16
**ControllerName
93 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
95 Status
= gBS
->OpenProtocol (
101 EFI_OPEN_PROTOCOL_GET_PROTOCOL
103 if (EFI_ERROR (Status
)) {
108 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
109 // keep its Virtio Device Protocol interface open BY_DRIVER.
112 EfiTestManagedDevice (
115 &gVirtioDeviceProtocolGuid
119 if (ChildHandle
== NULL
) {
121 // The caller is querying the name of the VGPU_DEV controller.
123 return LookupUnicodeString2 (
125 This
->SupportedLanguages
,
128 FALSE
/* Iso639Language */
133 // Otherwise, the caller is looking for the name of the GOP child controller.
134 // Check if it is asking about the GOP child controller that we manage. (The
135 // condition below covers the case when we haven't produced the GOP child
136 // controller yet, or we've destroyed it since.)
138 if ((VgpuDev
->Child
== NULL
) || (ChildHandle
!= VgpuDev
->Child
->GopHandle
)) {
139 return EFI_UNSUPPORTED
;
143 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
144 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
150 &gVirtioDeviceProtocolGuid
154 return LookupUnicodeString2 (
156 This
->SupportedLanguages
,
157 VgpuDev
->Child
->GopName
,
159 FALSE
/* Iso639Language */
163 STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
164 VirtioGpuGetDriverName
,
165 VirtioGpuGetControllerName
,
166 "en" // SupportedLanguages (RFC 4646)
170 // Helper functions for the Driver Binding Protocol Implementation.
174 Format the VGPU_DEV controller name, to be looked up and returned by
175 VirtioGpuGetControllerName().
177 @param[in] ControllerHandle The handle that identifies the VGPU_DEV
180 @param[in] AgentHandle The handle of the agent that will attempt to
181 temporarily open the PciIo protocol. This is the
182 DriverBindingHandle member of the
183 EFI_DRIVER_BINDING_PROTOCOL whose Start()
184 function is calling this function.
186 @param[in] DevicePath The device path that is installed on
189 @param[out] ControllerName A dynamically allocated unicode string that
190 unconditionally says "Virtio GPU Device", with a
191 PCI Segment:Bus:Device.Function location
192 optionally appended. The latter part is only
193 produced if DevicePath contains at least one
194 PciIo node; in that case, the most specific such
195 node is used for retrieving the location info.
196 The caller is responsible for freeing
197 ControllerName after use.
199 @retval EFI_SUCCESS ControllerName has been formatted.
201 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for ControllerName.
206 IN EFI_HANDLE ControllerHandle
,
207 IN EFI_HANDLE AgentHandle
,
208 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
209 OUT CHAR16
**ControllerName
212 EFI_HANDLE PciIoHandle
;
213 EFI_PCI_IO_PROTOCOL
*PciIo
;
214 UINTN Segment
, Bus
, Device
, Function
;
215 STATIC CONST CHAR16 ControllerNameStem
[] = L
"Virtio GPU Device";
216 UINTN ControllerNameSize
;
219 gBS
->LocateDevicePath (
220 &gEfiPciIoProtocolGuid
,
228 &gEfiPciIoProtocolGuid
,
232 EFI_OPEN_PROTOCOL_GET_PROTOCOL
246 // Failed to retrieve location info, return verbatim copy of static string.
248 *ControllerName
= AllocateCopyPool (
249 sizeof ControllerNameStem
,
252 return (*ControllerName
== NULL
) ? EFI_OUT_OF_RESOURCES
: EFI_SUCCESS
;
256 // Location info available, format ControllerName dynamically.
258 ControllerNameSize
= sizeof ControllerNameStem
+ // includes L'\0'
259 sizeof (CHAR16
) * (1 + 4 + // Segment
264 *ControllerName
= AllocatePool (ControllerNameSize
);
265 if (*ControllerName
== NULL
) {
266 return EFI_OUT_OF_RESOURCES
;
269 UnicodeSPrintAsciiFormat (
272 "%s %04x:%02x:%02x.%x",
283 Dynamically allocate and initialize the VGPU_GOP child object within an
284 otherwise configured parent VGPU_DEV object.
286 This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
287 VIRTIO_DEVICE_PROTOCOL interface.
289 @param[in,out] ParentBus The pre-initialized VGPU_DEV object that the
290 newly created VGPU_GOP object will be the
293 @param[in] ParentDevicePath The device path protocol instance that is
294 installed on ParentBusController.
296 @param[in] ParentBusController The UEFI controller handle on which the
297 ParentBus VGPU_DEV object and the
298 ParentDevicePath device path protocol are
301 @param[in] DriverBindingHandle The DriverBindingHandle member of
302 EFI_DRIVER_BINDING_PROTOCOL whose Start()
303 function is calling this function. It is
304 passed as AgentHandle to gBS->OpenProtocol()
305 when creating the BY_CHILD_CONTROLLER
308 @retval EFI_SUCCESS ParentBus->Child has been created and
309 populated, and ParentBus->Child->GopHandle now
310 references ParentBusController->VirtIo
313 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
315 @return Error codes from underlying functions.
320 IN OUT VGPU_DEV
*ParentBus
,
321 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
322 IN EFI_HANDLE ParentBusController
,
323 IN EFI_HANDLE DriverBindingHandle
328 CHAR16
*ParentBusName
;
329 STATIC CONST CHAR16 NameSuffix
[] = L
" Head #0";
335 VgpuGop
= AllocateZeroPool (sizeof *VgpuGop
);
336 if (VgpuGop
== NULL
) {
337 return EFI_OUT_OF_RESOURCES
;
340 VgpuGop
->Signature
= VGPU_GOP_SIG
;
341 VgpuGop
->ParentBus
= ParentBus
;
344 // Format a human-readable controller name for VGPU_GOP, and stash it for
345 // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
346 // ParentBus->BusName.
348 Status
= LookupUnicodeString2 (
350 mComponentName2
.SupportedLanguages
,
353 FALSE
/* Iso639Language */
355 ASSERT_EFI_ERROR (Status
);
356 NameSize
= StrSize (ParentBusName
) - sizeof (CHAR16
) + sizeof NameSuffix
;
357 Name
= AllocatePool (NameSize
);
359 Status
= EFI_OUT_OF_RESOURCES
;
363 UnicodeSPrintAsciiFormat (Name
, NameSize
, "%s%s", ParentBusName
, NameSuffix
);
364 Status
= AddUnicodeString2 (
366 mComponentName2
.SupportedLanguages
,
369 FALSE
/* Iso639Language */
372 if (EFI_ERROR (Status
)) {
377 // Create the child device path.
379 VgpuGop
->GopDevicePath
= AppendDevicePathNode (
383 if (VgpuGop
->GopDevicePath
== NULL
) {
384 Status
= EFI_OUT_OF_RESOURCES
;
385 goto FreeVgpuGopName
;
389 // Mask protocol notify callbacks until we're done.
391 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
394 // Create the child handle with the child device path.
396 Status
= gBS
->InstallProtocolInterface (
398 &gEfiDevicePathProtocolGuid
,
399 EFI_NATIVE_INTERFACE
,
400 VgpuGop
->GopDevicePath
402 if (EFI_ERROR (Status
)) {
407 // The child handle must present a reference to the parent handle's Virtio
408 // Device Protocol interface.
410 Status
= gBS
->OpenProtocol (
412 &gVirtioDeviceProtocolGuid
,
416 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
418 if (EFI_ERROR (Status
)) {
419 goto UninstallDevicePath
;
422 ASSERT (ParentVirtIo
== ParentBus
->VirtIo
);
425 // Initialize our Graphics Output Protocol.
427 // Fill in the function members of VgpuGop->Gop from the template, then set
428 // up the rest of the GOP infrastructure by calling SetMode() right now.
430 CopyMem (&VgpuGop
->Gop
, &mGopTemplate
, sizeof mGopTemplate
);
431 Status
= VgpuGop
->Gop
.SetMode (&VgpuGop
->Gop
, 0);
432 if (EFI_ERROR (Status
)) {
433 goto CloseVirtIoByChild
;
437 // Install the Graphics Output Protocol on the child handle.
439 Status
= gBS
->InstallProtocolInterface (
441 &gEfiGraphicsOutputProtocolGuid
,
442 EFI_NATIVE_INTERFACE
,
445 if (EFI_ERROR (Status
)) {
452 gBS
->RestoreTPL (OldTpl
);
453 ParentBus
->Child
= VgpuGop
;
457 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
462 &gVirtioDeviceProtocolGuid
,
468 gBS
->UninstallProtocolInterface (
470 &gEfiDevicePathProtocolGuid
,
471 VgpuGop
->GopDevicePath
475 gBS
->RestoreTPL (OldTpl
);
476 FreePool (VgpuGop
->GopDevicePath
);
479 FreeUnicodeStringTable (VgpuGop
->GopName
);
488 Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
491 This function removes the BY_CHILD_CONTROLLER reference from
492 ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
494 @param[in,out] ParentBus The VGPU_DEV object that the VGPU_GOP child
495 object will be removed from.
497 @param[in] ParentBusController The UEFI controller handle on which the
498 ParentBus VGPU_DEV object is installed.
500 @param[in] DriverBindingHandle The DriverBindingHandle member of
501 EFI_DRIVER_BINDING_PROTOCOL whose Stop()
502 function is calling this function. It is
503 passed as AgentHandle to gBS->CloseProtocol()
504 when removing the BY_CHILD_CONTROLLER
510 IN OUT VGPU_DEV
*ParentBus
,
511 IN EFI_HANDLE ParentBusController
,
512 IN EFI_HANDLE DriverBindingHandle
518 VgpuGop
= ParentBus
->Child
;
519 Status
= gBS
->UninstallProtocolInterface (
521 &gEfiGraphicsOutputProtocolGuid
,
524 ASSERT_EFI_ERROR (Status
);
527 // Uninitialize VgpuGop->Gop.
529 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
531 Status
= gBS
->CloseProtocol (
533 &gVirtioDeviceProtocolGuid
,
537 ASSERT_EFI_ERROR (Status
);
539 Status
= gBS
->UninstallProtocolInterface (
541 &gEfiDevicePathProtocolGuid
,
542 VgpuGop
->GopDevicePath
544 ASSERT_EFI_ERROR (Status
);
546 FreePool (VgpuGop
->GopDevicePath
);
547 FreeUnicodeStringTable (VgpuGop
->GopName
);
550 ParentBus
->Child
= NULL
;
554 // Driver Binding Protocol Implementation.
559 VirtioGpuDriverBindingSupported (
560 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
561 IN EFI_HANDLE ControllerHandle
,
562 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
566 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
569 // - If RemainingDevicePath is NULL: the caller is interested in creating all
571 // - If RemainingDevicePath points to an end node: the caller is not
572 // interested in creating any child handle.
573 // - Otherwise, the caller would like to create the one child handle
574 // specified in RemainingDevicePath. In this case we have to see if the
575 // requested device path is supportable.
577 if ((RemainingDevicePath
!= NULL
) &&
578 !IsDevicePathEnd (RemainingDevicePath
) &&
579 ((DevicePathNodeLength (RemainingDevicePath
) != sizeof mAcpiAdr
) ||
580 (CompareMem (RemainingDevicePath
, &mAcpiAdr
, sizeof mAcpiAdr
) != 0)))
582 return EFI_UNSUPPORTED
;
586 // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
588 Status
= gBS
->OpenProtocol (
590 &gVirtioDeviceProtocolGuid
,
592 This
->DriverBindingHandle
,
594 EFI_OPEN_PROTOCOL_BY_DRIVER
596 if (EFI_ERROR (Status
)) {
598 // If this fails, then by default we cannot support ControllerHandle. There
599 // is one exception: we've already bound the device, have not produced any
600 // GOP child controller, and now the caller wants us to produce the child
601 // controller (either specifically or as part of "all children"). That's
604 if (Status
== EFI_ALREADY_STARTED
) {
608 Status2
= gBS
->OpenProtocol (
612 This
->DriverBindingHandle
,
614 EFI_OPEN_PROTOCOL_GET_PROTOCOL
616 ASSERT_EFI_ERROR (Status2
);
618 if ((VgpuDev
->Child
== NULL
) &&
619 ((RemainingDevicePath
== NULL
) ||
620 !IsDevicePathEnd (RemainingDevicePath
)))
622 Status
= EFI_SUCCESS
;
630 // First BY_DRIVER open; check the VirtIo revision and subsystem.
632 if ((VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0)) ||
633 (VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_GPU_DEVICE
))
635 Status
= EFI_UNSUPPORTED
;
640 // We'll need the device path of the VirtIo device both for formatting
641 // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
643 Status
= gBS
->OpenProtocol (
645 &gEfiDevicePathProtocolGuid
,
647 This
->DriverBindingHandle
,
649 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
655 &gVirtioDeviceProtocolGuid
,
656 This
->DriverBindingHandle
,
666 VirtioGpuDriverBindingStart (
667 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
668 IN EFI_HANDLE ControllerHandle
,
669 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
673 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
674 BOOLEAN VirtIoBoundJustNow
;
676 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
679 // Open the Virtio Device Protocol.
681 // The result of this operation, combined with the checks in
682 // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
683 // binding the VirtIo controller on this call (with or without creating child
684 // controllers), or else we're *only* creating child controllers.
686 Status
= gBS
->OpenProtocol (
688 &gVirtioDeviceProtocolGuid
,
690 This
->DriverBindingHandle
,
692 EFI_OPEN_PROTOCOL_BY_DRIVER
694 if (EFI_ERROR (Status
)) {
696 // The assertions below are based on the success of
697 // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
698 // without producing child handles, and now we're producing the GOP child
701 ASSERT (Status
== EFI_ALREADY_STARTED
);
703 Status
= gBS
->OpenProtocol (
707 This
->DriverBindingHandle
,
709 EFI_OPEN_PROTOCOL_GET_PROTOCOL
711 ASSERT_EFI_ERROR (Status
);
713 ASSERT (VgpuDev
->Child
== NULL
);
715 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
)
718 VirtIoBoundJustNow
= FALSE
;
720 VirtIoBoundJustNow
= TRUE
;
723 // Allocate the private structure.
725 VgpuDev
= AllocateZeroPool (sizeof *VgpuDev
);
726 if (VgpuDev
== NULL
) {
727 Status
= EFI_OUT_OF_RESOURCES
;
731 VgpuDev
->VirtIo
= VirtIo
;
735 // Grab the VirtIo controller's device path. This is necessary regardless of
736 // VirtIoBoundJustNow.
738 Status
= gBS
->OpenProtocol (
740 &gEfiDevicePathProtocolGuid
,
741 (VOID
**)&DevicePath
,
742 This
->DriverBindingHandle
,
744 EFI_OPEN_PROTOCOL_GET_PROTOCOL
746 if (EFI_ERROR (Status
)) {
751 // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
752 // if we aren't *only* creating child handles).
754 if (VirtIoBoundJustNow
) {
758 // Format a human-readable controller name for VGPU_DEV, and stash it for
759 // VirtioGpuGetControllerName() to look up.
761 Status
= FormatVgpuDevName (
763 This
->DriverBindingHandle
,
767 if (EFI_ERROR (Status
)) {
771 Status
= AddUnicodeString2 (
773 mComponentName2
.SupportedLanguages
,
776 FALSE
/* Iso639Language */
778 FreePool (VgpuDevName
);
779 if (EFI_ERROR (Status
)) {
783 Status
= VirtioGpuInit (VgpuDev
);
784 if (EFI_ERROR (Status
)) {
785 goto FreeVgpuDevBusName
;
788 Status
= gBS
->CreateEvent (
789 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
792 VgpuDev
/* NotifyContext */,
795 if (EFI_ERROR (Status
)) {
800 // Install the VGPU_DEV "protocol interface" on ControllerHandle.
802 Status
= gBS
->InstallProtocolInterface (
805 EFI_NATIVE_INTERFACE
,
808 if (EFI_ERROR (Status
)) {
812 if ((RemainingDevicePath
!= NULL
) && IsDevicePathEnd (RemainingDevicePath
)) {
814 // No child handle should be produced; we're done.
818 "%a: bound VirtIo=%p without producing GOP\n",
820 (VOID
*)VgpuDev
->VirtIo
827 // Below we'll produce our single child handle: the caller requested it
828 // either specifically, or as part of all child handles.
830 ASSERT (VgpuDev
->Child
== NULL
);
832 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
)
835 Status
= InitVgpuGop (
839 This
->DriverBindingHandle
841 if (EFI_ERROR (Status
)) {
842 goto UninstallVgpuDev
;
850 "%a: produced GOP %a VirtIo=%p\n",
852 VirtIoBoundJustNow
? "while binding" : "for pre-bound",
853 (VOID
*)VgpuDev
->VirtIo
858 if (VirtIoBoundJustNow
) {
859 gBS
->UninstallProtocolInterface (
867 if (VirtIoBoundJustNow
) {
868 gBS
->CloseEvent (VgpuDev
->ExitBoot
);
872 if (VirtIoBoundJustNow
) {
873 VirtioGpuUninit (VgpuDev
);
877 if (VirtIoBoundJustNow
) {
878 FreeUnicodeStringTable (VgpuDev
->BusName
);
882 if (VirtIoBoundJustNow
) {
887 if (VirtIoBoundJustNow
) {
890 &gVirtioDeviceProtocolGuid
,
891 This
->DriverBindingHandle
,
902 VirtioGpuDriverBindingStop (
903 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
904 IN EFI_HANDLE ControllerHandle
,
905 IN UINTN NumberOfChildren
,
906 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
913 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
915 Status
= gBS
->OpenProtocol (
919 This
->DriverBindingHandle
,
921 EFI_OPEN_PROTOCOL_GET_PROTOCOL
923 if (EFI_ERROR (Status
)) {
928 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
929 // keep its Virtio Device Protocol interface open BY_DRIVER.
932 EfiTestManagedDevice (
934 This
->DriverBindingHandle
,
935 &gVirtioDeviceProtocolGuid
939 switch (NumberOfChildren
) {
942 // The caller wants us to unbind the VirtIo controller.
944 if (VgpuDev
->Child
!= NULL
) {
946 // We still have the GOP child.
948 Status
= EFI_DEVICE_ERROR
;
954 "%a: unbinding GOP-less VirtIo=%p\n",
956 (VOID
*)VgpuDev
->VirtIo
959 Status
= gBS
->UninstallProtocolInterface (
964 ASSERT_EFI_ERROR (Status
);
966 Status
= gBS
->CloseEvent (VgpuDev
->ExitBoot
);
967 ASSERT_EFI_ERROR (Status
);
969 VirtioGpuUninit (VgpuDev
);
970 FreeUnicodeStringTable (VgpuDev
->BusName
);
973 Status
= gBS
->CloseProtocol (
975 &gVirtioDeviceProtocolGuid
,
976 This
->DriverBindingHandle
,
979 ASSERT_EFI_ERROR (Status
);
984 // The caller wants us to destroy our child GOP controller.
986 if ((VgpuDev
->Child
== NULL
) ||
987 (ChildHandleBuffer
[0] != VgpuDev
->Child
->GopHandle
))
990 // We have no child controller at the moment, or it differs from the one
991 // the caller wants us to destroy. I.e., we don't own the child
992 // controller passed in.
994 Status
= EFI_DEVICE_ERROR
;
999 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
1000 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
1003 EfiTestChildHandle (
1005 VgpuDev
->Child
->GopHandle
,
1006 &gVirtioDeviceProtocolGuid
1012 "%a: destroying GOP under VirtIo=%p\n",
1014 (VOID
*)VgpuDev
->VirtIo
1016 UninitVgpuGop (VgpuDev
, ControllerHandle
, This
->DriverBindingHandle
);
1021 // Impossible, we never produced more than one child.
1023 Status
= EFI_DEVICE_ERROR
;
1030 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1031 VirtioGpuDriverBindingSupported
,
1032 VirtioGpuDriverBindingStart
,
1033 VirtioGpuDriverBindingStop
,
1035 NULL
, // ImageHandle, overwritten in entry point
1036 NULL
// DriverBindingHandle, ditto
1040 // Entry point of the driver.
1044 VirtioGpuEntryPoint (
1045 IN EFI_HANDLE ImageHandle
,
1046 IN EFI_SYSTEM_TABLE
*SystemTable
1049 return EfiLibInstallDriverBindingComponentName2 (
1054 NULL
/* ComponentName */,