/** @file Implement the driver binding protocol for Asix AX88179 Ethernet driver. Copyright (c) 2011, Intel Corporation Copyright (c) 2020, ARM Limited. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Ax88179.h" /** Verify the controller type @param [in] This 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 *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_USB_DEVICE_DESCRIPTOR Device; EFI_USB_IO_PROTOCOL *UsbIo; EFI_STATUS Status; // // Connect to the USB stack // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->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 = UsbIo->UsbGetDeviceDescriptor (UsbIo, &Device); if (EFI_ERROR(Status)) { Status = EFI_UNSUPPORTED; } else { // // Validate the adapter // if ((VENDOR_ID == Device.IdVendor) && (PRODUCT_ID == Device.IdProduct)) { Status = EFI_SUCCESS; } else if ((VENDOR_ID == Device.IdVendor) && (PRODUCT_ID_178A == Device.IdProduct)) { Status = EFI_SUCCESS; } else { Status = EFI_UNSUPPORTED; } } // // Done with the USB stack // gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->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 apEnded to it, install the NetworkInterfaceIdentifier protocol on the newly created Device Path. @param [in] This 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 *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; NIC_DEVICE *NicDevice; UINTN LengthInBytes; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath = NULL; MAC_ADDR_DEVICE_PATH MacDeviceNode; // // Allocate the device structure // LengthInBytes = sizeof (*NicDevice); Status = gBS->AllocatePool ( EfiBootServicesData, LengthInBytes, (VOID **) &NicDevice ); if (EFI_ERROR (Status)) { goto ERR; } // // Set the structure signature // ZeroMem (NicDevice, LengthInBytes); NicDevice->Signature = DEV_SIGNATURE; Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &NicDevice->UsbIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto ERR; } // // Initialize the simple network protocol // Status = SN_Setup (NicDevice); if (EFI_ERROR(Status)){ gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); goto ERR; } // // Set Device Path // Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR(Status)) { gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); goto ERR; } 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, &NicDevice->SimpleNetworkData.CurrentAddress, PXE_HWADDR_LEN_ETHER); MacDeviceNode.IfType = NicDevice->SimpleNetworkData.IfType; NicDevice->MyDevPath = AppendDevicePathNode ( ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &MacDeviceNode ); NicDevice->Controller = NULL; // // Install both the simple network and device path protocols. // Status = gBS->InstallMultipleProtocolInterfaces ( &NicDevice->Controller, &gEfiCallerIdGuid, NicDevice, &gEfiSimpleNetworkProtocolGuid, &NicDevice->SimpleNetwork, &gEfiDevicePathProtocolGuid, NicDevice->MyDevPath, NULL ); if (EFI_ERROR(Status)){ gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller); gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); goto ERR; } // // Open For Child Device // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &NicDevice->UsbIo, This->DriverBindingHandle, NicDevice->Controller, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR(Status)){ gBS->UninstallMultipleProtocolInterfaces ( &NicDevice->Controller, &gEfiCallerIdGuid, NicDevice, &gEfiSimpleNetworkProtocolGuid, &NicDevice->SimpleNetwork, &gEfiDevicePathProtocolGuid, NicDevice->MyDevPath, NULL ); gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller); gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); goto ERR; } return Status; ERR: if (NicDevice->BulkInbuf != NULL) { gBS->FreePool (NicDevice->BulkInbuf); } if (NicDevice->TxTest != NULL) { gBS->FreePool (NicDevice->TxTest); } if (NicDevice->MyDevPath != NULL) { gBS->FreePool (NicDevice->MyDevPath); } if (NicDevice != NULL) { gBS->FreePool (NicDevice); } return Status; } /** Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and closing the DevicePath and PciIo protocols on Controller. @param [in] This 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 * This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE * ChildHandleBuffer ) { BOOLEAN AllChildrenStopped; EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork; EFI_STATUS Status = EFI_SUCCESS; NIC_DEVICE *NicDevice; UINTN Index; // // 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, This->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, This->DriverBindingHandle, Controller ); gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); return EFI_SUCCESS; } NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork); Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiCallerIdGuid, NicDevice, &gEfiSimpleNetworkProtocolGuid, &NicDevice->SimpleNetwork, &gEfiDevicePathProtocolGuid, NicDevice->MyDevPath, NULL ); if (EFI_ERROR (Status)) { return Status; } // // Close the bus driver // Status = gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); Status = gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { Status = gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiSimpleNetworkProtocolGuid, (VOID **) &SimpleNetwork, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; continue; } NicDevice = DEV_FROM_SIMPLE_NETWORK (SimpleNetwork); gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiCallerIdGuid, NicDevice, &gEfiSimpleNetworkProtocolGuid, &NicDevice->SimpleNetwork, &gEfiDevicePathProtocolGuid, NicDevice->MyDevPath, NULL ); if (EFI_ERROR (Status)) { Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &NicDevice->UsbIo, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { if (NicDevice->BulkInbuf != NULL) { gBS->FreePool (NicDevice->BulkInbuf); } if (NicDevice->TxTest != NULL) { gBS->FreePool (NicDevice->TxTest); } if (NicDevice->MyDevPath != NULL) { gBS->FreePool (NicDevice->MyDevPath); } if (NicDevice != NULL) { gBS->FreePool (NicDevice); } } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Driver binding protocol declaration **/ EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { DriverSupported, DriverStart, DriverStop, 0xa, NULL, NULL }; /** Ax88179 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 *Handle; EFI_STATUS Status; // // Determine which devices are using this driver // BufferSize = 0; Handle = 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 ( EfiBootServicesData, BufferSize, (VOID **) &Handle ); if (EFI_ERROR (Status)) { break; } // // Locate the block IO devices // Status = gBS->LocateHandle ( ByProtocol, &gEfiCallerIdGuid, NULL, &BufferSize, Handle); if (EFI_ERROR (Status)) { // // Error getting handles // break; } // // Remove any use of the driver // Max = BufferSize / sizeof (Handle[0]); for (Index = 0; Max > Index; Index++) { Status = DriverStop (&gDriverBinding, Handle[Index], 0, NULL); if (EFI_ERROR (Status)) { break; } } break; } } else { if (EFI_NOT_FOUND == Status) { // // No devices were found // Status = EFI_SUCCESS; } } // // Free the handle array // if (Handle != NULL) { gBS->FreePool (Handle); } // // Remove the protocols installed by the EntryPoint routine. // if (!EFI_ERROR (Status)) { gBS->UninstallMultipleProtocolInterfaces ( ImageHandle, &gEfiDriverBindingProtocolGuid, &gDriverBinding, &gEfiComponentNameProtocolGuid, &gComponentName, &gEfiComponentName2ProtocolGuid, &gComponentName2, NULL ); } // // Return the unload status // return Status; } /** Ax88179 driver entry point. @param [in] ImageHandle Handle for the image. @param [in] SystemTable Address of the system table. @retval EFI_SUCCESS Image successfully loaded. **/ EFI_STATUS EFIAPI EntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_STATUS Status; // // Enable unload support // Status = gBS->HandleProtocol ( gImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage ); if (!EFI_ERROR (Status)) { LoadedImage->Unload = DriverUnload; } // // Add the driver to the list of drivers // Status = EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gDriverBinding, ImageHandle, &gComponentName, &gComponentName2 ); return Status; }