Adaptation/GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9.dita
author Graeme Price <GRAEME.PRICE@NOKIA.COM>
Fri, 15 Oct 2010 14:32:18 +0100
changeset 15 307f4279f433
permissions -rw-r--r--
Initial contribution of the Adaptation Documentation.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9" xml:lang="en"><title>LCD Extension Implementation Tutorial</title><shortdesc>This topic describes how to create an LCD Extension.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>The topic uses a reference board port named <filepath>template_variant</filepath> as an example implementation. </p>
<section id="GUID-7DDD91D2-A69F-4940-AA58-74EB2A989E55"><title>Build
environment</title> <p>In the template reference board port, the <filepath>.mmp</filepath> file for the LCD Extension is <filepath>...\template_variant\lcdtemplate.mmp</filepath>. This is one of the <codeph>PRJ_MMPFILES</codeph> referenced in
the template variant's <filepath>bld.inf</filepath> file in the <filepath>...\template_variant\...</filepath> directory, and means that the
LCD Extension is built as part of the Variant. </p> <p>The source
for the driver is contained entirely within <filepath>...\template_variant\specific\lcd.cpp</filepath>. </p> <p>The driver is defined as a kernel extension and is loaded
early in the boot sequence. </p> </section>
<section id="GUID-FC49B296-5DFA-4C19-BEDE-F641D70E5ED9"><title>Initialization</title> <p>The driver functionality is almost entirely encapsulated by the <codeph>DLcdPowerHandler</codeph> class. This is a power handler class derived
from <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita"><apiname>DPowerHandler</apiname></xref>. An instance of <codeph>DLcdPowerHandler</codeph> is created when the extension is loaded. </p> <p> <codeph>DLcdPowerHandler</codeph> is defined within the source file itself <filepath>...\template_variant\specific\lcd.cpp</filepath>. </p> <p>As the driver is a kernel extension, it must have a <codeph>DECLARE_STANDARD_EXTENSION()</codeph> statement. In the template
port, this is implemented as follows: </p> <codeblock id="GUID-BB93E7E7-06DA-5A12-ABA1-D07AA246D6FC" xml:space="preserve">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-&gt;Create();
    
    __KTRACE_OPT(KPOWER,Kern::Printf("Returns %d",r));
    return r;
    }
</codeblock> <p>This simply creates an instance of the <codeph>DLcdPowerHandler</codeph> class and then calls its <codeph>Create()</codeph> function which
implements the display setup. This function should do the following: </p> <ul>
<li id="GUID-4D3B36C6-C782-5B3F-8244-7FD33B9976C6"><p>map the video
RAM </p> </li>
<li id="GUID-B693BD2B-50FF-554D-AF2B-1992A472F586"><p>setup the video
info structure </p> </li>
<li id="GUID-1DF67FC0-90FA-5853-88C2-6DBA5C60F377"><p>install the
HAL handler </p> </li>
<li id="GUID-2B8080C4-2A9F-5AA2-B609-3DC8F5759DDE"><p>install the
power handler. </p> </li>
</ul> <p><b> Map the video RAM</b> </p> <p>The frame buffer is a <xref href="GUID-2A34A3DD-A7FE-34A0-B0B7-BB0A4F04B098.dita"><apiname>DPlatChunkHw</apiname></xref> object, and should be mapped as globally accessible,
readable and writeable. It should <i>not</i> 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. </p> <codeblock id="GUID-148795D9-45A2-526B-A2F7-57B5B2AAC8AB" xml:space="preserve">TInt DLcdPowerHandler::Create()
    {
    ...

    // map the video RAM
    TInt vSize = ((TemplateAssp*)Arch::TheAsic())-&gt;VideoRamSize();
    ivRamPhys = TTemplate::VideoRamPhys();                // EXAMPLE ONLY: assume TTemplate interface class
    TInt r = DPlatChunkHw::New(iChunk,ivRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC);
    if ® != KErrNone)
        return r;
 ...
</codeblock> <p>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 <xref href="GUID-3DC7B5F2-512E-3FF3-BC08-945DDE2AE680.dita#GUID-3DC7B5F2-512E-3FF3-BC08-945DDE2AE680/GUID-B506D835-505D-3D89-A840-475F291908DC"><apiname>Epoc::AllocPhysicalRam()</apiname></xref>. </p> <p>If the frame buffer does
not reside in main RAM, there is no problem about reserving it. </p> <p>If the frame buffer must reside at a specific address in main
RAM, there are two strategies available for reserving it: </p> <ul>
<li id="GUID-29D3BF5F-442B-5912-A8B9-4F1F76C1879E"><p>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 <xref href="GUID-3DC7B5F2-512E-3FF3-BC08-945DDE2AE680.dita#GUID-3DC7B5F2-512E-3FF3-BC08-945DDE2AE680/GUID-78F136DC-023B-30AB-A1AB-34D6BC4F1B3E"><apiname>Epoc::ClaimPhysicalRam()</apiname></xref>. This function just marks a region of physical RAM as allocated,
returning an error if any part of the region has already been used. </p> </li>
<li id="GUID-F2C5ED3A-767A-58CA-BDC6-78D3C1820C80"><p>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 <xref href="GUID-B3F6FC45-3BF0-5F92-8325-44C705BA47AE.dita#GUID-B3F6FC45-3BF0-5F92-8325-44C705BA47AE/GUID-B3C6ACE9-A803-59D4-8EBD-314363905427">BTF_Reserve</xref> when writing platform-specific source code for
the bootstrap. See the Bootstrap <xref href="GUID-5EB03086-A87D-5588-8927-7A7F8DB38366.dita">Port Implementation
Tutorial</xref> for more detail and look at <filepath>...\template_variant\bootstrap\template.s</filepath> for a concrete example. </p> </li>
</ul> <p>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. </p> <p id="GUID-57223C8C-0381-51AC-8E8A-771434136A5C"><b> Set up the video
information structure</b> </p> <p>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 <xref href="GUID-C4712A78-6C58-39ED-AF84-11038DB8571D.dita"><apiname>TVideoInfoV01</apiname></xref> defined in the header
file <filepath>...\eka\include\videodriver.h</filepath> and exported
to <filepath>...\epoc32\include</filepath>. </p> <codeblock id="GUID-0680E467-9552-5FD6-BBDE-60AE95F0B941" xml:space="preserve">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;
    ...
    }</codeblock> <p><b> Install the HAL handler</b> </p> <p>Control of the display is
done by using the HAL, the Hardware Abstraction Layer. </p> <p>The <codeph>DLcdPowerHandler</codeph> class provides the implementation for the
HAL handler for the HAL function group <xref href="GUID-7F299BFC-D8A5-3A5A-B8DA-39BF42C99DC6.dita"><apiname>EHalGroupDisplay</apiname></xref> and this needs to be registered with the kernel by calling <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-8C8DCE9D-0094-3909-8FDA-2F3134D0BC88"><apiname>Kern::AddHalEntry()</apiname></xref>. </p> <codeblock id="GUID-F9E86404-742D-5931-BA77-DA246A3975E5" xml:space="preserve">TInt DLcdPowerHandler::Create()
    {
       ...
       // install the HAL function
       r=Kern::AddHalEntry(EHalGroupDisplay, halFunction, this);
       if (r!=KErrNone)
              return r;
    ...
    }</codeblock> <p>See <xref href="GUID-2D977A02-5928-5441-8AE7-42A722F2A4B8.dita#GUID-2D977A02-5928-5441-8AE7-42A722F2A4B8/GUID-4DA41221-40B9-5BC7-B2C6-7C6EB4522508">User-Side Hardware Abstraction</xref> for more detailed information
on the HAL. </p> <p><b> Install the power handler</b> </p> <p>A call must be made to
the <codeph>Add()</codeph> function, which is supplied by the <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita"><apiname>DPowerHandler</apiname></xref> base class of <codeph>DLcdPowerHandler</codeph>, to register the handler with the power manager. </p> <codeblock id="GUID-9286C3A2-DC2B-54F1-9F28-4EBE085AEE84" xml:space="preserve">TInt DLcdPowerHandler::Create()
    {
       ...
        // install the power handler
        // power up the screen
        Add();
    ...
    }</codeblock> </section>
<section id="GUID-85B93308-2EDF-462C-8F64-6AE40B8B16B6"><title>HAL
handler implementation</title> <p>Requests to get and set hardware
attributes are made through calls to <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-573C49D6-7763-37AE-B2B2-4C8FB1327E21"><apiname>HAL::Get()</apiname></xref> and <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-9454F1B2-D525-3D6D-A872-C6457CACD4FC"><apiname>HAL::Set()</apiname></xref>. These two HAL functions take
a value that identifies a hardware attribute, one of the <xref href="GUID-8BE90160-2C60-3582-82C8-4A108C7C0317.dita#GUID-8BE90160-2C60-3582-82C8-4A108C7C0317/GUID-1959915A-BA99-3F94-AFD4-FD1AA540BFBF"><apiname>HALData::TAttribute</apiname></xref> values. </p> <p>For the LCD Extension,
the relevant hardware attributes are: <codeph>EDisplayMode</codeph>, <codeph>EDisplayBitsPerPixel</codeph>, <codeph>EDisplayIsPalettized</codeph>, <codeph>EDisplayIsMono</codeph>, <codeph>EDisplayMemoryAddress</codeph>, <codeph>EDisplayMemoryHandle</codeph>, <codeph>EDisplayOffsetToFirstPixel</codeph>, <codeph>EDisplayOffsetBetweenLines</codeph>, <codeph>EDisplayXPixels</codeph>, <codeph>EDisplayYPixels</codeph>, <codeph>EDisplayPaletteEntry</codeph> and <codeph>EDisplayOffsetBetweenLines</codeph>. </p> <p>The HAL
handler is registered with the kernel as the handler for the <xref href="GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7.dita#GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7/GUID-950EA0D3-747F-305E-92EA-1579023A111E"><apiname>THalFunctionGroup::EHalGroupDisplay</apiname></xref> group. The HAL handler
itself takes a function ID, which is one of the <xref href="GUID-BB011D9B-105F-345C-9FC0-39B0BA509394.dita"><apiname>TDisplayHalFunction</apiname></xref> enumerators. </p> <p>A call to <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-573C49D6-7763-37AE-B2B2-4C8FB1327E21"><apiname>HAL::Get()</apiname></xref> and <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-9454F1B2-D525-3D6D-A872-C6457CACD4FC"><apiname>HAL::Set()</apiname></xref> 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. </p> <p>See <xref href="GUID-2D977A02-5928-5441-8AE7-42A722F2A4B8.dita#GUID-2D977A02-5928-5441-8AE7-42A722F2A4B8/GUID-4DA41221-40B9-5BC7-B2C6-7C6EB4522508">User-Side Hardware Abstraction</xref> for more information on the
way this works in general. </p> <p>The HAL handler is implemented
as a case statement, switching on the function ID. For example, the
following code fragment taken from <codeph>DLcdPowerHandler::HalFunction()</codeph> gets and sets the brightness: </p> <codeblock id="GUID-41D5153A-107A-5FCC-9E51-C6250857F3AC" xml:space="preserve">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,&amp;iBrightness,sizeof(iBrightness));
             break;
        ...
</codeblock> <p>where <codeph>SetBrightness()</codeph> is implemented
as: </p> <codeblock id="GUID-82F38251-19A9-54BC-A066-80ED5AC549AF" xml:space="preserve">TInt DLcdPowerHandler::SetBrightness(TInt aValue)
    {
     __KTRACE_OPT(KEXTENSION,Kern::Printf("SetBrightness(%d)", aValue));

     if (aValue &gt;= KConfigLcdMinDisplayBrightness &amp;&amp; aValue &lt;= KConfigLcdMaxDisplayBrightness)
         {
         iBrightness=aValue;
    
         // TO DO: (mandatory)
         // set the brightness
         //
         return KErrNone;
         }
    return KErrArgument;
    }
</codeblock> <p>If an attribute does not have an implementation, the
HAL handler function should return <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p>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 <xref href="GUID-213DE05E-24F7-3E94-9B35-F4A72B3EBFD8.dita"><apiname>KErrPermissionDenied</apiname></xref>. </p> <p><b>Switch on and switch off operations</b> </p> <p>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. </p> <p>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. </p> <p>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. </p> <p>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. </p> <p><b>Accessing the video information structure</b> </p> <p>When any
part of the <xref href="GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9.dita#GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9/GUID-57223C8C-0381-51AC-8E8A-771434136A5C">video information structure</xref> 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. </p> <codeblock id="GUID-E30D9790-109C-541F-A534-C92CBD4E1706" xml:space="preserve">TInt DLcdPowerHandler::GetCurrentDisplayModeInfo(TVideoInfoV01&amp; aInfo, TBool aSecure)
    {
     __KTRACE_OPT(KEXTENSION,Kern::Printf("GetCurrentDisplayModeInfo"));
     NKern::FMWait(&amp;iLock);
     if (aSecure)
          aInfo = iSecureVideoInfo;
     else
         aInfo = iVideoInfo;
     NKern::FMSignal(&amp;iLock);
     return KErrNone;
     }
</codeblock> </section>
<section id="GUID-04C06DAE-EE8E-4EE9-940F-807F82FBACD1"><title>Power
handler implementation</title> <p>The <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita"><apiname>DPowerHandler</apiname></xref> 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 <codeph>DLcdPowerHandler</codeph> class derived from <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita"><apiname>DPowerHandler</apiname></xref>. </p> <p> <b>Note</b>: </p> <ul>
<li id="GUID-32D95977-F46B-50E0-B575-BE7369C05F62"><p> <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita#GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7/GUID-578DB5FB-731D-36B2-A459-AAC7F250D726"><apiname>DPowerHandler::PowerDown()</apiname></xref> and <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita#GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7/GUID-DDC564B4-BD12-30E9-B04A-DBA6CFAF8743"><apiname>DPowerHandler::PowerUp()</apiname></xref>  </p> <p>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. </p> </li>
<li id="GUID-7DC988A6-C60E-5951-9DD7-82DA129A8CB6"><p> <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita#GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7/GUID-038F9D7D-7DA0-3299-8AA2-85F175206887"><apiname>DPowerHandler::PowerUpLcd()</apiname></xref> and <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita#GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7/GUID-6EAF00D1-3CBA-3BC0-BAD9-7301EE5F9E12"><apiname>DPowerHandler::PowerDownLcd()</apiname></xref>  </p> <p>These
functions generally queue DFCs which then call platform-specific functions
to power the display up and down. </p> </li>
<li id="GUID-51152EA7-C1A5-5AB3-8ACD-6FF6F16A255D"><p> <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita#GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7/GUID-BF62042B-FB7B-3D5B-8379-490FBA284A7A"><apiname>DPowerHandler::PowerUpDone()</apiname></xref> and <xref href="GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7.dita#GUID-761AE02B-41A6-35EA-AA9F-0AEEFF67A6F7/GUID-EBE8CFF8-50BD-3AC3-A4C8-47094DA5674D"><apiname>DPowerHandler::PowerDownDone()</apiname></xref>  </p> <p>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. </p> </li>
</ul> </section>
</conbody><related-links>
<link href="GUID-0C3A4156-E5CF-55F9-91A0-A7961FDEE030.dita"><linktext>LCD
Extension Architecture</linktext></link>
<link href="GUID-8DF46A11-874A-52E5-9298-C083EA633BA0.dita"><linktext>Implementing
Dynamic DSA                 Allocation</linktext></link>
</related-links></concept>