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
38 ACPI_DISPLAY_ADR ( // ADR
39 1, // DeviceIdScheme: use the ACPI
40 // bit-field definitions
45 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL
, // Type
52 // Component Name 2 Protocol implementation.
54 STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
55 { "en", L
"Virtio GPU Driver" },
62 VirtioGpuGetDriverName (
63 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
65 OUT CHAR16
**DriverName
68 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
69 mDriverNameTable
, DriverName
, FALSE
/* Iso639Language */);
75 VirtioGpuGetControllerName (
76 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
77 IN EFI_HANDLE ControllerHandle
,
78 IN EFI_HANDLE ChildHandle OPTIONAL
,
80 OUT CHAR16
**ControllerName
87 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
89 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
90 (VOID
**)&VgpuDev
, gImageHandle
, ControllerHandle
,
91 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
92 if (EFI_ERROR (Status
)) {
96 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
97 // keep its Virtio Device Protocol interface open BY_DRIVER.
99 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
, gImageHandle
,
100 &gVirtioDeviceProtocolGuid
));
102 if (ChildHandle
== NULL
) {
104 // The caller is querying the name of the VGPU_DEV controller.
106 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
107 VgpuDev
->BusName
, ControllerName
, FALSE
/* Iso639Language */);
111 // Otherwise, the caller is looking for the name of the GOP child controller.
112 // Check if it is asking about the GOP child controller that we manage. (The
113 // condition below covers the case when we haven't produced the GOP child
114 // controller yet, or we've destroyed it since.)
116 if (VgpuDev
->Child
== NULL
|| ChildHandle
!= VgpuDev
->Child
->GopHandle
) {
117 return EFI_UNSUPPORTED
;
120 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
121 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
123 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
, ChildHandle
,
124 &gVirtioDeviceProtocolGuid
));
126 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
127 VgpuDev
->Child
->GopName
, ControllerName
,
128 FALSE
/* Iso639Language */);
131 STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
132 VirtioGpuGetDriverName
,
133 VirtioGpuGetControllerName
,
134 "en" // SupportedLanguages (RFC 4646)
138 // Helper functions for the Driver Binding Protocol Implementation.
141 Format the VGPU_DEV controller name, to be looked up and returned by
142 VirtioGpuGetControllerName().
144 @param[in] ControllerHandle The handle that identifies the VGPU_DEV
147 @param[in] AgentHandle The handle of the agent that will attempt to
148 temporarily open the PciIo protocol. This is the
149 DriverBindingHandle member of the
150 EFI_DRIVER_BINDING_PROTOCOL whose Start()
151 function is calling this function.
153 @param[in] DevicePath The device path that is installed on
156 @param[out] ControllerName A dynamically allocated unicode string that
157 unconditionally says "Virtio GPU Device", with a
158 PCI Segment:Bus:Device.Function location
159 optionally appended. The latter part is only
160 produced if DevicePath contains at least one
161 PciIo node; in that case, the most specific such
162 node is used for retrieving the location info.
163 The caller is responsible for freeing
164 ControllerName after use.
166 @retval EFI_SUCCESS ControllerName has been formatted.
168 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for ControllerName.
173 IN EFI_HANDLE ControllerHandle
,
174 IN EFI_HANDLE AgentHandle
,
175 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
176 OUT CHAR16
**ControllerName
179 EFI_HANDLE PciIoHandle
;
180 EFI_PCI_IO_PROTOCOL
*PciIo
;
181 UINTN Segment
, Bus
, Device
, Function
;
182 STATIC CONST CHAR16 ControllerNameStem
[] = L
"Virtio GPU Device";
183 UINTN ControllerNameSize
;
185 if (EFI_ERROR (gBS
->LocateDevicePath (&gEfiPciIoProtocolGuid
, &DevicePath
,
187 EFI_ERROR (gBS
->OpenProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
,
188 (VOID
**)&PciIo
, AgentHandle
, ControllerHandle
,
189 EFI_OPEN_PROTOCOL_GET_PROTOCOL
)) ||
190 EFI_ERROR (PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
,
193 // Failed to retrieve location info, return verbatim copy of static string.
195 *ControllerName
= AllocateCopyPool (sizeof ControllerNameStem
,
197 return (*ControllerName
== NULL
) ? EFI_OUT_OF_RESOURCES
: EFI_SUCCESS
;
200 // Location info available, format ControllerName dynamically.
202 ControllerNameSize
= sizeof ControllerNameStem
+ // includes L'\0'
203 sizeof (CHAR16
) * (1 + 4 + // Segment
208 *ControllerName
= AllocatePool (ControllerNameSize
);
209 if (*ControllerName
== NULL
) {
210 return EFI_OUT_OF_RESOURCES
;
213 UnicodeSPrintAsciiFormat (*ControllerName
, ControllerNameSize
,
214 "%s %04x:%02x:%02x.%x", ControllerNameStem
, (UINT32
)Segment
, (UINT32
)Bus
,
215 (UINT32
)Device
, (UINT32
)Function
);
220 Dynamically allocate and initialize the VGPU_GOP child object within an
221 otherwise configured parent VGPU_DEV object.
223 This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
224 VIRTIO_DEVICE_PROTOCOL interface.
226 @param[in,out] ParentBus The pre-initialized VGPU_DEV object that the
227 newly created VGPU_GOP object will be the
230 @param[in] ParentDevicePath The device path protocol instance that is
231 installed on ParentBusController.
233 @param[in] ParentBusController The UEFI controller handle on which the
234 ParentBus VGPU_DEV object and the
235 ParentDevicePath device path protocol are
238 @param[in] DriverBindingHandle The DriverBindingHandle member of
239 EFI_DRIVER_BINDING_PROTOCOL whose Start()
240 function is calling this function. It is
241 passed as AgentHandle to gBS->OpenProtocol()
242 when creating the BY_CHILD_CONTROLLER
245 @retval EFI_SUCCESS ParentBus->Child has been created and
246 populated, and ParentBus->Child->GopHandle now
247 references ParentBusController->VirtIo
250 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
252 @return Error codes from underlying functions.
257 IN OUT VGPU_DEV
*ParentBus
,
258 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
259 IN EFI_HANDLE ParentBusController
,
260 IN EFI_HANDLE DriverBindingHandle
265 CHAR16
*ParentBusName
;
266 STATIC CONST CHAR16 NameSuffix
[] = L
" Head #0";
272 VgpuGop
= AllocateZeroPool (sizeof *VgpuGop
);
273 if (VgpuGop
== NULL
) {
274 return EFI_OUT_OF_RESOURCES
;
277 VgpuGop
->Signature
= VGPU_GOP_SIG
;
278 VgpuGop
->ParentBus
= ParentBus
;
281 // Format a human-readable controller name for VGPU_GOP, and stash it for
282 // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
283 // ParentBus->BusName.
285 Status
= LookupUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
286 ParentBus
->BusName
, &ParentBusName
, FALSE
/* Iso639Language */);
287 ASSERT_EFI_ERROR (Status
);
288 NameSize
= StrSize (ParentBusName
) - sizeof (CHAR16
) + sizeof NameSuffix
;
289 Name
= AllocatePool (NameSize
);
291 Status
= EFI_OUT_OF_RESOURCES
;
294 UnicodeSPrintAsciiFormat (Name
, NameSize
, "%s%s", ParentBusName
, NameSuffix
);
295 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
296 &VgpuGop
->GopName
, Name
, FALSE
/* Iso639Language */);
298 if (EFI_ERROR (Status
)) {
303 // Create the child device path.
305 VgpuGop
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
,
307 if (VgpuGop
->GopDevicePath
== NULL
) {
308 Status
= EFI_OUT_OF_RESOURCES
;
309 goto FreeVgpuGopName
;
313 // Mask protocol notify callbacks until we're done.
315 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
318 // Create the child handle with the child device path.
320 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
321 &gEfiDevicePathProtocolGuid
, EFI_NATIVE_INTERFACE
,
322 VgpuGop
->GopDevicePath
);
323 if (EFI_ERROR (Status
)) {
328 // The child handle must present a reference to the parent handle's Virtio
329 // Device Protocol interface.
331 Status
= gBS
->OpenProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
332 &ParentVirtIo
, DriverBindingHandle
, VgpuGop
->GopHandle
,
333 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
334 if (EFI_ERROR (Status
)) {
335 goto UninstallDevicePath
;
337 ASSERT (ParentVirtIo
== ParentBus
->VirtIo
);
340 // Initialize our Graphics Output Protocol.
342 // Fill in the function members of VgpuGop->Gop from the template, then set
343 // up the rest of the GOP infrastructure by calling SetMode() right now.
345 CopyMem (&VgpuGop
->Gop
, &mGopTemplate
, sizeof mGopTemplate
);
346 Status
= VgpuGop
->Gop
.SetMode (&VgpuGop
->Gop
, 0);
347 if (EFI_ERROR (Status
)) {
348 goto CloseVirtIoByChild
;
352 // Install the Graphics Output Protocol on the child handle.
354 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
355 &gEfiGraphicsOutputProtocolGuid
, EFI_NATIVE_INTERFACE
,
357 if (EFI_ERROR (Status
)) {
364 gBS
->RestoreTPL (OldTpl
);
365 ParentBus
->Child
= VgpuGop
;
369 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
372 gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
373 DriverBindingHandle
, VgpuGop
->GopHandle
);
376 gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
377 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
380 gBS
->RestoreTPL (OldTpl
);
381 FreePool (VgpuGop
->GopDevicePath
);
384 FreeUnicodeStringTable (VgpuGop
->GopName
);
393 Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
396 This function removes the BY_CHILD_CONTROLLER reference from
397 ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
399 @param[in,out] ParentBus The VGPU_DEV object that the VGPU_GOP child
400 object will be removed from.
402 @param[in] ParentBusController The UEFI controller handle on which the
403 ParentBus VGPU_DEV object is installed.
405 @param[in] DriverBindingHandle The DriverBindingHandle member of
406 EFI_DRIVER_BINDING_PROTOCOL whose Stop()
407 function is calling this function. It is
408 passed as AgentHandle to gBS->CloseProtocol()
409 when removing the BY_CHILD_CONTROLLER
415 IN OUT VGPU_DEV
*ParentBus
,
416 IN EFI_HANDLE ParentBusController
,
417 IN EFI_HANDLE DriverBindingHandle
423 VgpuGop
= ParentBus
->Child
;
424 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
425 &gEfiGraphicsOutputProtocolGuid
, &VgpuGop
->Gop
);
426 ASSERT_EFI_ERROR (Status
);
429 // Uninitialize VgpuGop->Gop.
431 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
433 Status
= gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
434 DriverBindingHandle
, VgpuGop
->GopHandle
);
435 ASSERT_EFI_ERROR (Status
);
437 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
438 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
439 ASSERT_EFI_ERROR (Status
);
441 FreePool (VgpuGop
->GopDevicePath
);
442 FreeUnicodeStringTable (VgpuGop
->GopName
);
445 ParentBus
->Child
= NULL
;
449 // Driver Binding Protocol Implementation.
454 VirtioGpuDriverBindingSupported (
455 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
456 IN EFI_HANDLE ControllerHandle
,
457 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
461 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
464 // - If RemainingDevicePath is NULL: the caller is interested in creating all
466 // - If RemainingDevicePath points to an end node: the caller is not
467 // interested in creating any child handle.
468 // - Otherwise, the caller would like to create the one child handle
469 // specified in RemainingDevicePath. In this case we have to see if the
470 // requested device path is supportable.
472 if (RemainingDevicePath
!= NULL
&&
473 !IsDevicePathEnd (RemainingDevicePath
) &&
474 (DevicePathNodeLength (RemainingDevicePath
) != sizeof mAcpiAdr
||
475 CompareMem (RemainingDevicePath
, &mAcpiAdr
, sizeof mAcpiAdr
) != 0)) {
476 return EFI_UNSUPPORTED
;
480 // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
482 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
483 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
484 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
485 if (EFI_ERROR (Status
)) {
487 // If this fails, then by default we cannot support ControllerHandle. There
488 // is one exception: we've already bound the device, have not produced any
489 // GOP child controller, and now the caller wants us to produce the child
490 // controller (either specifically or as part of "all children"). That's
493 if (Status
== EFI_ALREADY_STARTED
) {
497 Status2
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
498 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
499 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
500 ASSERT_EFI_ERROR (Status2
);
502 if (VgpuDev
->Child
== NULL
&&
503 (RemainingDevicePath
== NULL
||
504 !IsDevicePathEnd (RemainingDevicePath
))) {
505 Status
= EFI_SUCCESS
;
513 // First BY_DRIVER open; check the VirtIo revision and subsystem.
515 if (VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0) ||
516 VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_GPU_DEVICE
) {
517 Status
= EFI_UNSUPPORTED
;
522 // We'll need the device path of the VirtIo device both for formatting
523 // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
525 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
526 NULL
, This
->DriverBindingHandle
, ControllerHandle
,
527 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
530 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
531 This
->DriverBindingHandle
, ControllerHandle
);
539 VirtioGpuDriverBindingStart (
540 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
541 IN EFI_HANDLE ControllerHandle
,
542 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
546 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
547 BOOLEAN VirtIoBoundJustNow
;
549 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
552 // Open the Virtio Device Protocol.
554 // The result of this operation, combined with the checks in
555 // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
556 // binding the VirtIo controller on this call (with or without creating child
557 // controllers), or else we're *only* creating child controllers.
559 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
560 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
561 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
562 if (EFI_ERROR (Status
)) {
564 // The assertions below are based on the success of
565 // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
566 // without producing child handles, and now we're producing the GOP child
569 ASSERT (Status
== EFI_ALREADY_STARTED
);
571 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
572 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
573 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
574 ASSERT_EFI_ERROR (Status
);
576 ASSERT (VgpuDev
->Child
== NULL
);
578 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
580 VirtIoBoundJustNow
= FALSE
;
582 VirtIoBoundJustNow
= TRUE
;
585 // Allocate the private structure.
587 VgpuDev
= AllocateZeroPool (sizeof *VgpuDev
);
588 if (VgpuDev
== NULL
) {
589 Status
= EFI_OUT_OF_RESOURCES
;
592 VgpuDev
->VirtIo
= VirtIo
;
596 // Grab the VirtIo controller's device path. This is necessary regardless of
597 // VirtIoBoundJustNow.
599 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
600 (VOID
**)&DevicePath
, This
->DriverBindingHandle
,
601 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
602 if (EFI_ERROR (Status
)) {
607 // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
608 // if we aren't *only* creating child handles).
610 if (VirtIoBoundJustNow
) {
614 // Format a human-readable controller name for VGPU_DEV, and stash it for
615 // VirtioGpuGetControllerName() to look up.
617 Status
= FormatVgpuDevName (ControllerHandle
, This
->DriverBindingHandle
,
618 DevicePath
, &VgpuDevName
);
619 if (EFI_ERROR (Status
)) {
622 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
623 &VgpuDev
->BusName
, VgpuDevName
, FALSE
/* Iso639Language */);
624 FreePool (VgpuDevName
);
625 if (EFI_ERROR (Status
)) {
629 Status
= VirtioGpuInit (VgpuDev
);
630 if (EFI_ERROR (Status
)) {
631 goto FreeVgpuDevBusName
;
634 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_CALLBACK
,
635 VirtioGpuExitBoot
, VgpuDev
/* NotifyContext */,
637 if (EFI_ERROR (Status
)) {
642 // Install the VGPU_DEV "protocol interface" on ControllerHandle.
644 Status
= gBS
->InstallProtocolInterface (&ControllerHandle
,
645 &gEfiCallerIdGuid
, EFI_NATIVE_INTERFACE
, VgpuDev
);
646 if (EFI_ERROR (Status
)) {
650 if (RemainingDevicePath
!= NULL
&& IsDevicePathEnd (RemainingDevicePath
)) {
652 // No child handle should be produced; we're done.
654 DEBUG ((EFI_D_INFO
, "%a: bound VirtIo=%p without producing GOP\n",
655 __FUNCTION__
, (VOID
*)VgpuDev
->VirtIo
));
661 // Below we'll produce our single child handle: the caller requested it
662 // either specifically, or as part of all child handles.
664 ASSERT (VgpuDev
->Child
== NULL
);
666 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
668 Status
= InitVgpuGop (VgpuDev
, DevicePath
, ControllerHandle
,
669 This
->DriverBindingHandle
);
670 if (EFI_ERROR (Status
)) {
671 goto UninstallVgpuDev
;
677 DEBUG ((EFI_D_INFO
, "%a: produced GOP %a VirtIo=%p\n", __FUNCTION__
,
678 VirtIoBoundJustNow
? "while binding" : "for pre-bound",
679 (VOID
*)VgpuDev
->VirtIo
));
683 if (VirtIoBoundJustNow
) {
684 gBS
->UninstallProtocolInterface (ControllerHandle
, &gEfiCallerIdGuid
,
689 if (VirtIoBoundJustNow
) {
690 gBS
->CloseEvent (VgpuDev
->ExitBoot
);
694 if (VirtIoBoundJustNow
) {
695 VirtioGpuUninit (VgpuDev
);
699 if (VirtIoBoundJustNow
) {
700 FreeUnicodeStringTable (VgpuDev
->BusName
);
704 if (VirtIoBoundJustNow
) {
709 if (VirtIoBoundJustNow
) {
710 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
711 This
->DriverBindingHandle
, ControllerHandle
);
720 VirtioGpuDriverBindingStop (
721 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
722 IN EFI_HANDLE ControllerHandle
,
723 IN UINTN NumberOfChildren
,
724 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
731 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
733 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
734 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
735 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
736 if (EFI_ERROR (Status
)) {
740 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
741 // keep its Virtio Device Protocol interface open BY_DRIVER.
743 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
,
744 This
->DriverBindingHandle
, &gVirtioDeviceProtocolGuid
));
746 switch (NumberOfChildren
) {
749 // The caller wants us to unbind the VirtIo controller.
751 if (VgpuDev
->Child
!= NULL
) {
753 // We still have the GOP child.
755 Status
= EFI_DEVICE_ERROR
;
759 DEBUG ((EFI_D_INFO
, "%a: unbinding GOP-less VirtIo=%p\n", __FUNCTION__
,
760 (VOID
*)VgpuDev
->VirtIo
));
762 Status
= gBS
->UninstallProtocolInterface (ControllerHandle
,
763 &gEfiCallerIdGuid
, VgpuDev
);
764 ASSERT_EFI_ERROR (Status
);
766 Status
= gBS
->CloseEvent (VgpuDev
->ExitBoot
);
767 ASSERT_EFI_ERROR (Status
);
769 VirtioGpuUninit (VgpuDev
);
770 FreeUnicodeStringTable (VgpuDev
->BusName
);
773 Status
= gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
774 This
->DriverBindingHandle
, ControllerHandle
);
775 ASSERT_EFI_ERROR (Status
);
780 // The caller wants us to destroy our child GOP controller.
782 if (VgpuDev
->Child
== NULL
||
783 ChildHandleBuffer
[0] != VgpuDev
->Child
->GopHandle
) {
785 // We have no child controller at the moment, or it differs from the one
786 // the caller wants us to destroy. I.e., we don't own the child
787 // controller passed in.
789 Status
= EFI_DEVICE_ERROR
;
793 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
794 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
796 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
,
797 VgpuDev
->Child
->GopHandle
,
798 &gVirtioDeviceProtocolGuid
));
800 DEBUG ((EFI_D_INFO
, "%a: destroying GOP under VirtIo=%p\n", __FUNCTION__
,
801 (VOID
*)VgpuDev
->VirtIo
));
802 UninitVgpuGop (VgpuDev
, ControllerHandle
, This
->DriverBindingHandle
);
807 // Impossible, we never produced more than one child.
809 Status
= EFI_DEVICE_ERROR
;
815 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
816 VirtioGpuDriverBindingSupported
,
817 VirtioGpuDriverBindingStart
,
818 VirtioGpuDriverBindingStop
,
820 NULL
, // ImageHandle, overwritten in entry point
821 NULL
// DriverBindingHandle, ditto
825 // Entry point of the driver.
829 VirtioGpuEntryPoint (
830 IN EFI_HANDLE ImageHandle
,
831 IN EFI_SYSTEM_TABLE
*SystemTable
834 return EfiLibInstallDriverBindingComponentName2 (ImageHandle
, SystemTable
,
835 &mDriverBinding
, ImageHandle
, NULL
/* ComponentName */,