4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2011, Apple Inc. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "EmuBusDriverDxe.h"
16 // DriverBinding protocol global
18 EFI_DRIVER_BINDING_PROTOCOL gEmuBusDriverBinding
= {
19 EmuBusDriverBindingSupported
,
20 EmuBusDriverBindingStart
,
21 EmuBusDriverBindingStop
,
31 EmuBusDriverBindingSupported (
32 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
33 IN EFI_HANDLE ControllerHandle
,
34 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
38 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
39 EMU_THUNK_PROTOCOL
*EmuThunk
;
42 // Check the contents of the first Device Path Node of RemainingDevicePath to make sure
43 // it is a legal Device Path Node for this bus driver's children.
45 if (RemainingDevicePath
!= NULL
) {
47 // Check if RemainingDevicePath is the End of Device Path Node,
48 // if yes, go on checking other conditions
50 if (!IsDevicePathEnd (RemainingDevicePath
)) {
52 // If RemainingDevicePath isn't the End of Device Path Node,
53 // check its validation
55 if (RemainingDevicePath
->Type
!= HARDWARE_DEVICE_PATH
||
56 RemainingDevicePath
->SubType
!= HW_VENDOR_DP
||
57 DevicePathNodeLength(RemainingDevicePath
) != sizeof(EMU_VENDOR_DEVICE_PATH_NODE
)) {
58 return EFI_UNSUPPORTED
;
64 // Open the IO Abstraction(s) needed to perform the supported test
66 Status
= gBS
->OpenProtocol (
68 &gEmuThunkProtocolGuid
,
70 This
->DriverBindingHandle
,
72 EFI_OPEN_PROTOCOL_BY_DRIVER
74 if (Status
== EFI_ALREADY_STARTED
) {
78 if (EFI_ERROR (Status
)) {
83 // Close the I/O Abstraction(s) used to perform the supported test
87 &gEmuThunkProtocolGuid
,
88 This
->DriverBindingHandle
,
93 // Open the EFI Device Path protocol needed to perform the supported test
95 Status
= gBS
->OpenProtocol (
97 &gEfiDevicePathProtocolGuid
,
98 (VOID
**)&ParentDevicePath
,
99 This
->DriverBindingHandle
,
101 EFI_OPEN_PROTOCOL_BY_DRIVER
103 if (Status
== EFI_ALREADY_STARTED
) {
107 if (EFI_ERROR (Status
)) {
113 // Close protocol, don't use device path protocol in the Support() function
117 &gEfiDevicePathProtocolGuid
,
118 This
->DriverBindingHandle
,
128 EmuBusDriverBindingStart (
129 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
130 IN EFI_HANDLE ControllerHandle
,
131 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
135 EFI_STATUS InstallStatus
;
136 EMU_THUNK_PROTOCOL
*EmuThunk
;
137 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
138 EMU_IO_DEVICE
*EmuDevice
;
139 EMU_BUS_DEVICE
*EmuBusDevice
;
140 EMU_IO_THUNK_PROTOCOL
*EmuIoThunk
;
141 UINT16 ComponentName
[512];
142 EMU_VENDOR_DEVICE_PATH_NODE
*Node
;
143 BOOLEAN CreateDevice
;
145 InstallStatus
= EFI_UNSUPPORTED
;
146 Status
= EFI_UNSUPPORTED
;
149 // Grab the protocols we need
151 Status
= gBS
->OpenProtocol (
153 &gEfiDevicePathProtocolGuid
,
154 (VOID
**)&ParentDevicePath
,
155 This
->DriverBindingHandle
,
157 EFI_OPEN_PROTOCOL_BY_DRIVER
159 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
163 Status
= gBS
->OpenProtocol (
165 &gEmuThunkProtocolGuid
,
167 This
->DriverBindingHandle
,
169 EFI_OPEN_PROTOCOL_BY_DRIVER
171 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
175 if (Status
!= EFI_ALREADY_STARTED
) {
176 EmuBusDevice
= AllocatePool (sizeof (EMU_BUS_DEVICE
));
177 if (EmuBusDevice
== NULL
) {
178 return EFI_OUT_OF_RESOURCES
;
181 EmuBusDevice
->Signature
= EMU_BUS_DEVICE_SIGNATURE
;
182 EmuBusDevice
->ControllerNameTable
= NULL
;
186 gEmuBusDriverComponentName
.SupportedLanguages
,
187 &EmuBusDevice
->ControllerNameTable
,
188 L
"Emulator Bus Controller",
193 gEmuBusDriverComponentName2
.SupportedLanguages
,
194 &EmuBusDevice
->ControllerNameTable
,
195 L
"Emulator Bus Controller",
200 Status
= gBS
->InstallMultipleProtocolInterfaces (
202 &gEfiCallerIdGuid
, EmuBusDevice
,
205 if (EFI_ERROR (Status
)) {
206 FreeUnicodeStringTable (EmuBusDevice
->ControllerNameTable
);
207 gBS
->FreePool (EmuBusDevice
);
213 for (Status
= EFI_SUCCESS
, EmuIoThunk
= NULL
; !EFI_ERROR (Status
); ) {
214 Status
= EmuThunk
->GetNextProtocol (TRUE
, &EmuIoThunk
);
215 if (EFI_ERROR (Status
)) {
220 if (RemainingDevicePath
!= NULL
) {
221 CreateDevice
= FALSE
;
223 // Check if RemainingDevicePath is the End of Device Path Node,
224 // if yes, don't create any child device
226 if (!IsDevicePathEnd (RemainingDevicePath
)) {
228 // If RemainingDevicePath isn't the End of Device Path Node,
229 // check its validation
231 Node
= (EMU_VENDOR_DEVICE_PATH_NODE
*) RemainingDevicePath
;
232 if (Node
->VendorDevicePath
.Header
.Type
== HARDWARE_DEVICE_PATH
&&
233 Node
->VendorDevicePath
.Header
.SubType
== HW_VENDOR_DP
&&
234 DevicePathNodeLength (&Node
->VendorDevicePath
.Header
) == sizeof (EMU_VENDOR_DEVICE_PATH_NODE
)
236 if (CompareGuid (&Node
->VendorDevicePath
.Guid
, EmuIoThunk
->Protocol
) && Node
->Instance
== EmuIoThunk
->Instance
) {
245 // Allocate instance structure, and fill in parent information.
247 EmuDevice
= AllocatePool (sizeof (EMU_IO_DEVICE
));
248 if (EmuDevice
== NULL
) {
249 return EFI_OUT_OF_RESOURCES
;
252 EmuDevice
->Handle
= NULL
;
253 EmuDevice
->ControllerHandle
= ControllerHandle
;
254 EmuDevice
->ParentDevicePath
= ParentDevicePath
;
255 CopyMem (&EmuDevice
->EmuIoThunk
, EmuIoThunk
, sizeof (EMU_IO_THUNK_PROTOCOL
));
257 EmuDevice
->ControllerNameTable
= NULL
;
259 StrnCpy (ComponentName
, EmuIoThunk
->ConfigString
, sizeof (ComponentName
)/sizeof (CHAR16
));
261 EmuDevice
->DevicePath
= EmuBusCreateDevicePath (
263 EmuIoThunk
->Protocol
,
266 if (EmuDevice
->DevicePath
== NULL
) {
267 gBS
->FreePool (EmuDevice
);
268 return EFI_OUT_OF_RESOURCES
;
273 gEmuBusDriverComponentName
.SupportedLanguages
,
274 &EmuDevice
->ControllerNameTable
,
278 EmuDevice
->Signature
= EMU_IO_DEVICE_SIGNATURE
;
280 InstallStatus
= gBS
->InstallMultipleProtocolInterfaces (
282 &gEfiDevicePathProtocolGuid
, EmuDevice
->DevicePath
,
283 &gEmuIoThunkProtocolGuid
, &EmuDevice
->EmuIoThunk
,
286 if (EFI_ERROR (InstallStatus
)) {
287 FreeUnicodeStringTable (EmuDevice
->ControllerNameTable
);
288 gBS
->FreePool (EmuDevice
);
291 // Open For Child Device
293 Status
= gBS
->OpenProtocol (
295 &gEmuThunkProtocolGuid
,
297 This
->DriverBindingHandle
,
299 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
301 if (!EFI_ERROR (Status
)) {
302 InstallStatus
= EFI_SUCCESS
;
308 return InstallStatus
;
314 EmuBusDriverBindingStop (
315 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
316 IN EFI_HANDLE ControllerHandle
,
317 IN UINTN NumberOfChildren
,
318 IN EFI_HANDLE
*ChildHandleBuffer
323 BOOLEAN AllChildrenStopped
;
324 EMU_IO_THUNK_PROTOCOL
*EmuIoThunk
;
325 EMU_BUS_DEVICE
*EmuBusDevice
;
326 EMU_IO_DEVICE
*EmuDevice
;
327 EMU_THUNK_PROTOCOL
*EmuThunk
;
330 // Complete all outstanding transactions to Controller.
331 // Don't allow any new transaction to Controller to be started.
334 if (NumberOfChildren
== 0) {
336 // Close the bus driver
338 Status
= gBS
->OpenProtocol (
341 (VOID
**)&EmuBusDevice
,
342 This
->DriverBindingHandle
,
344 EFI_OPEN_PROTOCOL_GET_PROTOCOL
346 if (EFI_ERROR (Status
)) {
350 gBS
->UninstallMultipleProtocolInterfaces (
352 &gEfiCallerIdGuid
, EmuBusDevice
,
356 FreeUnicodeStringTable (EmuBusDevice
->ControllerNameTable
);
358 gBS
->FreePool (EmuBusDevice
);
362 &gEmuThunkProtocolGuid
,
363 This
->DriverBindingHandle
,
369 &gEfiDevicePathProtocolGuid
,
370 This
->DriverBindingHandle
,
376 AllChildrenStopped
= TRUE
;
378 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
380 Status
= gBS
->OpenProtocol (
381 ChildHandleBuffer
[Index
],
382 &gEmuIoThunkProtocolGuid
,
383 (VOID
**)&EmuIoThunk
,
384 This
->DriverBindingHandle
,
386 EFI_OPEN_PROTOCOL_GET_PROTOCOL
388 if (!EFI_ERROR (Status
)) {
389 EmuDevice
= EMU_IO_DEVICE_FROM_THIS (EmuIoThunk
);
391 Status
= gBS
->CloseProtocol (
393 &gEmuThunkProtocolGuid
,
394 This
->DriverBindingHandle
,
398 Status
= gBS
->UninstallMultipleProtocolInterfaces (
400 &gEfiDevicePathProtocolGuid
, EmuDevice
->DevicePath
,
401 &gEmuIoThunkProtocolGuid
, &EmuDevice
->EmuIoThunk
,
405 if (EFI_ERROR (Status
)) {
408 &gEmuThunkProtocolGuid
,
409 (VOID
**) &EmuThunk
,
410 This
->DriverBindingHandle
,
412 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
416 // Close the child handle
418 FreeUnicodeStringTable (EmuDevice
->ControllerNameTable
);
419 FreePool (EmuDevice
);
423 if (EFI_ERROR (Status
)) {
424 AllChildrenStopped
= FALSE
;
428 if (!AllChildrenStopped
) {
429 return EFI_DEVICE_ERROR
;
439 Create a device path node using Guid and InstanceNumber and append it to
440 the passed in RootDevicePath
443 RootDevicePath - Root of the device path to return.
445 Guid - GUID to use in vendor device path node.
447 InstanceNumber - Instance number to use in the vendor device path. This
448 argument is needed to make sure each device path is unique.
452 EFI_DEVICE_PATH_PROTOCOL
455 EFI_DEVICE_PATH_PROTOCOL
*
456 EmuBusCreateDevicePath (
457 IN EFI_DEVICE_PATH_PROTOCOL
*RootDevicePath
,
459 IN UINT16 InstanceNumber
462 EMU_VENDOR_DEVICE_PATH_NODE DevicePath
;
464 DevicePath
.VendorDevicePath
.Header
.Type
= HARDWARE_DEVICE_PATH
;
465 DevicePath
.VendorDevicePath
.Header
.SubType
= HW_VENDOR_DP
;
466 SetDevicePathNodeLength (&DevicePath
.VendorDevicePath
.Header
, sizeof (EMU_VENDOR_DEVICE_PATH_NODE
));
469 // The GUID defines the Class
471 CopyMem (&DevicePath
.VendorDevicePath
.Guid
, Guid
, sizeof (EFI_GUID
));
474 // Add an instance number so we can make sure there are no Device Path
477 DevicePath
.Instance
= InstanceNumber
;
479 return AppendDevicePathNode (
481 (EFI_DEVICE_PATH_PROTOCOL
*) &DevicePath
488 The user Entry Point for module EmuBusDriver. The user code starts with this function.
490 @param[in] ImageHandle The firmware allocated handle for the EFI image.
491 @param[in] SystemTable A pointer to the EFI System Table.
493 @retval EFI_SUCCESS The entry point is executed successfully.
494 @retval other Some error occurs when executing this entry point.
499 InitializeEmuBusDriver (
500 IN EFI_HANDLE ImageHandle
,
501 IN EFI_SYSTEM_TABLE
*SystemTable
506 Status
= EfiLibInstallAllDriverProtocols (
509 &gEmuBusDriverBinding
,
511 &gEmuBusDriverComponentName
,
515 ASSERT_EFI_ERROR (Status
);