/** @file | |
Implement the driver binding protocol for Asix AX88772 Ethernet driver. | |
Copyright (c) 2011-2013, Intel Corporation. All rights reserved.<BR> | |
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 "Ax88772.h" | |
/** | |
Verify the controller type | |
@param [in] pThis Protocol instance pointer. | |
@param [in] Controller Handle of device to test. | |
@param [in] pRemainingDevicePath Not used. | |
@retval EFI_SUCCESS This driver supports this device. | |
@retval other This driver does not support this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DriverSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL * pThis, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath | |
) | |
{ | |
EFI_USB_DEVICE_DESCRIPTOR Device; | |
EFI_USB_IO_PROTOCOL * pUsbIo; | |
EFI_STATUS Status; | |
// | |
// Connect to the USB stack | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiUsbIoProtocolGuid, | |
(VOID **) &pUsbIo, | |
pThis->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (!EFI_ERROR ( Status )) { | |
// | |
// Get the interface descriptor to check the USB class and find a transport | |
// protocol handler. | |
// | |
Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device ); | |
if (!EFI_ERROR ( Status )) { | |
// | |
// Validate the adapter | |
// | |
if (( VENDOR_ID != Device.IdVendor ) | |
|| ( PRODUCT_ID != Device.IdProduct )) { | |
Status = EFI_UNSUPPORTED; | |
} | |
} | |
// | |
// Done with the USB stack | |
// | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsbIoProtocolGuid, | |
pThis->DriverBindingHandle, | |
Controller | |
); | |
} | |
// | |
// Return the device supported status | |
// | |
return Status; | |
} | |
/** | |
Start this driver on Controller by opening UsbIo and DevicePath protocols. | |
Initialize PXE structures, create a copy of the Controller Device Path with the | |
NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol | |
on the newly created Device Path. | |
@param [in] pThis Protocol instance pointer. | |
@param [in] Controller Handle of device to work with. | |
@param [in] pRemainingDevicePath Not used, always produce all possible children. | |
@retval EFI_SUCCESS This driver is added to Controller. | |
@retval other This driver does not support this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DriverStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL * pThis, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
NIC_DEVICE * pNicDevice; | |
UINTN LengthInBytes; | |
DBG_ENTER ( ); | |
// | |
// Allocate the device structure | |
// | |
LengthInBytes = sizeof ( *pNicDevice ); | |
Status = gBS->AllocatePool ( | |
EfiRuntimeServicesData, | |
LengthInBytes, | |
(VOID **) &pNicDevice | |
); | |
if ( !EFI_ERROR ( Status )) { | |
DEBUG (( DEBUG_POOL | DEBUG_INIT, | |
"0x%08x: Allocate pNicDevice, %d bytes\r\n", | |
pNicDevice, | |
sizeof ( *pNicDevice ))); | |
// | |
// Set the structure signature | |
// | |
ZeroMem ( pNicDevice, LengthInBytes ); | |
pNicDevice->Signature = DEV_SIGNATURE; | |
// | |
// Connect to the USB I/O protocol | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiUsbIoProtocolGuid, | |
(VOID **) &pNicDevice->pUsbIo, | |
pThis->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if ( !EFI_ERROR ( Status )) { | |
// | |
// Allocate the necessary events | |
// | |
Status = gBS->CreateEvent ( EVT_TIMER, | |
TPL_AX88772, | |
(EFI_EVENT_NOTIFY)Ax88772Timer, | |
pNicDevice, | |
(VOID **)&pNicDevice->Timer ); | |
if ( !EFI_ERROR ( Status )) { | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"0x%08x: Allocated timer\r\n", | |
pNicDevice->Timer )); | |
// | |
// Initialize the simple network protocol | |
// | |
pNicDevice->Controller = Controller; | |
SN_Setup ( pNicDevice ); | |
// | |
// Start the timer | |
// | |
Status = gBS->SetTimer ( pNicDevice->Timer, | |
TimerPeriodic, | |
TIMER_MSEC ); | |
if ( !EFI_ERROR ( Status )) { | |
// | |
// Install both the simple network and device path protocols. | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&Controller, | |
&gEfiCallerIdGuid, | |
pNicDevice, | |
&gEfiSimpleNetworkProtocolGuid, | |
&pNicDevice->SimpleNetwork, | |
NULL | |
); | |
if ( !EFI_ERROR ( Status )) { | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Installed: gEfiCallerIdGuid on 0x%08x\r\n", | |
Controller )); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Installed: gEfiSimpleNetworkProtocolGuid on 0x%08x\r\n", | |
Controller )); | |
DBG_EXIT_STATUS ( Status ); | |
return Status; | |
} | |
DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO, | |
"ERROR - Failed to install gEfiSimpleNetworkProtocol on 0x%08x\r\n", | |
Controller )); | |
} | |
else { | |
DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO, | |
"ERROR - Failed to start the timer, Status: %r\r\n", | |
Status )); | |
} | |
} | |
else { | |
DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO, | |
"ERROR - Failed to create timer event, Status: %r\r\n", | |
Status )); | |
} | |
// | |
// Done with the USB stack | |
// | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsbIoProtocolGuid, | |
pThis->DriverBindingHandle, | |
Controller | |
); | |
} | |
// | |
// Done with the device | |
// | |
gBS->FreePool ( pNicDevice ); | |
} | |
// | |
// Display the driver start status | |
// | |
DBG_EXIT_STATUS ( Status ); | |
return Status; | |
} | |
/** | |
Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and | |
closing the DevicePath and PciIo protocols on Controller. | |
@param [in] pThis Protocol instance pointer. | |
@param [in] Controller Handle of device to stop driver on. | |
@param [in] NumberOfChildren How many children need to be stopped. | |
@param [in] pChildHandleBuffer Not used. | |
@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 | |
DriverStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL * pThis, | |
IN EFI_HANDLE Controller, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE * pChildHandleBuffer | |
) | |
{ | |
NIC_DEVICE * pNicDevice; | |
EFI_STATUS Status; | |
DBG_ENTER ( ); | |
// | |
// Determine if this driver is already attached | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiCallerIdGuid, | |
(VOID **) &pNicDevice, | |
pThis->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if ( !EFI_ERROR ( Status )) { | |
// | |
// AX88772 driver is no longer running on this device | |
// | |
gBS->UninstallMultipleProtocolInterfaces ( | |
Controller, | |
&gEfiSimpleNetworkProtocolGuid, | |
&pNicDevice->SimpleNetwork, | |
&gEfiCallerIdGuid, | |
pNicDevice, | |
NULL ); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT, | |
"Removed: gEfiSimpleNetworkProtocolGuid from 0x%08x\r\n", | |
Controller )); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT, | |
"Removed: gEfiCallerIdGuid from 0x%08x\r\n", | |
Controller )); | |
// | |
// Stop the timer | |
// | |
if ( NULL != pNicDevice->Timer ) { | |
gBS->SetTimer ( pNicDevice->Timer, TimerCancel, 0 ); | |
gBS->CloseEvent ( pNicDevice->Timer ); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"0x%08x: Released timer\r\n", | |
pNicDevice->Timer )); | |
} | |
// | |
// Done with the device context | |
// | |
DEBUG (( DEBUG_POOL | DEBUG_INIT, | |
"0x%08x: Free pNicDevice, %d bytes\r\n", | |
pNicDevice, | |
sizeof ( *pNicDevice ))); | |
gBS->FreePool ( pNicDevice ); | |
} | |
// | |
// Return the shutdown status | |
// | |
DBG_EXIT_STATUS ( Status ); | |
return Status; | |
} | |
/** | |
Driver binding protocol declaration | |
**/ | |
EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { | |
DriverSupported, | |
DriverStart, | |
DriverStop, | |
0xa, | |
NULL, | |
NULL | |
}; | |
/** | |
Ax88772 driver unload routine. | |
@param [in] ImageHandle Handle for the image. | |
@retval EFI_SUCCESS Image may be unloaded | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DriverUnload ( | |
IN EFI_HANDLE ImageHandle | |
) | |
{ | |
UINTN BufferSize; | |
UINTN Index; | |
UINTN Max; | |
EFI_HANDLE * pHandle; | |
EFI_STATUS Status; | |
// | |
// Determine which devices are using this driver | |
// | |
BufferSize = 0; | |
pHandle = NULL; | |
Status = gBS->LocateHandle ( | |
ByProtocol, | |
&gEfiCallerIdGuid, | |
NULL, | |
&BufferSize, | |
NULL ); | |
if ( EFI_BUFFER_TOO_SMALL == Status ) { | |
for ( ; ; ) { | |
// | |
// One or more block IO devices are present | |
// | |
Status = gBS->AllocatePool ( | |
EfiRuntimeServicesData, | |
BufferSize, | |
(VOID **) &pHandle | |
); | |
if ( EFI_ERROR ( Status )) { | |
DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Insufficient memory, failed handle buffer allocation\r\n" )); | |
break; | |
} | |
// | |
// Locate the block IO devices | |
// | |
Status = gBS->LocateHandle ( | |
ByProtocol, | |
&gEfiCallerIdGuid, | |
NULL, | |
&BufferSize, | |
pHandle ); | |
if ( EFI_ERROR ( Status )) { | |
// | |
// Error getting handles | |
// | |
DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO, | |
"Failure getting Telnet handles\r\n" )); | |
break; | |
} | |
// | |
// Remove any use of the driver | |
// | |
Max = BufferSize / sizeof ( pHandle[ 0 ]); | |
for ( Index = 0; Max > Index; Index++ ) { | |
Status = DriverStop ( &gDriverBinding, | |
pHandle[ Index ], | |
0, | |
NULL ); | |
if ( EFI_ERROR ( Status )) { | |
DEBUG (( DEBUG_WARN | DEBUG_INIT | DEBUG_INFO, | |
"WARNING - Failed to shutdown the driver on handle %08x\r\n", pHandle[ Index ])); | |
break; | |
} | |
} | |
break; | |
} | |
} | |
else { | |
if ( EFI_NOT_FOUND == Status ) { | |
// | |
// No devices were found | |
// | |
Status = EFI_SUCCESS; | |
} | |
} | |
// | |
// Free the handle array | |
// | |
if ( NULL != pHandle ) { | |
gBS->FreePool ( pHandle ); | |
} | |
// | |
// Remove the protocols installed by the EntryPoint routine. | |
// | |
if ( !EFI_ERROR ( Status )) { | |
gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gDriverBinding, | |
&gEfiComponentNameProtocolGuid, | |
&gComponentName, | |
&gEfiComponentName2ProtocolGuid, | |
&gComponentName2, | |
NULL | |
); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Removed: gEfiComponentName2ProtocolGuid from 0x%08x\r\n", | |
ImageHandle )); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Removed: gEfiComponentNameProtocolGuid from 0x%08x\r\n", | |
ImageHandle )); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Removed: gEfiDriverBindingProtocolGuid from 0x%08x\r\n", | |
ImageHandle )); | |
} | |
// | |
// Return the unload status | |
// | |
return Status; | |
} | |
/** | |
Ax88772 driver entry point. | |
@param [in] ImageHandle Handle for the image. | |
@param [in] pSystemTable Address of the system table. | |
@retval EFI_SUCCESS Image successfully loaded. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE * pSystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
DBG_ENTER ( ); | |
// | |
// Add the driver to the list of drivers | |
// | |
Status = EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
pSystemTable, | |
&gDriverBinding, | |
ImageHandle, | |
&gComponentName, | |
&gComponentName2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
if ( !EFI_ERROR ( Status )) { | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Installed: gEfiDriverBindingProtocolGuid on 0x%08x\r\n", | |
ImageHandle )); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Installed: gEfiComponentNameProtocolGuid on 0x%08x\r\n", | |
ImageHandle )); | |
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO, | |
"Installed: gEfiComponentName2ProtocolGuid on 0x%08x\r\n", | |
ImageHandle )); | |
} | |
DBG_EXIT_STATUS ( Status ); | |
return Status; | |
} |