Adaptation/GUID-12A4418A-9BC6-4BEB-993D-B55E61240A15.dita
changeset 15 307f4279f433
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Adaptation/GUID-12A4418A-9BC6-4BEB-993D-B55E61240A15.dita	Fri Oct 15 14:32:18 2010 +0100
@@ -0,0 +1,342 @@
+<?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-12A4418A-9BC6-4BEB-993D-B55E61240A15" xml:lang="en"><title>SDIO
+Client Interface Guide</title><shortdesc>Describes how to use the SDIO interface in a device driver.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
+<p>This is a generic description of how to use SDIO in a kernel-side device
+driver. Specifics differ according to hardware and card function.</p>
+<section id="GUID-F6EC5141-075B-4B9A-8207-330FA8EC696A"><title>Socket, stack,
+card and function</title>       <p>SDIO is an input/output protocol originally
+introduced to enable a device to communicate with SDIO (Secure Digital) cards.
+It can also be used as input/output for media such as Bluetooth adapters and
+GPS receivers and for input/output within a device (for instance to talk to
+an internal bus). These different uses of SDIO are called functions.</p><p>Symbian
+platform implements SDIO as part of a larger framework involving SD cards,
+which are a type of MMC (multimedia) card. For this reason, to use SDIO in
+a device driver you will need to use classes representing SD and MMC cards
+and the associated communications stack even if you only want the basic I/O
+functionality. These classes are:</p><ul>
+<li><p><xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita"><apiname>DMMCSocket</apiname></xref></p></li>
+<li><p><xref href="GUID-908B4DA8-8E1C-3B38-90FF-14EC52277B91.dita"><apiname>DSDIOStack</apiname></xref></p></li>
+<li><p><xref href="GUID-731522ED-8259-3CBA-9AD3-09DDAE23257D.dita"><apiname>TSDIOCard</apiname></xref></p></li>
+<li><p><xref href="GUID-1342EC36-363F-3E7D-9B5F-4AFD3BAC98C8.dita"><apiname>TSDIOFunction</apiname></xref></p></li>
+</ul><p>The work of data transfer is performed by reading to and writing from
+registers in response to interrupts, and sometimes the read and write operations
+are performed in sessions. The classes used are these:</p><ul>
+<li><p><xref href="GUID-CC5352E2-DB21-393F-A7A4-108AA3684460.dita"><apiname>DSDIORegInterface</apiname></xref></p></li>
+<li><p><xref href="GUID-5A5218D4-E8AD-322F-BE5B-597137623B3F.dita"><apiname>TSDIOInterrupt</apiname></xref></p></li>
+<li><p><xref href="GUID-36C5854E-6FD4-3630-9FF9-7DB3D578F9BD.dita"><apiname>DSDIOSession</apiname></xref></p></li>
+</ul><p>This document illustrates the use of these classes to create a driver,
+with example code fragments in which the driver being created is called <codeph>DSDIODriver</codeph>.</p> 
+   </section>
+<section id="GUID-6C842F3D-12E5-44A3-8284-4BD8C1770B08"><title>Creation and
+initialization</title><p>The first step in writing a driver using SDIO is
+thus to create socket, stack and card objects.</p><codeblock xml:space="preserve">	DMMCSocket* iSocket = static_cast&lt;DMMCSocket&gt;DPBusSocket::SocketFromId(KSocketNumber));
+	if (NULL == iSocket)
+		return KErrNoMemory;
+
+	DMMCStack* iStack = static_cast&lt;DSDIOStack*&gt;(iSocket-&gt;Stack(KStackNumber));
+	if (NULL == iStack)
+		return KErrNoMemory;
+
+	TSDIOCard* iCard = static_cast&lt;TSDIOCard*&gt;(iStack-&gt;CardP(KCardNumber));
+	if (NULL == iCard)
+		return KErrNoMemory;
+
+</codeblock></section>
+<section id="GUID-6046097E-372A-4C06-941F-C37280668FDD"><title>Function types</title><p>The
+functions supported by SDIO are represented by the enumeration <xref href="GUID-14307AD8-424C-3AEC-964F-0488DE751CBA.dita"><apiname>TSdioFunctionType</apiname></xref><codeph/> which
+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
+	{
+	/** Not an SDIO standard interface */
+	ESdioFunctionTypeUnknown  = 0,
+	/** SDIO UART standard interface */
+	ESdioFunctionTypeUART	  = 1,
+	/** SDIO 'thin' Bluetooth standard interface */
+	ESdioFunctionTypeThinBT	  = 2,
+	/** SDIO 'complete' Bluetooth standard interface */
+	ESdioFunctionTypeFullBT	  = 3,
+	/** SDIO GPS standard interface */
+	ESdioFunctionTypeGPS	  = 4,
+	/** SDIO Camera standard interface */
+	ESdioFunctionTypeCamera	  = 5,
+	/** SDIO PHS Radio standard interface */
+	ESdioFunctionTypePHS	  = 6,
+	/** SDIO WLAN standard interface (Introduced in SDIO Rev. 1.10f) */
+	ESdioFunctionTypeWLAN	  = 7,
+	/** Extended SDIO standard interface (Introduced in SDIO Rev. 1.10f) */
+	ESdioFunctionTypeExtended = 15,
+	};
+</codeblock></section>
+<section id="GUID-8B81F9BF-167E-4E94-A019-E90EA8281319"><title>Kernel polling</title><p>Kernel
+polling means the use of the <codeph>Kern::PollingWait()</codeph> function
+of the kernel to call a function repeatedly if it is likely to fail on a first
+try. You specify the number of attempts and the delay between them as parameters.
+It is a recommended technique in writing kernel drivers and is used more than
+once in the example code in this document. </p></section>
+<section id="GUID-1784014E-0352-408E-8BDD-EF27F53AF17C"><title>Initialization</title><p>To
+initialize the card you must power it up and test whether it is ready for
+use. The following code uses kernel polling to perform the test 10 times at
+100 millisecond intervals.</p><codeblock xml:space="preserve">	…
+	iSocket-&gt;PowerUp();
+	Kern::PollingWait(CardReady, iCard, 100, 10);
+
+	if (!iCard-&gt;IsReady())
+		return(KErrNotReady);
+	…
+
+
+TBool DSDIODriver::CardReady(TAny* aSelfP)
+	{
+	TSDIOCard&amp; card = *(TSDIOCard*)aSelfP;
+	return card.IsReady();
+	}
+</codeblock><p>You may also want to test that the card is an SDIO card.</p><codeblock xml:space="preserve">	if (!pCard-&gt;IsIOCard())
+		return KErrNotReady;
+</codeblock><p>Next you locate and enable the function of the card (Bluetooth,
+UART etc.) which you want to use. A function has a location which differs
+from card to card and which is stored in a data structure called the CIS (Card
+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
+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();
+	if (KErrNone != err)
+		return err;
+</codeblock><p>The following code is a simple test to determine whether the
+passed in function type is present on the card.</p><codeblock xml:space="preserve">TSDIOFunction* DSdioDriver::FindFunction(TSdioFunctionType aFunctionType)
+	{
+	// We are going to try to match the function type
+	TUint32 capsMatchMask = TSDIOFunctionCaps::EFunctionType; 
+
+	// Create the caps specification for a BT function
+	TSDIOFunctionCaps functionCaps;
+	functionCaps.iType = aFunctionType;
+ 
+	// Request to find the function on the card
+	TSDIOFunction* pFunction = iCard-&gt;FindFunction(functionCaps, capsMatchMask);
+
+	// If the function cannot be found, pFunction will be NULL
+
+	return pFunction;
+	}
+</codeblock><p>Once you have the location of a function, you register the
+client driver with the stack and enable the function on the card.</p><codeblock xml:space="preserve">	TInt err = iFunction-&gt;RegisterClient(this);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+
+	// Enable the function
+	err = iFunction-&gt;Enable(ETrue);  
+	
+	if (KErrNone == err)
+		{
+		Kern::PollingWait(FunctionReady, this, 100, 10);
+		}
+
+	TBool isReady = EFalse;
+	iFunction-&gt;IsReady(isReady);
+	If (!isReady)
+		return KErrNotReady;
+	…
+
+
+TBool DSdioDriver::FunctionReady(TAny* aSelfP)
+	{
+	TSDIOFunction* pFunction = (TSDIOFunction*)aSelfP;
+	TBool isReady = EFalse;
+	pFunction-&gt;IsReady(isReady);
+	return isReady;
+	}
+</codeblock></section>
+<section id="GUID-44B9EA31-9BDD-4181-BF2F-FF80F5EDCE32"><title>Transferring
+data: registers and shared chunks</title><p>SDIO cards place data to be read
+or written in a register whose address depends on the function and is defined
+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
+to the card and to enable or disable interrupts. You access the register for
+a function using the <xref href="GUID-6BD11B5F-2269-3317-A40D-6547042CA463.dita"><apiname>DSDIORegisterInterface</apiname></xref> class which
+is obtained from the function pointer like this.</p><p/><codeblock xml:space="preserve">		// Get the register interface
+		DSDIORegisterInterface* pRegIfc = iFunction-&gt;RegisterInterface(this);
+</codeblock><p>Data can be transferred.</p><ul>
+<li><p>as individual bytes,</p></li>
+<li><p>as the contents of byte buffers (both directly and using shared chunks),
+and</p></li>
+<li><p>by setting bits in the register.</p></li>
+</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
+of the <xref href="GUID-6BD11B5F-2269-3317-A40D-6547042CA463.dita"><apiname>DSDIORegisterInterface</apiname></xref> class to read and write a
+single byte from and to the card function. You typically set registers on
+the card and enable interrupts by this method.</p><codeblock xml:space="preserve">	TUint8 readVal = 0;
+	TInt ret = pRegIfc-&gt;Read8(KReadRegister, &amp;readVal);
+	if (KErrNone != ret)
+		return ret;
+	
+	TUint8 writeVal = readVal + 1;
+	ret = pRegIfc-&gt;Write8(KWriteRegister, writeVal);
+	if (KErrNone != ret)
+		return ret;
+</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
+to read to and write from byte buffers.</p><codeblock xml:space="preserve">	TUint8 client[6];
+	memcpy(client, “client”, 6);
+	TInt ret = pRegIfc-&gt;WriteMultiple8(KWriteRegister, client, 6);
+	if (KErrNone != ret)
+		return ret;
+
+	TUint8 server[6];	
+	ret = pRegIfc-&gt;ReadMultiple8(KReadRegister, server, 6);
+	if (KErrNone != ret)
+		return ret;
+
+	if (memcmp(server, “server”) != 0)
+		return KErrNotFound;
+</codeblock><p>When large amounts of data are being transferred it is good
+practice to use a shared chunk. You call the same functions as before with
+the chunk as additional argument. The following example writes 1024 bytes
+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);
+	if (KErrNone != ret)
+		return ret;
+
+	ret = pRegIfc-&gt;ReadMultiple8(KReadRegister, chunk, 1024, 1024);
+	if (KErrNone != ret)
+		return ret;
+</codeblock><p>The advantages of shared chunks are that they can be used from
+user space and reduce copying overhead.</p><p>The following code example shows
+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
+of the <xref href="GUID-6BD11B5F-2269-3317-A40D-6547042CA463.dita"><apiname>DSDIORegisterInterface</apiname></xref> class</p><codeblock xml:space="preserve">	TUint8 setBits = 0x80;
+	TUint8 clearBis = 0x02;
+
+	ret = pRegIfc-&gt;Modify8(KModifyRegister, setBits, clearBits);
+	if (KErrNone != ret)
+		return ret;
+</codeblock><p>Another advantage of shared chunks is that they make it possible
+to send commands to the card while a multibyte data transfer is taking place.
+Not all cards support this functionality: you can check whether a particular
+card does so by reading the SDC bit in the Card Capability register. To do
+this, you need to create a second register interface to write the commands
+in the form of one byte transfers. This second interface (or 'second session')
+must run in a different thread from the interface performing the multibyte
+transfer and it is created in a different way, as in this code:</p><codeblock xml:space="preserve">	// Create a second session
+	DSDIORegisterInterface* interfaceP = new DSDIORegisterInterface(cardP, functionP-&gt;FunctionNumber());
+
+	// Using the second interface run a direct command 
+	TUint8 readVal = 0;
+	ret = interfaceP-&gt;Read8(KReadRegister, &amp;readVal);
+	
+	…
+</codeblock></section>
+<section id="GUID-11562A70-49EF-49BE-9323-6E1E69433907"><title>Controlling
+data transfer: interrupts</title><p>Cards generate interrupts which control
+the process of data transfer: for instance the arrival of data on the function
+of a card generates an interrupt which serves as a signal that a read operation
+should take place. The are two levels of interrupts. A card level interrupt
+indicates which function has triggered it and a separate function level interrupt
+gives information specific to that function which is covered in the documentation
+for a particular card.</p><p>You must provide ISRs (interrupt service routines)
+to handle interrupts. ISRs typically queue DFCs to perform the required actions
+such as read and write operations on the card since ISRs must complete very
+quickly to maintain real-time guarantees whereas data transfer can wait for
+the current time slice to complete. The exact functionality of the DFCs will
+vary depending on the nature of the function and the hardware. Two things
+you must do in any driver implementation are enabling and disabling interrupts
+and binding the ISRs to the stack. Also, when an interrupt is triggered you
+must read the interrupt register to make sure that the interrupt is applicable
+and then clear the function level interrupt and re-enable interrupts.</p><p>You
+enable card level interrupts as in this example code:</p><codeblock xml:space="preserve">	// Enable SDIO card interrupt
+	iFunction-&gt;Interrupt().Enable();
+
+	// Disable SDIO card interrupt
+	iFunction-&gt;Interrupt().Disable();
+</codeblock><p>How you enable function level interrupts is described in the
+documentation for a particular card.</p><p>You bind ISRs to the stack as in
+the following code fragment. </p><codeblock xml:space="preserve">	…
+	// Bind to interrupt
+	err = iFunction-&gt;Interrupt().Bind(DSDIODriver::Isr, this);
+	if (KErrNone != err)
+		return err;
+
+	…
+
+void DSDIODriver::Isr(TAny* aParam)
+	{
+	DSDIODriver* pDriver = (DSDIODriver*)aParam;
+	…
+	}
+</codeblock></section>
+<section id="GUID-458DACCF-1FAD-4F2A-8D79-AD3B77BE75F0"><title>Notifications
+and powering down: callbacks</title><p>Register callbacks to be notified of
+events. This mechanism is standard for handling the removal of a card and
+powering down.</p><p>The SDIO stack can notify clients of events they must
+react to such as power down or the removal of the card. Events of this kind
+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
+	{
+	/** Card has powered up */
+	ESdioNotifyPowerUp			 	 	= 0,
+	/** Card requests to power down */
+	ESdioNotifyPowerDownPending	  	= 1,
+	/** Card has powered down */
+	ESdioNotifyPowerDown		  			= 2,
+	/** Request to enter sleep mode */
+	ESdioNotifyPowerSleep		  	= 3,
+	/** Emergency power down */
+	ESdioNotifyEmergencyPowerDown 	= 4,
+	/** PSU fault */
+	ESdioNotifyPsuFault			  	= 5,
+	/** Card has been removed */
+	ESdioNotifyCardRemoved		  	= 6,
+	/** Card has been inserted */
+	ESdioNotifyCardInserted		  	= 7,
+	};
+</codeblock><p>You respond to notifications with callback functions which
+you write to provide appropriate functionality. Use the callback to initialize
+a <xref href="GUID-C07575EE-FCAA-3050-89F3-F0DF8EF8D122.dita"><apiname>TSDIOFunctionCallback</apiname></xref> object and then register that object
+with the socket. The following code uses an example callback <codeph>FnCallback()</codeph> and
+object <codeph>functionCallback</codeph>.</p><codeblock xml:space="preserve">	TSDIOFunctionCallback functionCallback(DSDIODriver::FnCallback, this);
+
+	// Register the callback
+	functionCallback.Register(iSocket);
+	…
+
+TInt DSDIODriver::FnCallback(TAny* aParam, TSDIOFunctionCallbackReason aReason)
+	{
+	DSDIODriver* pDriver = (DSDIODriver*)aParam;
+
+	switch(aReason)
+		{
+		case ESdioNotifyCardRemoved:
+			…
+			break;
+		}
+	…
+	}
+</codeblock><p>You typically use notifications and callbacks to perform cleanup
+before a pending power down event. The socket class has functions to postpone
+power down at the start of cleanup and to resume power down when cleanup is
+finished. They are used like this.</p><codeblock xml:space="preserve">	iSocket-&gt;RequestAsyncPowerDown();
+
+/* cleanup code here */
+	iSocket-&gt;PowerDownComplete();</codeblock></section>
+<section id="GUID-44A3E6CC-8EF1-45B5-92B9-3F440DC6791B"><title>Tutorials</title>The
+classes and commands used to create a device driver are discussed further
+in the tutorials.<ul>
+<li><p><xref href="GUID-2607CCFA-3D24-4716-A447-74304F861C44.dita">DSDIOREGInterface
+Class Tutorial</xref></p></li>
+<li><p><xref href="GUID-360DEB3A-3E38-413A-9941-6C758BA01ADE.dita">DSDIOSession
+Class Tutorial</xref></p></li>
+<li><p><xref href="GUID-E1277A18-7201-4856-8712-067022F92123.dita">DSDIOStack Class
+Tutorial</xref></p></li>
+<li><p><xref href="GUID-BA3B42A2-141C-49D9-B513-1571C246C19B.dita">TSDIOCard Class
+Tutorial</xref></p></li>
+<li><p><xref href="GUID-C57086D7-7672-4A52-8634-D28B37AC6290.dita">TSDIOFunction
+Class Tutorial</xref></p></li>
+<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
+Class Tutorial</xref></p></li>
+<li><p><xref href="GUID-BDF1F32B-796B-4D3D-9C91-43FF8E9DDAF9.dita">SDIO Commands
+Tutorial</xref></p></li>
+</ul><p>A reference implementation using Bluetooth is described in <xref href="GUID-53A6E46C-E961-47C7-A5FA-CB0B52266646.dita">SDIO
+BT Example</xref>.</p></section>
+</conbody></concept>
\ No newline at end of file