<!-- DOCTYPE part PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->

<!-- {{{ Banner                         -->

<!-- =============================================================== -->
<!--                                                                 -->
<!--     disk_mmc.sgml                                               -->
<!--                                                                 -->
<!--     Documentation for the MMC/SD disk device driver             -->
<!--                                                                 -->
<!-- =============================================================== -->
<!-- ####ECOSDOCCOPYRIGHTBEGIN####                                   -->
<!-- =============================================================== -->
<!-- Copyright (C) 2004, 2008 Free Software Foundation, Inc.         -->
<!-- Copyright (C) 2004, 2008 eCosCentric Limited                    -->
<!-- This material may be distributed only subject to the terms      -->
<!-- and conditions set forth in the Open Publication License, v1.0  -->
<!-- or later (the latest version is presently available at          -->
<!-- http://www.opencontent.org/openpub/)                            -->
<!-- Distribution of the work or derivative of the work in any       -->
<!-- standard (paper) book form is prohibited unless prior           -->
<!-- permission obtained from the copyright holder                   -->
<!-- =============================================================== -->
<!-- ####ECOSDOCCOPYRIGHTEND####                                     -->
<!-- =============================================================== -->
<!-- =============================================================== -->
<!-- #####DESCRIPTIONBEGIN####                                       -->
<!--                                                                 -->
<!-- Author(s):   bartv                                              -->
<!-- Contact(s):  bartv                                              -->
<!-- Date:        2004/04/25                                         -->
<!-- Version:     0.01                                               -->
<!--                                                                 -->
<!-- ####DESCRIPTIONEND####                                          -->
<!-- =============================================================== -->

<!-- }}} -->

<part id="devs-disk-mmcsd-part"><title>MMC and SD Media Card Disk Driver</title>

<refentry id="devs-disk-mmcsd">
  <refmeta>
    <refentrytitle>Device Driver for MMC and SD media Cards</refentrytitle>
  </refmeta>
  <refnamediv>
    <refname><varname>CYGPKG_DEVS_DISK_MMC</varname></refname>
    <refpurpose>eCos Support for MMC and SD media Cards</refpurpose>
  </refnamediv>

  <refsect1 id="devs-disk-mmcsd-description"><title>Description</title>
    <para>
This package provides a disk device driver for two commercial flash memory
card standards: MultiMedia Cards (MMC), and Secure Digital (SD) cards,
including the high-capacity SDHC variant. The MMC card implementation is intended to
allow operation with memory cards compliant with the MultiMediaCard Standard
version 2, as published by the <ulink url="http://www.mmca.org">MultiMediaCard
Association</ulink>. The SD implementation is intended to allow operation
with cards compliant with the SD Physical Layer Specification version 2,
as published by the <ulink url="http://www.sdcard.org/">SD Card
Association</ulink>.
    </para>
    <para>
This package evolved from an MMC-only implementation and as
such the naming of certain aspects such as the CDL package name reflects
that heritage. Any identifiers which reference MMC usually refer
to either MMC or SD cards unless otherwise noted.
    </para>
    <para>
An MMC/SD card provides non-volatile storage in a small footprint
(24mm &ast; 32mm &ast; 1.4mm), and weighing less than 2 grams. Typical
card sizes are 128MB to 2GB, with an upper limit of 4GB for MMC and
SDv1; and 32GB for SDHC cards in SDv2. It
should be noted that these sizes are measured in millions of bytes,
not 2^20. This driver provides support for 4GB MMC and SDv1
cards, although in practice, the FAT16 filesystem layout on such
cards is unusual and may not be supported by a filesystem
implementation using this driver. This problem should not occur
with cards of size 2GB and less, or with SDHC cards.
    </para>
    <para>
At the hardware level there are two ways of accessing an MMC card.  The
first it to use a custom interface frequently known as either an an MCI
(Multimedia Card Interface, although this allows supports for SD as
well) or an MMC/SD bus. The second interface is via connection to an SPI
bus. A card will detect the interface in use at run-time. The custom MCI
interface allows for better performance but requires additional
hardware. SPI peripheral support is more readily available on many
existing CPUs. At this time, the SPI bus mode of interface does not
support SD cards in this driver.
    </para>
    <para>
Theoretically an MMC/SD card can be used with any file system. In practice
all cards are formatted for PC compatibility, with a partition table in the
first block and a single FAT file system on the rest of the card. The SPI
mode driver always checks the format of the MMC card and will only allow
access to a card if it is formatted this way.  The MCI card bus driver can adapt
to a card with no partition table as long as it contains a FAT
filesystem starting from the first block. This non-standard format can
sometimes be created by Windows when reformatting a corrupted card.  This
ability is controlled by the
<varname>CYGSEM_IO_DISK_DETECT_FAT_BOOT</varname> CDL configuration option
in the generic disk device driver package <varname>CYGPKG_IO_DISK</varname>.
    </para>
  </refsect1>
  <refsect1 id="devs-disk-mmcsd-card-detection"><title>Card Insertion and Removal</title>
    <para>
An MMC or SD socket allows cards to be removed and inserted at any time.
It is a common feature for such sockets to contain a contact allowing
the presence of cards to be detected. On some hardware that signal
is routed to the processor allowing it to be sampled, usually connected
as a GPIO signal or to an interrupt line (or to a GPIO interrupt if
available).
    </para>
    <para>
In such cases, the MMC/SD bus driver layer in this package is able to be
informed by the hardware MMC/SD bus driver of whether cards are present
or not, and if possible, can be informed by an event callback that a
card has just been inserted or removed. The SPI mode driver in this
package does not yet support this feature.
    </para>
    <para>
If using the MMC/SD bus driver with appropriate hardware and driver
support, the MMC/SD bus driver layer in this package can plug into the
removeable media support offered by the generic disk driver layer
(<varname>CYGPKG_IO_DISK</varname>) if the configuration option
<varname>CYGFUN_DEVS_DISK_MMCSD_BUS_REMOVABLE_MEDIA_SUPPORT</varname> is
enabled. This option may only be enabled if a hardware driver indicates
that support is available. This facility allows for event notification
when a card is inserted or removed from the socket. This information can
be used directly by the application using the disk package APIs (see
that package's documentation), or to allow use of, for example, the
automounter support provided in the File I/O package
(<varname>CYGPKG_IO_FILEIO</varname>).
    </para>
    <para>
If card detection by an interrupt is not possible, or if using the
SPI bus driver, then the only time the device driver will detect
removal events is when the next I/O operation happens. At that point,
the operation will fail, typically with an error code such as 
<errorcode>ENODEV</errorcode>, <errorcode>ETIMEDOUT</errorcode> or
possible <errorcode>EIO</errorcode>. It is left to higher-level code
to recover from this error - the MMC/SD driver is unable to do
anything since the card has gone. In the case of the eCosPro
implementation of the FAT filesystem, it has been made robust to
such events such that it will always be able to force an unmount
using the <function>umount_force</function> function instead of
the standard <function>umount</function> function.
    </para>
    <para>
Without card detection by interrupt, use of the automounter is not
possible, therefore expected usage is that application code will
explicitly <function>mount</function> the card before attempting any
file I/O.
    </para>
    <para>
Irrespective of card detection abilities, it is expected that the
application will <function>umount</function> the card before it is
removed.  Until unmounted, the system is likely to keep some disk blocks
cached, for performance reasons. If the card is removed before the
<function>umount</function> then it may end up with a corrupted file
system. Application design to inform users of when it is safe to remove
card media, and regular uses of the standard <function>sync</function>
function will reduce the risk of file system corruption.
    </para>
    <para>
If card detection support is available, but is only pollable, rather than
being connected to an interrupt, then this has limited benefits other than
to accelerate the process of determining whether a card has been removed,
which otherwise necessitate attempting operations and waiting for potential
timeouts. In a future revision of this driver it may become possible to
use a polling thread to check periodically for whether cards have been
inserted or removed.
    </para>
  </refsect1>
  <refsect1 id="devs-disk-mmcsd-write-protection"><title>Write Protection and Security</title>
    <para>
The MMC and SD specifications allow cards to be write-protected in
software.  The current device driver does not yet make it possible to
mark a card as write-protected, however it does respect the setting, and
on mounting such a card will mark it internally as read-only. Any
attempt to write to the card will fail with the error
<errorcode>EROFS</errorcode>.
    </para>
    <para>
SD cards additionally feature a write-protect or 'lock' switch to
indicate that cards must not be written to. This is not a physical
protection however - instead it is expected that the lock switch
position is detected by a contact in the socket, and it is for software
to sample the state of that contact to determine whether the card is
write-protected. Therefore the lock switch may not be respected if
either the hardware or hardware driver does not support sampling the
lock switch position from the socket. If sampling is supported however,
the MMC/SD bus driver will respect that and mark the card internally
as read-only.
    </para>
    <para>
SD (and to a lesser extent MMC) support other security features such as
password protection and encryption. This driver does not yet support
these features.
    </para>
  </refsect1>
  <refsect1 id="devs-disk-mmcsd-config"><title>Configuration Options</title>
    <para>
<varname>CYGPKG_DEVS_DISK_MMC</varname> is a hardware package which
should get loaded automatically when you configure for a suitable eCos
target platform. In this case suitable means that the hardware either:
      <orderedlist numeration="loweralpha">
        <listitem>
          <para>
has an MMC/SD socket connected to an SPI bus, that an SPI bus driver package
exists and is also automatically loaded, and that the platform HAL
provides <link linkend="devs-disk-mmcsd-porting">information</link>
on how the card is connected to the SPI bus; or
          </para>
        </listitem>
        <listitem>
          <para>
has an MMC/SD socket connected to a custom MCI interface's card bus
and a driver package for the MCI exists and is also automatically loaded,
or exists in the HAL.
          </para>
        </listitem>
      </orderedlist>
    </para>
    <para>
The package depends on support from the generic disk package
<varname>CYGPKG_IO_DISK</varname>. That will not be loaded
automatically: the presence of an MMC/SD socket on the board does not
mean that the application has any need for a file system. Hence by
default <varname>CYGPKG_DEVS_DISK_MMC</varname> will be inactive and
will not contribute any code or data to the application's memory
footprint. To activate the driver it will be necessary to add one or
more packages to the configuration using
<command>ecosconfig&nbsp;add</command> or the graphical configuration
tool: the generic disk support <varname>CYGPKG_IO_DISK</varname>;
usually a file system, <varname>CYGPKG_FS_FAT</varname>; support for
the file I/O API <varname>CYGPKG_IO_FILEIO</varname>; and possibly
additional support packages that may be needed by the file system, for
example <varname>CYGPKG_LINUX_COMPAT</varname> for FAT. Depending on the
template used to create the initial configuration some of these may be
loaded already.
    </para>
    <refsect2 id="devs-disk-mmcsd-config-spi"><title>SPI mode operation configuration</title>
      <para>
The package provides two main configuration options when using the SPI
mode of operation.
<varname>CYGDAT_DEVS_DISK_MMC_SPI_DISK0_NAME</varname> specifies the
name of the raw disk device, for example <literal>/dev/mmcdisk0</literal>.
Allowing for partition tables that makes <literal>/dev/mmcdisk0/1</literal>
the first argument that shoul be passed to a
<function>mount</function> call. If the hardware has multiple disk
devices then each one will need a unique name.
<varname>CYGIMP_DEVS_DISK_MMC_SPI_POLLED</varname> controls whether
the SPI bus will be accessed in interrupt-driven or polled mode. It
will default to interrupt-driven if the application is multi-threaded,
which is assumed to be the case if the kernel is present. If the
kernel is absent, for example in a RedBoot configuration, then the
driver will default to polled mode. With some hardware polled mode may
significantly increase disk throughput even in a multi-threaded
application, but will consume cpu cycles that could be used by other
threads.
      </para>
    </refsect2>
    <refsect2 id="devs-disk-mmcsd-config-bus"><title>MMC/SD card bus mode operation configuration</title>
      <para>
When using an MMC/SD card bus, there a number of CDL configuration
settings to be aware of within this driver.
      </para>
      <variablelist>
        <varlistentry>
          <term>Number of sockets on the MMC/SD bus (<varname>CYGINT_DEVS_DISK_MMCSD_BUS_CONNECTORS</varname>)</term>
          <listitem>
            <para>
This CDL interface indicates the number of sockets capable of being
supported by the MMC/SD card bus driver. It is usually implemented by
either a hardware device driver or the platform HAL. At the present time
there can only be 1 socket supported. This limitation is intended to be
lifted in the future.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>SD card support (<varname>CYGFUN_DEVS_DISK_MMCSD_SD</varname>)</term>
          <listitem>
            <para>
This option is present to allow SD card support to be disabled. SD card
support is considered a superset of MMC support, and therefore it is not
possible to disable MMC card support. If SD cards are not to be used,
this option can be disabled to reduce code and memory footprints, along
with slightly faster execution.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Device name for the MMC/SD disk 0 device (<varname>CYGDAT_DEVS_DISK_MMCSD_BUS_DISK0_NAME</varname>)</term>
          <listitem>
            <para>
This is the name of the raw disk device. It provides the prefix used for
the separate disk device strings which are passed to the
<function>mount</function> call. For example, a setting of
<filename>/dev/mmcsd0/</filename> would allow the first partition on the
card to be accessed as <filename>/dev/mmcsd0/1</filename>, the second as
<filename>/dev/mmcsd0/2</filename>,
etc. <filename>/dev/mmcsd0/0</filename> is a special device name used to
access the entire device (including the partition table if
present. Furthermore, the <filename>/dev/mmcsd0</filename> device can be
used for registering disk insertion/removal events with the disk
layer. Consult the disk package documentation for details. The setting
of this configuration option must end with a slash character ('/').
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Hardware drivers support card detection (<varname>CYGINT_DEVS_DISK_MMCSD_BUS_CARD_DETECTION</varname>)</term>
          <listitem>
            <para>
This CDL interface is implemented by a hardware device driver or platform HAL to indicate that
it is able to report the presence or absence of cards.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Removable MMC/SD media support (<varname>CYGFUN_DEVS_DISK_MMCSD_BUS_REMOVABLE_MEDIA_SUPPORT</varname>)</term>
          <listitem>
            <para>
This option is used to determine whether the MMC/SD bus layer will plug
into the generic disk package's removeable media support, i.e. allowing
notification of insertion or removal of cards. There is no point
enabling this option without hardware and driver support, so it is not
possible to enable it if
<varname>CYGINT_DEVS_DISK_MMCSD_BUS_CARD_DETECTION</varname> has not
been implemented. Some code can be saved if this option is disabled.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>MMC/SD debug output (<varname>CYGDBG_DEVS_DISK_MMCSD_BUS_DEBUG</varname>)</term>
          <listitem>
            <para>
Detailed debugging output is possible via the diagnostic console. By default
there is no debugging output, but setting this option to 1 or 2 will provide
increased verbosity of debugging output.
            </para>
          </listitem>
        </varlistentry>
      </variablelist>
    </refsect2>
  </refsect1>
  
  <refsect1 id="devs-disk-mmcsd-extra"><title>Additional SPI Mode Functionality</title>
    <para>
When using the SPI mode to access MMC cards, the disk driver package
exports a variable <varname>cyg_mmc_spi_polled</varname>. This defaults
to true or false depending on the configuration option
<varname>CYGIMP_DEVS_DISK_MMC_SPI_POLLED</varname>. If the default
mode is interrupt-driven then file I/O, including mount operations,
are only allowed when the scheduler has started and interrupts have
been enabled. Any attempts at file I/O earlier during system
initialization, for example inside a C++ static constructor, will lock
up. If it is necessary to perform file I/O at this time then the
driver can be temporarily switched to polling mode before the I/O
operation by setting <varname>cyg_mmc_spi_polled</varname>, and
clearing it again after the I/O. Alternatively the default mode can be
changed to polling by editing the configuration, and then the
<function>main()</function> thread can change the mode to
interrupt-driven once the scheduler has started.
    </para>
  </refsect1>

  <refsect1 id="devs-disk-mmcsd-porting"><title>Porting to New Hardware</title>
    <refsect2 id="devs-disk-mmcsd-porting-spi"<title>SPI mode</title>
      <para>
Assuming that the MMC connector is hooked up to a standard SPI bus and
that there is already an eCos SPI bus driver, porting the MMC disk
driver package should be straightforward. Some other package, usually
the platform HAL, should provide a <type>cyg_spi_device</type>
structure <varname>cyg_spi_mmc_dev0</varname>. That structure contains
the information needed by this package to interact with the MMC card
via the usual SPI interface, for example how to activate the
appropriate chip select. The platform HAL should also implement the
CDL interface <varname>CYGINT_DEVS_DISK_MMC_SPI_CONNECTORS</varname>.
      </para>
      <para>
When defining <varname>cyg_spi_mmc_dev0</varname> special care must be
taken with the chip select. The MMC protocol is transaction-oriented.
For example a read operation involves an initial command sent to the
card, then a reply, then the actual data, and finally a checksum. The
card's chip select must be kept asserted for the entire operation, and
there can be no interactions with other devices on the same SPI bus
during this time.
      </para>
      <para>
Optionally the platform HAL may define a macro
<function>HAL_MMC_SPI_INIT</function> which will be invoked during a
mount operation. This can take any hardware-specific actions that may
be necessary, for example manipulating GPIO pins. Usually no such
macro is needed because the hardware is set up during platform
initialization.
      </para>
      <para>
On some targets there may be
additional hardware to detect events such as card insertion or
removal, but there is no support for exploiting such hardware at
present.
      </para>
      <para>
Only a single MMC socket is supported. Given
the nature of SPI buses there is a problem if the MMC socket is hooked
up via an expansion connector rather than being attached to the main
board. The platform HAL would not know about the socket so would not
implement the CDL interface
<varname>CYGINT_DEVS_DISK_MMC_SPI_CONNECTORS</varname>, and the
<database>ecos.db</database> target entry would not include
<varname>CYGPKG_DEVS_DISK_MMC</varname>. Because this is a hardware
package it cannot easily be added by hand. Instead this scenario would
require some editing of the existing platform HAL and target entry.
      </para>
    </refsect2>
    <refsect2 id="devs-disk-mmcsd-porting-bus"<title>Card bus mode</title>
      <para>
Creating a hardware driver for accessing a card connected via a card bus
requires a large amount of detailed description closely related to the
specific code definitions. Therefore comprehensive descriptions of
functionality has been provided in the <filename>mmcsd_bus.h</filename>
header file in the <filename class=directory>include</filename>
directory of this package. Drivers should include this file, although
before doing so they must define the C preprocessor macro
<varname>__MMCSD_DRIVER_PRIVATE</varname> in order to obtain definitions
private to card bus drivers.
      </para>
      <para>
It is appropriate to provide a high-level overview of the porting process
however. A driver package must implement the CDL interface
<varname>CYGINT_DEVS_DISK_MMCSD_BUS_CONNECTORS</varname> to indicate the
presence of a socket driven as a card bus. It may also implement
<varname>CYGINT_DEVS_DISK_MMCSD_BUS_CARD_DETECTION</varname> if appropriate.
      </para>
      <para>
The driver in this package accesses the hardware driver through the
abstraction of the card bus. This is done by instantiating a bus object
using the <function>CYG_MMCSD_BUS</function> macro. This takes as
arguments an opaque word of private data which may be useful to
the hardware driver for identifying this bus or for any relevant
bus state, and it also takes a function callback list. The
<function>CYG_MMCSD_BUS</function> instantiation must exist in a
module which is always included in the program image. This is
usually performed when building the package by including it in the
libextras.a library (which is converted to extras.o in the eCos
build process and forcibly included in the program image that way).
      </para>
      <para>
This function callback list must be instantiated using the
<function>CYG_MMCSD_BUS_FUNS</function> macro. This provides
a table identifying driver functions to: initialise the bus
at system startup time; (re-)initialise the socket when
attempting to access a card in it for the first time; shutting
down a socket to conserve power; doing specialised configuration
options; preparing to select a card in a socket; sending a command
to a card; and transferring data blocks to or from a card. At this point
the byte and stream operations may be left as <varname>NULL</varname>
and are only present for potential future expansion.  Details
on the purpose and arguments to these functions can be found in
<filename>mmcsd_bus.h</filename>.
      </para>
      <para>
If the hardware and driver is capable of reporting card
insertion/removal events, then notification of insertion or removal can
be performed by calling the
<function>MMCSD_CARD_DETECT_EVENT()</function> macro to register this
with the MMC/SD layer, which will perform any further processing
required. It must be called in DSR or thread context, not ISR context.
      </para>
    </refsect2>
  </refsect1>
</refentry>  
</part>
