Adaptation/GUID-EBF025DB-1552-5E99-8C07-09932DB60552.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-EBF025DB-1552-5E99-8C07-09932DB60552" xml:lang="en"><title>Physical
       
    13 Channel Implementation</title><shortdesc>A media driver must implement a physical channel class derived
       
    14 from the <codeph>DMediaDriver</codeph> base class. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    15 <p/>
       
    16 <p>This includes those drivers associated with fixed media, such as the internal
       
    17 drive, or removable media, such as a PC Card or MultiMediaCard. </p>
       
    18 <p> <codeph>DMediaDriver</codeph> is an abstract class that has virtual functions
       
    19 that must be implemented by your derived class. The following class definition
       
    20 is typical: </p>
       
    21 <codeblock id="GUID-B39837DA-6037-58D2-A1BE-3E7F1E218F7B" xml:space="preserve">class DMyMediaDriver : public DMediaDriver
       
    22     {
       
    23 public:
       
    24     DMyMediaDriver (TInt aMediaId);
       
    25     ~DMmcMediaDriver ();
       
    26 public:    
       
    27     virtual void Close();
       
    28 public:    
       
    29     virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*);
       
    30     virtual TInt Request(TLocDrvRequest&amp; aRequest);
       
    31     virtual TInt PartitionInfo(TPartitionInfo&amp; anInfo);
       
    32     virtual void NotifyPowerDown();
       
    33     virtual void NotifyEmergencyPowerDown();
       
    34 public:
       
    35     TInt DoCreate(TInt aMediaId);
       
    36     };
       
    37       </codeblock>
       
    38 <p>All the functions except the constructor and <codeph>DoCreate()</codeph> either
       
    39 implement or re-implement virtual functions defined by <codeph>DMediaDriver</codeph>. </p>
       
    40 <p>The framework does not require the <codeph>DoCreate()</codeph> function,
       
    41 but it is useful to implement such a function to act as a second-phase constructor
       
    42 in the creation of the media driver. In the example code fragments, we call <codeph>DoCreate()</codeph> from
       
    43 the <xref href="GUID-A6D14A03-ADBF-570D-8AC7-E8BC2700F930.dita#GUID-A6D14A03-ADBF-570D-8AC7-E8BC2700F930/GUID-32B157E9-0F71-5C1B-A0FA-08D5B1ACA700">PDD
       
    44 factory object's Create()</xref> function that is responsible for creating
       
    45 the media driver. </p>
       
    46 <p>There is, of course, nothing to stop you from adding your own functions
       
    47 and data members, if this is appropriate for your implementation. In addition,
       
    48 your are also free to add other classes, functions and enums to your media
       
    49 driver implementation. </p>
       
    50 <ul>
       
    51 <li id="GUID-E17276B8-4595-5A45-89B0-D053A659A17E"><p> <xref href="GUID-EBF025DB-1552-5E99-8C07-09932DB60552.dita#GUID-EBF025DB-1552-5E99-8C07-09932DB60552/GUID-FE5BB479-7AC4-5DB8-87A3-55E855E1A176">Constructor</xref> </p> </li>
       
    52 <li id="GUID-927ED2FA-9A58-5C99-85B6-44BAD9F2F47A"><p> <xref href="GUID-EBF025DB-1552-5E99-8C07-09932DB60552.dita#GUID-EBF025DB-1552-5E99-8C07-09932DB60552/GUID-D308D7F7-25B9-5A3A-BC19-A01C5948B949">DoCreate() - second phase constructor</xref>  </p> </li>
       
    53 <li id="GUID-380702AD-FBC8-584A-B875-B7C23AC841DE"><p> <xref href="GUID-EBF025DB-1552-5E99-8C07-09932DB60552.dita#GUID-EBF025DB-1552-5E99-8C07-09932DB60552/GUID-4ABC799E-33EE-5260-9CD0-71F0A5E7F980">PartitionInfo() - return the partition information</xref>  </p> </li>
       
    54 <li id="GUID-D0EC11D5-CC9C-5A45-BF5B-06CDBEB8738B"><p> <xref href="GUID-EBF025DB-1552-5E99-8C07-09932DB60552.dita#GUID-EBF025DB-1552-5E99-8C07-09932DB60552/GUID-EC193360-31C2-5012-8ED2-19F1C48C8FC5">Request() - handling requests</xref>  </p> </li>
       
    55 </ul>
       
    56 <section id="GUID-FE5BB479-7AC4-5DB8-87A3-55E855E1A176"><title>Constructor</title> <p>The
       
    57 media driver object is created by your PDD factory object's implementation
       
    58 of the <xref href="GUID-A6D14A03-ADBF-570D-8AC7-E8BC2700F930.dita#GUID-A6D14A03-ADBF-570D-8AC7-E8BC2700F930/GUID-32B157E9-0F71-5C1B-A0FA-08D5B1ACA700">Create()</xref> function.
       
    59 The following is the relevant line of code: </p> <codeblock id="GUID-012D3CB1-7C35-590E-AA5D-FBD0F21F957F" xml:space="preserve">...
       
    60 //Create my DMediaDriver derived object
       
    61 DMyMediaDriver* pD=new DMyMediaDriver (aMediaId);
       
    62 ...</codeblock> <p>Your constructor, prototyped as: </p> <codeblock id="GUID-66FD6B05-D32B-5CD6-A546-B1B8E7733EE5" xml:space="preserve">DMyMediaDriver (TInt aMediaId);</codeblock> <p>gives you the chance to do any initialisation that is safe, i.e. that
       
    63 cannot fail. Typically, this is the kind of initialisation that does not need
       
    64 to acquire resources. This is the first phase of the typical Symbian platform
       
    65 two-phase construction process. </p> <codeblock id="GUID-A1C95B09-C03B-531A-9E38-0E77F9E574F5" xml:space="preserve">DMyMediaDriver::DMyMediaDriver (TInt aMediaId)
       
    66     :DMediaDriver(aMediaId)
       
    67     {
       
    68     //…do safe initialisation here
       
    69     }
       
    70         </codeblock> <p>As this code fragment shows, you need to call the
       
    71 base class constructor first, forwarding the <codeph>TInt aMediaId</codeph> value.
       
    72 You do not need to do anything else with this value. Note that this value
       
    73 is the unique media ID used when the media driver was registered. </p> </section>
       
    74 <section id="GUID-D308D7F7-25B9-5A3A-BC19-A01C5948B949"><title>DoCreate()
       
    75 - second phase constructor</title> <p>The media driver object is created by
       
    76 your PDD factory object's implementation of the <xref href="GUID-A6D14A03-ADBF-570D-8AC7-E8BC2700F930.dita#GUID-A6D14A03-ADBF-570D-8AC7-E8BC2700F930/GUID-32B157E9-0F71-5C1B-A0FA-08D5B1ACA700">Create()</xref> function. The following is the relevant line of code, which is called after
       
    77 successful creation of the media driver object: </p> <codeblock id="GUID-003B4A82-853B-5ABF-A33F-69ED7AC520F9" xml:space="preserve">...
       
    78 // Call my media driver’s second-stage constructor
       
    79 Tint r = KErrNoMemory;
       
    80     if(pD)
       
    81         {
       
    82         r = pD-&gt;DoCreate(aMediaId);
       
    83         }
       
    84 ...
       
    85         </codeblock> <p>This is a second-phase constructor that allows you
       
    86 to do more complex initialisation, and initialisation that might fail. Typically,
       
    87 this is initialisation that acquires resources (including memory). The outline
       
    88 implementation of <codeph>DoCreate()</codeph> is: </p> <codeblock id="GUID-4380C850-B722-52E5-A849-602312C2441D" xml:space="preserve">TInt DMyMediaDriver::DoCreate(TInt aMediaId)
       
    89     {
       
    90     TInt r = KErrNone;
       
    91     //…do complex initialisation here
       
    92     return r;
       
    93     }
       
    94         </codeblock> <p>Depending on the complexity of your initialisation,
       
    95 you can either do all your initialisation here, and complete immediately,
       
    96 or you can do the initialisation as an asynchronous operation, in which case
       
    97 initialisation will complete at some later time. </p> <p>If you do this <i>synchronously</i>,
       
    98 then the return code should reflect the success or failure of the operation.
       
    99 In practice, this will almost always be <codeph>KErrNone</codeph>. </p> <p>If
       
   100 you do this <i>asynchronously</i>, then, on completion of the initialisation
       
   101 processing, a call should be made to: <codeph>DMediaDriver::OpenMediaDriverComplete()</codeph> passing
       
   102 either <codeph>KErrNone</codeph> or one of the other system-wide codes as
       
   103 appropriate. </p> </section>
       
   104 <section id="GUID-4ABC799E-33EE-5260-9CD0-71F0A5E7F980"><title>PartitionInfo()
       
   105 - return the partition information</title> <p>Once the media driver has been
       
   106 successfully created and initialised, and has informed the media driver subsystem
       
   107 of this fact by a call to <codeph>DMediaDriver::OpenMediaDriverComplete()</codeph>,
       
   108 then the subsystem makes a call to the media driver's <codeph>PartitionInfo()</codeph> function
       
   109 to get partition information for the media device. </p> <p>The prototype function
       
   110 is: </p> <codeblock id="GUID-C22CA159-CDD5-5900-B753-64E1A481B6F1" xml:space="preserve">TInt PartitionInfo(TPartitionInfo&amp; anInfo);</codeblock> <p>A <xref href="GUID-00D1DAB7-C23A-30F4-B5A3-B47EED5A5DD3.dita"><apiname>TPartitionInfo</apiname></xref> object is passed to the function, which the media driver must fill in. </p> <p>Decoding
       
   111 of partition information may require media access, and as such may be a long
       
   112 running activity. Support is provided that allows this to be done asynchronously.
       
   113 You use the <i>return code</i> from <codeph>PartitionInfo()</codeph> to tell
       
   114 the media driver subsystem which operational mode you are using: </p> <ul>
       
   115 <li id="GUID-6A5496C7-3896-5EA4-AF92-72BFAEAEED55"><p>return <b>KErrNone</b>,
       
   116 if the decoding operation is to be done <b>asynchronously</b>. Note that on
       
   117 completion, the asynchronous operation must call <xref href="GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC.dita#GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC/GUID-1E38DA87-4D5C-3D3C-8FE9-145E5877D02A"><apiname>DMediaDriver::PartitionInfoComplete()</apiname></xref>,
       
   118 returning <codeph>KErrNone</codeph>, or one of the other system-wide error
       
   119 codes, if appropriate. </p> </li>
       
   120 <li id="GUID-4F34B295-062F-5FCB-809B-73F19E4DE1A2"><p>return a value <b>other
       
   121 than KErrNone </b>, if the decoding operation has been done <b>synchronously</b>.
       
   122 If the synchronous operation is successful, return <i>KErrCompletion</i>,
       
   123 otherwise return one of the other system-wide error codes, but not KErrNone. </p> </li>
       
   124 </ul> <p><b>Decoding
       
   125 simple partitions</b> </p> <p>The following example shows the implementation
       
   126 of a simple <codeph>PartitionInfo()</codeph> function. Such an implementation
       
   127 would be provided for non-removable media, such as internal Flash memory,
       
   128 where the layout is simple and known to the system. </p> <p>This implementation
       
   129 reports a single partition with the size of the entire media. The partition
       
   130 expects to be mounted with the FAT filesystem. </p> <p>Note that this operation
       
   131 is done synchronously, and the function returns <codeph>KErrCompletion</codeph> to
       
   132 indicate this. </p> <codeblock id="GUID-3D99CC4D-5996-502B-8A3F-6DE4675EAFE5" xml:space="preserve">TInt DMyMediaDriver::PartitionInfo(TPartitionInfo&amp; aInfo)
       
   133     {
       
   134     aInfo.iPartitionCount                = 1;
       
   135     aInfo.iEntry[0].iPartitionBaseAddr    = 0;
       
   136     aInfo.iEntry[0].iPartitionLen        = TotalSizeInBytes();
       
   137     aInfo.iEntry[0].iPartitionType        = KPartitionTypeFAT12;
       
   138     
       
   139     aInfo.iMediaSizeInBytes                = TotalSizeInBytes();
       
   140 
       
   141     return KErrCompletion;
       
   142     }
       
   143           </codeblock> <p><b>Decoding
       
   144 FAT Partitions</b> </p> <p>More complex implementations of <codeph>PartitionInfo()</codeph> may
       
   145 be required when handling removable media or more complex internal media where
       
   146 the layout of the media is unknown to the system. </p> <p>This example shows
       
   147 a typical implementation for a FAT based removable media device. Here, <codeph>PartitionInfo()</codeph> starts
       
   148 the operation, which is done asynchronously by the <codeph>DoPartitionInfo()</codeph> function. </p> <p>Note
       
   149 that <codeph>PartitionInfo()</codeph> returns <codeph>KErrNone</codeph>, which
       
   150 tells the media driver subsystem that the operation will be done asynchronously. </p> <p>Note
       
   151 also that on completion, <codeph>DoPartitionInfo()</codeph> calls <codeph>PartitionInfoComplete()</codeph> to
       
   152 tell the media driver subsystem that the operation is complete. </p> <codeblock id="GUID-17F9AD37-7D5F-5F8F-960B-EF36FBE03A04" xml:space="preserve">TInt DMyMediaDriverFlash::PartitionInfo(TPartitionInfo&amp; aInfo)
       
   153     {
       
   154     iPartitionInfo = &amp;anInfo                        // Store aInfo until needed
       
   155 
       
   156     TInt errCode = LaunchPartitionInfoRequest();    // Start the asynchronous request
       
   157 
       
   158     return(errCode);    // This needs to be KErrNone to indicate that the operation
       
   159                         // will be completed asynchronously (unless an error occurs launching
       
   160                         // the asynchronous request!)
       
   161     }
       
   162           </codeblock> <p>This is the function that runs asynchronously </p> <codeblock id="GUID-84368231-7B29-5EE9-A93B-851C7E5C0B62" xml:space="preserve">TInt DMyMediaDriver::DoPartitionInfo()
       
   163     {
       
   164     TInt partitionCount = iPartitionInfo-&gt;iPartitionCount = 0;
       
   165 
       
   166     // Read of the first sector successful so check for a Master Boot Record
       
   167     if (*(TUint16*)(&amp;iIntBuf[KMBRSignatureOffset])!=0xAA55)
       
   168         {
       
   169         return(KErrCorrupt);
       
   170         }
       
   171 
       
   172     // Move the partition entries to a 4 byte boundary
       
   173     memcpy(&amp;iIntBuf[0],&amp;iIntBuf[KMBRFirstPartitionEntry],(sizeof(TMBRPartitionEntry)&lt;&lt;2)); 
       
   174 
       
   175     // Search for a x86 default boot partition - let this be the first
       
   176     TMBRPartitionEntry *pe=(TMBRPartitionEntry*)(&amp;iIntBuf[0]);
       
   177 
       
   178     TInt i;
       
   179     TInt defaultPartitionNumber=-1;
       
   180     for (i=0;i&lt;KMaxPartitionEntries;i++,pe++)
       
   181         {
       
   182         if (pe-&gt;IsDefaultBootPartition())
       
   183             {
       
   184             SetPartitionEntry(&amp;iPartitionInfo-&gt;iEntry[0],pe-&gt;iFirstSector,pe-&gt;iNumSectors);
       
   185             iHiddenSectors=pe-&gt;iFirstSector;
       
   186             defaultPartitionNumber=i;
       
   187             partitionCount++;
       
   188             break;
       
   189             }
       
   190         }
       
   191 
       
   192     // Now add any other partitions
       
   193     pe=(TMBRPartitionEntry*)(&amp;iIntBuf[0]);     // Reset it
       
   194     for (i=0;i&lt;KMaxPartitionEntries;i++,pe++)
       
   195         {
       
   196         if (defaultPartitionNumber==i)
       
   197             {
       
   198             continue;    // Already sorted
       
   199             }
       
   200         if (pe-&gt;IsValidDosPartition())
       
   201             {
       
   202             SetPartitionEntry(&amp;iPartitionInfo-&gt;iEntry[partitionCount],pe-&gt;iFirstSector,pe-&gt;iNumSectors);
       
   203             if (partitionCount==0)
       
   204             iHiddenSectors=pe-&gt;iFirstSector;
       
   205             partitionCount++;
       
   206             }
       
   207         }
       
   208 
       
   209     if (defaultPartitionNumber==(-1) &amp;&amp; partitionCount==0)
       
   210         {
       
   211         // Assume it has no MBR, and the Boot Sector is in the 1st sector
       
   212         SetPartitionEntry(&amp;iPartitionInfo-&gt;iEntry[0], 0, iMediaSize);
       
   213         iHiddenSectors=0;
       
   214         partitionCount=1;
       
   215         }
       
   216         
       
   217     iPartitionInfo-&gt;iPartitionCount=partitionCount;
       
   218     iPartitionInfo-&gt;iMediaSizeInBytes=TotalSizeInBytes();
       
   219 
       
   220     PartitionInfoComplete(err);
       
   221     
       
   222     return(KErrNone);
       
   223     }
       
   224           </codeblock> </section>
       
   225 <section id="GUID-EC193360-31C2-5012-8ED2-19F1C48C8FC5"><title>Request() -
       
   226 handling requests</title> <p>You handle requests by implementing your media
       
   227 driver's <codeph>Request()</codeph> function. This is prototyped as: </p> <codeblock id="GUID-2DABBFE2-5F74-5DC4-B1A5-E50A41258E8A" xml:space="preserve">TInt Request(TLocDrvRequest&amp; aRequest)=0;</codeblock> <p>This
       
   228 function is usually called in the context of the client thread that originally
       
   229 initiated the I/O request to the file server, although you should never assume
       
   230 so. Note that you may also see the originating thread referred to as <i>the
       
   231 remote thread</i>. </p> <p>The request type, as identified by the request
       
   232 ID, and the information associated with the request is accessed through the <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita"><apiname>TLocDrvRequest</apiname></xref> object,
       
   233 which is passed to the <codeph>Request()</codeph> function. The information
       
   234 supplied includes offsets, data lengths, the requesting thread etc, but clearly
       
   235 depends on the request ID. You get the request ID by calling <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-615CA1FE-0FDA-39F4-875D-FBB7B6F6FAD8"><apiname>TLocDrvRequest::Id()</apiname></xref>,
       
   236 and this will be one of the <xref href="GUID-720001A0-79E6-3E25-B5F0-4B39EAF95D12.dita#GUID-720001A0-79E6-3E25-B5F0-4B39EAF95D12/GUID-0559A1ED-05A1-386E-B728-0D500ED4E3EA"><apiname>DLocalDrive::TRequestId</apiname></xref> enum
       
   237 values. </p> <p>Each request ID, as defined by <xref href="GUID-720001A0-79E6-3E25-B5F0-4B39EAF95D12.dita#GUID-720001A0-79E6-3E25-B5F0-4B39EAF95D12/GUID-0559A1ED-05A1-386E-B728-0D500ED4E3EA"><apiname>DLocalDrive::TRequestId</apiname></xref> has
       
   238 a specific meaning. The information that is available also depends on the
       
   239 request ID. </p> <p>Depending on the request ID, the operation can be done
       
   240 synchronously or asynchronously. However, it is the responsibility of the
       
   241 implementor of the media driver to handle the incoming requests and to handle
       
   242 them as appropriate to the specific media, i.e. synchronously or asynchronously. </p> <p>In
       
   243 general, the function should return once the request is initiated. If the
       
   244 entire operation cannot be completed immediately, then further request processing
       
   245 must occur within ISRs and DFCs, i.e. using some hardware specific mechanism
       
   246 to indicate completion, or by the use of considerate poll timers to considerately
       
   247 poll the device for it’s current status, with the final request completion
       
   248 being done from within a DFC. The code that implements the asynchronous requests
       
   249 can run within its own thread, or use one of the default threads provided
       
   250 by the kernel (DFC queue thread 0). </p> <p>The underlying media driver framework
       
   251 allows multiple requests to be processed simultaneously. However, other than
       
   252 being able to issue multiple requests, there is no inherent support in the
       
   253 media driver framework to support the handling of multiple requests, so such
       
   254 functionality must be handled by the media driver itself. The underlying media
       
   255 driver framework does, however, provide basic support for deferring requests
       
   256 for later processing should the media driver not be capable of supporting
       
   257 multiple requests. </p> <table id="GUID-A216F849-6301-5C82-8D54-40BE612770F8">
       
   258 <tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
       
   259 <tbody>
       
   260 <row>
       
   261 <entry><p>ECaps </p> </entry>
       
   262 <entry><p>This is a request for information about the size, type, attributes
       
   263 etc of the media. <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-F16E34E3-7DB1-3C6C-800D-173814AADC22"><apiname>TLocDrvRequest::RemoteDes()</apiname></xref> gives you
       
   264 access to the object into which the media driver should put the requested
       
   265 information. The object passed across is a <xref href="GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F.dita"><apiname>TLocalDriveCapsV2</apiname></xref> type,
       
   266 and this is passed by the media driver subsystem in the form of a package
       
   267 buffer, a <xref href="GUID-C7A094BD-846F-3ED2-8CCE-C0743DB3712A.dita"><apiname>TPckgBuf</apiname></xref> type. </p> <p>In practice, you just
       
   268 need to use a simple cast to access the object. The following code fragment
       
   269 is always used: </p> <codeblock id="GUID-35711E5C-5F23-5EC6-8B43-81C2168E1437" xml:space="preserve">...
       
   270 if (id == DLocalDrive::ECaps)
       
   271     {
       
   272     TLocalDriveCapsV2&amp; c = *(TLocalDriveCapsV2*)aRequest.RemoteDes();
       
   273     ...
       
   274     }
       
   275 ....
       
   276               </codeblock> <p>This request type is synchronous. </p> </entry>
       
   277 </row>
       
   278 <row>
       
   279 <entry><p>ERead </p> </entry>
       
   280 <entry><p>This is a request to read data from the media device asynchronously. </p> <p>You
       
   281 need to start an asynchronous operation that reads <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-5D4ABE07-1186-392F-911F-5586150A5FB4"><apiname>TLocDrvRequest::Length()</apiname></xref> bytes
       
   282 from the media, starting at position <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-0BF048C8-81F1-3E71-B13C-7605A6668A30"><apiname>TLocDrvRequest::Pos()</apiname></xref> on
       
   283 the media. </p> <p>You transfer the data to the requesting thread's process
       
   284 by calling <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-842F91FF-C780-3E2A-8860-8F34815452FC"><apiname>TLocDrvRequest::WriteRemote()</apiname></xref>, where the first
       
   285 parameter is the source descriptor representing the data you have just read.
       
   286 For example: </p> <codeblock id="GUID-80E5A231-3F69-5C33-ADE0-1E0C7674992E" xml:space="preserve">...
       
   287 TPtrC8 des((const TUint8*)(iBase),len);
       
   288 TInt r=iReadReq-&gt;WriteRemote(&amp;des,0);
       
   289 ...
       
   290               </codeblock> <p>In this example, <codeph>iBase</codeph> is the
       
   291 location of the data that has just been read in from the device, and <codeph>len</codeph> is
       
   292 the length of this data. The code fragment also assumes that the data to be
       
   293 returned starts at iBase, and not at some offset from iBase. </p> <p>As this
       
   294 is an asynchronous operation, then when all data has been transferred, the
       
   295 request must be completed by calling <xref href="GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC.dita#GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC/GUID-8B9BB560-808F-3424-9638-7DED6737423E"><apiname>DMediaDriver::Complete()</apiname></xref>,
       
   296 passing the original request and a completion code. </p> </entry>
       
   297 </row>
       
   298 <row>
       
   299 <entry><p>EWrite </p> </entry>
       
   300 <entry><p>This is a request to write data to the media device asynchronously. </p> <p>You
       
   301 need to start an asynchronous operation that writes <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-5D4ABE07-1186-392F-911F-5586150A5FB4"><apiname>TLocDrvRequest::Length()</apiname></xref> bytes
       
   302 to the media, starting at position <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-0BF048C8-81F1-3E71-B13C-7605A6668A30"><apiname>TLocDrvRequest::Pos()</apiname></xref> on
       
   303 the media. </p> <p>Before doing the write, then you need to transfer the data
       
   304 to be written from the requesting thread's process by calling <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-96B80631-AD1C-35E8-8613-0A630BD7D9E9"><apiname>TLocDrvRequest::ReadRemote()</apiname></xref>,
       
   305 where the first parameter is the target descriptor. </p> <p>As this is an
       
   306 asynchronous operation, then when all data has been transferred, the request
       
   307 must be completed by calling <xref href="GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC.dita#GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC/GUID-8B9BB560-808F-3424-9638-7DED6737423E"><apiname>DMediaDriver::Complete()</apiname></xref>,
       
   308 passing the original request and a completion code. </p> </entry>
       
   309 </row>
       
   310 <row>
       
   311 <entry><p>EFormat </p> </entry>
       
   312 <entry><p>This is a request to format a section of the media asynchronously. </p> <p>The
       
   313 start position of the section to be formatted can be found by calling <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-0BF048C8-81F1-3E71-B13C-7605A6668A30"><apiname>TLocDrvRequest::Pos()</apiname></xref>,
       
   314 and the number of bytes to be formatted can be found by calling <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-5D4ABE07-1186-392F-911F-5586150A5FB4"><apiname>TLocDrvRequest::Length()</apiname></xref>. </p> <p>Following
       
   315 a format operation, the state of the formatted section depends on the type
       
   316 of media. In practice, you should access locations within the specified section,
       
   317 so that bad regions can be detected and reported. </p> <p>The length of each
       
   318 format request is usually based on the value of <xref href="GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F.dita#GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F/GUID-BDF05FE9-56B5-328B-B562-9F59EF14DAB2"><apiname>TLocalDriveCapsV2::iEraseBlockSize</apiname></xref>,
       
   319 as returned by the <codeph>ECaps</codeph> request. If you need to adjust the
       
   320 start address of the next format request, you can return a positive value
       
   321 that is interpreted as indicating the actual number of bytes formatted in
       
   322 the current step. This feature is useful for media that prefers format operations
       
   323 to be performed on specific boundaries; for example MultiMedia Cards. </p> <p>As
       
   324 this is an asynchronous operation, then when the format operation has been
       
   325 done, the request must be completed by calling <xref href="GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC.dita#GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC/GUID-8B9BB560-808F-3424-9638-7DED6737423E"><apiname>DMediaDriver::Complete()</apiname></xref>,
       
   326 passing the original request and a completion code. </p> </entry>
       
   327 </row>
       
   328 <row>
       
   329 <entry><p>EEnlarge </p> </entry>
       
   330 <entry><p>This is a request to enlarge the accessible range of the media asynchronously.
       
   331 For example, this is used on the internal RAM drive. </p> <p>Calling <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-5D4ABE07-1186-392F-911F-5586150A5FB4"><apiname>TLocDrvRequest::Length()</apiname></xref> gives
       
   332 you the number of bytes by which the accessible range is to be increased. </p> <p>The
       
   333 media attributes, as defined by the settings in <xref href="GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F.dita#GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F/GUID-886205BC-3234-3FDC-B17E-F9293C957097"><apiname>TLocalDriveCapsV2::iMediaAtt</apiname></xref> returned
       
   334 by the <codeph>ECaps</codeph> request, must have <xref href="GUID-8F5CB589-F631-3216-9BB0-DCCF96836E4E.dita"><apiname>KMediaAttVariableSize</apiname></xref> set,
       
   335 otherwise the request fails with <codeph>KErrNotSupported</codeph>. </p> <p>As
       
   336 this is an asynchronous operation, then when the operation is complete, the
       
   337 request must be completed by calling <xref href="GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC.dita#GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC/GUID-8B9BB560-808F-3424-9638-7DED6737423E"><apiname>DMediaDriver::Complete()</apiname></xref>,
       
   338 passing the original request and a completion code. </p> </entry>
       
   339 </row>
       
   340 <row>
       
   341 <entry><p>EReduce </p> </entry>
       
   342 <entry><p>This is a request to reduce the accessible range of the media asynchronously.
       
   343 For example, this is used on the internal RAM drive. </p> <p>The range to
       
   344 be removed is defined as <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-5D4ABE07-1186-392F-911F-5586150A5FB4"><apiname>TLocDrvRequest::Length()</apiname></xref> bytes
       
   345 starting at <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-0BF048C8-81F1-3E71-B13C-7605A6668A30"><apiname>TLocDrvRequest::Pos()</apiname></xref>. In effect, the request
       
   346 removes the section from <codeph>Pos()</codeph> to <codeph>Pos()</codeph> + <codeph>Length()</codeph>,
       
   347 and the length is reduced by <codeph>Length()</codeph>. </p> <p>The media
       
   348 attributes, as defined by the settings in <xref href="GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F.dita#GUID-414CD5E5-216F-3D97-9F04-A93B1A0EA74F/GUID-886205BC-3234-3FDC-B17E-F9293C957097"><apiname>TLocalDriveCapsV2::iMediaAtt</apiname></xref> returned
       
   349 by the <codeph>ECaps</codeph> request, must have <xref href="GUID-8F5CB589-F631-3216-9BB0-DCCF96836E4E.dita"><apiname>KMediaAttVariableSize</apiname></xref> set,
       
   350 otherwise the request fails with <codeph>KErrNotSupported</codeph>. </p> <p>As
       
   351 this is an asynchronous operation, then when the operation is complete, the
       
   352 request must be completed by calling <xref href="GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC.dita#GUID-A0D4EB25-0BA4-39EE-874B-465EB9628DCC/GUID-8B9BB560-808F-3424-9638-7DED6737423E"><apiname>DMediaDriver::Complete()</apiname></xref>,
       
   353 passing the original request and a completion code. </p> </entry>
       
   354 </row>
       
   355 </tbody>
       
   356 </tgroup>
       
   357 </table> <p id="GUID-E6DF6D45-ACB1-5C0C-A4F1-02778EA69D34"><b>A simple implementation</b> </p> <codeblock id="GUID-6AABA189-4F0A-586D-B3DC-DC38F54A8721" xml:space="preserve">TInt DMyMediaDriver::Request(TLocDrvRequest&amp; aRequest)
       
   358     {
       
   359     TInt err = KErrNotSupported;
       
   360     TInt id  = aRequest.Id();
       
   361 
       
   362     if (id == DLocalDrive::ECaps)
       
   363         {
       
   364         TLocalDriveCapsV2&amp; c = *(TLocalDriveCapsV2*)aRequest.RemoteDes();
       
   365         err = Caps(c);
       
   366         c.iSize = m.Drive()-&gt;iPartitionLen;
       
   367         c.iPartitionType = m.Drive()-&gt;iPartitionType;
       
   368         return(err);
       
   369         }
       
   370 
       
   371     if(iCurrentReq != NULL)
       
   372         {
       
   373         return(KMediaDriverDeferRequest);
       
   374         }
       
   375 
       
   376     iCurrentReq = &amp;aRequest;
       
   377 
       
   378     switch(id)
       
   379         {
       
   380         case DLocalDrive::ERead:
       
   381             r = StartRead();
       
   382             break;
       
   383         case DLocalDrive::EWrite:
       
   384             r = StartWrite();
       
   385             break;
       
   386         case DLocalDrive::EFormat:
       
   387             r = StartErase();
       
   388             break;
       
   389         }
       
   390 
       
   391     if (err &lt; 0)
       
   392         {
       
   393         iCurrentReq = NULL;
       
   394         DMediaDriver::Complete(aRequest, err);
       
   395         }
       
   396     
       
   397     return(err);
       
   398     }
       
   399             </codeblock> <p>This demonstrates the following behaviour: </p> <ul>
       
   400 <li id="GUID-12FE8B56-D998-5FDC-B3B8-CAAD3CBDD6C8"><p>The <codeph>ECaps</codeph> request
       
   401 is inherently synchronous, and must complete immediately. </p> </li>
       
   402 <li id="GUID-4188EC10-8F2D-5755-BC7A-9BEB663114E5"><p>This example only handles
       
   403 a single request at a time. If the media driver is busy handling a request,
       
   404 it can return the value <xref href="GUID-4E76E7B3-202A-3FE1-AAF2-5B41FF13843D.dita"><apiname>KMediaDriverDeferRequest</apiname></xref> which
       
   405 defers the message until the current request is complete. </p> </li>
       
   406 <li id="GUID-2A148BC4-E4B8-5EF5-ACF7-50BA52E5A02E"><p>Each message is passed
       
   407 on to the specific function that is responsible for handling the message.
       
   408 This provides readability and ease of maintenance. </p> </li>
       
   409 <li id="GUID-648C0A4B-3481-55A9-B0A4-887378B0EB7A"><p>If an error occurs,
       
   410 the request is completed immediately with the specified error code. </p> </li>
       
   411 </ul> <p>The following code is the implementation of the <codeph>StartWrite()</codeph> function
       
   412 that initiates the asynchronous write operation. It gets the length and position
       
   413 information, and then calls <codeph>DoWriteStep()</codeph>: </p> <codeblock id="GUID-B853FBC7-7A25-5A6B-8799-CB577595B461" xml:space="preserve">TInt DMyMediaDriver::StartWrite()
       
   414     {
       
   415     // Start an asynchronous write operation
       
   416 
       
   417     iCurrentPos = iCurrentReq-&gt;Pos();
       
   418     iCurrentLength = iCurrentReq-&gt;Length();
       
   419 
       
   420     TInt err = DoWriteStep();
       
   421         
       
   422     return(err);
       
   423     }
       
   424                 </codeblock> <p> <codeph>DoWriteStep()</codeph> performs a
       
   425 single write operation. In this example, a single write operation cannot exceed
       
   426 the capabilities of the hardware, so the request is split up into chunks of <codeph>KMyMediaDriverWriteLength</codeph> bytes. </p> <codeblock id="GUID-3C11FDAE-EA06-5B7C-9FC5-DA2C591FFF49" xml:space="preserve">TInt DMyMediaDriver::DoWriteStep()
       
   427     {
       
   428     // Perform a single write step
       
   429 
       
   430     TUint8* destAddress = iBaseAddress + iCurrentPos;
       
   431     TInt writeLength = MIN(iCurrentLength, KMyMediaDriverWriteLength);
       
   432         
       
   433     TPtr8 des(iData, writeLength);
       
   434     TInt err = iCurrentReq-&gt;ReadRemote(&amp;des, iCurrentPos - iCurrentReq-&gt;Pos());
       
   435     if (err != KErrNone)
       
   436         {
       
   437         return(err);
       
   438         }
       
   439 
       
   440         iCurrentPos += writeLength;
       
   441         iCurrentLength -= writeLength;
       
   442 
       
   443         TheHardware::StartWrite(iCurrentPos, writeLength, iData);
       
   444     }
       
   445                 </codeblock> <p>The write operation to the hardware is performed
       
   446 by <codeph>TheHardware::StartWrite()</codeph>. For most hardware, completion
       
   447 is signalled by an interrupt, and the ISR handling the interrupt will queue
       
   448 a DFC. This in turn can call a function like <codeph>WriteComplete()</codeph> shown
       
   449 below: </p> <codeblock id="GUID-E1F615B2-E148-5C79-8F78-41407C0C2013" xml:space="preserve">TInt DMyMediaDriver::WriteComplete(TInt aResult)
       
   450     {
       
   451     // Called upon completion of the write operation
       
   452     // (ie – in DFC after completion interrupt or polled status completion)
       
   453 
       
   454     TBool completeRequest = (iCurrentLength == 0) || (aResult ! = KErrNone);
       
   455         
       
   456     if(!completeRequest)
       
   457         {
       
   458         // There is more data remaining, so write some more data…
       
   459         if((aResult = DoWriteStep()) != KErrNone)
       
   460             {
       
   461             completeRequest = ETrue;
       
   462             }
       
   463         }
       
   464         
       
   465     if(completeRequest)
       
   466         {
       
   467         // We are all done, or an error occurred…
       
   468         DMediaDriver::Complete(iCurrentReq, aResult);
       
   469         iCurrentReq = NULL;
       
   470         }
       
   471     }
       
   472                 </codeblock> <p> <codeph>WriteComplete()</codeph> is an example
       
   473 of a callback or completion function, and shows how a single request may be
       
   474 broken up into a number of smaller chunks. The write request is only completed
       
   475 when the entire write operation is complete or an error occurs. </p> <p>This
       
   476 simple example has demonstrated how a simple <codeph>EWrite</codeph> request
       
   477 may be handled. The <codeph>ERead</codeph> and <codeph>EFormat</codeph> requests
       
   478 are handled in exactly the same way, taking into account the message parameters
       
   479 shown in the previous table. </p> <p id="GUID-2FF89E43-6F12-5A63-A8A5-298667C5D7A2"><b>Issues about physical addresses</b> </p> <p>If
       
   480 the media driver can use physical addresses, you need to be aware of a number
       
   481 of issues. </p> <ul>
       
   482 <li id="GUID-3CCA7A0E-B245-5221-AA0F-AA9CA1F33869"><p> <i>The address scheme
       
   483 used by the hardware</i>  </p> <p>All media devices have a minimum number
       
   484 of bytes that they can transfer. For example, the architecture of some memory
       
   485 card types requires data transfer in blocks of 512 bytes. To read one byte
       
   486 from this type of media device, the media driver must read a block of 512
       
   487 bytes and extract the byte from the block. To write one byte to a media device,
       
   488 the media driver must read a block of 512 bytes, change the content of the
       
   489 byte, and write the block to the media device. </p> </li>
       
   490 <li id="GUID-6AA344A1-607A-5220-AE65-70F1A5B35967"><p> <i>Data transfer smaller
       
   491 than the minimum size</i>  </p> <p>If the local media subsystem receives a
       
   492 request to transfer data with a length smaller than the minimum transfer size,
       
   493 the local media subsystem does not make a physical address available to the
       
   494 media driver. A call to <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-DD6773B4-9EF5-322F-B53D-29174DF3B3BF"><apiname>TLocDrvRequest::IsPhysicalAddress()</apiname></xref> returns
       
   495 false. It is considered unsafe to give access to the physical data surrounding
       
   496 the requested memory location. </p> </li>
       
   497 <li id="GUID-B5CA6F1A-CCD3-5DA0-9297-547F0E80506A"><p> <i>Data transfer not
       
   498 aligned to the media device block boundary</i>  </p> <p>If the local media
       
   499 subsystem receives a request to transfer data, and the address on the media
       
   500 device is <i>not aligned</i> to the media device block boundary, you need
       
   501 to adopt the technique suggested below. The local media subsystem will make
       
   502 the physical address available to the media driver. A call to <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-DD6773B4-9EF5-322F-B53D-29174DF3B3BF"><apiname>TLocDrvRequest::IsPhysicalAddress()</apiname></xref> returns
       
   503 true. </p> <p>Consider the following case. A request has been made to read
       
   504 1024 bytes from a media device that has a block size of 512 bytes. The 1024
       
   505 bytes start at offset +256 on the media device. </p> <fig id="GUID-30EA5683-9B12-59D6-88EF-21F4E84988B3">
       
   506 <image href="GUID-12CD8E91-4102-5253-A7DE-E5436028764F_d0e18431_href.png" placement="inline"/>
       
   507 </fig> <p>To get the first 256 bytes, you must read the first block of 512
       
   508 bytes from the media device. This can corrupt the physical memory passed in
       
   509 the I/O request. The solution is to read the first block from the media device
       
   510 into an intermediate buffer. Copy the 256 bytes from that buffer into the
       
   511 physical memory passed in the I/O request. </p> <p>To get the last 256 bytes,
       
   512 you must read the third block of 512 bytes from the media device into the
       
   513 intermediate buffer. Copy the 256 bytes from that buffer into the correct
       
   514 position in the physical memory passed in the I/O request. </p> <p>The middle
       
   515 512 bytes are aligned on the media device block boundary. The media driver
       
   516 can read this data into the correct position in the physical memory passed
       
   517 in the I/O request. </p> </li>
       
   518 <li id="GUID-27C1D94D-09CB-5C70-94DF-B1FDC8784DE9"><p> <i>Scatter/Gather DMA
       
   519 controllers</i>  </p> <p>DMA controllers can support the Scatter/Gather mode
       
   520 of operation. Each request in this mode of operation consists of a set of
       
   521 smaller requests chained together. This chain of requests is called the Scatter/Gather
       
   522 list. Each item in the list consists of a physical address and a length. </p> <p>Use <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-9879145B-D996-327E-87F6-3B8337A86A56"><apiname>TLocDrvRequest::GetNextPhysicalAddress()</apiname></xref> to
       
   523 help you populate the Scatter/Gather list. </p> <p>The following code fragment
       
   524 shows how you do this. The example assumes that the DMA controller supports
       
   525 a Scatter/Gather list with an unlimited number of entries. In practice, the
       
   526 number of entries in the list is finite. </p> <codeblock id="GUID-51D14E43-D388-507C-826E-8249EAA83287" xml:space="preserve">TPhysAddr physAddr; 
       
   527    TInt physLength;
       
   528    TInt err = KErrNone;
       
   529 
       
   530    while (iRemaining &gt; 0)
       
   531       {
       
   532       err = iCurrentReq-&gt;GetNextPhysicalAddress(physAddr, physLength);
       
   533       if(err != KErrNone)
       
   534          return err;
       
   535 
       
   536       iRemaining -= physLength;
       
   537       PopulateScatterGatherList(physAddr, physLength);
       
   538       }                            
       
   539 
       
   540    return DoDataTransfer(pos, length);</codeblock> </li>
       
   541 </ul> <p>See also <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-575211BC-BF66-5817-9825-EE402648D0CD">Register
       
   542 media driver support for physical addresses</xref>  </p> </section>
       
   543 </conbody></concept>