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 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/DevicePathLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/PrintLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include <Protocol/ComponentName2.h>
24 #include <Protocol/DevicePath.h>
25 #include <Protocol/DriverBinding.h>
26 #include <Protocol/PciIo.h>
28 #include "VirtioGpu.h"
31 // The device path node that describes the Video Output Device Attributes for
32 // the single head (UEFI child handle) that we support.
34 // The ACPI_DISPLAY_ADR() macro corresponds to Table B-2, section "B.4.2 _DOD"
35 // in the ACPI 3.0b spec, or more recently, to Table B-379, section "B.3.2
36 // _DOD" in the ACPI 6.0 spec.
38 STATIC CONST ACPI_ADR_DEVICE_PATH mAcpiAdr
= {
40 ACPI_DEVICE_PATH
, // Type
41 ACPI_ADR_DP
, // SubType
42 { sizeof mAcpiAdr
, 0 }, // Length
44 ACPI_DISPLAY_ADR ( // ADR
45 1, // DeviceIdScheme: use the ACPI
46 // bit-field definitions
51 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL
, // Type
58 // Component Name 2 Protocol implementation.
60 STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
61 { "en", L
"Virtio GPU Driver" },
68 VirtioGpuGetDriverName (
69 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
71 OUT CHAR16
**DriverName
74 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
75 mDriverNameTable
, DriverName
, 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 (ControllerHandle
, &gEfiCallerIdGuid
,
96 (VOID
**)&VgpuDev
, gImageHandle
, ControllerHandle
,
97 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
98 if (EFI_ERROR (Status
)) {
102 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
103 // keep its Virtio Device Protocol interface open BY_DRIVER.
105 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
, gImageHandle
,
106 &gVirtioDeviceProtocolGuid
));
108 if (ChildHandle
== NULL
) {
110 // The caller is querying the name of the VGPU_DEV controller.
112 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
113 VgpuDev
->BusName
, ControllerName
, FALSE
/* Iso639Language */);
117 // Otherwise, the caller is looking for the name of the GOP child controller.
118 // Check if it is asking about the GOP child controller that we manage. (The
119 // condition below covers the case when we haven't produced the GOP child
120 // controller yet, or we've destroyed it since.)
122 if (VgpuDev
->Child
== NULL
|| ChildHandle
!= VgpuDev
->Child
->GopHandle
) {
123 return EFI_UNSUPPORTED
;
126 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
127 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
129 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
, ChildHandle
,
130 &gVirtioDeviceProtocolGuid
));
132 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
133 VgpuDev
->Child
->GopName
, ControllerName
,
134 FALSE
/* Iso639Language */);
137 STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
138 VirtioGpuGetDriverName
,
139 VirtioGpuGetControllerName
,
140 "en" // SupportedLanguages (RFC 4646)
144 // Helper functions for the Driver Binding Protocol Implementation.
147 Format the VGPU_DEV controller name, to be looked up and returned by
148 VirtioGpuGetControllerName().
150 @param[in] ControllerHandle The handle that identifies the VGPU_DEV
153 @param[in] AgentHandle The handle of the agent that will attempt to
154 temporarily open the PciIo protocol. This is the
155 DriverBindingHandle member of the
156 EFI_DRIVER_BINDING_PROTOCOL whose Start()
157 function is calling this function.
159 @param[in] DevicePath The device path that is installed on
162 @param[out] ControllerName A dynamically allocated unicode string that
163 unconditionally says "Virtio GPU Device", with a
164 PCI Segment:Bus:Device.Function location
165 optionally appended. The latter part is only
166 produced if DevicePath contains at least one
167 PciIo node; in that case, the most specific such
168 node is used for retrieving the location info.
169 The caller is responsible for freeing
170 ControllerName after use.
172 @retval EFI_SUCCESS ControllerName has been formatted.
174 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for ControllerName.
179 IN EFI_HANDLE ControllerHandle
,
180 IN EFI_HANDLE AgentHandle
,
181 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
182 OUT CHAR16
**ControllerName
185 EFI_HANDLE PciIoHandle
;
186 EFI_PCI_IO_PROTOCOL
*PciIo
;
187 UINTN Segment
, Bus
, Device
, Function
;
188 STATIC CONST CHAR16 ControllerNameStem
[] = L
"Virtio GPU Device";
189 UINTN ControllerNameSize
;
191 if (EFI_ERROR (gBS
->LocateDevicePath (&gEfiPciIoProtocolGuid
, &DevicePath
,
193 EFI_ERROR (gBS
->OpenProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
,
194 (VOID
**)&PciIo
, AgentHandle
, ControllerHandle
,
195 EFI_OPEN_PROTOCOL_GET_PROTOCOL
)) ||
196 EFI_ERROR (PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
,
199 // Failed to retrieve location info, return verbatim copy of static string.
201 *ControllerName
= AllocateCopyPool (sizeof ControllerNameStem
,
203 return (*ControllerName
== NULL
) ? EFI_OUT_OF_RESOURCES
: EFI_SUCCESS
;
206 // Location info available, format ControllerName dynamically.
208 ControllerNameSize
= sizeof ControllerNameStem
+ // includes L'\0'
209 sizeof (CHAR16
) * (1 + 4 + // Segment
214 *ControllerName
= AllocatePool (ControllerNameSize
);
215 if (*ControllerName
== NULL
) {
216 return EFI_OUT_OF_RESOURCES
;
219 UnicodeSPrintAsciiFormat (*ControllerName
, ControllerNameSize
,
220 "%s %04x:%02x:%02x.%x", ControllerNameStem
, (UINT32
)Segment
, (UINT32
)Bus
,
221 (UINT32
)Device
, (UINT32
)Function
);
226 Dynamically allocate and initialize the VGPU_GOP child object within an
227 otherwise configured parent VGPU_DEV object.
229 This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
230 VIRTIO_DEVICE_PROTOCOL interface.
232 @param[in,out] ParentBus The pre-initialized VGPU_DEV object that the
233 newly created VGPU_GOP object will be the
236 @param[in] ParentDevicePath The device path protocol instance that is
237 installed on ParentBusController.
239 @param[in] ParentBusController The UEFI controller handle on which the
240 ParentBus VGPU_DEV object and the
241 ParentDevicePath device path protocol are
244 @param[in] DriverBindingHandle The DriverBindingHandle member of
245 EFI_DRIVER_BINDING_PROTOCOL whose Start()
246 function is calling this function. It is
247 passed as AgentHandle to gBS->OpenProtocol()
248 when creating the BY_CHILD_CONTROLLER
251 @retval EFI_SUCCESS ParentBus->Child has been created and
252 populated, and ParentBus->Child->GopHandle now
253 references ParentBusController->VirtIo
256 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
258 @return Error codes from underlying functions.
263 IN OUT VGPU_DEV
*ParentBus
,
264 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
265 IN EFI_HANDLE ParentBusController
,
266 IN EFI_HANDLE DriverBindingHandle
271 CHAR16
*ParentBusName
;
272 STATIC CONST CHAR16 NameSuffix
[] = L
" Head #0";
278 VgpuGop
= AllocateZeroPool (sizeof *VgpuGop
);
279 if (VgpuGop
== NULL
) {
280 return EFI_OUT_OF_RESOURCES
;
283 VgpuGop
->Signature
= VGPU_GOP_SIG
;
284 VgpuGop
->ParentBus
= ParentBus
;
287 // Format a human-readable controller name for VGPU_GOP, and stash it for
288 // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
289 // ParentBus->BusName.
291 Status
= LookupUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
292 ParentBus
->BusName
, &ParentBusName
, FALSE
/* Iso639Language */);
293 ASSERT_EFI_ERROR (Status
);
294 NameSize
= StrSize (ParentBusName
) - sizeof (CHAR16
) + sizeof NameSuffix
;
295 Name
= AllocatePool (NameSize
);
297 Status
= EFI_OUT_OF_RESOURCES
;
300 UnicodeSPrintAsciiFormat (Name
, NameSize
, "%s%s", ParentBusName
, NameSuffix
);
301 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
302 &VgpuGop
->GopName
, Name
, FALSE
/* Iso639Language */);
304 if (EFI_ERROR (Status
)) {
309 // Create the child device path.
311 VgpuGop
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
,
313 if (VgpuGop
->GopDevicePath
== NULL
) {
314 Status
= EFI_OUT_OF_RESOURCES
;
315 goto FreeVgpuGopName
;
319 // Mask protocol notify callbacks until we're done.
321 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
324 // Create the child handle with the child device path.
326 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
327 &gEfiDevicePathProtocolGuid
, EFI_NATIVE_INTERFACE
,
328 VgpuGop
->GopDevicePath
);
329 if (EFI_ERROR (Status
)) {
334 // The child handle must present a reference to the parent handle's Virtio
335 // Device Protocol interface.
337 Status
= gBS
->OpenProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
338 &ParentVirtIo
, DriverBindingHandle
, VgpuGop
->GopHandle
,
339 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
340 if (EFI_ERROR (Status
)) {
341 goto UninstallDevicePath
;
343 ASSERT (ParentVirtIo
== ParentBus
->VirtIo
);
346 // Initialize our Graphics Output Protocol.
348 // Fill in the function members of VgpuGop->Gop from the template, then set
349 // up the rest of the GOP infrastructure by calling SetMode() right now.
351 CopyMem (&VgpuGop
->Gop
, &mGopTemplate
, sizeof mGopTemplate
);
352 Status
= VgpuGop
->Gop
.SetMode (&VgpuGop
->Gop
, 0);
353 if (EFI_ERROR (Status
)) {
354 goto CloseVirtIoByChild
;
358 // Install the Graphics Output Protocol on the child handle.
360 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
361 &gEfiGraphicsOutputProtocolGuid
, EFI_NATIVE_INTERFACE
,
363 if (EFI_ERROR (Status
)) {
370 gBS
->RestoreTPL (OldTpl
);
371 ParentBus
->Child
= VgpuGop
;
375 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
378 gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
379 DriverBindingHandle
, VgpuGop
->GopHandle
);
382 gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
383 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
386 gBS
->RestoreTPL (OldTpl
);
387 FreePool (VgpuGop
->GopDevicePath
);
390 FreeUnicodeStringTable (VgpuGop
->GopName
);
399 Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
402 This function removes the BY_CHILD_CONTROLLER reference from
403 ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
405 @param[in,out] ParentBus The VGPU_DEV object that the VGPU_GOP child
406 object will be removed from.
408 @param[in] ParentBusController The UEFI controller handle on which the
409 ParentBus VGPU_DEV object is installed.
411 @param[in] DriverBindingHandle The DriverBindingHandle member of
412 EFI_DRIVER_BINDING_PROTOCOL whose Stop()
413 function is calling this function. It is
414 passed as AgentHandle to gBS->CloseProtocol()
415 when removing the BY_CHILD_CONTROLLER
421 IN OUT VGPU_DEV
*ParentBus
,
422 IN EFI_HANDLE ParentBusController
,
423 IN EFI_HANDLE DriverBindingHandle
429 VgpuGop
= ParentBus
->Child
;
430 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
431 &gEfiGraphicsOutputProtocolGuid
, &VgpuGop
->Gop
);
432 ASSERT_EFI_ERROR (Status
);
435 // Uninitialize VgpuGop->Gop.
437 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
439 Status
= gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
440 DriverBindingHandle
, VgpuGop
->GopHandle
);
441 ASSERT_EFI_ERROR (Status
);
443 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
444 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
445 ASSERT_EFI_ERROR (Status
);
447 FreePool (VgpuGop
->GopDevicePath
);
448 FreeUnicodeStringTable (VgpuGop
->GopName
);
451 ParentBus
->Child
= NULL
;
455 // Driver Binding Protocol Implementation.
460 VirtioGpuDriverBindingSupported (
461 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
462 IN EFI_HANDLE ControllerHandle
,
463 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
467 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
470 // - If RemainingDevicePath is NULL: the caller is interested in creating all
472 // - If RemainingDevicePath points to an end node: the caller is not
473 // interested in creating any child handle.
474 // - Otherwise, the caller would like to create the one child handle
475 // specified in RemainingDevicePath. In this case we have to see if the
476 // requested device path is supportable.
478 if (RemainingDevicePath
!= NULL
&&
479 !IsDevicePathEnd (RemainingDevicePath
) &&
480 (DevicePathNodeLength (RemainingDevicePath
) != sizeof mAcpiAdr
||
481 CompareMem (RemainingDevicePath
, &mAcpiAdr
, sizeof mAcpiAdr
) != 0)) {
482 return EFI_UNSUPPORTED
;
486 // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
488 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
489 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
490 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
491 if (EFI_ERROR (Status
)) {
493 // If this fails, then by default we cannot support ControllerHandle. There
494 // is one exception: we've already bound the device, have not produced any
495 // GOP child controller, and now the caller wants us to produce the child
496 // controller (either specifically or as part of "all children"). That's
499 if (Status
== EFI_ALREADY_STARTED
) {
503 Status2
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
504 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
505 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
506 ASSERT_EFI_ERROR (Status2
);
508 if (VgpuDev
->Child
== NULL
&&
509 (RemainingDevicePath
== NULL
||
510 !IsDevicePathEnd (RemainingDevicePath
))) {
511 Status
= EFI_SUCCESS
;
519 // First BY_DRIVER open; check the VirtIo revision and subsystem.
521 if (VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0) ||
522 VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_GPU_DEVICE
) {
523 Status
= EFI_UNSUPPORTED
;
528 // We'll need the device path of the VirtIo device both for formatting
529 // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
531 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
532 NULL
, This
->DriverBindingHandle
, ControllerHandle
,
533 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
536 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
537 This
->DriverBindingHandle
, ControllerHandle
);
545 VirtioGpuDriverBindingStart (
546 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
547 IN EFI_HANDLE ControllerHandle
,
548 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
552 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
553 BOOLEAN VirtIoBoundJustNow
;
555 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
558 // Open the Virtio Device Protocol.
560 // The result of this operation, combined with the checks in
561 // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
562 // binding the VirtIo controller on this call (with or without creating child
563 // controllers), or else we're *only* creating child controllers.
565 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
566 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
567 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
568 if (EFI_ERROR (Status
)) {
570 // The assertions below are based on the success of
571 // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
572 // without producing child handles, and now we're producing the GOP child
575 ASSERT (Status
== EFI_ALREADY_STARTED
);
577 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
578 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
579 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
580 ASSERT_EFI_ERROR (Status
);
582 ASSERT (VgpuDev
->Child
== NULL
);
584 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
586 VirtIoBoundJustNow
= FALSE
;
588 VirtIoBoundJustNow
= TRUE
;
591 // Allocate the private structure.
593 VgpuDev
= AllocateZeroPool (sizeof *VgpuDev
);
594 if (VgpuDev
== NULL
) {
595 Status
= EFI_OUT_OF_RESOURCES
;
598 VgpuDev
->VirtIo
= VirtIo
;
602 // Grab the VirtIo controller's device path. This is necessary regardless of
603 // VirtIoBoundJustNow.
605 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
606 (VOID
**)&DevicePath
, This
->DriverBindingHandle
,
607 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
608 if (EFI_ERROR (Status
)) {
613 // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
614 // if we aren't *only* creating child handles).
616 if (VirtIoBoundJustNow
) {
620 // Format a human-readable controller name for VGPU_DEV, and stash it for
621 // VirtioGpuGetControllerName() to look up.
623 Status
= FormatVgpuDevName (ControllerHandle
, This
->DriverBindingHandle
,
624 DevicePath
, &VgpuDevName
);
625 if (EFI_ERROR (Status
)) {
628 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
629 &VgpuDev
->BusName
, VgpuDevName
, FALSE
/* Iso639Language */);
630 FreePool (VgpuDevName
);
631 if (EFI_ERROR (Status
)) {
635 Status
= VirtioGpuInit (VgpuDev
);
636 if (EFI_ERROR (Status
)) {
637 goto FreeVgpuDevBusName
;
640 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_CALLBACK
,
641 VirtioGpuExitBoot
, VgpuDev
/* NotifyContext */,
643 if (EFI_ERROR (Status
)) {
648 // Install the VGPU_DEV "protocol interface" on ControllerHandle.
650 Status
= gBS
->InstallProtocolInterface (&ControllerHandle
,
651 &gEfiCallerIdGuid
, EFI_NATIVE_INTERFACE
, VgpuDev
);
652 if (EFI_ERROR (Status
)) {
656 if (RemainingDevicePath
!= NULL
&& IsDevicePathEnd (RemainingDevicePath
)) {
658 // No child handle should be produced; we're done.
660 DEBUG ((EFI_D_INFO
, "%a: bound VirtIo=%p without producing GOP\n",
661 __FUNCTION__
, (VOID
*)VgpuDev
->VirtIo
));
667 // Below we'll produce our single child handle: the caller requested it
668 // either specifically, or as part of all child handles.
670 ASSERT (VgpuDev
->Child
== NULL
);
672 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
674 Status
= InitVgpuGop (VgpuDev
, DevicePath
, ControllerHandle
,
675 This
->DriverBindingHandle
);
676 if (EFI_ERROR (Status
)) {
677 goto UninstallVgpuDev
;
683 DEBUG ((EFI_D_INFO
, "%a: produced GOP %a VirtIo=%p\n", __FUNCTION__
,
684 VirtIoBoundJustNow
? "while binding" : "for pre-bound",
685 (VOID
*)VgpuDev
->VirtIo
));
689 if (VirtIoBoundJustNow
) {
690 gBS
->UninstallProtocolInterface (ControllerHandle
, &gEfiCallerIdGuid
,
695 if (VirtIoBoundJustNow
) {
696 gBS
->CloseEvent (VgpuDev
->ExitBoot
);
700 if (VirtIoBoundJustNow
) {
701 VirtioGpuUninit (VgpuDev
);
705 if (VirtIoBoundJustNow
) {
706 FreeUnicodeStringTable (VgpuDev
->BusName
);
710 if (VirtIoBoundJustNow
) {
715 if (VirtIoBoundJustNow
) {
716 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
717 This
->DriverBindingHandle
, ControllerHandle
);
726 VirtioGpuDriverBindingStop (
727 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
728 IN EFI_HANDLE ControllerHandle
,
729 IN UINTN NumberOfChildren
,
730 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
737 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
739 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
740 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
741 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
742 if (EFI_ERROR (Status
)) {
746 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
747 // keep its Virtio Device Protocol interface open BY_DRIVER.
749 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
,
750 This
->DriverBindingHandle
, &gVirtioDeviceProtocolGuid
));
752 switch (NumberOfChildren
) {
755 // The caller wants us to unbind the VirtIo controller.
757 if (VgpuDev
->Child
!= NULL
) {
759 // We still have the GOP child.
761 Status
= EFI_DEVICE_ERROR
;
765 DEBUG ((EFI_D_INFO
, "%a: unbinding GOP-less VirtIo=%p\n", __FUNCTION__
,
766 (VOID
*)VgpuDev
->VirtIo
));
768 Status
= gBS
->UninstallProtocolInterface (ControllerHandle
,
769 &gEfiCallerIdGuid
, VgpuDev
);
770 ASSERT_EFI_ERROR (Status
);
772 Status
= gBS
->CloseEvent (VgpuDev
->ExitBoot
);
773 ASSERT_EFI_ERROR (Status
);
775 VirtioGpuUninit (VgpuDev
);
776 FreeUnicodeStringTable (VgpuDev
->BusName
);
779 Status
= gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
780 This
->DriverBindingHandle
, ControllerHandle
);
781 ASSERT_EFI_ERROR (Status
);
786 // The caller wants us to destroy our child GOP controller.
788 if (VgpuDev
->Child
== NULL
||
789 ChildHandleBuffer
[0] != VgpuDev
->Child
->GopHandle
) {
791 // We have no child controller at the moment, or it differs from the one
792 // the caller wants us to destroy. I.e., we don't own the child
793 // controller passed in.
795 Status
= EFI_DEVICE_ERROR
;
799 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
800 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
802 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
,
803 VgpuDev
->Child
->GopHandle
,
804 &gVirtioDeviceProtocolGuid
));
806 DEBUG ((EFI_D_INFO
, "%a: destroying GOP under VirtIo=%p\n", __FUNCTION__
,
807 (VOID
*)VgpuDev
->VirtIo
));
808 UninitVgpuGop (VgpuDev
, ControllerHandle
, This
->DriverBindingHandle
);
813 // Impossible, we never produced more than one child.
815 Status
= EFI_DEVICE_ERROR
;
821 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
822 VirtioGpuDriverBindingSupported
,
823 VirtioGpuDriverBindingStart
,
824 VirtioGpuDriverBindingStop
,
826 NULL
, // ImageHandle, overwritten in entry point
827 NULL
// DriverBindingHandle, ditto
831 // Entry point of the driver.
835 VirtioGpuEntryPoint (
836 IN EFI_HANDLE ImageHandle
,
837 IN EFI_SYSTEM_TABLE
*SystemTable
840 return EfiLibInstallDriverBindingComponentName2 (ImageHandle
, SystemTable
,
841 &mDriverBinding
, ImageHandle
, NULL
/* ComponentName */,