--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ notify.c\r
+\r
+Abstract:\r
+\r
+ EFI notify infrastructure\r
+\r
+\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include <DxeMain.h>\r
+\r
+VOID\r
+CoreNotifyProtocolEntry (\r
+ IN PROTOCOL_ENTRY *ProtEntry\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Signal event for every protocol in protocol entry.\r
+\r
+Arguments:\r
+\r
+ ProtEntry - Protocol entry\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ LIST_ENTRY *Link;\r
+\r
+ ASSERT_LOCKED (&gProtocolDatabaseLock);\r
+\r
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+ CoreSignalEvent (ProtNotify->Event);\r
+ }\r
+}\r
+\r
+\r
+PROTOCOL_INTERFACE *\r
+CoreRemoveInterfaceFromProtocol (\r
+ IN IHANDLE *Handle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Removes Protocol from the protocol list (but not the handle list).\r
+\r
+Arguments:\r
+\r
+ Handle - The handle to remove protocol on.\r
+\r
+ Protocol - GUID of the protocol to be moved\r
+\r
+ Interface - The interface of the protocol\r
+\r
+Returns:\r
+\r
+ Protocol Entry\r
+\r
+--*/\r
+{\r
+ PROTOCOL_INTERFACE *Prot;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ ASSERT_LOCKED (&gProtocolDatabaseLock);\r
+\r
+ Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);\r
+ if (Prot != NULL) {\r
+\r
+ ProtEntry = Prot->Protocol;\r
+\r
+ //\r
+ // If there's a protocol notify location pointing to this entry, back it up one\r
+ //\r
+\r
+ for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+\r
+ if (ProtNotify->Position == &Prot->ByProtocol) {\r
+ ProtNotify->Position = Prot->ByProtocol.BackLink;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Remove the protocol interface entry\r
+ //\r
+\r
+ RemoveEntryList (&Prot->ByProtocol);\r
+ }\r
+\r
+ return Prot;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreRegisterProtocolNotify (\r
+ IN EFI_GUID *Protocol,\r
+ IN EFI_EVENT Event,\r
+ OUT VOID **Registration\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Add a new protocol notification record for the request protocol.\r
+\r
+Arguments:\r
+\r
+ Protocol - The requested protocol to add the notify registration\r
+\r
+ Event - The event to signal \r
+\r
+ Registration - Returns the registration record\r
+\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - Invalid parameter\r
+\r
+ EFI_SUCCESS - Successfully returned the registration record that has been added\r
+ \r
+--*/\r
+{\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ EFI_STATUS Status;\r
+ \r
+ if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CoreAcquireProtocolLock ();\r
+\r
+ ProtNotify = NULL;\r
+ \r
+ //\r
+ // Get the protocol entry to add the notification too\r
+ //\r
+\r
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);\r
+ if (ProtEntry != NULL) {\r
+\r
+ //\r
+ // Allocate a new notification record\r
+ //\r
+\r
+ ProtNotify = CoreAllocateBootServicesPool (sizeof(PROTOCOL_NOTIFY));\r
+\r
+ if (ProtNotify != NULL) {\r
+ \r
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;\r
+ ProtNotify->Protocol = ProtEntry;\r
+ ProtNotify->Event = Event;\r
+ //\r
+ // start at the begining\r
+ //\r
+ ProtNotify->Position = &ProtEntry->Protocols; \r
+\r
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);\r
+ }\r
+ }\r
+\r
+ CoreReleaseProtocolLock ();\r
+\r
+ //\r
+ // Done. If we have a protocol notify entry, then return it.\r
+ // Otherwise, we must have run out of resources trying to add one\r
+ //\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ if (ProtNotify != NULL) {\r
+ *Registration = ProtNotify;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreReinstallProtocolInterface (\r
+ IN EFI_HANDLE UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *OldInterface,\r
+ IN VOID *NewInterface\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.\r
+\r
+Arguments:\r
+\r
+ UserHandle - Handle on which the interface is to be reinstalled\r
+ Protocol - The numeric ID of the interface\r
+ OldInterface - A pointer to the old interface\r
+ NewInterface - A pointer to the new interface \r
+\r
+\r
+Returns:\r
+\r
+ Status code.\r
+\r
+ On EFI_SUCCESS The protocol interface was installed\r
+ On EFI_NOT_FOUND The OldInterface on the handle was not found\r
+ On EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
+ \r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ IHANDLE *Handle;\r
+ PROTOCOL_INTERFACE *Prot;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+\r
+ Status = CoreValidateHandle (UserHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Protocol == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Handle = (IHANDLE *) UserHandle;\r
+\r
+ //\r
+ // Lock the protocol database\r
+ //\r
+ CoreAcquireProtocolLock ();\r
+\r
+ //\r
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database\r
+ //\r
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);\r
+ if (Prot == NULL) {\r
+ CoreReleaseProtocolLock ();\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled\r
+ //\r
+ Status = CoreDisconnectControllersUsingProtocolInterface (\r
+ UserHandle,\r
+ Prot\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // One or more drivers refused to release, so return the error\r
+ //\r
+ CoreReleaseProtocolLock ();\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Remove the protocol interface from the protocol\r
+ //\r
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);\r
+\r
+ if (Prot == NULL) {\r
+ CoreReleaseProtocolLock ();\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ProtEntry = Prot->Protocol;\r
+\r
+ //\r
+ // Update the interface on the protocol\r
+ //\r
+ Prot->Interface = NewInterface;\r
+\r
+ //\r
+ // Add this protocol interface to the tail of the\r
+ // protocol entry\r
+ //\r
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);\r
+\r
+ //\r
+ // Update the Key to show that the handle has been created/modified\r
+ //\r
+ gHandleDatabaseKey++;\r
+ Handle->Key = gHandleDatabaseKey;\r
+\r
+ //\r
+ // Release the lock and connect all drivers to UserHandle\r
+ //\r
+ CoreReleaseProtocolLock ();\r
+ Status = CoreConnectController (\r
+ UserHandle, \r
+ NULL, \r
+ NULL, \r
+ TRUE\r
+ );\r
+ CoreAcquireProtocolLock ();\r
+ \r
+ //\r
+ // Notify the notification list for this protocol\r
+ //\r
+ CoreNotifyProtocolEntry (ProtEntry);\r
+\r
+ CoreReleaseProtocolLock ();\r
+ \r
+ return EFI_SUCCESS;\r
+}\r