audk/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding.c

697 lines
21 KiB
C

/** @file
Implement the driver binding protocol for Asix AX88772 Ethernet driver.
Copyright (c) 2011-2013, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Ax88772.h"
ASIX_DONGLE ASIX_DONGLES[] = {
{ 0x05AC, 0x1402, FLAG_TYPE_AX88772 }, // Apple USB Ethernet Adapter
// ASIX 88772B
{ 0x0B95, 0x772B, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
{ 0x0000, 0x0000, FLAG_NONE } // END - Do not remove
};
/**
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;
UINT32 Index;
//
// 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 )) {
Status = EFI_UNSUPPORTED;
}
else {
//
// Validate the adapter
//
for (Index = 0; ASIX_DONGLES[Index].VendorId != 0; Index++) {
if (ASIX_DONGLES[Index].VendorId == Device.IdVendor &&
ASIX_DONGLES[Index].ProductId == Device.IdProduct) {
DEBUG ((EFI_D_INFO, "Found the AX88772B\r\n"));
break;
}
}
if (ASIX_DONGLES[Index].VendorId == 0)
Status = EFI_UNSUPPORTED;
}
//
// Done with the USB stack
//
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
}
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;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath = NULL;
MAC_ADDR_DEVICE_PATH MacDeviceNode;
EFI_USB_DEVICE_DESCRIPTOR Device;
UINT32 Index;
//
// Allocate the device structure
//
LengthInBytes = sizeof ( *pNicDevice );
Status = gBS->AllocatePool (
EfiRuntimeServicesData,
LengthInBytes,
(VOID **) &pNicDevice
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "gBS->AllocatePool:pNicDevice ERROR Status = %r\n", Status));
goto EXIT;
}
//
// Set the structure signature
//
ZeroMem ( pNicDevice, LengthInBytes );
pNicDevice->Signature = DEV_SIGNATURE;
Status = gBS->OpenProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
(VOID **) &pNicDevice->pUsbIo,
pThis->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "gBS->OpenProtocol:EFI_USB_IO_PROTOCOL ERROR Status = %r\n", Status));
gBS->FreePool ( pNicDevice );
goto EXIT;
}
//
// Initialize the simple network protocol
//
Status = SN_Setup ( pNicDevice );
if (EFI_ERROR(Status)){
DEBUG ((EFI_D_ERROR, "SN_Setup ERROR Status = %r\n", Status));
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->FreePool ( pNicDevice );
goto EXIT;
}
Status = pNicDevice->pUsbIo->UsbGetDeviceDescriptor ( pNicDevice->pUsbIo, &Device );
if (EFI_ERROR ( Status )) {
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->FreePool ( pNicDevice );
goto EXIT;
} else {
//
// Validate the adapter
//
for (Index = 0; ASIX_DONGLES[Index].VendorId != 0; Index++) {
if (ASIX_DONGLES[Index].VendorId == Device.IdVendor &&
ASIX_DONGLES[Index].ProductId == Device.IdProduct) {
break;
}
}
if (ASIX_DONGLES[Index].VendorId == 0) {
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->FreePool ( pNicDevice );
goto EXIT;
}
pNicDevice->Flags = ASIX_DONGLES[Index].Flags;
}
//
// Set Device Path
//
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &ParentDevicePath,
pThis->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "gBS->OpenProtocol:EFI_DEVICE_PATH_PROTOCOL error. Status = %r\n",
Status));
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->FreePool ( pNicDevice );
goto EXIT;
}
ZeroMem (&MacDeviceNode, sizeof (MAC_ADDR_DEVICE_PATH));
MacDeviceNode.Header.Type = MESSAGING_DEVICE_PATH;
MacDeviceNode.Header.SubType = MSG_MAC_ADDR_DP;
SetDevicePathNodeLength (&MacDeviceNode.Header, sizeof (MAC_ADDR_DEVICE_PATH));
CopyMem (&MacDeviceNode.MacAddress,
&pNicDevice->SimpleNetworkData.CurrentAddress,
PXE_HWADDR_LEN_ETHER);
MacDeviceNode.IfType = pNicDevice->SimpleNetworkData.IfType;
pNicDevice->MyDevPath = AppendDevicePathNode (
ParentDevicePath,
(EFI_DEVICE_PATH_PROTOCOL *) &MacDeviceNode
);
pNicDevice->Controller = NULL;
//
// Install both the simple network and device path protocols.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&pNicDevice->Controller,
&gEfiCallerIdGuid,
pNicDevice,
&gEfiSimpleNetworkProtocolGuid,
&pNicDevice->SimpleNetwork,
&gEfiDevicePathProtocolGuid,
pNicDevice->MyDevPath,
NULL
);
if (EFI_ERROR(Status)){
DEBUG ((EFI_D_ERROR, "gBS->InstallMultipleProtocolInterfaces error. Status = %r\n",
Status));
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
pThis->DriverBindingHandle,
Controller);
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->FreePool ( pNicDevice );
goto EXIT;
}
//
// Open For Child Device
//
Status = gBS->OpenProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
(VOID **) &pNicDevice->pUsbIo,
pThis->DriverBindingHandle,
pNicDevice->Controller,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR(Status)){
gBS->UninstallMultipleProtocolInterfaces (
&pNicDevice->Controller,
&gEfiCallerIdGuid,
pNicDevice,
&gEfiSimpleNetworkProtocolGuid,
&pNicDevice->SimpleNetwork,
&gEfiDevicePathProtocolGuid,
pNicDevice->MyDevPath,
NULL
);
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
pThis->DriverBindingHandle,
Controller);
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->FreePool ( pNicDevice );
}
EXIT:
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 * ChildHandleBuffer
)
{
BOOLEAN AllChildrenStopped;
UINTN Index;
EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
EFI_STATUS Status = EFI_SUCCESS;
NIC_DEVICE *pNicDevice;
//
// Complete all outstanding transactions to Controller.
// Don't allow any new transaction to Controller to be started.
//
if (NumberOfChildren == 0) {
Status = gBS->OpenProtocol (
Controller,
&gEfiSimpleNetworkProtocolGuid,
(VOID **) &SimpleNetwork,
pThis->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR(Status)) {
//
// This is a 2nd type handle(multi-lun root), it needs to close devicepath
// and usbio protocol.
//
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
return EFI_SUCCESS;
}
pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork );
Status = gBS->UninstallMultipleProtocolInterfaces (
Controller,
&gEfiCallerIdGuid,
pNicDevice,
&gEfiSimpleNetworkProtocolGuid,
&pNicDevice->SimpleNetwork,
&gEfiDevicePathProtocolGuid,
pNicDevice->MyDevPath,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Close the bus driver
//
Status = gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
if (EFI_ERROR(Status)){
DEBUG ((EFI_D_ERROR, "driver stop: gBS->CloseProtocol:EfiDevicePathProtocol error. Status %r\n", Status));
}
Status = gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
Controller
);
if (EFI_ERROR(Status)){
DEBUG ((EFI_D_ERROR, "driver stop: gBS->CloseProtocol:EfiUsbIoProtocol error. Status %r\n", Status));
}
return EFI_SUCCESS;
}
AllChildrenStopped = TRUE;
for (Index = 0; Index < NumberOfChildren; Index++) {
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiSimpleNetworkProtocolGuid,
(VOID **) &SimpleNetwork,
pThis->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening SimpleNetwork\n", (UINT32)Index));
continue;
}
pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork );
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
pThis->DriverBindingHandle,
ChildHandleBuffer[Index]
);
Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandleBuffer[Index],
&gEfiCallerIdGuid,
pNicDevice,
&gEfiSimpleNetworkProtocolGuid,
&pNicDevice->SimpleNetwork,
&gEfiDevicePathProtocolGuid,
pNicDevice->MyDevPath,
NULL
);
if (EFI_ERROR (Status)) {
Status = gBS->OpenProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
(VOID **) &pNicDevice->pUsbIo,
pThis->DriverBindingHandle,
ChildHandleBuffer[Index],
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
}
else {
int i;
RX_PKT * pCurr = pNicDevice->QueueHead;
RX_PKT * pFree;
for ( i = 0 ; i < MAX_QUEUE_SIZE ; i++) {
if ( NULL != pCurr ) {
pFree = pCurr;
pCurr = pCurr->pNext;
gBS->FreePool (pFree);
}
}
if ( NULL != pNicDevice->pRxTest)
gBS->FreePool (pNicDevice->pRxTest);
if ( NULL != pNicDevice->pTxTest)
gBS->FreePool (pNicDevice->pTxTest);
if ( NULL != pNicDevice->MyDevPath)
gBS->FreePool (pNicDevice->MyDevPath);
if ( NULL != pNicDevice)
gBS->FreePool (pNicDevice);
}
}
if (!AllChildrenStopped) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
/**
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 ((EFI_D_ERROR, "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
//
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 ((EFI_D_ERROR, "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 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;
//
// Add the driver to the list of drivers
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
pSystemTable,
&gDriverBinding,
ImageHandle,
&gComponentName,
&gComponentName2
);
if ( !EFI_ERROR ( Status )) {
DEBUG ((EFI_D_INFO, "Installed: gEfiDriverBindingProtocolGuid on 0x%08x\r\n",
ImageHandle));
DEBUG ((EFI_D_INFO, "Installed: gEfiComponentNameProtocolGuid on 0x%08x\r\n",
ImageHandle));
DEBUG ((EFI_D_INFO,"Installed: gEfiComponentName2ProtocolGuid on 0x%08x\r\n",
ImageHandle ));
}
return Status;
}