Symbian3/PDK/Source/GUID-6A4FE3A3-2E5D-51BB-8272-5995586291E9.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Thu, 11 Mar 2010 18:02:22 +0000
changeset 3 46218c8b8afa
parent 1 25a17d01db0c
child 5 f345bda72bc4
permissions -rw-r--r--
week 10 bug fix submission (SF PDK version): Bug 1892, Bug 1897, Bug 1319. Also 3 or 4 documents were found to contain code blocks with SFL, which has been fixed. Partial fix for broken links, links to Forum Nokia, and the 'Symbian platform' terminology issues.

<?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/><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>This topic describes how to create an LCD Extension. </p>
<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>