1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222 |
- /** @file
- This file implements I2C Host Protocol which provides callers with the ability to
- do I/O transactions to all of the devices on the I2C bus.
- Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
- Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "I2cDxe.h"
- EFI_DRIVER_BINDING_PROTOCOL gI2cHostDriverBinding = {
- I2cHostDriverSupported,
- I2cHostDriverStart,
- I2cHostDriverStop,
- 0x10,
- NULL,
- NULL
- };
- //
- // Driver name table
- //
- GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mI2cHostDriverNameTable[] = {
- { "eng;en", L"I2c Host Driver" },
- { NULL , NULL }
- };
- //
- // EFI Component Name Protocol
- //
- GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gI2cHostComponentName = {
- (EFI_COMPONENT_NAME_GET_DRIVER_NAME) I2cHostComponentNameGetDriverName,
- (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) I2cHostComponentNameGetControllerName,
- "eng"
- };
- //
- // EFI Component Name 2 Protocol
- //
- GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gI2cHostComponentName2 = {
- I2cHostComponentNameGetDriverName,
- I2cHostComponentNameGetControllerName,
- "en"
- };
- /**
- Retrieves a Unicode string that is the user readable name of the driver.
- This function retrieves the user readable name of a driver in the form of a
- Unicode string. If the driver specified by This has a user readable name in
- the language specified by Language, then a pointer to the driver name is
- returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
- by This does not support the language specified by Language,
- then EFI_UNSUPPORTED is returned.
- @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
- EFI_COMPONENT_NAME_PROTOCOL instance.
- @param Language[in] A pointer to a Null-terminated ASCII string
- array indicating the language. This is the
- language of the driver name that the caller is
- requesting, and it must match one of the
- languages specified in SupportedLanguages. The
- number of languages supported by a driver is up
- to the driver writer. Language is specified
- in RFC 4646 or ISO 639-2 language code format.
- @param DriverName[out] A pointer to the Unicode string to return.
- This Unicode string is the name of the
- driver specified by This in the language
- specified by Language.
- @retval EFI_SUCCESS The Unicode string for the Driver specified by
- This and the language specified by Language was
- returned in DriverName.
- @retval EFI_INVALID_PARAMETER Language is NULL.
- @retval EFI_INVALID_PARAMETER DriverName is NULL.
- @retval EFI_UNSUPPORTED The driver specified by This does not support
- the language specified by Language.
- **/
- EFI_STATUS
- EFIAPI
- I2cHostComponentNameGetDriverName (
- IN EFI_COMPONENT_NAME2_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- )
- {
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- mI2cHostDriverNameTable,
- DriverName,
- (BOOLEAN)(This != &gI2cHostComponentName2)
- );
- }
- /**
- Retrieves a Unicode string that is the user readable name of the controller
- that is being managed by a driver.
- This function retrieves the user readable name of the controller specified by
- ControllerHandle and ChildHandle in the form of a Unicode string. If the
- driver specified by This has a user readable name in the language specified by
- Language, then a pointer to the controller name is returned in ControllerName,
- and EFI_SUCCESS is returned. If the driver specified by This is not currently
- managing the controller specified by ControllerHandle and ChildHandle,
- then EFI_UNSUPPORTED is returned. If the driver specified by This does not
- support the language specified by Language, then EFI_UNSUPPORTED is returned.
- @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
- EFI_COMPONENT_NAME_PROTOCOL instance.
- @param ControllerHandle[in] The handle of a controller that the driver
- specified by This is managing. This handle
- specifies the controller whose name is to be
- returned.
- @param ChildHandle[in] The handle of the child controller to retrieve
- the name of. This is an optional parameter that
- may be NULL. It will be NULL for device
- drivers. It will also be NULL for a bus drivers
- that wish to retrieve the name of the bus
- controller. It will not be NULL for a bus
- driver that wishes to retrieve the name of a
- child controller.
- @param Language[in] A pointer to a Null-terminated ASCII string
- array indicating the language. This is the
- language of the driver name that the caller is
- requesting, and it must match one of the
- languages specified in SupportedLanguages. The
- number of languages supported by a driver is up
- to the driver writer. Language is specified in
- RFC 4646 or ISO 639-2 language code format.
- @param ControllerName[out] A pointer to the Unicode string to return.
- This Unicode string is the name of the
- controller specified by ControllerHandle and
- ChildHandle in the language specified by
- Language from the point of view of the driver
- specified by This.
- @retval EFI_SUCCESS The Unicode string for the user readable name in
- the language specified by Language for the
- driver specified by This was returned in
- DriverName.
- @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
- @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
- EFI_HANDLE.
- @retval EFI_INVALID_PARAMETER Language is NULL.
- @retval EFI_INVALID_PARAMETER ControllerName is NULL.
- @retval EFI_UNSUPPORTED The driver specified by This is not currently
- managing the controller specified by
- ControllerHandle and ChildHandle.
- @retval EFI_UNSUPPORTED The driver specified by This does not support
- the language specified by Language.
- **/
- EFI_STATUS
- EFIAPI
- I2cHostComponentNameGetControllerName (
- IN EFI_COMPONENT_NAME2_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE ChildHandle OPTIONAL,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- )
- {
- return EFI_UNSUPPORTED;
- }
- /**
- Tests to see if this driver supports a given controller. If a child device is provided,
- it further tests to see if this driver supports creating a handle for the specified child device.
- This function checks to see if the driver specified by This supports the device specified by
- ControllerHandle. Drivers will typically use the device path attached to
- ControllerHandle and/or the services from the bus I/O abstraction attached to
- ControllerHandle to determine if the driver supports ControllerHandle. This function
- may be called many times during platform initialization. In order to reduce boot times, the tests
- performed by this function must be very small, and take as little time as possible to execute. This
- function must not change the state of any hardware devices, and this function must be aware that the
- device specified by ControllerHandle may already be managed by the same driver or a
- different driver. This function must match its calls to AllocatePages() with FreePages(),
- AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
- Since ControllerHandle may have been previously started by the same driver, if a protocol is
- already in the opened state, then it must not be closed with CloseProtocol(). This is required
- to guarantee the state of ControllerHandle is not modified by this function.
- @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
- @param[in] ControllerHandle The handle of the controller to test. This handle
- must support a protocol interface that supplies
- an I/O abstraction to the driver.
- @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
- parameter is ignored by device drivers, and is optional for bus
- drivers. For bus drivers, if this parameter is not NULL, then
- the bus driver must determine if the bus controller specified
- by ControllerHandle and the child controller specified
- by RemainingDevicePath are both supported by this
- bus driver.
- @retval EFI_SUCCESS The device specified by ControllerHandle and
- RemainingDevicePath is supported by the driver specified by This.
- @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
- RemainingDevicePath is already being managed by the driver
- specified by This.
- @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
- RemainingDevicePath is already being managed by a different
- driver or an application that requires exclusive access.
- Currently not implemented.
- @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
- RemainingDevicePath is not supported by the driver specified by This.
- **/
- EFI_STATUS
- EFIAPI
- I2cHostDriverSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- )
- {
- EFI_I2C_MASTER_PROTOCOL *I2cMaster;
- EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
- EFI_STATUS Status;
- //
- // Locate I2C Bus Configuration Management Protocol
- //
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiI2cBusConfigurationManagementProtocolGuid,
- (VOID **)&I2cBusConfigurationManagement,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Close the protocol because we don't use it here
- //
- gBS->CloseProtocol (
- Controller,
- &gEfiI2cBusConfigurationManagementProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- //
- // Locate I2C Master Protocol
- //
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiI2cMasterProtocolGuid,
- (VOID **)&I2cMaster,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- /**
- Starts a device controller or a bus controller.
- The Start() function is designed to be invoked from the EFI boot service ConnectController().
- As a result, much of the error checking on the parameters to Start() has been moved into this
- common boot service. It is legal to call Start() 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.
- 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
- EFI_DEVICE_PATH_PROTOCOL.
- 3. Prior to calling Start(), the Supported() function for the driver specified by This must
- have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
- @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
- @param[in] ControllerHandle The handle of the controller to start. This handle
- must support a protocol interface that supplies
- an I/O abstraction to the driver.
- @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
- parameter is ignored by device drivers, and is optional for bus
- drivers. For a bus driver, if this parameter is NULL, then handles
- for all the children of Controller are created by this driver.
- If this parameter is not NULL and the first Device Path Node is
- not the End of Device Path Node, then only the handle for the
- child device specified by the first Device Path Node of
- RemainingDevicePath is created by this driver.
- If the first Device Path Node of RemainingDevicePath is
- the End of Device Path Node, no child handle is created by this
- driver.
- @retval EFI_SUCCESS The device was started.
- @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval Others The driver failded to start the device.
- **/
- EFI_STATUS
- EFIAPI
- I2cHostDriverStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
- )
- {
- EFI_STATUS Status;
- EFI_I2C_MASTER_PROTOCOL *I2cMaster;
- EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
- I2C_HOST_CONTEXT *I2cHostContext;
- I2cMaster = NULL;
- I2cHostContext = NULL;
- I2cBusConfigurationManagement = NULL;
- //
- // Locate I2C Bus Configuration Management Protocol
- //
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiI2cBusConfigurationManagementProtocolGuid,
- (VOID **)&I2cBusConfigurationManagement,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "I2cHost: Open I2C bus configuration error, Status = %r\n", Status));
- return Status;
- }
- //
- // Locate I2C Master Protocol
- //
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiI2cMasterProtocolGuid,
- (VOID **)&I2cMaster,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "I2cHost: Open I2C master error, Status = %r\n", Status));
- goto Exit;
- }
- //
- // Allocate the I2C Host Context structure
- //
- I2cHostContext = AllocateZeroPool (sizeof (I2C_HOST_CONTEXT));
- if (I2cHostContext == NULL) {
- DEBUG ((EFI_D_ERROR, "I2cHost: there is no enough memory to allocate.\n"));
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- //
- // Initialize the context structure for the current I2C Controller
- //
- I2cHostContext->Signature = I2C_HOST_SIGNATURE;
- I2cHostContext->I2cMaster = I2cMaster;
- I2cHostContext->I2cBusConfigurationManagement = I2cBusConfigurationManagement;
- I2cHostContext->I2cBusConfiguration = (UINTN) -1;
- InitializeListHead(&I2cHostContext->RequestList);
- //
- // Reset the controller
- //
- Status = I2cMaster->Reset (I2cMaster);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "I2cHost: I2C controller reset failed!\n"));
- goto Exit;
- }
- //
- // Create the I2C transaction complete event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_I2C_SYNC,
- I2cHostRequestCompleteEvent,
- I2cHostContext,
- &I2cHostContext->I2cEvent
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "I2cHost: create complete event error, Status = %r\n", Status));
- goto Exit;
- }
- //
- // Get the bus management event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_I2C_SYNC,
- I2cHostI2cBusConfigurationAvailable,
- I2cHostContext,
- &I2cHostContext->I2cBusConfigurationEvent
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "I2cHost: create bus available event error, Status = %r\n", Status));
- goto Exit;
- }
- //
- // Build the I2C host protocol for the current I2C controller
- //
- I2cHostContext->I2cHost.QueueRequest = I2cHostQueueRequest;
- I2cHostContext->I2cHost.I2cControllerCapabilities = I2cMaster->I2cControllerCapabilities;
- //
- // Install the driver protocol
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Controller,
- &gEfiI2cHostProtocolGuid,
- &I2cHostContext->I2cHost,
- NULL
- );
- Exit:
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "I2cHost: Start() function failed, Status = %r\n", Status));
- if (I2cBusConfigurationManagement != NULL) {
- gBS->CloseProtocol (
- Controller,
- &gEfiI2cBusConfigurationManagementProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- }
- if ((I2cHostContext != NULL) && (I2cHostContext->I2cEvent != NULL)) {
- gBS->CloseEvent (I2cHostContext->I2cEvent);
- I2cHostContext->I2cEvent = NULL;
- }
- if ((I2cHostContext != NULL) && (I2cHostContext->I2cBusConfigurationEvent != NULL)) {
- gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent);
- I2cHostContext->I2cBusConfigurationEvent = NULL;
- }
- //
- // Release the context structure upon failure
- //
- if (I2cHostContext != NULL) {
- FreePool (I2cHostContext);
- }
- }
- //
- // Return the operation 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;
- }
- /**
- Handle the I2C bus configuration available event
- This routine is called at TPL_I2C_SYNC.
- @param[in] Event Address of an EFI_EVENT handle
- @param[in] Context Address of an I2C_HOST_CONTEXT structure
- **/
- VOID
- EFIAPI
- I2cHostI2cBusConfigurationAvailable (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- I2C_HOST_CONTEXT *I2cHostContext;
- EFI_I2C_MASTER_PROTOCOL *I2cMaster;
- I2C_REQUEST *I2cRequest;
- LIST_ENTRY *EntryHeader;
- LIST_ENTRY *Entry;
- EFI_STATUS Status;
- //
- // Mark this I2C bus configuration management operation as complete
- //
- I2cHostContext = (I2C_HOST_CONTEXT *)Context;
- I2cMaster = I2cHostContext->I2cMaster;
- ASSERT (I2cMaster != NULL);
- //
- // Clear flag to indicate I2C bus configuration is finished
- //
- I2cHostContext->I2cBusConfigurationManagementPending = FALSE;
- //
- // Validate the completion status
- //
- if (EFI_ERROR (I2cHostContext->Status)) {
- //
- // Setting I2C bus configuration failed before
- //
- I2cHostRequestComplete (I2cHostContext, I2cHostContext->Status);
- //
- // Unknown I2C bus configuration
- // Force next operation to enable the I2C bus configuration
- //
- I2cHostContext->I2cBusConfiguration = (UINTN) -1;
- //
- // Do not continue current I2C request
- //
- return;
- }
- //
- // Get the first request in the link with FIFO order
- //
- EntryHeader = &I2cHostContext->RequestList;
- Entry = GetFirstNode (EntryHeader);
- I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);
- //
- // Update the I2C bus configuration of the current I2C request
- //
- I2cHostContext->I2cBusConfiguration = I2cRequest->I2cBusConfiguration;
- //
- // Start an I2C operation on the host, the status is returned by I2cHostContext->Status
- //
- Status = I2cMaster->StartRequest (
- I2cMaster,
- I2cRequest->SlaveAddress,
- I2cRequest->RequestPacket,
- I2cHostContext->I2cEvent,
- &I2cHostContext->Status
- );
- if (EFI_ERROR (Status)) {
- DEBUG((DEBUG_ERROR, "I2cHostI2cBusConfigurationAvailable: Error starting I2C operation, %r\n", Status));
- }
- }
- /**
- Complete the current request
- This routine is called at TPL_I2C_SYNC.
- @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure.
- @param[in] Status Status of the I2C operation.
- @return This routine returns the input status value.
- **/
- EFI_STATUS
- I2cHostRequestComplete (
- I2C_HOST_CONTEXT *I2cHostContext,
- EFI_STATUS Status
- )
- {
- I2C_REQUEST *I2cRequest;
- LIST_ENTRY *EntryHeader;
- LIST_ENTRY *Entry;
- //
- // Remove the current I2C request from the list
- //
- EntryHeader = &I2cHostContext->RequestList;
- Entry = GetFirstNode (EntryHeader);
- I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);
- //
- // Save the status for QueueRequest
- //
- if ( NULL != I2cRequest->Status ) {
- *I2cRequest->Status = Status;
- }
- //
- // Notify the user of the I2C request completion
- //
- if ( NULL != I2cRequest->Event ) {
- gBS->SignalEvent (I2cRequest->Event);
- }
- //
- // Done with this request, remove the current request from list
- //
- RemoveEntryList (&I2cRequest->Link);
- FreePool (I2cRequest->RequestPacket);
- FreePool (I2cRequest);
- //
- // If there is more I2C request, start next one
- //
- if(!IsListEmpty (EntryHeader)) {
- I2cHostRequestEnable (I2cHostContext);
- }
- return Status;
- }
- /**
- Handle the bus available event
- This routine is called at TPL_I2C_SYNC.
- @param[in] Event Address of an EFI_EVENT handle
- @param[in] Context Address of an I2C_HOST_CONTEXT structure
- **/
- VOID
- EFIAPI
- I2cHostRequestCompleteEvent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- I2C_HOST_CONTEXT *I2cHostContext;
- //
- // Handle the completion event
- //
- I2cHostContext = (I2C_HOST_CONTEXT *)Context;
- I2cHostRequestComplete (I2cHostContext, I2cHostContext->Status);
- }
- /**
- Enable access to the I2C bus configuration
- @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_ABORTED The request did not complete because the driver
- was shutdown.
- @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.
- @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.
- This could indicate the slave device is not present.
- @retval EFI_INVALID_PARAMETER RequestPacket is NULL
- @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value
- @retval EFI_NO_RESPONSE The I2C device is not responding to the
- slave address. EFI_DEVICE_ERROR may also be
- returned if the controller can not distinguish
- when the NACK occurred.
- @retval EFI_NOT_FOUND I2C slave address exceeds maximum address
- @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for
- the event and then read status.
- @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation
- @retval EFI_TIMEOUT The transaction did not complete within an internally
- specified timeout period.
- **/
- EFI_STATUS
- I2cHostRequestEnable (
- I2C_HOST_CONTEXT *I2cHostContext
- )
- {
- UINTN I2cBusConfiguration;
- CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
- I2C_REQUEST *I2cRequest;
- EFI_STATUS Status;
- EFI_TPL TplPrevious;
- LIST_ENTRY *EntryHeader;
- LIST_ENTRY *Entry;
- //
- // Assume pending request
- //
- Status = EFI_NOT_READY;
- I2cBusConfigurationManagement = I2cHostContext->I2cBusConfigurationManagement;
- //
- // Validate the I2c bus configuration
- //
- EntryHeader = &I2cHostContext->RequestList;
- Entry = GetFirstNode (EntryHeader);
- I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);
- I2cBusConfiguration = I2cRequest->I2cBusConfiguration;
- if (I2cHostContext->I2cBusConfiguration != I2cBusConfiguration ) {
- //
- // Set flag to indicate I2C bus configuration is in progress
- //
- I2cHostContext->I2cBusConfigurationManagementPending = TRUE;
- //
- // Update bus configuration for this device's requesting bus configuration
- //
- Status = I2cBusConfigurationManagement->EnableI2cBusConfiguration (
- I2cBusConfigurationManagement,
- I2cBusConfiguration,
- I2cHostContext->I2cBusConfigurationEvent,
- &I2cHostContext->Status
- );
- } else {
- //
- // I2C bus configuration is same, no need change configuration and start I2c transaction directly
- //
- TplPrevious = gBS->RaiseTPL ( TPL_I2C_SYNC );
- //
- // Same I2C bus configuration
- //
- I2cHostContext->Status = EFI_SUCCESS;
- I2cHostI2cBusConfigurationAvailable (I2cHostContext->I2cBusConfigurationEvent, I2cHostContext);
- //
- // Release the thread synchronization
- //
- gBS->RestoreTPL ( TplPrevious );
- }
- return Status;
- }
- /**
- Queue an I2C operation for execution on the I2C controller.
- This routine must be called at or below TPL_NOTIFY. For synchronous
- requests this routine must be called at or below TPL_CALLBACK.
- N.B. The typical consumers of this API are the I2C bus driver and
- on rare occasions the I2C test application. Extreme care must be
- taken by other consumers of this API to prevent confusing the
- third party I2C drivers due to a state change at the I2C device
- which the third party I2C drivers did not initiate. I2C platform
- drivers may use this API within these guidelines.
- This layer uses the concept of I2C bus configurations to describe
- the I2C bus. An I2C bus configuration is defined as a unique
- setting of the multiplexers and switches in the I2C bus which
- enable access to one or more I2C devices. When using a switch
- to divide a bus, due to speed differences, the I2C platform layer
- would define an I2C bus configuration for the I2C devices on each
- side of the switch. When using a multiplexer, the I2C platform
- layer defines an I2C bus configuration for each of the selector
- values required to control the multiplexer. See Figure 1 in the
- <a href="http://www.nxp.com/documents/user_manual/UM10204.pdf">I<sup>2</sup>C
- Specification</a> for a complex I2C bus configuration.
- The I2C host driver processes all operations in FIFO order. Prior to
- performing the operation, the I2C host driver calls the I2C platform
- driver to reconfigure the switches and multiplexers in the I2C bus
- enabling access to the specified I2C device. The I2C platform driver
- also selects the maximum bus speed for the device. After the I2C bus
- is configured, the I2C host driver calls the I2C port driver to
- initialize the I2C controller and start the I2C operation.
- @param[in] This Address of an EFI_I2C_HOST_PROTOCOL instance.
- @param[in] I2cBusConfiguration I2C bus configuration to access the I2C
- device.
- @param[in] SlaveAddress Address of the device on the I2C bus.
- @param[in] Event Event to set for asynchronous operations,
- NULL for synchronous operations
- @param[in] RequestPacket Address of an EFI_I2C_REQUEST_PACKET
- structure describing the I2C operation
- @param[out] I2cStatus Optional buffer to receive the I2C operation
- completion status
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.
- @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.
- This could indicate the slave device is not present.
- @retval EFI_INVALID_PARAMETER RequestPacket is NULL
- @retval EFI_INVALID_PARAMETER TPL is too high
- @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value
- @retval EFI_NO_RESPONSE The I2C device is not responding to the
- slave address. EFI_DEVICE_ERROR may also be
- returned if the controller can not distinguish
- when the NACK occurred.
- @retval EFI_NOT_FOUND I2C slave address exceeds maximum address
- @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for
- the event and then read status pointed to by
- the request packet.
- @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation
- @retval EFI_TIMEOUT The transaction did not complete within an internally
- specified timeout period.
- **/
- EFI_STATUS
- EFIAPI
- I2cHostQueueRequest (
- IN CONST EFI_I2C_HOST_PROTOCOL *This,
- IN UINTN I2cBusConfiguration,
- IN UINTN SlaveAddress,
- IN EFI_EVENT Event OPTIONAL,
- IN EFI_I2C_REQUEST_PACKET *RequestPacket,
- OUT EFI_STATUS *I2cStatus OPTIONAL
- )
- {
- EFI_STATUS Status;
- EFI_EVENT SyncEvent;
- EFI_TPL TplPrevious;
- I2C_REQUEST *I2cRequest;
- I2C_HOST_CONTEXT *I2cHostContext;
- BOOLEAN FirstRequest;
- UINTN RequestPacketSize;
- UINTN StartBit;
- SyncEvent = NULL;
- FirstRequest = FALSE;
- Status = EFI_SUCCESS;
- if (RequestPacket == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if ((SlaveAddress & I2C_ADDRESSING_10_BIT) != 0) {
- //
- // 10-bit address, bits 0-9 are used for 10-bit I2C slave addresses,
- // bits 10-30 are reserved bits and must be zero
- //
- StartBit = 10;
- } else {
- //
- // 7-bit address, Bits 0-6 are used for 7-bit I2C slave addresses,
- // bits 7-30 are reserved bits and must be zero
- //
- StartBit = 7;
- }
- if (BitFieldRead32 ((UINT32)SlaveAddress, StartBit, 30) != 0) {
- //
- // Reserved bit set in the SlaveAddress parameter
- //
- return EFI_NOT_FOUND;
- }
- I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (This);
- if (Event == NULL) {
- //
- // For synchronous transaction, register an event used to wait for finishing synchronous transaction
- //
- Status = gBS->CreateEvent (
- 0,
- TPL_I2C_SYNC,
- NULL,
- NULL,
- &SyncEvent
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- //
- // TPL should be at or below TPL_NOTIFY.
- // For synchronous requests this routine must be called at or below TPL_CALLBACK.
- //
- TplPrevious = EfiGetCurrentTpl ();
- if ((TplPrevious > TPL_I2C_SYNC) || ((Event == NULL) && (TplPrevious > TPL_CALLBACK))) {
- DEBUG ((EFI_D_ERROR, "ERROR - TPL %d is too high!\n", TplPrevious));
- return EFI_INVALID_PARAMETER;
- }
- //
- // Allocate the request structure
- //
- I2cRequest = AllocateZeroPool (sizeof (I2C_REQUEST));
- if (I2cRequest == NULL) {
- DEBUG ((EFI_D_ERROR, "WARNING - Failed to allocate I2C_REQUEST!\n"));
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Initialize the request
- //
- I2cRequest->Signature = I2C_REQUEST_SIGNATURE;
- I2cRequest->I2cBusConfiguration = I2cBusConfiguration;
- I2cRequest->SlaveAddress = SlaveAddress;
- I2cRequest->Event = (Event == NULL) ? SyncEvent : Event;
- I2cRequest->Status = I2cStatus;
- //
- // Copy request packet into private buffer, as RequestPacket may be freed during asynchronous transaction
- //
- RequestPacketSize = sizeof (UINTN) + RequestPacket->OperationCount * sizeof (EFI_I2C_OPERATION);
- I2cRequest->RequestPacket = AllocateZeroPool (RequestPacketSize);
- ASSERT (I2cRequest->RequestPacket != NULL);
- CopyMem (I2cRequest->RequestPacket, RequestPacket, RequestPacketSize);
- //
- // Synchronize with the other threads
- //
- gBS->RaiseTPL ( TPL_I2C_SYNC );
- FirstRequest = IsListEmpty (&I2cHostContext->RequestList);
- //
- // Insert new I2C request in the list
- //
- InsertTailList (&I2cHostContext->RequestList, &I2cRequest->Link);
- //
- // Release the thread synchronization
- //
- gBS->RestoreTPL (TplPrevious);
- if (FirstRequest) {
- //
- // Start the first I2C request, then the subsequent of I2C request will continue
- //
- Status = I2cHostRequestEnable (I2cHostContext);
- }
- if (Event != NULL) {
- //
- // For asynchronous, return EFI_SUCCESS indicating that the asynchronously I2C transaction was queued.
- // No real I2C operation status in I2cStatus
- //
- return EFI_SUCCESS;
- }
- //
- // For synchronous transaction, wait for the operation completion
- //
- do {
- Status = gBS->CheckEvent (SyncEvent);
- } while (Status == EFI_NOT_READY);
- //
- // Get the I2C operation status
- //
- Status = I2cHostContext->Status;
- //
- // Return the I2C operation status
- //
- if (I2cStatus != NULL) {
- *I2cStatus = Status;
- }
- //
- // Close the event if necessary
- //
- if (SyncEvent != NULL) {
- gBS->CloseEvent (SyncEvent);
- }
- return Status;
- }
- /**
- The user Entry Point for I2C host module. The user code starts with this function.
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval other Some error occurs when executing this entry point.
- **/
- EFI_STATUS
- EFIAPI
- InitializeI2cHost(
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- //
- // Install driver model protocol(s).
- //
- Status = EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &gI2cHostDriverBinding,
- ImageHandle,
- &gI2cHostComponentName,
- &gI2cHostComponentName2
- );
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
- /**
- This is the unload handle for I2C host module.
- Disconnect the driver specified by ImageHandle from all the devices in the handle database.
- Uninstall all the protocols installed in the driver entry point.
- @param[in] ImageHandle The drivers' driver image.
- @retval EFI_SUCCESS The image is unloaded.
- @retval Others Failed to unload the image.
- **/
- EFI_STATUS
- EFIAPI
- I2cHostUnload (
- IN EFI_HANDLE ImageHandle
- )
- {
- EFI_STATUS Status;
- EFI_HANDLE *DeviceHandleBuffer;
- UINTN DeviceHandleCount;
- UINTN Index;
- EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
- EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
- //
- // Get the list of all I2C Controller handles in the handle database.
- // If there is an error getting the list, then the unload
- // operation fails.
- //
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiI2cHostProtocolGuid,
- NULL,
- &DeviceHandleCount,
- &DeviceHandleBuffer
- );
- if (!EFI_ERROR (Status)) {
- //
- // Disconnect the driver specified by ImageHandle from all
- // the devices in the handle database.
- //
- for (Index = 0; Index < DeviceHandleCount; Index++) {
- Status = gBS->DisconnectController (
- DeviceHandleBuffer[Index],
- ImageHandle,
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
- }
- //
- // Uninstall all the protocols installed in the driver entry point
- //
- Status = gBS->UninstallMultipleProtocolInterfaces (
- gI2cHostDriverBinding.DriverBindingHandle,
- &gEfiDriverBindingProtocolGuid,
- &gI2cHostDriverBinding,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
- //
- // Note we have to one by one uninstall the following protocols.
- // It's because some of them are optionally installed based on
- // the following PCD settings.
- // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable
- // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable
- // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable
- // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable
- //
- Status = gBS->HandleProtocol (
- gI2cHostDriverBinding.DriverBindingHandle,
- &gEfiComponentNameProtocolGuid,
- (VOID **) &ComponentName
- );
- if (!EFI_ERROR (Status)) {
- gBS->UninstallProtocolInterface (
- gI2cHostDriverBinding.DriverBindingHandle,
- &gEfiComponentNameProtocolGuid,
- ComponentName
- );
- }
- Status = gBS->HandleProtocol (
- gI2cHostDriverBinding.DriverBindingHandle,
- &gEfiComponentName2ProtocolGuid,
- (VOID **) &ComponentName2
- );
- if (!EFI_ERROR (Status)) {
- gBS->UninstallProtocolInterface (
- gI2cHostDriverBinding.DriverBindingHandle,
- &gEfiComponentName2ProtocolGuid,
- ComponentName2
- );
- }
- Status = EFI_SUCCESS;
- Done:
- //
- // Free the buffer containing the list of handles from the handle database
- //
- if (DeviceHandleBuffer != NULL) {
- gBS->FreePool (DeviceHandleBuffer);
- }
- return Status;
- }
|