Files
system76-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c
2019-04-09 10:58:18 -07:00

508 lines
14 KiB
C

/** @file
Implement the driver binding protocol for Asix AX88772 Ethernet driver.
Copyright (c) 2011-2013, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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;
}