User-Side Hardware Abstraction Technology

Description of HAL types and interfaces.

The User-Side Hardware Abstraction (HAL) component provides a platform-independent way to access and control many device specific features, and to hide hardware-specific functionality. For example, HAL can be used to find out if a screen backlight is present or not, or to set the display contrast. This topic

Attributes

Specific items of hardware related information are referred to as attributes. Symbian platform defines two types of attribute:

  • Non-derived attribute. This is an attribute where the information it represent is simply a value that is stored in, and retrieved from, the HAL.

  • Derived attribute. This is an attribute that requires a software call to obtain and set its value. The software component is, ultimately provided by a driver, kernel extension or by the kernel itself. The drivers or kernel extensions normally need porting.

Attributes are identified by the enumeration values of the enumerator HALData::TAttribute defined in ...\hal\inc\hal_data.h and is exported to ...\epoc32\include\.

To maintain backwards compatibility, the numbers identifying HAL attributes are allocated strictly increasing consecutive values, and that a given HAL attribute always has the same enumeration number on all implementations of Symbian platform. This means that new HAL attributes can only be added by Symbian. This also means that the addition of custom HAL attributes is not possible.

User-side interface

Symbian platform provides the following static functions to get and set information about specific hardware features:

The HAL class is defined in the source tree header file ...\hal\inc\hal.h, and is exported to ...\epoc32\include\. The functions are exported from the HAL DLL, which is built as part of the Variant.

Get() and Set() take an attribute to identify specific hardware functionality.

GetAll(), as its name implies gets all available hardware information, but is rarely used. See Dealing with the HAL::GetAll() function for more information.

Get() and Set() each have a variation that allows a device number to be specified. The device number allows more than one set of attributes to be used. Each set is associated with a different device number. This is motivated by the need to support multiple display screens where each screen is identified as a separate device of the same 'type'. The idea of a device can be extended other hardware, and indeed the underlying implementation assumes a device number. If a device number is not specified and has no meaning, then a default device number of 0 is assumed for compatibility with the underlying implementation.

For example, on return from code such as:

...
TInt xpixels;
HAL::Get(EDisplayXPixels, xpixels);
...

xpixels contains the horizontal size of the display screen in terms of the number of pixels. If you have more than one screen, i.e. more than one device, then you would use the API variant that takes a device number.

HAL handler interface

A request for fetching and setting information about hardware is dealt with by an entity called a HAL handler on the kernel side. This section describes the types and concepts used to implement a HAL handler.

HAL groups and function-ids

It is useful to group together requests for information about related hardware features so that they can be dealt with by a single HAL handler. As an example, all the HAL screen attributes are in the display group and are handled by the screen (i.e. video or LCD) driver. This means that a HAL group has a one-to-one association with a HAL handler.

A HAL group has an associated set of function-ids, which identify requests for different pieces of information to the HAL handler.

Symbian platform identifies HAL groups by a number defined by the THalFunctionGroup enum in u32hal.h, which is exported to ...\epoc32\include. For example, the EHalGroupDisplay enum value identifies the group associated with the HAL screen attributes.

The function-ids associated with each HAL group are also defined in u32hal.h. Each set of function-ids is defined by an enum; for example the enum TDisplayHalFunction defines the function-ids associated with the HAL group EHalGroupDisplay.

The idea of the HAL group is what allows HAL handling functionality to be implemented in the Variant, rather than in the kernel.

Up to 32 groups can be defined. Often, a HAL group is concerned with mode settings for a particular piece of hardware; for example there are standard HAL groups for keyboard, digitiser and display. However, some groups are concerned with some overall aspect of the platform which extends across all devices; for example, there is a group to handle emulation parameters on emulator platforms.

An attribute maps to a HAL group/function-id pair, although the mapping is not necessarily a one-to-one relationship. For example, the calls:

TInt xPixels, yPixels;
...
HAL::Get(HALData::EDisplayXPixels,xPixels);
HAL::Get(HALData::EDisplayYPixels,yPixels);
...

both result in calls to the screen (i.e. video or LCD) HAL handler, as represented by the HAL group number THalFunctionGroup::EHalGroupDisplay, using the same function-id TDisplayHalFunction::EDisplayHalScreenInfo.

However, there are HAL group/function-id pairs for which there are no corresponding generic attributes. In these cases, the hardware attributes represented by the HAL group/function-id pair are used internally, and can only be accessed using the kernel side function Kern::HalFunction() **.

The following picture shows the general idea:

**Technically, the user side function UserSvr::HalFunction() will achieve the same thing, but this is internal to Symbian and is not intended for general use.

HAL handler implementation

Most HAL handlers are implemented as part of a driver, a kernel extension, the Variant or the kernel itself. Some will need porting. See Groups and the location of their HAL handlers.

An extension or a device driver must register a handler for HAL group. It does so by calling Kern::AddHalEntry(), specifying the group number. It is important to note that it is the extension or driver's responsibility to do this; in other words, the kernel cannot know what entity within a final ported Symbian platform is going to be the HAL handler until it is explicitly told by registration. One point to note is that the HAL handlers for the groups: EHalGroupKernel, EHalGroupVariant and EHalGroupPower are not explicitly registered - they are registered internally by the kernel itself.

Internally, pointers to the HAL handler are stored in the array K::HalFunction[], and this is indexed by the group number.

On the template board, for example, the HAL handler for the display group is part of the screen driver. The screen driver source can be found in ...\template_variant\specific\lcd.cpp. The HAL handler itself is the function:

LOCAL_C TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
    {
    DLcdPowerHandler* pH=(DLcdPowerHandler*)aPtr;
    return pH->HalFunction(aFunction,a1,a2);
    }

The following code, implemented in the Create() function of the main class, does the registration.

TInt DLcdPowerHandler::Create()
    {
    ...
    // install the HAL function
    r=Kern::AddHalEntry(EHalGroupDisplay,halFunction,this);
    if (r!=KErrNone)
        return r;
    ...
    }

Security is the responsibility of the HAL handler. If necessary, it needs to check the capability of the caller's process. Each information item, as identified by the function-id, can have an associated capability.

Each function-id defined in u32hal.h is documented with the required capability. If no capability is listed, then no specific capability is required.

See Implementing HAL handlers for details.

Kernel-side interface

Code such as device drivers that runs on the kernel side need not use the generic interface provided by the HAL class functions. The Kern::HalFunction() API is provided to access HAL information.

Unlike the HAL class functions, Kern::HalFunction() uses the group number and function-ids to identify hardware related information. This means that kernel side code does not use attributes to identify hardware related information. The implication here is that you may have to make changes to your kernel side code when porting to another platform. In practice, no changes may be needed, but at the very least you need to check.

Config and Values files define attributes

Although an attribute is generic, some attributes may not have meaning on some platforms. In addition, each platform needs to define whether an attribute is either:

  • non-derived, i.e. has a value that is simply stored in the HAL,

or:

  • derived, i.e. requires a call to a software entity to get and set the value.

This is the role of the Config file.

The Config file contains a list of all the attributes that have meaning on a platform, and uses the symbols defined in the enum HALData::TAttribute to identify them. Using a simple syntax, an attribute can be defined as being derived by associating the attribute symbol with the name of a function. This function is known as the accessor function.

There is also a file known as the Values file that defines the initial values for all of the non-derived attributes, i.e. those attributes that are simply stored in, and retrieved from, the HAL.

The Config and Values files are text files that, for a specific implementation of the HAL, reside in the ...\variant\hal directory. The MMP file also resides there, and the HAL is built as part of the Variant. As part of the build process, the Config and Values files are passed to a Perl script, halcfg.pl, which translates the contents into C++ source files. The resulting binaries are linked in as part of the resulting HAL DLL.

In effect, these C++ source files implement the static data arrays defined by the HalInternal class. As its name suggests, this class is internal to Symbian platform, and is only discussed here to help with understanding.

class HalInternal
    {
    ...
    static const TUint8 Properties[HAL::ENumHalAttributes];
       ...
    static const TInt InitialValue[HAL::ENumHalAttributes];
    static const THalImplementation Implementation[HAL::ENumHalAttributes];
    ...
    }

The data member Implementation[] is an array of pointers to the accessor functions

See Creating the Config & Values files for detailed syntax.

Derived attributes require accessor functions

Each derived attribute has a corresponding accessor function. For example, ProcessDisplayContrast().

All accessor functions are implemented in ...\hal\src\userhal.cpp, and are provided by Symbian platform because of the 'connection' to attributes which are themselves defined as part of the generic platform.

Generally there is one accessor function per derived attribute, although there is nothing to prevent an accessor function dealing with more than one attribute. The attribute number is used to route calls made to HAL::Get() and HAL::Set() forward to the correct accessor function. Internally, Symbian platform routes calls to Get() and Set() for an attribute to the same accessor function, distinguishing between the two by a boolean value.

A new implementation of an accessor function should rarely, if ever, be needed as all likely accessor functions are already defined and implemented by Symbian platform in ...\hal\src\userhal.cpp.

See Writing accessor functions for derived attributes.

Accessor functions call UserSvr::HalFunction()

Typically, an accessor function implementation calls UserSvr::HalFunction(), specifying a group number, as defined in THalFunctionGroup, and a function-id that is related to the attribute, but is not the attribute number as defined in TAttribute. Function numbers are published in u32hal.h, and exported into ...\epoc32\include; for example, the enumerators of the enum TDigitiserHalFunction.

This means that it is the accessor function, which is part of Symbian platform generic code, that decides which HAL handler is to deal with a request (as identified by the attribute).

The kernel uses the HAL group number as an index to dispatch the call to the correct HAL handler.

Note that there may be cases where access to a HAL attribute may be handled through a device driver or server.

UserSvr::HalFunction() calls ExecHandler::HalFunction()

The static function UserSvr::HalFunction(), which is internal to Symbian platform, is the user side point of access. It takes a HAL group to identify a set of related hardware features. In addition, it takes a function-id to identify specific hardware functionality within the HAL group, for example, one of the TDisplayHalFunction enumerators.

A call to this function results in a call to the kernel side function exechandler::HalFunction(), passing the group number and the function-id. This, in turn, finds the appropriate HAL handler function in the internal array K::HalFunction[], using the group number as the index.

UserSvr::HalFunction() is exported from euser.dll, and is therefore accessible from the user side. However, it is not intended for general third party use.

For information purposes, the UserSvr class is defined in the source tree header file ...\e32\include\e32svr.h, which is exported to ...\epoc32\include\.