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