/** Disconnect from the I2C host controller. This routine disconnects from the I2C controller. This routine is called by DriverUnload when the I2C host driver is being unloaded. @param [in] DriverBinding 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] ChildHandleBuffer 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 I2cHostDriverStop ( IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { I2C_HOST_CONTEXT *I2cHost; CONST EFI_I2C_HOST_PROTOCOL *I2cHostProtocol; EFI_STATUS Status; // // Display entry // DEBUG (( DEBUG_LOAD, "I2cHostDriverStop entered\r\n" )); // // Disconnect any connected drivers and locate the context // structure // Status = gBS->OpenProtocol ( Controller, mDriverProtocol, (VOID**)&I2cHostProtocol, DriverBinding->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE ); if ( !EFI_ERROR ( Status )) { I2cHost = I2C_HOST_CONTEXT_FROM_PROTOCOL ( I2cHostProtocol ); // // Done with the I2C host protocol // Status = gBS->CloseProtocol ( Controller, mDriverProtocol, DriverBinding->DriverBindingHandle, Controller ); if ( !EFI_ERROR ( Status )) { // // Remove the I2C host protocol // Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, mDriverProtocol, I2cHostProtocol, NULL ); if ( !EFI_ERROR ( Status )) { // // Stop the driver // DEBUG (( DEBUG_INIT, "0x%016lx: I2cHost stopped\r\n", (UINT64)(UINTN)I2cHost )); I2cHostApiStop ( I2cHost ); // // Release the I2C controller // gBS->CloseProtocol ( Controller, &gEfiI2cBusConfigurationManagementProtocolGuid, DriverBinding->DriverBindingHandle, Controller ); // // Release the context // DEBUG (( DEBUG_POOL | DEBUG_INFO, "0x%016lx: I2cHost released\r\n", (UINT64)(UINTN)I2cHost )); FreePool ( I2cHost ); } else { DEBUG (( DEBUG_ERROR, "ERROR - Failed to uninstall I2C host protocol, Status: %r\r\n", Status )); } } else { DEBUG (( DEBUG_ERROR, "ERROR - Failed to close I2C host protocol, Status: %r\r\n", Status )); } } // // Display exit // DEBUG (( DEBUG_LOAD, "I2cHostDriverStop exiting, Status: %r\r\n", Status )); // // Return the stop status // return Status; }
/** Stops a device controller or a bus controller. The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). As a result, much of the error checking on the parameters to Stop() has been moved into this common boot service. It is legal to call Stop() from other locations, but the following calling restrictions must be followed, or the system behavior will not be deterministic. 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this same driver's Start() function. 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid EFI_HANDLE. In addition, all of these handles must have been created in this driver's Start() function, and the Start() function must have called OpenProtocol() on ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. @param[in] ControllerHandle A handle to the device being stopped. The handle must support a bus specific I/O protocol for the driver to use to stop the device. @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL if NumberOfChildren is 0. @retval EFI_SUCCESS The device was stopped. @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. **/ EFI_STATUS EFIAPI I2cHostDriverStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; I2C_HOST_CONTEXT *I2cHostContext; EFI_I2C_HOST_PROTOCOL *I2cHost; EFI_TPL TplPrevious; TplPrevious = EfiGetCurrentTpl (); if (TplPrevious > TPL_I2C_SYNC) { DEBUG ((EFI_D_ERROR, "I2cHost: TPL %d is too high in Stop.\n", TplPrevious)); return EFI_DEVICE_ERROR; } Status = gBS->OpenProtocol ( Controller, &gEfiI2cHostProtocolGuid, (VOID **) &I2cHost, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (I2cHost); // // Raise TPL for critical section // TplPrevious = gBS->RaiseTPL (TPL_I2C_SYNC); // // If there is pending request or pending bus configuration, do not stop // Status = EFI_DEVICE_ERROR; if (( !I2cHostContext->I2cBusConfigurationManagementPending ) && IsListEmpty (&I2cHostContext->RequestList)) { // // Remove the I2C host protocol // Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiI2cHostProtocolGuid, I2cHost, NULL ); } // // Leave critical section // gBS->RestoreTPL (TplPrevious); if (!EFI_ERROR (Status)) { gBS->CloseProtocol ( Controller, &gEfiI2cBusConfigurationManagementProtocolGuid, This->DriverBindingHandle, Controller ); // // Release I2c Host resources // if (I2cHostContext->I2cBusConfigurationEvent != NULL) { gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent); I2cHostContext->I2cBusConfigurationEvent = NULL; } if (I2cHostContext->I2cEvent != NULL) { gBS->CloseEvent (I2cHostContext->I2cEvent); I2cHostContext->I2cEvent = NULL; } FreePool (I2cHostContext); } // // Return the stop status // return Status; }