diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,222 @@ + + + + + +LCD Extension Implementation TutorialThis topic describes how to create an LCD Extension. +

The topic uses a reference board port named template_variant as an example implementation.

+
Build +environment

In the template reference board port, the .mmp file for the LCD Extension is ...\template_variant\lcdtemplate.mmp. This is one of the PRJ_MMPFILES referenced in +the template variant's bld.inf file in the ...\template_variant\... directory, and means that the +LCD Extension is built as part of the Variant.

The source +for the driver is contained entirely within ...\template_variant\specific\lcd.cpp.

The driver is defined as a kernel extension and is loaded +early in the boot sequence.

+
Initialization

The driver functionality is almost entirely encapsulated by the DLcdPowerHandler class. This is a power handler class derived +from DPowerHandler. An instance of DLcdPowerHandler is created when the extension is loaded.

DLcdPowerHandler is defined within the source file itself ...\template_variant\specific\lcd.cpp.

As the driver is a kernel extension, it must have a DECLARE_STANDARD_EXTENSION() statement. In the template +port, this is implemented as follows:

DECLARE_STANDARD_EXTENSION() + { + __KTRACE_OPT(KPOWER,Kern::Printf("Starting LCD power manager")); + + // create LCD power handler + TInt r=KErrNoMemory; + DLcdPowerHandler* pH=new DLcdPowerHandler; + if (pH) + r=pH->Create(); + + __KTRACE_OPT(KPOWER,Kern::Printf("Returns %d",r)); + return r; + } +

This simply creates an instance of the DLcdPowerHandler class and then calls its Create() function which +implements the display setup. This function should do the following:

    +
  • map the video +RAM

  • +
  • setup the video +info structure

  • +
  • install the +HAL handler

  • +
  • install the +power handler.

  • +

Map the video RAM

The frame buffer is a DPlatChunkHw object, and should be mapped as globally accessible, +readable and writeable. It should not be mapped as writeback +cached, it should be either not-cached or write-through. The advantage +of write through is that it allows the use of the write buffer.

TInt DLcdPowerHandler::Create() + { + ... + + // map the video RAM + TInt vSize = ((TemplateAssp*)Arch::TheAsic())->VideoRamSize(); + ivRamPhys = TTemplate::VideoRamPhys(); // EXAMPLE ONLY: assume TTemplate interface class + TInt r = DPlatChunkHw::New(iChunk,ivRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC); + if ® != KErrNone) + return r; + ... +

If the frame buffer resides in main RAM and there +is no restriction on which physical addresses may be used for it, +physical RAM for the frame buffer should be reserved by using Epoc::AllocPhysicalRam().

If the frame buffer does +not reside in main RAM, there is no problem about reserving it.

If the frame buffer must reside at a specific address in main +RAM, there are two strategies available for reserving it:

    +
  • If no conflicts +are permitted between the frame buffer and memory allocations made +during the kernel boot (for example, if the frame buffer must reside +at the end of main memory), simply use Epoc::ClaimPhysicalRam(). This function just marks a region of physical RAM as allocated, +returning an error if any part of the region has already been used.

  • +
  • The required +physical RAM region can be reserved in the bootstrap. The correct +place to do this is in the implementation of the boot table function BTF_Reserve when writing platform-specific source code for +the bootstrap. See the Bootstrap Port Implementation +Tutorial for more detail and look at ...\template_variant\bootstrap\template.s for a concrete example.

  • +

Note that all Symbian platform base ports currently create +a second frame buffer for a secure screen. However, as platform security +is not yet implemented, this is wasteful of RAM and should be omitted.

Set up the video +information structure

The video information structure +is used to define several aspects of the display including display +size, bits per pixel and address of the frame buffer. This structure +is the class TVideoInfoV01 defined in the header +file ...\eka\include\videodriver.h and exported +to ...\epoc32\include.

TInt DLcdPowerHandler::Create() + { + ... + // setup the video info structure, this will be used to remember the video settings + iVideoInfo.iDisplayMode = KConfigLcdInitialDisplayMode; + iVideoInfo.iOffsetToFirstPixel = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iOffsetToFirstVideoBuffer; + iVideoInfo.iIsPalettized = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iIsPalettized; + iVideoInfo.iOffsetBetweenLines = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iOffsetBetweenLines; + iVideoInfo.iBitsPerPixel = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iBitsPerPixel; + + iVideoInfo.iSizeInPixels.iWidth = KConfigLcdWidth; + iVideoInfo.iSizeInPixels.iHeight = KConfigLcdHeight; + iVideoInfo.iSizeInTwips.iWidth = KConfigLcdWidthInTwips; + iVideoInfo.iSizeInTwips.iHeight = KConfigLcdHeightInTwips; + iVideoInfo.iIsMono = KConfigLcdIsMono; + iVideoInfo.iVideoAddress=(TInt)pV; + iVideoInfo.iIsPixelOrderLandscape = KConfigLcdPixelOrderLandscape; + iVideoInfo.iIsPixelOrderRGB = KConfigLcdPixelOrderRGB; + ... + }

Install the HAL handler

Control of the display is +done by using the HAL, the Hardware Abstraction Layer.

The DLcdPowerHandler class provides the implementation for the +HAL handler for the HAL function group EHalGroupDisplay and this needs to be registered with the kernel by calling Kern::AddHalEntry().

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

See User-Side Hardware Abstraction for more detailed information +on the HAL.

Install the power handler

A call must be made to +the Add() function, which is supplied by the DPowerHandler base class of DLcdPowerHandler, to register the handler with the power manager.

TInt DLcdPowerHandler::Create() + { + ... + // install the power handler + // power up the screen + Add(); + ... + }
+
HAL +handler implementation

Requests to get and set hardware +attributes are made through calls to HAL::Get() and HAL::Set(). These two HAL functions take +a value that identifies a hardware attribute, one of the HALData::TAttribute values.

For the LCD Extension, +the relevant hardware attributes are: EDisplayMode, EDisplayBitsPerPixel, EDisplayIsPalettized, EDisplayIsMono, EDisplayMemoryAddress, EDisplayMemoryHandle, EDisplayOffsetToFirstPixel, EDisplayOffsetBetweenLines, EDisplayXPixels, EDisplayYPixels, EDisplayPaletteEntry and EDisplayOffsetBetweenLines.

The HAL +handler is registered with the kernel as the handler for the THalFunctionGroup::EHalGroupDisplay group. The HAL handler +itself takes a function ID, which is one of the TDisplayHalFunction enumerators.

A call to HAL::Get() and HAL::Set() that takes one of the hardware attributes relevant +to the LCD Extension is ultimately routed to a call to this HAL handler +function passing an appropriate function ID. The association between +the hardware attribute and the function ID is the responsibility of +the accessor functions.

See User-Side Hardware Abstraction for more information on the +way this works in general.

The HAL handler is implemented +as a case statement, switching on the function ID. For example, the +following code fragment taken from DLcdPowerHandler::HalFunction() gets and sets the brightness:

TInt DLcdPowerHandler::HalFunction(TInt aFunction, TAny* a1, TAny* a2) + { + TInt r=KErrNone; + switch(aFunction) + { + + ... + case EDisplayHalSetDisplayBrightness: + if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData, + __PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetDisplayBrightness"))) + return KErrPermissionDenied; + r=SetBrightness(TInt(a1)); + break; + + case EDisplayHalDisplayBrightness: + kumemput32(a1,&iBrightness,sizeof(iBrightness)); + break; + ... +

where SetBrightness() is implemented +as:

TInt DLcdPowerHandler::SetBrightness(TInt aValue) + { + __KTRACE_OPT(KEXTENSION,Kern::Printf("SetBrightness(%d)", aValue)); + + if (aValue >= KConfigLcdMinDisplayBrightness && aValue <= KConfigLcdMaxDisplayBrightness) + { + iBrightness=aValue; + + // TO DO: (mandatory) + // set the brightness + // + return KErrNone; + } + return KErrArgument; + } +

If an attribute does not have an implementation, the +HAL handler function should return KErrNotSupported.

For platform security, the code only allows the attribute +to be set if the current thread has been authorized to write system +data. Otherwise, it returns KErrPermissionDenied.

Switch on and switch off operations

All of the HAL +operations are seen to be synchronous by the user side. However there +are some operations such as turning the display on and off which may +need to be implemented asynchronously.

The display on/off +code is implemented using synchronous kernel-side messages. There +is only one message per thread and the thread always blocks while +a message is outstanding. This means it is possible to make an asynchronous +operation appear synchronous.

When turning on the screen the +kernel-side message is queued and this thread is blocked until the +message is completed, which happens when the display has been turned +on.

If a display needs to be turned on and off truly asynchronously +(for example, if millisecond timer waits are required during the process +of turning on the display), the above functionality must be changed +so that the complete occurs when the display is truly on.

Accessing the video information structure

When any +part of the video information structure is read or written to, this must +be done within a critical section to prevent potential collisions +with other threads attempting to access the structure concurrently. +A fast mutex is used to ensure that only one thread can access the +video information at any one time, as the code segment below shows.

TInt DLcdPowerHandler::GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure) + { + __KTRACE_OPT(KEXTENSION,Kern::Printf("GetCurrentDisplayModeInfo")); + NKern::FMWait(&iLock); + if (aSecure) + aInfo = iSecureVideoInfo; + else + aInfo = iVideoInfo; + NKern::FMSignal(&iLock); + return KErrNone; + } +
+
Power +handler implementation

The DPowerHandler class defines the interface that the driver must implement to provide +power handling behaviour. For the template reference board, the LCD +Extension defines and implements the DLcdPowerHandler class derived from DPowerHandler.

Note:

    +
  • DPowerHandler::PowerDown() and DPowerHandler::PowerUp()

    These functions +are called in the context of the thread that initiates power down +or power up, and synchronization is required, typically by means of +power up and power down DFCs.

  • +
  • DPowerHandler::PowerUpLcd() and DPowerHandler::PowerDownLcd()

    These +functions generally queue DFCs which then call platform-specific functions +to power the display up and down.

  • +
  • DPowerHandler::PowerUpDone() and DPowerHandler::PowerDownDone()

    When +power up or down is complete, the interface supplies a set of acknowledgment +functions which must be called when the change of state has taken +place.

  • +
+
+LCD +Extension Architecture +Implementing +Dynamic DSA Allocation +
\ No newline at end of file