mirror of https://github.com/acidanthera/audk.git
495 lines
15 KiB
C
495 lines
15 KiB
C
/** @file
|
|
Connect to and disconnect from the various network layers
|
|
|
|
Copyright (c) 2011, Intel Corporation
|
|
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 "Socket.h"
|
|
|
|
|
|
/**
|
|
Connect to the network service bindings
|
|
|
|
Walk the network service protocols on the controller handle and
|
|
locate any that are not in use. Create ::ESL_SERVICE structures to
|
|
manage the network layer interfaces for the socket driver. Tag
|
|
each of the network interfaces that are being used. Finally, this
|
|
routine calls ESL_SOCKET_BINDING::pfnInitialize to prepare the network
|
|
interface for use by the socket layer.
|
|
|
|
@param [in] BindingHandle Handle for protocol binding.
|
|
@param [in] Controller Handle of device to work with.
|
|
|
|
@retval EFI_SUCCESS This driver is added to Controller.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EslServiceConnect (
|
|
IN EFI_HANDLE BindingHandle,
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
BOOLEAN bInUse;
|
|
UINTN LengthInBytes;
|
|
UINT8 * pBuffer;
|
|
CONST ESL_SOCKET_BINDING * pEnd;
|
|
VOID * pJunk;
|
|
ESL_SERVICE ** ppServiceListHead;
|
|
ESL_SERVICE * pService;
|
|
CONST ESL_SOCKET_BINDING * pSocketBinding;
|
|
EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
|
|
EFI_STATUS Status;
|
|
EFI_TPL TplPrevious;
|
|
|
|
DBG_ENTER ( );
|
|
|
|
//
|
|
// Assume the list is empty
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
bInUse = FALSE;
|
|
|
|
//
|
|
// Walk the list of network connection points
|
|
//
|
|
pSocketBinding = &cEslSocketBinding[0];
|
|
pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
|
|
while ( pEnd > pSocketBinding ) {
|
|
//
|
|
// Determine if the controller supports the network protocol
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
pSocketBinding->pNetworkBinding,
|
|
(VOID**)&pServiceBinding,
|
|
BindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if ( !EFI_ERROR ( Status )) {
|
|
//
|
|
// Determine if the socket layer is already connected
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
(EFI_GUID *)pSocketBinding->pTagGuid,
|
|
&pJunk,
|
|
BindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if ( EFI_UNSUPPORTED == Status ) {
|
|
//
|
|
// Allocate a service structure since the tag is not present
|
|
//
|
|
LengthInBytes = sizeof ( *pService );
|
|
Status = gBS->AllocatePool (
|
|
EfiRuntimeServicesData,
|
|
LengthInBytes,
|
|
(VOID **) &pService
|
|
);
|
|
if ( !EFI_ERROR ( Status )) {
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT,
|
|
"0x%08x: Allocate pService, %d bytes\r\n",
|
|
pService,
|
|
LengthInBytes ));
|
|
|
|
//
|
|
// Set the structure signature and service binding
|
|
//
|
|
ZeroMem ( pService, LengthInBytes );
|
|
pService->Signature = SERVICE_SIGNATURE;
|
|
pService->pSocketBinding = pSocketBinding;
|
|
pService->Controller = Controller;
|
|
pService->pServiceBinding = pServiceBinding;
|
|
|
|
//
|
|
// Mark the controller in use
|
|
//
|
|
if ( !bInUse ) {
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Controller,
|
|
&gEfiCallerIdGuid,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( !EFI_ERROR ( Status )) {
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
|
|
"Installed: gEfiCallerIdGuid on 0x%08x\r\n",
|
|
Controller ));
|
|
bInUse = TRUE;
|
|
}
|
|
else {
|
|
if ( EFI_INVALID_PARAMETER == Status ) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
if ( !EFI_ERROR ( Status )) {
|
|
//
|
|
// Mark the network service protocol in use
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Controller,
|
|
pSocketBinding->pTagGuid,
|
|
pService,
|
|
NULL
|
|
);
|
|
if ( !EFI_ERROR ( Status )) {
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
|
|
"Installed: %s TagGuid on 0x%08x\r\n",
|
|
pSocketBinding->pName,
|
|
Controller ));
|
|
|
|
//
|
|
// Synchronize with the socket layer
|
|
//
|
|
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
|
|
|
|
//
|
|
// Connect the service to the list
|
|
//
|
|
pBuffer = (UINT8 *)&mEslLayer;
|
|
pBuffer = &pBuffer[ pSocketBinding->ServiceListOffset ];
|
|
ppServiceListHead = (ESL_SERVICE **)pBuffer;
|
|
pService->pNext = *ppServiceListHead;
|
|
*ppServiceListHead = pService;
|
|
|
|
//
|
|
// Release the socket layer synchronization
|
|
//
|
|
RESTORE_TPL ( TplPrevious );
|
|
|
|
//
|
|
// Determine if the initialization was successful
|
|
//
|
|
if ( EFI_ERROR ( Status )) {
|
|
DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
|
|
"ERROR - Failed to initialize service %s on 0x%08x, Status: %r\r\n",
|
|
pSocketBinding->pName,
|
|
Controller,
|
|
Status ));
|
|
|
|
//
|
|
// Free the network service binding if necessary
|
|
//
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
pSocketBinding->pTagGuid,
|
|
pService,
|
|
NULL );
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
|
|
"Removed: %s TagGuid from 0x%08x\r\n",
|
|
pSocketBinding->pName,
|
|
Controller ));
|
|
}
|
|
}
|
|
else {
|
|
DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
|
|
"ERROR - Failed to install %s TagGuid on 0x%08x, Status: %r\r\n",
|
|
pSocketBinding->pName,
|
|
Controller,
|
|
Status ));
|
|
}
|
|
|
|
if ( EFI_ERROR ( Status )) {
|
|
//
|
|
// The controller is no longer in use
|
|
//
|
|
if ( bInUse ) {
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
&gEfiCallerIdGuid,
|
|
NULL,
|
|
NULL );
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
|
|
"Removed: gEfiCallerIdGuid from 0x%08x\r\n",
|
|
Controller ));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DEBUG (( DEBUG_ERROR | DEBUG_INIT,
|
|
"ERROR - Failed to install gEfiCallerIdGuid on 0x%08x, Status: %r\r\n",
|
|
Controller,
|
|
Status ));
|
|
}
|
|
|
|
//
|
|
// Release the service if necessary
|
|
//
|
|
if ( EFI_ERROR ( Status )) {
|
|
gBS->FreePool ( pService );
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT,
|
|
"0x%08x: Free pService, %d bytes\r\n",
|
|
pService,
|
|
sizeof ( *pService )));
|
|
pService = NULL;
|
|
}
|
|
}
|
|
else {
|
|
DEBUG (( DEBUG_ERROR | DEBUG_INIT,
|
|
"ERROR - Failed service allocation, Status: %r\r\n",
|
|
Status ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the next network protocol
|
|
//
|
|
pSocketBinding += 1;
|
|
}
|
|
|
|
//
|
|
// Display the driver start status
|
|
//
|
|
DBG_EXIT_STATUS ( Status );
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Shutdown the connections to the network layer by locating the
|
|
tags on the network interfaces established by ::EslServiceConnect.
|
|
This routine shutdowns any activity on the network interface and
|
|
then frees the ::ESL_SERVICE structures.
|
|
|
|
@param [in] BindingHandle Handle for protocol binding.
|
|
@param [in] Controller Handle of device to stop driver on.
|
|
|
|
@retval EFI_SUCCESS This driver is removed Controller.
|
|
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
|
@retval other This driver was not removed from this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EslServiceDisconnect (
|
|
IN EFI_HANDLE BindingHandle,
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
UINT8 * pBuffer;
|
|
CONST ESL_SOCKET_BINDING * pEnd;
|
|
ESL_PORT * pPort;
|
|
ESL_SERVICE * pPreviousService;
|
|
ESL_SERVICE * pService;
|
|
ESL_SERVICE ** ppServiceListHead;
|
|
CONST ESL_SOCKET_BINDING * pSocketBinding;
|
|
EFI_STATUS Status;
|
|
EFI_TPL TplPrevious;
|
|
|
|
DBG_ENTER ( );
|
|
|
|
//
|
|
// Walk the list of network connection points in reverse order
|
|
//
|
|
pEnd = &cEslSocketBinding[0];
|
|
pSocketBinding = &pEnd[ cEslSocketBindingEntries ];
|
|
while ( pEnd < pSocketBinding ) {
|
|
//
|
|
// Set the next network protocol
|
|
//
|
|
pSocketBinding -= 1;
|
|
|
|
//
|
|
// Determine if the driver connected
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
(EFI_GUID *)pSocketBinding->pTagGuid,
|
|
(VOID **)&pService,
|
|
BindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if ( !EFI_ERROR ( Status )) {
|
|
|
|
//
|
|
// Synchronize with the socket layer
|
|
//
|
|
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
|
|
|
|
//
|
|
// Walk the list of ports
|
|
//
|
|
pPort = pService->pPortList;
|
|
while ( NULL != pPort ) {
|
|
//
|
|
// Remove the port from the port list
|
|
//
|
|
pPort->pService = NULL;
|
|
pService->pPortList = pPort->pLinkService;
|
|
|
|
//
|
|
// Close the port
|
|
//
|
|
EslSocketPortCloseStart ( pPort,
|
|
TRUE,
|
|
DEBUG_POOL | DEBUG_INIT );
|
|
|
|
//
|
|
// Set the next port
|
|
//
|
|
pPort = pService->pPortList;
|
|
}
|
|
|
|
//
|
|
// Remove the service from the service list
|
|
//
|
|
pBuffer = (UINT8 *)&mEslLayer;
|
|
pBuffer = &pBuffer[ pService->pSocketBinding->ServiceListOffset ];
|
|
ppServiceListHead = (ESL_SERVICE **)pBuffer;
|
|
pPreviousService = *ppServiceListHead;
|
|
if ( pService == pPreviousService ) {
|
|
//
|
|
// Remove the service from the beginning of the list
|
|
//
|
|
*ppServiceListHead = pService->pNext;
|
|
}
|
|
else {
|
|
//
|
|
// Remove the service from the middle of the list
|
|
//
|
|
while ( NULL != pPreviousService ) {
|
|
if ( pService == pPreviousService->pNext ) {
|
|
pPreviousService->pNext = pService->pNext;
|
|
break;
|
|
}
|
|
pPreviousService = pPreviousService->pNext;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the socket layer synchronization
|
|
//
|
|
RESTORE_TPL ( TplPrevious );
|
|
|
|
//
|
|
// Break the driver connection
|
|
//
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
pSocketBinding->pTagGuid,
|
|
pService,
|
|
NULL );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT,
|
|
"Removed: %s TagGuid from 0x%08x\r\n",
|
|
pSocketBinding->pName,
|
|
Controller ));
|
|
}
|
|
else {
|
|
DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
|
|
"ERROR - Failed to removed %s TagGuid from 0x%08x, Status: %r\r\n",
|
|
pSocketBinding->pName,
|
|
Controller,
|
|
Status ));
|
|
}
|
|
|
|
//
|
|
// Free the service structure
|
|
//
|
|
Status = gBS->FreePool ( pService );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT,
|
|
"0x%08x: Free pService, %d bytes\r\n",
|
|
pService,
|
|
sizeof ( *pService )));
|
|
}
|
|
else {
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT,
|
|
"ERROR - Failed to free pService 0x%08x, Status: %r\r\n",
|
|
pService,
|
|
Status ));
|
|
}
|
|
pService = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The controller is no longer in use
|
|
//
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
&gEfiCallerIdGuid,
|
|
NULL,
|
|
NULL );
|
|
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
|
|
"Removed: gEfiCallerIdGuid from 0x%08x\r\n",
|
|
Controller ));
|
|
|
|
//
|
|
// The driver is disconnected from the network controller
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Display the driver start status
|
|
//
|
|
DBG_EXIT_STATUS ( Status );
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Initialize the service layer
|
|
|
|
@param [in] ImageHandle Handle for the image.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EslServiceLoad (
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
ESL_LAYER * pLayer;
|
|
|
|
//
|
|
// Save the image handle
|
|
//
|
|
pLayer = &mEslLayer;
|
|
ZeroMem ( pLayer, sizeof ( *pLayer ));
|
|
pLayer->Signature = LAYER_SIGNATURE;
|
|
pLayer->ImageHandle = ImageHandle;
|
|
|
|
//
|
|
// Connect the service binding protocol to the image handle
|
|
//
|
|
pLayer->pServiceBinding = &mEfiServiceBinding;
|
|
}
|
|
|
|
|
|
/**
|
|
Shutdown the service layer
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EslServiceUnload (
|
|
VOID
|
|
)
|
|
{
|
|
ESL_LAYER * pLayer;
|
|
|
|
//
|
|
// Undo the work by ServiceLoad
|
|
//
|
|
pLayer = &mEslLayer;
|
|
pLayer->ImageHandle = NULL;
|
|
pLayer->pServiceBinding = NULL;
|
|
}
|