Accessor Functions for Derived Attributes

Explains how to add accessor functions for derived attributes.

You can change HAL to add accessor functions for new derived attributes. This step is not often done, because all normal accessor functions are already defined in ...\hal\src\userhal.cpp.

Each derived attribute is declared with an associated function name in Config file. A function with that name must be provided, and it must have the following signature, which is also defined by the THalImplementation typedef:

TInt Function(TInt aAttrib, TBool aSet, TAny* aInOut);

This function is called whenever any client of the HAL references the associated attribute.

aAttrib

Contains the attribute number.

aSet

Defines whether the attribute is being set or being read: ETrue means that the attribute value is being set; EFalse means that the attribute value is being read.

Note that if the attribute, as defined in the config.hcf file, does not have the settable property, then aSet is ignored .

aInOut

A pointer to a TInt type, that contains:

  • the attribute value to be set, if aSet is ETrue

  • the attribute value to be read, if aSet is EFalse.

Once the config file has been written, the Perl script ...\hal\group\halcfg.pl can be used to generate a skeleton implementation file. For example, calling

perl \hal\group\halcfg.pl -s \hal\inc\hal_data.h config.hcf imp.cpp

produces the file imp.cpp containing the following skeleton code for each derived attribute:

// EAttributeName
TInt Function(TInt /*aAttrib*/, TBool /*aSet*/, TAny* aInOut)
    {
    return KErrNone;
    }

The full implementation for the function can now be written.

Notes:

  • The aAttrib parameter is always marked as a comment because it is not usually needed; it is only needed if the same function is used to implement more than one attribute.

  • The aSet parameter is marked as a comment if the attribute does not have the settable property.

  • On some platforms it may be necessary to access some HAL attributes via a device driver or server, rather than using UserSvr::HalFunction() . In this case, a handle to the device driver or server must be opened on the first access. Use the HalInternal::Tls() function to do this.

  • Access to any HAL attribute requiring the use of a server or device driver can fail due to lack of memory.

Thee code fragments in the example accessor functions show the cases where the HAL has an attribute that requires a device driver and another attribute that requires a server.

See also halcfg.pl Syntax.

Example accessor functions for derived attributes using a device driver and a server

This code fragment shows the implementation of accessor functions for two HAL derived attributes. One uses a device driver, and the other uses a server to provide the necessary functionality.

The examples assume that the attributes are defined in the config.hcf file with function names Attrib1 and Attrib2.

Using a device driver

TInt Attrib1(TInt /*aAttrib*/, TBool aSet, TAny* aInOut)
    {
       // Do something with the device driver
       RHwDevice d;
       TInt r=GetDeviceDriverHandle(d);
       if (r==KErrNone)
        {
        if (aSet)
            {
            r=d.Write((TInt)aInOut);
            }
        else
            {
            r=d.Read(*(TInt*)aInOut);
            }
         }
    return r;
    }
TInt GetDeviceDriverHandle(RHwDevice& aDevice)
    {
    // Return the device driver handle for this thread
    // If it doesn't exist, attempt to open a handle
    // Careful with OOM errors

    SHandles* pH=GetHandles();
    if (!pH)
        {
        return KErrNoMemory;    // couldn't allocate TLS memory
        }
    if (pH->iDevHandle)
        {
        // device driver handle already open
        aDevice.SetHandle(pH->iDevHandle);
        return KErrNone;
        }

    // note: Someone should have previously loaded the required
    // device driver.  Eg.
    // User::LoadLogicalDevice(_L("HARDWARE.LDD"));
    // This can be done here, but it is inefficient since it will
    // happen once per thread.  It's much better to do it once
    // at Hal start-up.

    TInt r=aDevice.Open();    // open handle to driver
    if (r==KErrNone)
        {
           pH->iDevHandle=aDevice.Handle();    // store handle
        }
    return r;
    }
struct SHandles
    {
    TInt iDevHandle;
    TInt iSvrHandle;
    };
SHandles* GetHandles()
    {
    // Return a pointer to the SHandles structure for this thread
    // If it doesn't exist, attempt to create it

    // This function zeros a newly allocated memory block
    return (SHandles*)HalInternal::Tls(sizeof(SHandles));
    }

Using a server

TInt Attrib2(TInt /*aAttrib*/, TBool aSet, TAny* aInOut)
    {
    // Do something with the server
    RHwServer s;
    TInt r=GetServerHandle(s);
    if (r==KErrNone)
        {
        if (aSet)
            {
            r=s.Write((TInt)aInOut);
            }
            else
            {
            r=s.Read(*(TInt*)aInOut);
            }
        }
    return r;
    }
TInt GetServerHandle(RHwServer& aServer)
    {
    // Return the server handle for this thread
    // If it doesn't exist, attempt to open a handle
    // Careful with OOM errors

    SHandles* pH=GetHandles();
    if (!pH)
        {
        return KErrNoMemory;    // couldn't allocate TLS memory
        }
    if (pH->iSvrHandle)
        {
        // server handle already open
           aServer.SetHandle(pH->iSvrHandle);
           return KErrNone;
        }
    TInt r=aServer.Connect();    // create session with server
    if (r==KErrNone)
        {
        pH->iSvrHandle=aServer.Handle();    // store handle
        }
    return r;
    }
struct SHandles
    {
    TInt iDevHandle;
    TInt iSvrHandle;
    };
SHandles* GetHandles()
    {
    // Return a pointer to the SHandles structure for this thread
    // If it doesn't exist, attempt to create it

    // This function zeros a newly allocated memory block
    return (SHandles*)HalInternal::Tls(sizeof(SHandles));
    }