Adaptation/GUID-12A4418A-9BC6-4BEB-993D-B55E61240A15.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-12A4418A-9BC6-4BEB-993D-B55E61240A15" xml:lang="en"><title>SDIO
       
    13 Client Interface Guide</title><shortdesc>Describes how to use the SDIO interface in a device driver.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    14 <p>This is a generic description of how to use SDIO in a kernel-side device
       
    15 driver. Specifics differ according to hardware and card function.</p>
       
    16 <section id="GUID-F6EC5141-075B-4B9A-8207-330FA8EC696A"><title>Socket, stack,
       
    17 card and function</title>       <p>SDIO is an input/output protocol originally
       
    18 introduced to enable a device to communicate with SDIO (Secure Digital) cards.
       
    19 It can also be used as input/output for media such as Bluetooth adapters and
       
    20 GPS receivers and for input/output within a device (for instance to talk to
       
    21 an internal bus). These different uses of SDIO are called functions.</p><p>Symbian
       
    22 platform implements SDIO as part of a larger framework involving SD cards,
       
    23 which are a type of MMC (multimedia) card. For this reason, to use SDIO in
       
    24 a device driver you will need to use classes representing SD and MMC cards
       
    25 and the associated communications stack even if you only want the basic I/O
       
    26 functionality. These classes are:</p><ul>
       
    27 <li><p><xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita"><apiname>DMMCSocket</apiname></xref></p></li>
       
    28 <li><p><xref href="GUID-908B4DA8-8E1C-3B38-90FF-14EC52277B91.dita"><apiname>DSDIOStack</apiname></xref></p></li>
       
    29 <li><p><xref href="GUID-731522ED-8259-3CBA-9AD3-09DDAE23257D.dita"><apiname>TSDIOCard</apiname></xref></p></li>
       
    30 <li><p><xref href="GUID-1342EC36-363F-3E7D-9B5F-4AFD3BAC98C8.dita"><apiname>TSDIOFunction</apiname></xref></p></li>
       
    31 </ul><p>The work of data transfer is performed by reading to and writing from
       
    32 registers in response to interrupts, and sometimes the read and write operations
       
    33 are performed in sessions. The classes used are these:</p><ul>
       
    34 <li><p><xref href="GUID-CC5352E2-DB21-393F-A7A4-108AA3684460.dita"><apiname>DSDIORegInterface</apiname></xref></p></li>
       
    35 <li><p><xref href="GUID-5A5218D4-E8AD-322F-BE5B-597137623B3F.dita"><apiname>TSDIOInterrupt</apiname></xref></p></li>
       
    36 <li><p><xref href="GUID-36C5854E-6FD4-3630-9FF9-7DB3D578F9BD.dita"><apiname>DSDIOSession</apiname></xref></p></li>
       
    37 </ul><p>This document illustrates the use of these classes to create a driver,
       
    38 with example code fragments in which the driver being created is called <codeph>DSDIODriver</codeph>.</p> 
       
    39    </section>
       
    40 <section id="GUID-6C842F3D-12E5-44A3-8284-4BD8C1770B08"><title>Creation and
       
    41 initialization</title><p>The first step in writing a driver using SDIO is
       
    42 thus to create socket, stack and card objects.</p><codeblock xml:space="preserve">	DMMCSocket* iSocket = static_cast&lt;DMMCSocket&gt;DPBusSocket::SocketFromId(KSocketNumber));
       
    43 	if (NULL == iSocket)
       
    44 		return KErrNoMemory;
       
    45 
       
    46 	DMMCStack* iStack = static_cast&lt;DSDIOStack*&gt;(iSocket-&gt;Stack(KStackNumber));
       
    47 	if (NULL == iStack)
       
    48 		return KErrNoMemory;
       
    49 
       
    50 	TSDIOCard* iCard = static_cast&lt;TSDIOCard*&gt;(iStack-&gt;CardP(KCardNumber));
       
    51 	if (NULL == iCard)
       
    52 		return KErrNoMemory;
       
    53 
       
    54 </codeblock></section>
       
    55 <section id="GUID-6046097E-372A-4C06-941F-C37280668FDD"><title>Function types</title><p>The
       
    56 functions supported by SDIO are represented by the enumeration <xref href="GUID-14307AD8-424C-3AEC-964F-0488DE751CBA.dita"><apiname>TSdioFunctionType</apiname></xref><codeph/> which
       
    57 is declared in the <xref href="GUID-B05522D8-A05B-334F-AA92-05FDC2451000.dita"><apiname>TSdioFunctionCaps</apiname></xref> class. </p><codeblock xml:space="preserve">enum TSdioFunctionType
       
    58 	{
       
    59 	/** Not an SDIO standard interface */
       
    60 	ESdioFunctionTypeUnknown  = 0,
       
    61 	/** SDIO UART standard interface */
       
    62 	ESdioFunctionTypeUART	  = 1,
       
    63 	/** SDIO 'thin' Bluetooth standard interface */
       
    64 	ESdioFunctionTypeThinBT	  = 2,
       
    65 	/** SDIO 'complete' Bluetooth standard interface */
       
    66 	ESdioFunctionTypeFullBT	  = 3,
       
    67 	/** SDIO GPS standard interface */
       
    68 	ESdioFunctionTypeGPS	  = 4,
       
    69 	/** SDIO Camera standard interface */
       
    70 	ESdioFunctionTypeCamera	  = 5,
       
    71 	/** SDIO PHS Radio standard interface */
       
    72 	ESdioFunctionTypePHS	  = 6,
       
    73 	/** SDIO WLAN standard interface (Introduced in SDIO Rev. 1.10f) */
       
    74 	ESdioFunctionTypeWLAN	  = 7,
       
    75 	/** Extended SDIO standard interface (Introduced in SDIO Rev. 1.10f) */
       
    76 	ESdioFunctionTypeExtended = 15,
       
    77 	};
       
    78 </codeblock></section>
       
    79 <section id="GUID-8B81F9BF-167E-4E94-A019-E90EA8281319"><title>Kernel polling</title><p>Kernel
       
    80 polling means the use of the <codeph>Kern::PollingWait()</codeph> function
       
    81 of the kernel to call a function repeatedly if it is likely to fail on a first
       
    82 try. You specify the number of attempts and the delay between them as parameters.
       
    83 It is a recommended technique in writing kernel drivers and is used more than
       
    84 once in the example code in this document. </p></section>
       
    85 <section id="GUID-1784014E-0352-408E-8BDD-EF27F53AF17C"><title>Initialization</title><p>To
       
    86 initialize the card you must power it up and test whether it is ready for
       
    87 use. The following code uses kernel polling to perform the test 10 times at
       
    88 100 millisecond intervals.</p><codeblock xml:space="preserve">	…
       
    89 	iSocket-&gt;PowerUp();
       
    90 	Kern::PollingWait(CardReady, iCard, 100, 10);
       
    91 
       
    92 	if (!iCard-&gt;IsReady())
       
    93 		return(KErrNotReady);
       
    94
       
    95 
       
    96 
       
    97 TBool DSDIODriver::CardReady(TAny* aSelfP)
       
    98 	{
       
    99 	TSDIOCard&amp; card = *(TSDIOCard*)aSelfP;
       
   100 	return card.IsReady();
       
   101 	}
       
   102 </codeblock><p>You may also want to test that the card is an SDIO card.</p><codeblock xml:space="preserve">	if (!pCard-&gt;IsIOCard())
       
   103 		return KErrNotReady;
       
   104 </codeblock><p>Next you locate and enable the function of the card (Bluetooth,
       
   105 UART etc.) which you want to use. A function has a location which differs
       
   106 from card to card and which is stored in a data structure called the CIS (Card
       
   107 Information Structure. To use a card's CIS you load it using the <xref href="GUID-98450844-1ED3-3696-B1A6-C1A97AED83A9.dita"><apiname>CheckCis()</apiname></xref> function
       
   108 of the <xref href="GUID-731522ED-8259-3CBA-9AD3-09DDAE23257D.dita"><apiname>TSDIOCard</apiname></xref> class.</p><codeblock xml:space="preserve">	TInt err = iCard-&gt;CheckCIS();
       
   109 	if (KErrNone != err)
       
   110 		return err;
       
   111 </codeblock><p>The following code is a simple test to determine whether the
       
   112 passed in function type is present on the card.</p><codeblock xml:space="preserve">TSDIOFunction* DSdioDriver::FindFunction(TSdioFunctionType aFunctionType)
       
   113 	{
       
   114 	// We are going to try to match the function type
       
   115 	TUint32 capsMatchMask = TSDIOFunctionCaps::EFunctionType; 
       
   116 
       
   117 	// Create the caps specification for a BT function
       
   118 	TSDIOFunctionCaps functionCaps;
       
   119 	functionCaps.iType = aFunctionType;
       
   120  
       
   121 	// Request to find the function on the card
       
   122 	TSDIOFunction* pFunction = iCard-&gt;FindFunction(functionCaps, capsMatchMask);
       
   123 
       
   124 	// If the function cannot be found, pFunction will be NULL
       
   125 
       
   126 	return pFunction;
       
   127 	}
       
   128 </codeblock><p>Once you have the location of a function, you register the
       
   129 client driver with the stack and enable the function on the card.</p><codeblock xml:space="preserve">	TInt err = iFunction-&gt;RegisterClient(this);
       
   130 	if (err != KErrNone)
       
   131 		{
       
   132 		return err;
       
   133 		}
       
   134 
       
   135 	// Enable the function
       
   136 	err = iFunction-&gt;Enable(ETrue);  
       
   137 	
       
   138 	if (KErrNone == err)
       
   139 		{
       
   140 		Kern::PollingWait(FunctionReady, this, 100, 10);
       
   141 		}
       
   142 
       
   143 	TBool isReady = EFalse;
       
   144 	iFunction-&gt;IsReady(isReady);
       
   145 	If (!isReady)
       
   146 		return KErrNotReady;
       
   147
       
   148 
       
   149 
       
   150 TBool DSdioDriver::FunctionReady(TAny* aSelfP)
       
   151 	{
       
   152 	TSDIOFunction* pFunction = (TSDIOFunction*)aSelfP;
       
   153 	TBool isReady = EFalse;
       
   154 	pFunction-&gt;IsReady(isReady);
       
   155 	return isReady;
       
   156 	}
       
   157 </codeblock></section>
       
   158 <section id="GUID-44B9EA31-9BDD-4181-BF2F-FF80F5EDCE32"><title>Transferring
       
   159 data: registers and shared chunks</title><p>SDIO cards place data to be read
       
   160 or written in a register whose address depends on the function and is defined
       
   161 in the relevant specification available at <xref href="http://www.sdcard.org/home/" scope="external">www.sdcard.org</xref>. Registers are also used to send commands
       
   162 to the card and to enable or disable interrupts. You access the register for
       
   163 a function using the <xref href="GUID-6BD11B5F-2269-3317-A40D-6547042CA463.dita"><apiname>DSDIORegisterInterface</apiname></xref> class which
       
   164 is obtained from the function pointer like this.</p><p/><codeblock xml:space="preserve">		// Get the register interface
       
   165 		DSDIORegisterInterface* pRegIfc = iFunction-&gt;RegisterInterface(this);
       
   166 </codeblock><p>Data can be transferred.</p><ul>
       
   167 <li><p>as individual bytes,</p></li>
       
   168 <li><p>as the contents of byte buffers (both directly and using shared chunks),
       
   169 and</p></li>
       
   170 <li><p>by setting bits in the register.</p></li>
       
   171 </ul><p>The following code uses the <xref href="GUID-53280C38-1734-332D-A432-0A56AB16CD04.dita"><apiname>Read8()</apiname></xref> and <xref href="GUID-BF2E636A-FA49-39F6-9A52-A09E4879F3FC.dita"><apiname>Write8()</apiname></xref> functions
       
   172 of the <xref href="GUID-6BD11B5F-2269-3317-A40D-6547042CA463.dita"><apiname>DSDIORegisterInterface</apiname></xref> class to read and write a
       
   173 single byte from and to the card function. You typically set registers on
       
   174 the card and enable interrupts by this method.</p><codeblock xml:space="preserve">	TUint8 readVal = 0;
       
   175 	TInt ret = pRegIfc-&gt;Read8(KReadRegister, &amp;readVal);
       
   176 	if (KErrNone != ret)
       
   177 		return ret;
       
   178 	
       
   179 	TUint8 writeVal = readVal + 1;
       
   180 	ret = pRegIfc-&gt;Write8(KWriteRegister, writeVal);
       
   181 	if (KErrNone != ret)
       
   182 		return ret;
       
   183 </codeblock><p>This code demonstrates the use of the <xref href="GUID-2E0277CD-3CB8-3A8C-AAD3-8083E8BA7B60.dita"><apiname>ReadMultiple8()</apiname></xref> and <xref href="GUID-F29DFD6B-9CA4-3170-B829-F3881B152614.dita"><apiname>WriteMultiple8()</apiname></xref> functions
       
   184 to read to and write from byte buffers.</p><codeblock xml:space="preserve">	TUint8 client[6];
       
   185 	memcpy(client, “client”, 6);
       
   186 	TInt ret = pRegIfc-&gt;WriteMultiple8(KWriteRegister, client, 6);
       
   187 	if (KErrNone != ret)
       
   188 		return ret;
       
   189 
       
   190 	TUint8 server[6];	
       
   191 	ret = pRegIfc-&gt;ReadMultiple8(KReadRegister, server, 6);
       
   192 	if (KErrNone != ret)
       
   193 		return ret;
       
   194 
       
   195 	if (memcmp(server, “server”) != 0)
       
   196 		return KErrNotFound;
       
   197 </codeblock><p>When large amounts of data are being transferred it is good
       
   198 practice to use a shared chunk. You call the same functions as before with
       
   199 the chunk as additional argument. The following example writes 1024 bytes
       
   200 with an offset of zero and reads 1024 bytes with an offset of 1024.</p><codeblock xml:space="preserve">	TInt ret = pRegIfc-&gt;WriteMultiple8(KWriteRegister, chunk, 0, 1024);
       
   201 	if (KErrNone != ret)
       
   202 		return ret;
       
   203 
       
   204 	ret = pRegIfc-&gt;ReadMultiple8(KReadRegister, chunk, 1024, 1024);
       
   205 	if (KErrNone != ret)
       
   206 		return ret;
       
   207 </codeblock><p>The advantages of shared chunks are that they can be used from
       
   208 user space and reduce copying overhead.</p><p>The following code example shows
       
   209 how to set and clear bits in a register using the <xref href="GUID-312948B9-5338-3030-9130-821E9BDDCE62.dita"><apiname>Modify8()</apiname></xref> function
       
   210 of the <xref href="GUID-6BD11B5F-2269-3317-A40D-6547042CA463.dita"><apiname>DSDIORegisterInterface</apiname></xref> class</p><codeblock xml:space="preserve">	TUint8 setBits = 0x80;
       
   211 	TUint8 clearBis = 0x02;
       
   212 
       
   213 	ret = pRegIfc-&gt;Modify8(KModifyRegister, setBits, clearBits);
       
   214 	if (KErrNone != ret)
       
   215 		return ret;
       
   216 </codeblock><p>Another advantage of shared chunks is that they make it possible
       
   217 to send commands to the card while a multibyte data transfer is taking place.
       
   218 Not all cards support this functionality: you can check whether a particular
       
   219 card does so by reading the SDC bit in the Card Capability register. To do
       
   220 this, you need to create a second register interface to write the commands
       
   221 in the form of one byte transfers. This second interface (or 'second session')
       
   222 must run in a different thread from the interface performing the multibyte
       
   223 transfer and it is created in a different way, as in this code:</p><codeblock xml:space="preserve">	// Create a second session
       
   224 	DSDIORegisterInterface* interfaceP = new DSDIORegisterInterface(cardP, functionP-&gt;FunctionNumber());
       
   225 
       
   226 	// Using the second interface run a direct command 
       
   227 	TUint8 readVal = 0;
       
   228 	ret = interfaceP-&gt;Read8(KReadRegister, &amp;readVal);
       
   229 	
       
   230
       
   231 </codeblock></section>
       
   232 <section id="GUID-11562A70-49EF-49BE-9323-6E1E69433907"><title>Controlling
       
   233 data transfer: interrupts</title><p>Cards generate interrupts which control
       
   234 the process of data transfer: for instance the arrival of data on the function
       
   235 of a card generates an interrupt which serves as a signal that a read operation
       
   236 should take place. The are two levels of interrupts. A card level interrupt
       
   237 indicates which function has triggered it and a separate function level interrupt
       
   238 gives information specific to that function which is covered in the documentation
       
   239 for a particular card.</p><p>You must provide ISRs (interrupt service routines)
       
   240 to handle interrupts. ISRs typically queue DFCs to perform the required actions
       
   241 such as read and write operations on the card since ISRs must complete very
       
   242 quickly to maintain real-time guarantees whereas data transfer can wait for
       
   243 the current time slice to complete. The exact functionality of the DFCs will
       
   244 vary depending on the nature of the function and the hardware. Two things
       
   245 you must do in any driver implementation are enabling and disabling interrupts
       
   246 and binding the ISRs to the stack. Also, when an interrupt is triggered you
       
   247 must read the interrupt register to make sure that the interrupt is applicable
       
   248 and then clear the function level interrupt and re-enable interrupts.</p><p>You
       
   249 enable card level interrupts as in this example code:</p><codeblock xml:space="preserve">	// Enable SDIO card interrupt
       
   250 	iFunction-&gt;Interrupt().Enable();
       
   251 
       
   252 	// Disable SDIO card interrupt
       
   253 	iFunction-&gt;Interrupt().Disable();
       
   254 </codeblock><p>How you enable function level interrupts is described in the
       
   255 documentation for a particular card.</p><p>You bind ISRs to the stack as in
       
   256 the following code fragment. </p><codeblock xml:space="preserve">	…
       
   257 	// Bind to interrupt
       
   258 	err = iFunction-&gt;Interrupt().Bind(DSDIODriver::Isr, this);
       
   259 	if (KErrNone != err)
       
   260 		return err;
       
   261 
       
   262
       
   263 
       
   264 void DSDIODriver::Isr(TAny* aParam)
       
   265 	{
       
   266 	DSDIODriver* pDriver = (DSDIODriver*)aParam;
       
   267
       
   268 	}
       
   269 </codeblock></section>
       
   270 <section id="GUID-458DACCF-1FAD-4F2A-8D79-AD3B77BE75F0"><title>Notifications
       
   271 and powering down: callbacks</title><p>Register callbacks to be notified of
       
   272 events. This mechanism is standard for handling the removal of a card and
       
   273 powering down.</p><p>The SDIO stack can notify clients of events they must
       
   274 react to such as power down or the removal of the card. Events of this kind
       
   275 are listed in the enumeration <xref href="GUID-84D32429-8E04-39BA-A032-478976C7991C.dita"><apiname>TSDIOFunctionCallbackReason</apiname></xref>.</p><codeblock xml:space="preserve">enum TSDIOFunctionCallbackReason
       
   276 	{
       
   277 	/** Card has powered up */
       
   278 	ESdioNotifyPowerUp			 	 	= 0,
       
   279 	/** Card requests to power down */
       
   280 	ESdioNotifyPowerDownPending	  	= 1,
       
   281 	/** Card has powered down */
       
   282 	ESdioNotifyPowerDown		  			= 2,
       
   283 	/** Request to enter sleep mode */
       
   284 	ESdioNotifyPowerSleep		  	= 3,
       
   285 	/** Emergency power down */
       
   286 	ESdioNotifyEmergencyPowerDown 	= 4,
       
   287 	/** PSU fault */
       
   288 	ESdioNotifyPsuFault			  	= 5,
       
   289 	/** Card has been removed */
       
   290 	ESdioNotifyCardRemoved		  	= 6,
       
   291 	/** Card has been inserted */
       
   292 	ESdioNotifyCardInserted		  	= 7,
       
   293 	};
       
   294 </codeblock><p>You respond to notifications with callback functions which
       
   295 you write to provide appropriate functionality. Use the callback to initialize
       
   296 a <xref href="GUID-C07575EE-FCAA-3050-89F3-F0DF8EF8D122.dita"><apiname>TSDIOFunctionCallback</apiname></xref> object and then register that object
       
   297 with the socket. The following code uses an example callback <codeph>FnCallback()</codeph> and
       
   298 object <codeph>functionCallback</codeph>.</p><codeblock xml:space="preserve">	TSDIOFunctionCallback functionCallback(DSDIODriver::FnCallback, this);
       
   299 
       
   300 	// Register the callback
       
   301 	functionCallback.Register(iSocket);
       
   302
       
   303 
       
   304 TInt DSDIODriver::FnCallback(TAny* aParam, TSDIOFunctionCallbackReason aReason)
       
   305 	{
       
   306 	DSDIODriver* pDriver = (DSDIODriver*)aParam;
       
   307 
       
   308 	switch(aReason)
       
   309 		{
       
   310 		case ESdioNotifyCardRemoved:
       
   311
       
   312 			break;
       
   313 		}
       
   314
       
   315 	}
       
   316 </codeblock><p>You typically use notifications and callbacks to perform cleanup
       
   317 before a pending power down event. The socket class has functions to postpone
       
   318 power down at the start of cleanup and to resume power down when cleanup is
       
   319 finished. They are used like this.</p><codeblock xml:space="preserve">	iSocket-&gt;RequestAsyncPowerDown();
       
   320 
       
   321 /* cleanup code here */
       
   322 	iSocket-&gt;PowerDownComplete();</codeblock></section>
       
   323 <section id="GUID-44A3E6CC-8EF1-45B5-92B9-3F440DC6791B"><title>Tutorials</title>The
       
   324 classes and commands used to create a device driver are discussed further
       
   325 in the tutorials.<ul>
       
   326 <li><p><xref href="GUID-2607CCFA-3D24-4716-A447-74304F861C44.dita">DSDIOREGInterface
       
   327 Class Tutorial</xref></p></li>
       
   328 <li><p><xref href="GUID-360DEB3A-3E38-413A-9941-6C758BA01ADE.dita">DSDIOSession
       
   329 Class Tutorial</xref></p></li>
       
   330 <li><p><xref href="GUID-E1277A18-7201-4856-8712-067022F92123.dita">DSDIOStack Class
       
   331 Tutorial</xref></p></li>
       
   332 <li><p><xref href="GUID-BA3B42A2-141C-49D9-B513-1571C246C19B.dita">TSDIOCard Class
       
   333 Tutorial</xref></p></li>
       
   334 <li><p><xref href="GUID-C57086D7-7672-4A52-8634-D28B37AC6290.dita">TSDIOFunction
       
   335 Class Tutorial</xref></p></li>
       
   336 <li><p><xref href="GUID-535C66C9-8B45-4DF3-8404-8ED03ABB4799-GENID-1-2-1-10-1-5-1-9-1-1-7-1-4-1-4-1.dita">TSDIOInterrupt
       
   337 Class Tutorial</xref></p></li>
       
   338 <li><p><xref href="GUID-BDF1F32B-796B-4D3D-9C91-43FF8E9DDAF9.dita">SDIO Commands
       
   339 Tutorial</xref></p></li>
       
   340 </ul><p>A reference implementation using Bluetooth is described in <xref href="GUID-53A6E46C-E961-47C7-A5FA-CB0B52266646.dita">SDIO
       
   341 BT Example</xref>.</p></section>
       
   342 </conbody></concept>