Describes how to implement or change a new HAL handler when you create a base port.
A HAL handler gets or sets hardware-specific settings, for example, the display contrast.
A HAL handler is normally implemented in the kernel extension or a driver that provides the hardware-specific functionality.
The easiest way to see the general pattern for implementing HAL handlers is to look at a real example. We will use the screen (i.e. video or LCD) driver for the template reference board, which is implemented in ...\template_variant\specific\lcd.cpp.
The HAL handler function has a signature that is defined by the THalFunc typedef that is exported in epoc32\include\kernel\kernel.h.
For example:
TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
Before the handler can do anything, the extension or driver must register its handler for a specific HAL group. It does so by calling:
Kern::AddHalEntry(group, handler_func, ptr);
where:
group is the number of the HAL group attribute for which the HAL handler is being registered.
handler_func is a pointer to the HAL handler function.
ptr is a pointer that is passed to the HAL handler function when it is called. This is usually a pointer to an object that can handle the specified HAL attribute.
Nearly all the functionality of the template screen driver is implemented in a single class, the LCD power handler object; its DLcdPowerHandler::Create() function is called as part of startup processing. It is this function that registers the HAL handler:
... // install the HAL function r=Kern::AddHalEntry(EHalGroupDisplay,halFunction,this); if (r!=KErrNone) return r; ...
Note that the third parameter is, in general, an optional pointer. It is a pointer to the current object, i.e. the DLcdPowerHandler object. It is this pointer that is passed on to the HAL handler function as its first argument.
Using the template screen driver as an example, the driver provides the HAL handler for dealing with information related to the display HAL group, EHalGroupDisplay. The HAL handler 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); }
This is a stand-alone function. The first parameter aPtr is the pointer that was originally passed to the kernel when the HAL handler was registered via the Kern::AddHalEntry() call, and in this case, points to the LCD's power handler object. In this example, the main implementation of the HAL handler is the member function HalFunction() of the DLcdPowerHandler instance.
Whether you use this kind of technique depends on the way your drivers are implemented, but it is a pattern that is also used by the digitiser and the keyboard driver, as well as by the Symbian implemented HAL handlers.
The other parameters passed to the HAL handler function, i.e. aFunction, a1, and a2 are the ones passed into a call to UserSvr::HalFunction(), which itself is called by the various accessory functions; see the Architecture of User-Side Hardware Abstraction (HAL) component.
It's useful to note that a single HAL handler may end up being called as a result of calls to different accessory functions. For example, ProcessDisplayCurrentModeInfo() and GetBacklightPresent() are accessory functions that result in a call to the screen driver's HAL handler.
To further distinguish between the different characteristics represented by a group, each group has an associated set of function-ids. The function id is the second parameter passed to the HAL handler function, and the most common pattern for an implementation is to code a simple switch statement based on this value. For example, the function-ids associated with the EHalGroupDisplay are represented by the set of enum values defined by the TDisplayHalFunction enum. This is a fragment taken from the template screen driver:
TInt DLcdPowerHandler::HalFunction(TInt aFunction, TAny* a1, TAny* a2) { TInt r=KErrNone; switch(aFunction) { case EDisplayHalScreenInfo: { TPckgBuf<TScreenInfoV01> vPckg; ScreenInfo(vPckg()); Kern::InfoCopy(*(TDes8*)a1,vPckg); break; } case EDisplayHalWsRegisterSwitchOnScreenHandling: iWsSwitchOnScreen=(TBool)a1; break; case EDisplayHalWsSwitchOnScreen: WsSwitchOnScreen(); break; case EDisplayHalMaxDisplayContrast: { TInt mc=KMaxDisplayContrast; kumemput32(a1,&mc,sizeof(mc)); break; } ... default: r=KErrNotSupported; break; } ... }
If the HAL handler function does not deal with a specific function-id, then it returns KErrNotSupported.
The meaning of the parameters a1 and a2 passed to the HAL handler depends on the group and function-id; see the list: HAL Groups and Handlers and HAL Attributes and Function IDs for the more detail.
Dealing with the HAL::GetAll() function
Calls that come through the HAL::GetAll() function must be dealt with by the HAL handler implementation in a particular way.
GetAll() calls the HAL handler and passes -1. The HAL handler must return the HAL attribute value when it is passed a -1 as its parameter unless the handler requires additional parameters. If the handler expects more than one parameter then it must return the error code KErrArgument.
For example, using a HAL::Get() request with the attribute EDisplayBrightness returns the brightness for the specified device (screen).
HALArg = 0; ret = HAL::Get(screen, HAL::EDisplayBrightness, HALArg);
The information cannot be retrieved by the GetAll() function.
When the HAL handler is expecting a value that specifies a particular mode or setting but receives a -1 the HAL handler must return the error code KErrArgument to indicate that an additional parameter was expected.
See >THalImplementation and HAL::GetAll().
The HAL handler itself is only called by the kernel, and is the end result of a sequence that starts either with a call to the user interface functions provided by the HAL class (HAL::Set(), HAL::Get() or HAL::GetAll()), or with a call to the kernel side Kern::HalFunction().
The handler runs on the kernel side in the context of the calling thread with no kernel mutexes or fast mutexes held; the calling thread is not placed into a critical section. It is the responsibility of the handler to do any thread synchronisation required. The handler returns a TInt, which is passed back to the user side, or the caller of Kern::HalFunction().
If you are providing or porting a HAL handler, you need to be aware of platform security issues. In principle, for each call into the HAL handler, you need to check the capabilities of the caller's process.
Recall that function-ids are used to distinguish between the different requests made on a given HAL handler. Different requests may require different capabilities, although many requests require no special capabilities. This means that each function-id is associated with a capability, and means that code that is dealing with a request associated with a specific function-id, must check the associated capability.
For example, the screen (i.e. video or LCD) driver must check that the caller has the ECapabilityWriteDeviceData capability before proceeding with a request to set the device's backlight on. This is a capability that grants write access to settings that control the behaviour of the device.
TInt DLcdPowerHandler::HalFunction(TInt aFunction, TAny* a1, TAny* a2) { TInt r=KErrNone; switch(aFunction) { ... case EDisplayHalSetBacklightOn: if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetBacklightOn"))) { return KErrPermissionDenied; ) ... break; ... }
To find the capabilities associated with function-ids, see the HAL Attributes and Related Function IDs Tables section. Capabilities are documented as part of the API reference for each function-id.
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.