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/BaseMemoryLib.h>
19 #include <Library/DevicePathLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/PrintLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
24 #include <Protocol/ComponentName2.h>
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/DriverBinding.h>
27 #include <Protocol/PciIo.h>
29 #include "VirtioGpu.h"
32 // Dummy Graphics Output Protocol GUID: a temporary placeholder for the EFI
33 // counterpart. It will be replaced with the real thing as soon as we implement
34 // the EFI GOP. Refer to VGPU_GOP.Gop.
36 STATIC EFI_GUID mDummyGraphicsOutputProtocolGuid
= {
37 0x4983f8dc, 0x2782, 0x415b,
38 { 0x91, 0xf5, 0x2c, 0xeb, 0x48, 0x4a, 0x0f, 0xe9 }
42 // The device path node that describes the Video Output Device Attributes for
43 // the single head (UEFI child handle) that we support.
45 // The ACPI_DISPLAY_ADR() macro corresponds to Table B-2, section "B.4.2 _DOD"
46 // in the ACPI 3.0b spec, or more recently, to Table B-379, section "B.3.2
47 // _DOD" in the ACPI 6.0 spec.
49 STATIC CONST ACPI_ADR_DEVICE_PATH mAcpiAdr
= {
51 ACPI_DEVICE_PATH
, // Type
52 ACPI_ADR_DP
, // SubType
53 { sizeof mAcpiAdr
, 0 }, // Length
55 ACPI_DISPLAY_ADR ( // ADR
56 1, // DeviceIdScheme: use the ACPI
57 // bit-field definitions
62 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL
, // Type
69 // Component Name 2 Protocol implementation.
71 STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
72 { "en", L
"Virtio GPU Driver" },
79 VirtioGpuGetDriverName (
80 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
82 OUT CHAR16
**DriverName
85 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
86 mDriverNameTable
, DriverName
, FALSE
/* Iso639Language */);
92 VirtioGpuGetControllerName (
93 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
94 IN EFI_HANDLE ControllerHandle
,
95 IN EFI_HANDLE ChildHandle OPTIONAL
,
97 OUT CHAR16
**ControllerName
104 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
106 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
107 (VOID
**)&VgpuDev
, gImageHandle
, ControllerHandle
,
108 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
109 if (EFI_ERROR (Status
)) {
113 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
114 // keep its Virtio Device Protocol interface open BY_DRIVER.
116 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
, gImageHandle
,
117 &gVirtioDeviceProtocolGuid
));
119 if (ChildHandle
== NULL
) {
121 // The caller is querying the name of the VGPU_DEV controller.
123 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
124 VgpuDev
->BusName
, ControllerName
, FALSE
/* Iso639Language */);
128 // Otherwise, the caller is looking for the name of the GOP child controller.
129 // Check if it is asking about the GOP child controller that we manage. (The
130 // condition below covers the case when we haven't produced the GOP child
131 // controller yet, or we've destroyed it since.)
133 if (VgpuDev
->Child
== NULL
|| ChildHandle
!= VgpuDev
->Child
->GopHandle
) {
134 return EFI_UNSUPPORTED
;
137 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
138 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
140 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
, ChildHandle
,
141 &gVirtioDeviceProtocolGuid
));
143 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
144 VgpuDev
->Child
->GopName
, ControllerName
,
145 FALSE
/* Iso639Language */);
148 STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
149 VirtioGpuGetDriverName
,
150 VirtioGpuGetControllerName
,
151 "en" // SupportedLanguages (RFC 4646)
155 // Helper functions for the Driver Binding Protocol Implementation.
158 Format the VGPU_DEV controller name, to be looked up and returned by
159 VirtioGpuGetControllerName().
161 @param[in] ControllerHandle The handle that identifies the VGPU_DEV
164 @param[in] AgentHandle The handle of the agent that will attempt to
165 temporarily open the PciIo protocol. This is the
166 DriverBindingHandle member of the
167 EFI_DRIVER_BINDING_PROTOCOL whose Start()
168 function is calling this function.
170 @param[in] DevicePath The device path that is installed on
173 @param[out] ControllerName A dynamically allocated unicode string that
174 unconditionally says "Virtio GPU Device", with a
175 PCI Segment:Bus:Device.Function location
176 optionally appended. The latter part is only
177 produced if DevicePath contains at least one
178 PciIo node; in that case, the most specific such
179 node is used for retrieving the location info.
180 The caller is responsible for freeing
181 ControllerName after use.
183 @retval EFI_SUCCESS ControllerName has been formatted.
185 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for ControllerName.
190 IN EFI_HANDLE ControllerHandle
,
191 IN EFI_HANDLE AgentHandle
,
192 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
193 OUT CHAR16
**ControllerName
196 EFI_HANDLE PciIoHandle
;
197 EFI_PCI_IO_PROTOCOL
*PciIo
;
198 UINTN Segment
, Bus
, Device
, Function
;
199 STATIC CONST CHAR16 ControllerNameStem
[] = L
"Virtio GPU Device";
200 UINTN ControllerNameSize
;
202 if (EFI_ERROR (gBS
->LocateDevicePath (&gEfiPciIoProtocolGuid
, &DevicePath
,
204 EFI_ERROR (gBS
->OpenProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
,
205 (VOID
**)&PciIo
, AgentHandle
, ControllerHandle
,
206 EFI_OPEN_PROTOCOL_GET_PROTOCOL
)) ||
207 EFI_ERROR (PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
,
210 // Failed to retrieve location info, return verbatim copy of static string.
212 *ControllerName
= AllocateCopyPool (sizeof ControllerNameStem
,
214 return (*ControllerName
== NULL
) ? EFI_OUT_OF_RESOURCES
: EFI_SUCCESS
;
217 // Location info available, format ControllerName dynamically.
219 ControllerNameSize
= sizeof ControllerNameStem
+ // includes L'\0'
220 sizeof (CHAR16
) * (1 + 4 + // Segment
225 *ControllerName
= AllocatePool (ControllerNameSize
);
226 if (*ControllerName
== NULL
) {
227 return EFI_OUT_OF_RESOURCES
;
230 UnicodeSPrintAsciiFormat (*ControllerName
, ControllerNameSize
,
231 "%s %04x:%02x:%02x.%x", ControllerNameStem
, (UINT32
)Segment
, (UINT32
)Bus
,
232 (UINT32
)Device
, (UINT32
)Function
);
237 Dynamically allocate and initialize the VGPU_GOP child object within an
238 otherwise configured parent VGPU_DEV object.
240 This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
241 VIRTIO_DEVICE_PROTOCOL interface.
243 @param[in,out] ParentBus The pre-initialized VGPU_DEV object that the
244 newly created VGPU_GOP object will be the
247 @param[in] ParentDevicePath The device path protocol instance that is
248 installed on ParentBusController.
250 @param[in] ParentBusController The UEFI controller handle on which the
251 ParentBus VGPU_DEV object and the
252 ParentDevicePath device path protocol are
255 @param[in] DriverBindingHandle The DriverBindingHandle member of
256 EFI_DRIVER_BINDING_PROTOCOL whose Start()
257 function is calling this function. It is
258 passed as AgentHandle to gBS->OpenProtocol()
259 when creating the BY_CHILD_CONTROLLER
262 @retval EFI_SUCCESS ParentBus->Child has been created and
263 populated, and ParentBus->Child->GopHandle now
264 references ParentBusController->VirtIo
267 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
269 @return Error codes from underlying functions.
274 IN OUT VGPU_DEV
*ParentBus
,
275 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
276 IN EFI_HANDLE ParentBusController
,
277 IN EFI_HANDLE DriverBindingHandle
282 CHAR16
*ParentBusName
;
283 STATIC CONST CHAR16 NameSuffix
[] = L
" Head #0";
289 VgpuGop
= AllocateZeroPool (sizeof *VgpuGop
);
290 if (VgpuGop
== NULL
) {
291 return EFI_OUT_OF_RESOURCES
;
294 VgpuGop
->Signature
= VGPU_GOP_SIG
;
295 VgpuGop
->ParentBus
= ParentBus
;
298 // Format a human-readable controller name for VGPU_GOP, and stash it for
299 // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
300 // ParentBus->BusName.
302 Status
= LookupUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
303 ParentBus
->BusName
, &ParentBusName
, FALSE
/* Iso639Language */);
304 ASSERT_EFI_ERROR (Status
);
305 NameSize
= StrSize (ParentBusName
) - sizeof (CHAR16
) + sizeof NameSuffix
;
306 Name
= AllocatePool (NameSize
);
308 Status
= EFI_OUT_OF_RESOURCES
;
311 UnicodeSPrintAsciiFormat (Name
, NameSize
, "%s%s", ParentBusName
, NameSuffix
);
312 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
313 &VgpuGop
->GopName
, Name
, FALSE
/* Iso639Language */);
315 if (EFI_ERROR (Status
)) {
320 // Create the child device path.
322 VgpuGop
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
,
324 if (VgpuGop
->GopDevicePath
== NULL
) {
325 Status
= EFI_OUT_OF_RESOURCES
;
326 goto FreeVgpuGopName
;
330 // Mask protocol notify callbacks until we're done.
332 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
335 // Create the child handle with the child device path.
337 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
338 &gEfiDevicePathProtocolGuid
, EFI_NATIVE_INTERFACE
,
339 VgpuGop
->GopDevicePath
);
340 if (EFI_ERROR (Status
)) {
345 // The child handle must present a reference to the parent handle's Virtio
346 // Device Protocol interface.
348 Status
= gBS
->OpenProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
349 &ParentVirtIo
, DriverBindingHandle
, VgpuGop
->GopHandle
,
350 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
351 if (EFI_ERROR (Status
)) {
352 goto UninstallDevicePath
;
354 ASSERT (ParentVirtIo
== ParentBus
->VirtIo
);
357 // Initialize our Graphics Output Protocol.
359 // This means "nothing" for now.
361 Status
= EFI_SUCCESS
;
362 if (EFI_ERROR (Status
)) {
363 goto CloseVirtIoByChild
;
367 // Install the Graphics Output Protocol on the child handle.
369 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
370 &mDummyGraphicsOutputProtocolGuid
, EFI_NATIVE_INTERFACE
,
372 if (EFI_ERROR (Status
)) {
379 gBS
->RestoreTPL (OldTpl
);
380 ParentBus
->Child
= VgpuGop
;
389 gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
390 DriverBindingHandle
, VgpuGop
->GopHandle
);
393 gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
394 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
397 gBS
->RestoreTPL (OldTpl
);
398 FreePool (VgpuGop
->GopDevicePath
);
401 FreeUnicodeStringTable (VgpuGop
->GopName
);
410 Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
413 This function removes the BY_CHILD_CONTROLLER reference from
414 ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
416 @param[in,out] ParentBus The VGPU_DEV object that the VGPU_GOP child
417 object will be removed from.
419 @param[in] ParentBusController The UEFI controller handle on which the
420 ParentBus VGPU_DEV object is installed.
422 @param[in] DriverBindingHandle The DriverBindingHandle member of
423 EFI_DRIVER_BINDING_PROTOCOL whose Stop()
424 function is calling this function. It is
425 passed as AgentHandle to gBS->CloseProtocol()
426 when removing the BY_CHILD_CONTROLLER
432 IN OUT VGPU_DEV
*ParentBus
,
433 IN EFI_HANDLE ParentBusController
,
434 IN EFI_HANDLE DriverBindingHandle
440 VgpuGop
= ParentBus
->Child
;
441 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
442 &mDummyGraphicsOutputProtocolGuid
, &VgpuGop
->Gop
);
443 ASSERT_EFI_ERROR (Status
);
446 // Uninitialize VgpuGop->Gop.
450 Status
= EFI_SUCCESS
;
451 ASSERT_EFI_ERROR (Status
);
453 Status
= gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
454 DriverBindingHandle
, VgpuGop
->GopHandle
);
455 ASSERT_EFI_ERROR (Status
);
457 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
458 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
459 ASSERT_EFI_ERROR (Status
);
461 FreePool (VgpuGop
->GopDevicePath
);
462 FreeUnicodeStringTable (VgpuGop
->GopName
);
465 ParentBus
->Child
= NULL
;
469 // Driver Binding Protocol Implementation.
474 VirtioGpuDriverBindingSupported (
475 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
476 IN EFI_HANDLE ControllerHandle
,
477 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
481 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
484 // - If RemainingDevicePath is NULL: the caller is interested in creating all
486 // - If RemainingDevicePath points to an end node: the caller is not
487 // interested in creating any child handle.
488 // - Otherwise, the caller would like to create the one child handle
489 // specified in RemainingDevicePath. In this case we have to see if the
490 // requested device path is supportable.
492 if (RemainingDevicePath
!= NULL
&&
493 !IsDevicePathEnd (RemainingDevicePath
) &&
494 (DevicePathNodeLength (RemainingDevicePath
) != sizeof mAcpiAdr
||
495 CompareMem (RemainingDevicePath
, &mAcpiAdr
, sizeof mAcpiAdr
) != 0)) {
496 return EFI_UNSUPPORTED
;
500 // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
502 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
503 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
504 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
505 if (EFI_ERROR (Status
)) {
507 // If this fails, then by default we cannot support ControllerHandle. There
508 // is one exception: we've already bound the device, have not produced any
509 // GOP child controller, and now the caller wants us to produce the child
510 // controller (either specifically or as part of "all children"). That's
513 if (Status
== EFI_ALREADY_STARTED
) {
517 Status2
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
518 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
519 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
520 ASSERT_EFI_ERROR (Status2
);
522 if (VgpuDev
->Child
== NULL
&&
523 (RemainingDevicePath
== NULL
||
524 !IsDevicePathEnd (RemainingDevicePath
))) {
525 Status
= EFI_SUCCESS
;
533 // First BY_DRIVER open; check the VirtIo revision and subsystem.
535 if (VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0) ||
536 VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_GPU_DEVICE
) {
537 Status
= EFI_UNSUPPORTED
;
542 // We'll need the device path of the VirtIo device both for formatting
543 // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
545 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
546 NULL
, This
->DriverBindingHandle
, ControllerHandle
,
547 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
550 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
551 This
->DriverBindingHandle
, ControllerHandle
);
559 VirtioGpuDriverBindingStart (
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
;
567 BOOLEAN VirtIoBoundJustNow
;
569 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
572 // Open the Virtio Device Protocol.
574 // The result of this operation, combined with the checks in
575 // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
576 // binding the VirtIo controller on this call (with or without creating child
577 // controllers), or else we're *only* creating child controllers.
579 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
580 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
581 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
582 if (EFI_ERROR (Status
)) {
584 // The assertions below are based on the success of
585 // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
586 // without producing child handles, and now we're producing the GOP child
589 ASSERT (Status
== EFI_ALREADY_STARTED
);
591 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
592 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
593 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
594 ASSERT_EFI_ERROR (Status
);
596 ASSERT (VgpuDev
->Child
== NULL
);
598 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
600 VirtIoBoundJustNow
= FALSE
;
602 VirtIoBoundJustNow
= TRUE
;
605 // Allocate the private structure.
607 VgpuDev
= AllocateZeroPool (sizeof *VgpuDev
);
608 if (VgpuDev
== NULL
) {
609 Status
= EFI_OUT_OF_RESOURCES
;
612 VgpuDev
->VirtIo
= VirtIo
;
616 // Grab the VirtIo controller's device path. This is necessary regardless of
617 // VirtIoBoundJustNow.
619 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
620 (VOID
**)&DevicePath
, This
->DriverBindingHandle
,
621 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
622 if (EFI_ERROR (Status
)) {
627 // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
628 // if we aren't *only* creating child handles).
630 if (VirtIoBoundJustNow
) {
634 // Format a human-readable controller name for VGPU_DEV, and stash it for
635 // VirtioGpuGetControllerName() to look up.
637 Status
= FormatVgpuDevName (ControllerHandle
, This
->DriverBindingHandle
,
638 DevicePath
, &VgpuDevName
);
639 if (EFI_ERROR (Status
)) {
642 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
643 &VgpuDev
->BusName
, VgpuDevName
, FALSE
/* Iso639Language */);
644 FreePool (VgpuDevName
);
645 if (EFI_ERROR (Status
)) {
650 // Install the VGPU_DEV "protocol interface" on ControllerHandle.
652 Status
= gBS
->InstallProtocolInterface (&ControllerHandle
,
653 &gEfiCallerIdGuid
, EFI_NATIVE_INTERFACE
, VgpuDev
);
654 if (EFI_ERROR (Status
)) {
655 goto FreeVgpuDevBusName
;
658 if (RemainingDevicePath
!= NULL
&& IsDevicePathEnd (RemainingDevicePath
)) {
660 // No child handle should be produced; we're done.
662 DEBUG ((EFI_D_INFO
, "%a: bound VirtIo=%p without producing GOP\n",
663 __FUNCTION__
, (VOID
*)VgpuDev
->VirtIo
));
669 // Below we'll produce our single child handle: the caller requested it
670 // either specifically, or as part of all child handles.
672 ASSERT (VgpuDev
->Child
== NULL
);
674 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
676 Status
= InitVgpuGop (VgpuDev
, DevicePath
, ControllerHandle
,
677 This
->DriverBindingHandle
);
678 if (EFI_ERROR (Status
)) {
679 goto UninstallVgpuDev
;
685 DEBUG ((EFI_D_INFO
, "%a: produced GOP %a VirtIo=%p\n", __FUNCTION__
,
686 VirtIoBoundJustNow
? "while binding" : "for pre-bound",
687 (VOID
*)VgpuDev
->VirtIo
));
691 if (VirtIoBoundJustNow
) {
692 gBS
->UninstallProtocolInterface (ControllerHandle
, &gEfiCallerIdGuid
,
697 if (VirtIoBoundJustNow
) {
698 FreeUnicodeStringTable (VgpuDev
->BusName
);
702 if (VirtIoBoundJustNow
) {
707 if (VirtIoBoundJustNow
) {
708 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
709 This
->DriverBindingHandle
, ControllerHandle
);
718 VirtioGpuDriverBindingStop (
719 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
720 IN EFI_HANDLE ControllerHandle
,
721 IN UINTN NumberOfChildren
,
722 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
729 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
731 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
732 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
733 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
734 if (EFI_ERROR (Status
)) {
738 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
739 // keep its Virtio Device Protocol interface open BY_DRIVER.
741 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
,
742 This
->DriverBindingHandle
, &gVirtioDeviceProtocolGuid
));
744 switch (NumberOfChildren
) {
747 // The caller wants us to unbind the VirtIo controller.
749 if (VgpuDev
->Child
!= NULL
) {
751 // We still have the GOP child.
753 Status
= EFI_DEVICE_ERROR
;
757 DEBUG ((EFI_D_INFO
, "%a: unbinding GOP-less VirtIo=%p\n", __FUNCTION__
,
758 (VOID
*)VgpuDev
->VirtIo
));
760 Status
= gBS
->UninstallProtocolInterface (ControllerHandle
,
761 &gEfiCallerIdGuid
, VgpuDev
);
762 ASSERT_EFI_ERROR (Status
);
764 FreeUnicodeStringTable (VgpuDev
->BusName
);
767 Status
= gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
768 This
->DriverBindingHandle
, ControllerHandle
);
769 ASSERT_EFI_ERROR (Status
);
774 // The caller wants us to destroy our child GOP controller.
776 if (VgpuDev
->Child
== NULL
||
777 ChildHandleBuffer
[0] != VgpuDev
->Child
->GopHandle
) {
779 // We have no child controller at the moment, or it differs from the one
780 // the caller wants us to destroy. I.e., we don't own the child
781 // controller passed in.
783 Status
= EFI_DEVICE_ERROR
;
787 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
788 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
790 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
,
791 VgpuDev
->Child
->GopHandle
,
792 &gVirtioDeviceProtocolGuid
));
794 DEBUG ((EFI_D_INFO
, "%a: destroying GOP under VirtIo=%p\n", __FUNCTION__
,
795 (VOID
*)VgpuDev
->VirtIo
));
796 UninitVgpuGop (VgpuDev
, ControllerHandle
, This
->DriverBindingHandle
);
801 // Impossible, we never produced more than one child.
803 Status
= EFI_DEVICE_ERROR
;
809 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
810 VirtioGpuDriverBindingSupported
,
811 VirtioGpuDriverBindingStart
,
812 VirtioGpuDriverBindingStop
,
814 NULL
, // ImageHandle, overwritten in entry point
815 NULL
// DriverBindingHandle, ditto
819 // Entry point of the driver.
823 VirtioGpuEntryPoint (
824 IN EFI_HANDLE ImageHandle
,
825 IN EFI_SYSTEM_TABLE
*SystemTable
828 return EfiLibInstallDriverBindingComponentName2 (ImageHandle
, SystemTable
,
829 &mDriverBinding
, ImageHandle
, NULL
/* ComponentName */,