changeset 2975:faa94c77900c

* ecos.db, io/usb/msd/slave/current/*: Initial check-in of USB mass storage function driver. Contributed by Christophe Coutand. [ Bugzilla 1000987 ]
author jld
date Fri, 12 Nov 2010 13:19:06 +0000
parents 1a427c29fd0f
children 9843108eda9d
files packages/ChangeLog packages/NEWS packages/ecos.db packages/io/usb/msd/slave/current/ChangeLog packages/io/usb/msd/slave/current/cdl/usbs_msd.cdl packages/io/usb/msd/slave/current/include/usbs_msd.h packages/io/usb/msd/slave/current/include/usbs_msd.inl packages/io/usb/msd/slave/current/include/usbs_msd_io.h packages/io/usb/msd/slave/current/include/usbs_msd_opcode.h packages/io/usb/msd/slave/current/include/usbs_msd_scsi.h packages/io/usb/msd/slave/current/src/usbs_msd.c packages/io/usb/msd/slave/current/src/usbs_msd_handler.c packages/io/usb/msd/slave/current/src/usbs_msd_scsi.c packages/io/usb/msd/slave/current/tests/usbs_test_ramdisk.c
diffstat 14 files changed, 3248 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,11 @@
+2010-11-12  John Dallaway  <john@dallaway.org.uk>
+
+	* ecos.db: Add USB mass storage function driver package.
+
+2010-10-27  John Dallaway  <john@dallaway.org.uk>
+
+	* ecos.db: Add STM32 USB slave driver package.
+
 2010-05-30  Christophe Coutand  <ccoutand@stmi.com>
 
 	* ecos.db: Add AT91 ADC driver.
--- a/packages/NEWS
+++ b/packages/NEWS
@@ -1,3 +1,5 @@
+* USB mass storage function driver by Christophe Coutand
+* AT91 USB slave driver halting endpoint support by Christophe Coutand
 * USB slave device driver for STM32 by Chris Holgate
 * Support for dynamic data endpoint configuration in USB serial function
   device package by John Dallaway
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -1533,6 +1533,14 @@ package CYGPKG_IO_USB_SLAVE_SERIAL {
                          as serial devices to the host."
 }
 
+package CYGPKG_IO_USB_SLAVE_MSD {
+       alias           { "USB slave-side mass-storage drivers" usbs_msd }
+       directory       io/usb/msd/slave
+       script          usbs_msd.cdl
+       description     "Support for USB peripherals that present themselves 
+                        as mass storage devices to the host."
+}
+
 package CYGPKG_DEVS_USB_SA11X0 {
         alias           { "Device-driver for the SA11X0 on-chip USB support" usb_sa11x0 }
         hardware
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/ChangeLog
@@ -0,0 +1,36 @@
+2010-11-12  Christophe Coutand  <ccoutand@stmi.com>
+
+     *include/usbs_msd_opcode.h
+     *include/usbs_msd_io.h
+     *include/usbs_msd.h
+     *include/usbs_msd.inl
+     *include/usbs_msd_scsi.h
+     *tests/usbs_test_ramdisk.c
+     *src/usbs_msd_handler.c
+     *src/usbs_msd_scsi.c
+     *src/usbs_msd.c
+     *cdl/usbs_msd.cdl: Initial contribution. [ Bugzilla 1000987 ]
+
+//===========================================================================
+// ####GPLCOPYRIGHTBEGIN####                                                
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2010 Free Software Foundation, Inc.                        
+//
+// This program is free software; you can redistribute it and/or modify     
+// it under the terms of the GNU General Public License as published by     
+// the Free Software Foundation; either version 2 or (at your option) any   
+// later version.                                                           
+//
+// This program is distributed in the hope that it will be useful, but      
+// WITHOUT ANY WARRANTY; without even the implied warranty of               
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
+// General Public License for more details.                                 
+//
+// You should have received a copy of the GNU General Public License        
+// along with this program; if not, write to the                            
+// Free Software Foundation, Inc., 51 Franklin Street,                      
+// Fifth Floor, Boston, MA  02110-1301, USA.                                
+// -------------------------------------------                              
+// ####GPLCOPYRIGHTEND####                                                  
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/cdl/usbs_msd.cdl
@@ -0,0 +1,363 @@
+# ====================================================================
+#
+#      usbs_msd.cdl
+#
+#      USB slave-side mass storage package.
+#
+# ====================================================================
+## ####ECOSGPLCOPYRIGHTBEGIN####                                            
+## -------------------------------------------                              
+## This file is part of eCos, the Embedded Configurable Operating System.   
+## Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.                        
+##
+## eCos is free software; you can redistribute it and/or modify it under    
+## the terms of the GNU General Public License as published by the Free     
+## Software Foundation; either version 2 or (at your option) any later      
+## version.                                                                 
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT      
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+## for more details.                                                        
+##
+## You should have received a copy of the GNU General Public License        
+## along with eCos; if not, write to the Free Software Foundation, Inc.,    
+## 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+##
+## As a special exception, if other files instantiate templates or use      
+## macros or inline functions from this file, or you compile this file      
+## and link it with other works to produce a work based on this file,       
+## this file does not by itself cause the resulting work to be covered by   
+## the GNU General Public License. However the source code for this file    
+## must still be made available in accordance with section (3) of the GNU   
+## General Public License v2.                                               
+##
+## This exception does not invalidate any other reasons why a work based    
+## on this file might be covered by the GNU General Public License.         
+## -------------------------------------------                              
+## ####ECOSGPLCOPYRIGHTEND####                                              
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      USB Slave Mass Storage, ccoutand <ccoutand@stmi.com>
+#    
+# Contributors:   jld
+# Date:           2010-06-04
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+cdl_package CYGPKG_IO_USB_SLAVE_MSD {
+
+    display     "USB slave mass storage support"
+    include_dir "cyg/io/usb"
+    parent      CYGPKG_IO_USB_SLAVE
+
+    requires    { CYGPKG_KERNEL }
+    requires    { CYGPKG_IO_DISK }
+    requires    { CYGHWR_IO_USB_SLAVE_OUT_ENDPOINTS >= 1 }
+    requires    { CYGHWR_IO_USB_SLAVE_IN_ENDPOINTS >= 1 }
+
+    compile     usbs_msd.c usbs_msd_handler.c usbs_msd_scsi.c
+
+    implements  CYGINT_IO_USB_SLAVE_CLIENTS
+
+    define_proc {
+      puts $::cdl_system_header "#define CYGDAT_IO_USB_SLAVE_MSD_INL <cyg/io/usb/usbs_msd.inl>"
+    }    
+
+    description "
+        The USB slave mass storage device (MSD) package supports 
+        the development of USB peripherals which act has mass storage
+        device to the host machine. The actual storage must be implemented
+        on top of the disk package."
+
+    # 
+    # Mass Storage Device 0
+    #
+    cdl_component CYGPKG_IO_USB_SLAVE_MSD0 {
+       display        "USB slave mass storage support for device 0"
+       flavor         bool
+       default_value  1
+       description "
+           This option implement the USB MSD device 0."
+
+       cdl_option CYGDAT_IO_USB_SLAVE_MSD0_SUB_CLASS_TYPE {
+           display         "Mass-storage Device USB Sub Class"
+           flavor          data
+           default_value   { "SCSI" }
+           legal_values    { "SCSI" "RBC" }
+           description     "
+               Specify the transport protocols and command code systems
+               transported by the interface. Currently only the SCSI
+               transparent command set is implemented."
+       }
+
+       cdl_option CYGDAT_IO_USB_SLAVE_MSD0_EP0 {
+           display       "Name of EP0 structure"
+           flavor        data               
+           default_value { "usbs_at91_ep0" }
+           description   "
+               The name of the variable that contains the endpoint 0
+               structure.  This should be set to the EP0 structure for
+               the desired USB device driver such as usbs_at91_ep0,
+               usbs_sa11x0_ep0, etc"
+       }
+
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_EP0_MAX_PACKET_SIZE {
+           display       "The size of EP0"
+           flavor        data
+           default_value 8
+           legal_values  { 8 16 64 } 
+           description   "
+               The size of the EP0 hardware buffer on the specific USB
+               chip used."
+       } 
+
+
+       cdl_component CYGPKG_IO_USB_SLAVE_MSD0_STATIC_EP {
+           display         "Use static I/O endpoint structures"
+           flavor          bool
+           default_value   1
+           description     "
+               Enables the use of static I/O endpoint structures. Some
+               USB slave device drivers implement dynamic endpoint
+               configuration and therefore require this component to be
+               disabled."
+
+           cdl_option  CYGDAT_IO_USB_SLAVE_MSD0_TX_EP {
+               display         "The Tx (USB IN) endpoint structure"
+               flavor         data               
+               default_value  { "usbs_at91_ep1" }
+               description    "
+                   The endpoint structure that corresponds to the selected
+                   Tx endpoint number. This is dependent on the USBS device
+                   driver selected, and could be usbs_at91_ep1,
+                   usbs_sa11x0_ep1, etc"
+           }
+       
+           cdl_option CYGDAT_IO_USB_SLAVE_MSD0_RX_EP {
+               display         "The Rx (USB OUT) endpoint structure"
+               flavor         data               
+               default_value  { "usbs_at91_ep2" }
+               description    "
+                   The endpoint structure that corresponds to the selected
+                   Rx endpoint number. This is dependent on the USBS device
+                   driver selected, and could be usbs_at91_ep2,
+                   usbs_sa11x0_ep2, etc"
+          }
+       }
+
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_TX_EP_NUM {
+           display       "Tx (USB IN) endpoint number"
+           flavor        data
+           default_value 1
+           description   "
+               The endpoint that should be used for the device-side
+               transmitter, which is the USB IN direction."
+       }
+       
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_TX_EP_MAX_PACKET_SIZE {
+           display       "Tx (USB IN) endpoint sze"
+           flavor        data
+           default_value 64
+           legal_values  { 32 64 128 256 512 } 
+           description   "
+               The size of the Tx EP hardware buffer on the specific USB
+               chip used."
+       }        
+
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_RX_EP_NUM {
+           display         "Rx (USB OUT) endpoint number"
+           flavor          data
+           default_value   2
+           description     "
+               The endpoint that should be used for the device-side
+               receiver, which is the USB OUT direction."
+       } 
+
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_RX_EP_MAX_PACKET_SIZE {
+           display       "Rx (USB OUT) endpoint size"
+           flavor        data
+           default_value 64
+           legal_values  { 32 64 128 256 512} 
+           description   "
+               The size of the Rx EP hardware buffer on the specific USB
+               chip used."
+       }  
+       
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_VENDOR_ID {
+           display       "USB Forum Vendor ID"
+           flavor        data
+           default_value 0xFFFF
+           legal_values  1 to 0xFFFF
+           description   "
+               Each USB vendor has an Vendor ID allocated to it by the
+               USB-IF organization.  Any arbitrary value can be selected
+               for testing provided that it doesn't conflict with devices
+               on the development host, but a device should NEVER be
+               released publicly without a valid Vendor ID"
+       }
+
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_PRODUCT_ID {
+           display       "USB product ID"
+           flavor        data
+           default_value 1
+           legal_values  1 to 0xFFFF
+           description   "
+               You are free to select an arbitrary 16-bit Product ID for
+               a device. The combination of Vendor ID and Product ID
+               uniquely identified a USB device."
+       }
+
+       cdl_option CYGDAT_IO_USB_SLAVE_MSD0_MFG_STR {
+          display       "The Device Vendor's Name (Manufacturer String)"
+           flavor        data
+           default_value { "\"eCos\"" }
+           description "
+                   The standard USB enumeration allows for a
+                   manufacturer's name which is normally reported to the
+                   user when the device is first plugged into the host."
+       }
+
+       cdl_option CYGDAT_IO_USB_SLAVE_MSD0_PRODUCT_STR {
+           display       "The Device Product Name"
+           flavor        data
+           default_value { "\"eCos USB Mass Storage Device\"" }
+           description "
+                   The standard USB enumeration allows for a product name
+                   which is normally reported to the user when the device
+                   is first plugged into the host."
+       }
+
+       cdl_option CYGDAT_IO_USB_SLAVE_MSD0_SERIAL_STR {
+           display       "The Device Product Serial Number"
+           flavor        data
+           default_value { "\"123456789AB\"" }
+           description "
+                   The standard USB enumeration allows for a serial number."
+       }
+       
+        cdl_option CYGDAT_IO_USB_SLAVE_MSD0_LUN0_NAME {
+           display       "LUN0 entry name"
+           flavor        data
+           default_value { "\"/dev/ramdisk0/1\"" }
+           description "
+               Specify the logical unit 0 devtab entry name. The default value
+               correspond to the partition 1 of the RAM disk created in the
+               USBS mass storage example application."
+       }               
+       
+       cdl_option CYGOPT_IO_USB_SLAVE_MSD0_BUSPOWERED {
+           display       "The Device is bus powered"
+           default_value 0
+           flavor        bool
+           description   "
+               Tells the host whether the Device is a bus powered
+               device or a self powered device."
+       }
+
+       cdl_option CYGNUM_IO_USB_SLAVE_MSD0_CURRENTDRAW {
+           display       "Maximum current (in mA) drawn from USB bus"
+           flavor        data
+           default_value 100
+           legal_values  1 to 500
+           requires      { (CYGNUM_IO_USB_SLAVE_MSD_CURRENTDRAW > 100) 
+                         implies CYGOPT_IO_USB_SLAVE_MSD_BUSPOWERED }
+           description   "
+               The maximum current drawn by the Device from the USB bus.
+               It should report the peak value. A self powered device
+               can draw up to 100mA, a bus powered device can draw up to
+               500mA. (If it is sometimes below 100mA and sometimes over,
+               then a transition could be done at runtime between self and
+               bus powered modes, but that would be complicated and the
+               device would have to return from configured to addressed
+               state. For details, see the USB specification.)"
+       }
+
+    }
+
+    cdl_option  CYGBLD_IO_USB_SLAVE_MSD_DEBUG {
+        display       "Enable debug output from the driver"
+        default_value 0
+        flavor        bool
+        description   "
+            The driver may produce debug output which can be
+            useful to work out why it is not working as expected."
+    }
+    
+    cdl_option  CYGBLD_IO_USB_SLAVE_MSD_TRACE {
+        display       "Enable trace output from the driver"
+        default_value 0
+        flavor        bool
+        description   "
+            Allow tracing of every USB transaction for debugging 
+            purpose."
+    }    
+
+    cdl_option CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE {
+        display       "Enable application to stall endpoints"
+        default_value 0
+        flavor        bool
+        description   "
+            A mass storage device must stall one or both bulk endpoints in 
+            several situations. However, not all USB device drivers seems
+            to implement this functionality correctly. Hence this option is
+            disable be default. Testing shows that both Linux and Windows can
+            handle mass storage with stall disable."
+    }   
+
+    cdl_component CYGPKG_IO_USB_SLAVE_MSD_OPTIONS {
+    display     "Build options"
+    flavor      none
+
+    description "
+        Package-specific build options including control over compiler
+        flags used only in building this package."
+
+        cdl_option CYGPKG_IO_USB_SLAVE_MSD_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building this package. These flags are used in addition
+                to the set of global flags."
+        }
+ 
+        cdl_option CYGPKG_IO_USB_SLAVE_MSD_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building this package. These flags are removed from
+                the set of global flags if present."
+        }
+        
+        cdl_component CYGBLD_IO_USB_SLAVE_MSD_EXAMPLES {
+            display "Build example programs"
+            no_define     
+            description "
+                Enabling this option will cause the example program
+                to be built using the normal test case infrastructure."
+            
+             cdl_option CYGPKG_IO_USB_SLAVE_MSD_TESTS {
+                 display "USBS MSD example/test program"
+                 no_define
+                 flavor data
+                 calculated { "tests/usbs_test_ramdisk" }
+                 description "
+                     usbs_test_ramdisk creates a tiny FAT12 file-system
+                     on top of a 'ram disk' device. The USB MSD service is
+                     started and the disk should appear at the host side as
+                     a regular mass storage device. If the FAT file-system 
+                     package is included, some files will be created prior to
+                     the USB MSD device to be started."
+             }
+        }
+
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/include/usbs_msd.h
@@ -0,0 +1,282 @@
+#ifndef CYGONCE_USBS_MSD_H
+#define CYGONCE_USBS_MSD_H
+//==========================================================================
+//
+//      include/usbs_msd.h
+//
+//      Description of the USB slave-side MSD
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand
+// Contributors:
+// Date:         2010-06-03
+// Purpose:
+// Description:  USB slave-side MSD support
+//
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/io/usb/usbs.h>
+
+// ----------------------------------------------------------------------------
+// The Mass Storage class requests
+//
+#define USBS_MSD_CLASS_REQ_ADSC          0x00
+#define USBS_MSD_CLASS_REQ_GET_REQUEST   0xFC
+#define USBS_MSD_CLASS_REQ_PUT_REQUEST   0xFD
+#define USBS_MSD_CLASS_REQ_GET_MAX_LUN   0xFE
+#define USBS_MSD_CLASS_REQ_BOMSR         0xFF
+
+// ----------------------------------------------------------------------------
+// Subclass values
+//
+#define USBS_MSD_SUB_CLASS_RBC           0x01 // Reduced Block Commands, typically for flash device
+#define USBS_MSD_SUB_CLASS_SFF8020I      0x02 // For CDROM devices
+#define USBS_MSD_SUB_CLASS_QIC_157       0x03 // QIC-157, Tape devices
+#define USBS_MSD_SUB_CLASS_UFI           0x04 // For Floppy Drive Device
+#define USBS_MSD_SUB_CLASS_SFF8070I      0x05 // For Floppy Drive Device
+#define USBS_MSD_SUB_CLASS_SCSI          0x06 // SCSI transparent
+
+#define USBS_MSD_DATA_IFACE_CLASS        0x8  // mass-storage
+
+// ----------------------------------------------------------------------------
+// Command Wrapper values
+//
+#define USBS_MSD_CSW_STATUS_PASSED       0x0
+#define USBS_MSD_CSW_STATUS_FAILED       0x1
+
+#define USBS_MSD_CBW_SIGNATURE           0x43425355
+#define USBS_MSD_CSW_SIGNATURE           0x53425355
+
+#define USBS_MSD_CBW_HOST2DEVICE         0x00
+#define USBS_MSD_CBW_DEVICE2HOST         0x80
+
+#define USBS_MSD_DEVICE_CLASS            0
+#define USBS_MSD_NUM_IFACE               1
+#define USBS_MSD_NUM_ENDP                2
+
+// ----------------------------------------------------------------------------
+// Helper macros
+//
+#define LO_BYTE_16(word16)          ((cyg_uint8) ((word16) & 0xFF))
+#define HI_BYTE_16(word16)          ((cyg_uint8) (((word16) >> 8) & 0xFF))
+
+#define BYTE0_32(word32)            ((cyg_uint8) ((word32) & 0xFF))
+#define BYTE1_32(word32)            ((cyg_uint8) (((word32) >>  8) & 0xFF))
+#define BYTE2_32(word32)            ((cyg_uint8) (((word32) >> 16) & 0xFF))
+#define BYTE3_32(word32)            ((cyg_uint8) (((word32) >> 24) & 0xFF))
+
+#define USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH(interfaces, endpoints) \
+            (USB_CONFIGURATION_DESCRIPTOR_LENGTH +            \
+            ((interfaces) * USB_INTERFACE_DESCRIPTOR_LENGTH) +  \
+            ((endpoints)  * USB_ENDPOINT_DESCRIPTOR_LENGTH))
+
+// ----------------------------------------------------------------------------
+// Interface values
+//
+#define USBS_MSD_INTERFACE_PROTO          0x50 // Bulk mode
+
+#define USBS_MSD_CBW_MAX_LUN               2
+#define USBS_MSD_CBW_MIN_SCSI_CMD_LEN      1
+#define USBS_MSD_CBW_MAX_SCSI_CMD_LEN     16
+
+#define USBS_MSD_DISK_SECTOR_SIZE        512
+
+// ----------------------------------------------------------------------------
+// Mass Storage task constant
+//
+#define USBS_MSD_THREAD_STACK_SIZE       2048
+#define USBS_MSD_THREAD_STACK_PRIORITY   15
+
+// command block wrapper
+typedef struct usbs_msd_cbw {
+    cyg_uint32 signature;
+    cyg_uint32 tag;
+    cyg_uint32 data_transfert_len;
+    cyg_uint8 flags;
+    cyg_uint8 lun;
+    struct cb {
+      cyg_uint8 len;
+      cyg_uint8 data[16];
+    } cb;
+} __attribute__((packed)) usbs_msd_cbw;
+
+// command status wrapper
+typedef struct usbs_msd_csw {
+    cyg_uint32 signature;
+    cyg_uint32 tag;
+    cyg_uint32 data_residue;
+    cyg_uint8  status;
+} __attribute__((packed)) usbs_msd_csw;
+
+// command block wrapper state
+typedef enum {
+    CYG_USBS_MSD_WAIT,
+    CYG_USBS_MSD_DATA_IN,
+    CYG_USBS_MSD_DATA_OUT
+} usbs_msd_state_t;
+
+// End-point type
+typedef enum {
+    CYG_USBS_EP0,
+    CYG_USBS_EP_RX,
+    CYG_USBS_EP_TX
+} usbs_msd_ep_t;
+
+// End-point status / control
+typedef struct usbs_msd_ep_sc_t {
+    cyg_sem_t   ready;
+    cyg_int32   result;
+} usbs_msd_ep_sc_t;
+
+// Storage devices
+typedef struct usbs_msd_lun {
+    cyg_io_handle_t handle[USBS_MSD_CBW_MAX_LUN];
+    const char    * name[USBS_MSD_CBW_MAX_LUN];
+    cyg_uint8       max_lun;
+} usbs_msd_lun;
+
+typedef struct usbs_msd usbs_msd;
+
+// Sub Class Handler
+typedef cyg_int32 (*handler_cmd_fn)( usbs_msd * );
+typedef bool (*handler_init_fn)(void **);
+
+// End-point functions
+typedef cyg_int32 (*send_fn)   ( usbs_msd *, const void * , cyg_int32 );
+typedef cyg_int32 (*receive_fn)( usbs_msd *, const void * , cyg_int32 );
+typedef cyg_int32 (*stall_fn)  ( usbs_msd* msd, usbs_msd_ep_t ep );
+
+// Mass-storage device structure
+struct usbs_msd {
+    // Specify end-points to be used
+    usbs_control_endpoint* ctrl_ep;
+    usbs_tx_endpoint*   tx_ep;
+    usbs_rx_endpoint*   rx_ep;
+
+    cyg_uint8           tx_ep_num;
+    cyg_uint8           rx_ep_num;
+
+    cyg_bool            static_ep;
+
+    // Enumeration data for this device
+    usbs_enumeration_data* enum_data;
+
+    // Enumeration string
+    const char*         mfg_str;
+    const char*         product_str;
+    const char*         serial_str;
+    char*               enum_mfg_str;
+    char*               enum_product_str;
+    char*               enum_serial_str;
+
+    // End-point internal status/control
+    usbs_msd_ep_sc_t    rx;
+    usbs_msd_ep_sc_t    tx;
+
+    // Lock for the state
+    cyg_mutex_t         lock;
+
+    // Condition variable for state changes
+    cyg_cond_t          state_cond;
+
+    // State of the USB interface
+    cyg_uint32          usb_state;
+
+    // Data transport-phase buffer
+    cyg_uint8           buffer[USBS_MSD_DISK_SECTOR_SIZE];
+
+    // State of the MSD
+    usbs_msd_state_t    state;
+
+    void (*app_state_change_fn)(struct usbs_control_endpoint*,
+                                               void*, usbs_state_change, int);
+
+    // Pointer to handler data
+    void*               handler_data;
+
+    // Commands Handler
+    handler_cmd_fn      handler_cmd;
+
+    // Initialize Command Handler
+    handler_init_fn     handler_init;
+
+    send_fn             send;
+    receive_fn          receive;
+    stall_fn            stall;
+
+    // Mass-Storage Service
+    char                serv_stack[USBS_MSD_THREAD_STACK_SIZE];
+    cyg_handle_t        serv_handle;
+    cyg_thread          serv_thread;
+    char*               serv_name;
+
+    // Storage Device
+    usbs_msd_lun*       lun;
+
+    // Command Block Wrapper
+    usbs_msd_cbw        cbw;
+
+    // Command Status Wrapper
+    usbs_msd_csw        csw;
+};
+
+// ----------------------------------------------------------------------------
+// A C interface to the MSD USB code.
+// This is the interface for internal code
+
+// Block the calling thread until the host configures the USB device.
+void usbs_msd_wait_until_configured( usbs_msd* );
+
+// Determines if the USB subsystem is configured
+cyg_bool usbs_msd_is_configured( usbs_msd* );
+
+// MSD main thread
+void usbs_msd_handler( cyg_addrword_t );
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CYGONCE_USBS_MSD_H
+
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/include/usbs_msd.inl
@@ -0,0 +1,241 @@
+//==========================================================================
+//
+//      usbs_msd.inl
+//
+//      Support for slave-side USB mass storage devices
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand <ccoutand@stmi.com>
+//              
+// Contributors: jld
+// Date:         2010-06-06
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef CYGONCE_IO_USB_SLAVE_MSD_INL
+#define CYGONCE_IO_USB_SLAVE_MSD_INL
+
+#define MFG_STR_INDEX           '\x01'
+#define PRODUCT_STR_INDEX       '\x02'
+#define SERIAL_STR_INDEX        '\x03'
+
+#define USB_MAX_STR_LEN         256
+
+// Declare Mass Storage Device 0
+#ifdef CYGPKG_IO_USB_SLAVE_MSD0
+
+#ifdef CYGDAT_IO_USB_SLAVE_MSD0_SUB_CLASS_TYPE_SCSI
+#define USBS_MSD0_DATA_IFACE_SUB_CLASS USBS_MSD_SUB_CLASS_SCSI
+#else
+# error "Only SCSI Sub Class is implemented"
+#endif
+
+// ----- USB external definition
+extern usbs_control_endpoint    CYGDAT_IO_USB_SLAVE_MSD0_EP0;
+#if defined(CYGPKG_IO_USB_SLAVE_MSD0_STATIC_EP)
+extern usbs_tx_endpoint         CYGDAT_IO_USB_SLAVE_MSD0_TX_EP;
+extern usbs_rx_endpoint         CYGDAT_IO_USB_SLAVE_MSD0_RX_EP;
+#endif
+
+
+// ----- Configuration Descriptor -----
+
+static const usb_configuration_descriptor usbs_msd0_configuration = {
+    length            : sizeof(usb_configuration_descriptor),
+    type              : USB_CONFIGURATION_DESCRIPTOR_TYPE,
+    total_length_lo   :    
+        USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(USBS_MSD_NUM_IFACE, 
+                                                     USBS_MSD_NUM_ENDP),
+    total_length_hi   :    
+        USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(USBS_MSD_NUM_IFACE, 
+                                                     USBS_MSD_NUM_ENDP),
+    number_interfaces : USBS_MSD_NUM_IFACE,
+    configuration_id  : 1,
+    configuration_str : 0,
+#ifdef CYGOPT_IO_USB_SLAVE_MSD0_BUSPOWERED
+    attributes        : (USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED),
+#else
+    attributes        : (USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED |
+                         USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED),
+#endif
+    max_power         : ((CYGNUM_IO_USB_SLAVE_MSD0_CURRENTDRAW+1) >> 1)
+};
+
+// ----- Interface Descriptor -----
+
+static const usb_interface_descriptor usbs_msd0_interface[] = {
+    {
+        length:             sizeof(usb_interface_descriptor),
+        type:               USB_INTERFACE_DESCRIPTOR_TYPE,
+        interface_id:       0,
+        alternate_setting:  0,
+        number_endpoints:   2,
+        interface_class:    USBS_MSD_DATA_IFACE_CLASS,
+        interface_subclass: USBS_MSD0_DATA_IFACE_SUB_CLASS,
+        interface_protocol: USBS_MSD_INTERFACE_PROTO,
+        interface_str:      0x00
+    }
+};
+
+// ----- Endpoint Descriptors -----
+
+static const usb_endpoint_descriptor usbs_msd0_endpoints[] =
+{ 
+    // Tx (Bulk IN) Endpoint Descriptor
+    {
+        sizeof(usb_endpoint_descriptor),
+        USB_ENDPOINT_DESCRIPTOR_TYPE,
+        USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN  | \
+                CYGNUM_IO_USB_SLAVE_MSD0_TX_EP_NUM,
+        USB_ENDPOINT_DESCRIPTOR_ATTR_BULK,
+        LO_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_TX_EP_MAX_PACKET_SIZE),
+        HI_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_TX_EP_MAX_PACKET_SIZE),
+        0
+    },
+
+    // Rx (Bulk OUT) Endpoint Descriptor
+    {
+        sizeof(usb_endpoint_descriptor),
+        USB_ENDPOINT_DESCRIPTOR_TYPE,
+        USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT | \
+               CYGNUM_IO_USB_SLAVE_MSD0_RX_EP_NUM,
+        USB_ENDPOINT_DESCRIPTOR_ATTR_BULK,
+        LO_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_RX_EP_MAX_PACKET_SIZE),
+        HI_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_RX_EP_MAX_PACKET_SIZE),
+        0
+    }
+};
+
+// ----- String Descriptors -----
+
+static char usbs_msd0_mfg_str_descr[USB_MAX_STR_LEN],
+            usbs_msd0_product_str_descr[USB_MAX_STR_LEN],
+            usbs_msd0_serial_str_descr[USB_MAX_STR_LEN];
+
+static const char* usbs_msd0_strings[] = {
+    "\x04\x03\x09\x04",
+    usbs_msd0_mfg_str_descr,
+    usbs_msd0_product_str_descr,
+    usbs_msd0_serial_str_descr
+};     
+
+// ----- Enumeration Data w/ Device Descriptor -----
+
+static usbs_enumeration_data usbs_msd0_enum_data = {
+    {
+        length:                 sizeof(usb_device_descriptor),
+        type:                   USB_DEVICE_DESCRIPTOR_TYPE,
+        usb_spec_lo:            0x00, 
+        usb_spec_hi:            0x02,
+        device_class:           USBS_MSD_DEVICE_CLASS,
+        device_subclass:        0,
+        device_protocol:        0,
+        max_packet_size:        CYGNUM_IO_USB_SLAVE_MSD0_EP0_MAX_PACKET_SIZE,
+        vendor_lo:              LO_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_VENDOR_ID),
+        vendor_hi:              HI_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_VENDOR_ID),
+        product_lo:             LO_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_PRODUCT_ID),
+        product_hi:             HI_BYTE_16(CYGNUM_IO_USB_SLAVE_MSD0_PRODUCT_ID),
+        device_lo:              0x00,
+        device_hi:              0x00,
+        manufacturer_str:       MFG_STR_INDEX,
+        product_str:            PRODUCT_STR_INDEX,
+        serial_number_str:      SERIAL_STR_INDEX, // must be > 0 for mass-storage
+        number_configurations:  1
+    },
+
+    total_number_interfaces:    USBS_MSD_NUM_IFACE,
+    total_number_endpoints:     USBS_MSD_NUM_ENDP,
+    total_number_strings:       3,
+    configurations:             &usbs_msd0_configuration,
+    interfaces:                 usbs_msd0_interface,
+    endpoints:                  usbs_msd0_endpoints,
+    strings:                    (const unsigned char **) usbs_msd0_strings
+};
+
+// Logical Unit
+usbs_msd_lun msd0_lun = {
+#ifdef CYGDAT_IO_USB_SLAVE_MSD0_LUN0_NAME
+  .name[0] = CYGDAT_IO_USB_SLAVE_MSD0_LUN0_NAME,
+#else
+  .name[0] = NULL,
+#endif  
+#ifdef CYGDAT_IO_USB_SLAVE_MSD0_LUN1_NAME
+  .name[1] = CYGDAT_IO_USB_SLAVE_MSD0_LUN1_NAME
+#else
+  .name[1] = NULL
+#endif 
+};
+
+
+// USBS Mass Storage Device 0
+usbs_msd msd0 = {
+#ifdef CYGDAT_IO_USB_SLAVE_MSD0_SUB_CLASS_TYPE_SCSI
+ .handler_cmd      = usbs_msd_scsi_handle_cmd,
+ .handler_init     = usbs_msd_scsi_init,
+#else
+ .handler_cmd      = NULL,
+ .handler_init     = NULL,
+#endif
+ .ctrl_ep          = &CYGDAT_IO_USB_SLAVE_MSD0_EP0,
+#if defined(CYGPKG_IO_USB_SLAVE_MSD0_STATIC_EP)
+ .tx_ep            = &CYGDAT_IO_USB_SLAVE_MSD0_TX_EP,
+ .rx_ep            = &CYGDAT_IO_USB_SLAVE_MSD0_RX_EP,
+ .static_ep        = true,
+#else
+ .static_ep        = false,
+#endif
+ .tx_ep_num        = CYGNUM_IO_USB_SLAVE_MSD0_TX_EP_NUM,
+ .rx_ep_num        = CYGNUM_IO_USB_SLAVE_MSD0_RX_EP_NUM,
+ .lun              = &msd0_lun,
+ .handler_data     = NULL,
+ .serv_name        = "msd0_service",
+ .enum_data        = &usbs_msd0_enum_data,
+ .enum_mfg_str     = &usbs_msd0_mfg_str_descr[0],
+ .enum_product_str = &usbs_msd0_product_str_descr[0],
+ .enum_serial_str  = &usbs_msd0_serial_str_descr[0],
+ .mfg_str          = CYGDAT_IO_USB_SLAVE_MSD0_MFG_STR,
+ .product_str      = CYGDAT_IO_USB_SLAVE_MSD0_PRODUCT_STR,
+ .serial_str       = CYGDAT_IO_USB_SLAVE_MSD0_SERIAL_STR
+};
+
+#endif // CYGPKG_IO_USB_SLAVE_MSD0
+
+#endif // CYGONCE_IO_USB_SLAVE_MSD_INL
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/include/usbs_msd_io.h
@@ -0,0 +1,66 @@
+#ifndef CYGONCE_USBS_MSD_IO_H
+#define CYGONCE_USBS_MSD_IO_H
+//==========================================================================
+//
+//      include/usbs_msd_io.h
+//
+//      Application API for the USB slave-side MSD device
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand <ccoutand@stmi.com>
+// Contributors:
+// Date:         2010-06-04
+// Purpose:
+// Description:  USB slave-side MSD support
+//
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Starts the USB subsystem
+bool usbs_msd_start(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CYGONCE_USBS_MSD_IO_H
+
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/include/usbs_msd_opcode.h
@@ -0,0 +1,114 @@
+#ifndef CYGONCE_USBS_MSD_OPCODE_H
+#define CYGONCE_USBS_MSD_OPCODE_H
+//==========================================================================
+//
+//      include/usbs_msd_opcode.h
+//
+//      SCSI support for the USB slave-side MSD device
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand <ccoutand@stmi.com>
+// Contributors:
+// Date:         2010-06-02
+// Purpose:
+// Description:  USB slave-side MSD support
+//
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// SCSI commands from SBC-2 or SBC-3
+#define USBS_SCSI_FORMAT_UNIT            0x04
+#define USBS_SCSI_INQUIRY                0x12
+#define USBS_SCSI_MODE_SELECT_6          0x15
+#define USBS_SCSI_MODE_SELECT_10         0x55
+#define USBS_SCSI_SENSE_6                0x1A
+#define USBS_SCSI_SENSE_10               0x5A
+#define USBS_SCSI_READ_6                 0x08
+#define USBS_SCSI_READ_10                0x28
+#define USBS_SCSI_READ_12                0xA8
+#define USBS_SCSI_READ_CAPACITY          0x25
+#define USBS_SCSI_READ_FORMAT_CAPACITIES 0x23
+#define USBS_SCSI_READ_TOC               0x43
+#define USBS_SCSI_REPORT_LUNS            0xA0
+#define USBS_SCSI_REQUEST_SENSE          0x03
+#define USBS_SCSI_SEND_DIAGNOSTIC        0x1D
+#define USBS_SCSI_START_STOP_UNIT        0x1B
+#define USBS_SCSI_SYNC_CACHE_10          0x35
+#define USBS_SCSI_TEST_UNIT_READY        0x00
+#define USBS_SCSI_VERIFY_10              0x2F
+#define USBS_SCSI_WRITE_6                0x0A
+#define USBS_SCSI_WRITE_10               0x2A
+#define USBS_SCSI_WRITE_12               0xAA
+#define USBS_SCSI_PREVENT_ALLOW_REMOVAL  0x1E
+
+// Sense result
+#define USBS_MSD_SCSI_SENSE_NOT_READY                            0x2
+#define USBS_MSD_SCSI_SENSE_MEDIUM_ERROR                         0x3
+#define USBS_MSD_SCSI_SENSE_ILLEGAL_REQUEST                      0x5
+#define USBS_MSD_SCSI_SENSE_UNIT_ATTENTION                       0x6
+#define USBS_MSD_SCSI_SENSE_ASC_LOGICAL_BLOCK_ADDR_OUT_OF_RANGE  0x21
+#define USBS_MSD_SCSI_SENSE_ASCQ_LOGICAL_BLOCK_ADDR_OUT_OF_RANGE 0x0
+#define USBS_MSD_SCSI_SENSE_ASC_INVALID_OPCODE                   0x20
+#define USBS_MSD_SCSI_SENSE_ASCQ_INVALID_OPCODE                  0x0
+#define USBS_MSD_SCSI_SENSE_ASC_MEDIUM_NOT_PRESENT               0x3a
+#define USBS_MSD_SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT              0x00
+#define USBS_MSD_SCSI_SENSE_ASC_PERIPHERAL_DEVICE_WRITE_FAULT    0x03
+#define USBS_MSD_SCSI_SENSE_ASCQ_PERIPHERAL_DEVICE_WRITE_FAULT   0x00
+#define USBS_MSD_SCSI_SENSE_ASC_UNRECOVERED_READ_ERROR           0x11
+#define USBS_MSD_SCSI_SENSE_ASCQ_UNRECOVERED_READ_ERROR          0x00
+#define USBS_MSD_SCSI_SENSE_ASC_WRITE_ERROR                      0x0C
+#define USBS_MSD_SCSI_SENSE_ASCQ_WRITE_ERROR                     0x00
+#define USBS_MSD_SCSI_SENSE_ASC_WRITE_PROTECTED                  0x27
+#define USBS_MSD_SCSI_SENSE_ASCQ_WRITE_PROTECTED                 0x00
+#define USBS_MSD_SCSI_SENSE_ASC_INVALID_FIELD_IN_CBD             0x24
+
+// Mode Page
+#define USBS_MSD_SCSI_MODE_PAGE_CODE_ALL     0x3F
+#define USBS_MSD_SCSI_MODE_PAGE_CODE_IEC     0x1C
+#define USBS_MSD_SCSI_MODE_PAGE_CODE_CACHING 0x08
+#define USBS_MSD_SCSI_MODE_PAGE_CODE_FDM     0x05
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CYGONCE_USBS_MSD_OPCODE_H
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/include/usbs_msd_scsi.h
@@ -0,0 +1,143 @@
+#ifndef CYGONCE_USBS_MSD_SCSI_H
+#define CYGONCE_USBS_MSD_SCSI_H
+//==========================================================================
+//
+//      include/usbs_msd_scsi.h
+//
+//      SCSI support for the USB slave-side MSD device
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand
+// Contributors:
+// Date:         2010-06-02
+// Purpose:
+// Description:  USB slave-side MSD support
+//
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The standard INQUIRY data shall contain at least 36 bytes
+// This is the reduced structure for Mass Storage Devices
+typedef struct
+{
+   cyg_uint8 peripheral;         // Device Type
+   cyg_uint8 rmb;                // Removable Media Bit
+   cyg_uint8 version;            // Version Field
+   cyg_uint8 resp_data_format;   // Response Data Format
+   cyg_uint8 additional_len;     // Additional Length
+   cyg_uint8 sccstp;             // SCC Supported (include embedded storage array)
+   cyg_uint8 bque;               // Basic Queuing
+   cyg_uint8 cmdque;             // Command Queuing
+   cyg_uint8 vendor_id[8];
+   cyg_uint8 product_id[16];
+   cyg_uint8 product_rev[4];
+} msd_scsi_inq_resp;
+
+#define USBS_SCSI_DIRECT_ACCESS_BLOCK_DEVICE 0x00
+#define USBS_SCSI_REMOVABLE_DEVICE           0x80
+
+// Fixed-format Sense Data ( defined as a 18 bytes array )
+typedef struct
+{
+   cyg_uint8 byte[18];
+} msd_scsi_req_sense_resp;
+
+// Set Valid information field
+#define USBS_MSD_SCSI_SET_SENSE_VALID( ptr_sense, _valid_ ) \
+{ \
+  if( _valid_ ) \
+    ptr_sense[0] |= 0x80; \
+  else \
+    ptr_sense[0] &= ~0x80; \
+};
+
+// Set Response Code field
+#define USBS_MSD_SCSI_SET_SENSE_RESP_CODE( ptr_sense, _code_ ) \
+{ \
+    cyg_uint8 byte = ptr_sense[0] & 0x80; \
+    ptr_sense[0] = ((_code_ & 0x7F) | byte); \
+};
+
+// Set Sense Key field
+#define USBS_MSD_SCSI_SET_SENSE_KEY( ptr_sense, _key_ ) \
+{ \
+    cyg_uint8 byte = ptr_sense[0] & 0xF0; \
+    ptr_sense[0] = ((_key_ & 0x0F) | byte); \
+};
+
+// Set Additional Sense Length field
+#define USBS_MSD_SCSI_SET_SENSE_ASL( ptr_sense, _asl_ ) \
+{ \
+    ptr_sense[7] = _asl_; \
+};
+
+// Set Additional Sense Code field
+#define USBS_MSD_SCSI_SET_SENSE_ASC( ptr_sense, _asc_ ) \
+{ \
+    ptr_sense[12] = _asc_; \
+};
+
+// Set Additional Sense Code Qualifier field
+#define USBS_MSD_SCSI_SET_SENSE_ASCQ( ptr_sense, _ascq_ ) \
+{ \
+    ptr_sense[13] = _ascq_; \
+};
+
+// Init Sense Data structure
+#define USBS_MSD_SCSI_INIT_SENSE_DATA( _array_ ) \
+{ \
+   cyg_int32 i; \
+   for(i = 0; i < sizeof(msd_scsi_req_sense_resp); i++) \
+   _array_[i] = 0; \
+   USBS_MSD_SCSI_SET_SENSE_VALID( _array_, 1); \
+   USBS_MSD_SCSI_SET_SENSE_RESP_CODE( _array_, 0x70 ); \
+   USBS_MSD_SCSI_SET_SENSE_ASC( _array_, 0x0a ); \
+};
+
+cyg_int32 usbs_msd_scsi_handle_cmd( usbs_msd * );
+bool usbs_msd_scsi_init( void ** ctxt );
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CYGONCE_USBS_MSD_SCSI_H
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/src/usbs_msd.c
@@ -0,0 +1,471 @@
+//==========================================================================
+//
+//      usbs_msd.c
+//
+//      Support for slave-side USB mass storage devices.
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand
+//
+// Contributors: jld
+// Date:         2010-05-27
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+#include <pkgconf/system.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h>
+#include <cyg/io/devtab.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/kernel/kapi.h>
+
+#include <pkgconf/io_usb_slave_msd.h>
+#include <cyg/io/usb/usbs_msd.h>
+
+#ifdef CYGDAT_IO_USB_SLAVE_MSD0_SUB_CLASS_TYPE_SCSI
+#include <cyg/io/usb/usbs_msd_scsi.h>
+#endif
+
+#include <string.h>
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_DEBUG)
+#define DBG diag_printf
+#else
+#define DBG (1) ? (void)0 : diag_printf
+#endif
+
+#include CYGDAT_IO_USB_SLAVE_MSD_INL // Declaration of the Mass Storage devices
+
+// --------------------------------------------------------------------------
+// Create a USB String Descriptor from a C string.
+//
+void
+usbs_msd_create_str_descriptor(char descr[], const char *str)
+{
+    cyg_uint32 i, n = strlen(str);
+
+    if (n > (USB_MAX_STR_LEN/2 - 2))
+        n = USB_MAX_STR_LEN/2 - 2;
+
+    descr[0] = (cyg_uint8) (2*n + 2);
+    descr[1] = USB_DEVREQ_DESCRIPTOR_TYPE_STRING;
+
+    for (i=0; i<n; i++) {
+        descr[i*2+2] = str[i];
+        descr[i*2+3] = '\x00';
+    }
+}
+
+// --------------------------------------------------------------------------
+// Mass Storage Device Class Handler
+//
+static usbs_control_return
+usbs_msd_class_handler(usbs_control_endpoint* ep0, void* callback_data)
+{
+  usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN;
+  usb_devreq *req = (usb_devreq *) ep0->control_buffer;
+  usbs_msd   *msd = (usbs_msd *) callback_data;
+  static cyg_uint8 rsp_buf[32];
+
+  DBG("USB MSD Class Handler: ");
+
+  switch (req->request) {
+
+    case USBS_MSD_CLASS_REQ_GET_MAX_LUN :
+      DBG("USB MSD Request: Get MAX LUN %d\n", \
+                                 msd->lun->max_lun);
+      rsp_buf[0]  = msd->lun->max_lun - 1;
+      ep0->buffer = rsp_buf;
+      ep0->buffer_size = 1;
+      result = USBS_CONTROL_RETURN_HANDLED;
+      break;
+
+    case USBS_MSD_CLASS_REQ_BOMSR :
+      DBG("USB MSD Request: Reset\n");
+      // FIXME : Handle Reset
+      ep0->buffer_size = 0;
+      result = USBS_CONTROL_RETURN_HANDLED;
+      break;
+
+    default :
+      DBG("*** USB MSD Request: 0x%02X not implemented !***\n",
+          (unsigned) req->request);
+  }
+
+  return result;
+}
+
+
+// --------------------------------------------------------------------------
+// Callback for a USB state change
+//
+void
+usbs_msd_state_change_handler(usbs_control_endpoint* ep, void* callback_data,
+                                 usbs_state_change change, int prev_state)
+{
+  usbs_msd *msd = (usbs_msd *) callback_data;
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_DEBUG)
+  const char *STATE_CHG_STR[] = { "Detached", "Attached", "Powered", "Reset",
+                                  "Addressed", "Configured", "Deconfigured",
+                                  "Suspended", "Resumed" };
+
+  if (change > 0 && change < 10) {
+    DBG("### %d:%s ###\n", change, STATE_CHG_STR[(int) change-1]);
+  }
+  else {
+    DBG("### %d ###\n", change);
+  }
+#endif
+
+  // Called from DSR, cond broadcast should be ok without mutex lock
+  msd->usb_state = msd->ctrl_ep->state;
+
+  cyg_cond_broadcast( &msd->state_cond );
+
+  if (msd->app_state_change_fn)
+    (*msd->app_state_change_fn)(ep, callback_data, change, prev_state);
+
+}
+
+
+// --------------------------------------------------------------------------
+// Block the calling thread until the USB is configured.
+ //
+void
+usbs_msd_wait_until_configured( usbs_msd* msd )
+{
+  cyg_mutex_lock( &msd->lock );
+  while ( msd->usb_state != USBS_STATE_CONFIGURED )
+    cyg_cond_wait( &msd->state_cond );
+
+  // Dynamic end-points configuration
+  if ( msd->static_ep == false )
+  {
+    msd->tx_ep = usbs_get_tx_endpoint( msd->ctrl_ep, msd->tx_ep_num );
+    msd->rx_ep = usbs_get_rx_endpoint( msd->ctrl_ep, msd->rx_ep_num );
+    DBG("tx_ep = %p\n", msd->tx_ep);
+    DBG("rx_ep = %p\n", msd->rx_ep);
+  }
+
+  cyg_mutex_unlock( &msd->lock );
+}
+
+
+// --------------------------------------------------------------------------
+// Determine if the device is currently configured.
+//
+cyg_bool
+usbs_msd_is_configured( usbs_msd* msd )
+{
+  return msd->usb_state == USBS_STATE_CONFIGURED;
+}
+
+
+// --------------------------------------------------------------------------
+// Callback for when a transmit / stall is complete
+//
+static void
+usbs_msd_tx_complete( void *p, cyg_int32 result )
+{
+  usbs_msd* msd  = (usbs_msd*) p;
+  msd->tx.result = result;
+  cyg_semaphore_post( &msd->tx.ready );
+}
+
+
+// --------------------------------------------------------------------------
+// Callback for when a receive / stall is complete
+//
+static void
+usbs_msd_rx_complete( void *p, cyg_int32 result )
+{
+  usbs_msd* msd  = (usbs_msd*) p;
+  msd->rx.result = result;
+  cyg_semaphore_post( &msd->rx.ready );
+}
+
+
+// --------------------------------------------------------------------------
+// Start an asynchronous transmit of a buffer.
+//
+static void
+usbs_msd_start_tx(usbs_msd* msd, const void* buf, cyg_int32 n)
+{
+  usbs_start_tx_buffer( msd->tx_ep, (unsigned char*) buf, n,
+                       usbs_msd_tx_complete, msd );
+}
+
+
+// --------------------------------------------------------------------------
+// Block the caller until the transmit / stall is complete
+//
+static int
+usbs_msd_wait_for_tx(usbs_msd* msd)
+{
+  cyg_semaphore_wait( &msd->tx.ready );
+  return msd->tx.result;
+}
+
+
+// --------------------------------------------------------------------------
+// Perform a synchronous transmit and wait for it to complete.
+//
+static cyg_int32
+usbs_msd_tx(usbs_msd* msd, const void* buf, cyg_int32 n)
+{
+  usbs_msd_start_tx( msd, buf, n );
+  return usbs_msd_wait_for_tx( msd );
+}
+
+
+// --------------------------------------------------------------------------
+// Start an asynchronous receive of a buffer.
+//
+static void
+usbs_msd_start_rx(usbs_msd* msd, void* buf, cyg_int32 n)
+{
+  usbs_start_rx_buffer( msd->rx_ep, (unsigned char*) buf, n,
+                       usbs_msd_rx_complete, msd );
+}
+
+
+// --------------------------------------------------------------------------
+// Block the caller until the receive / stall is complete
+//
+static cyg_int32
+usbs_msd_wait_for_rx(usbs_msd* msd)
+{
+  cyg_semaphore_wait( &msd->rx.ready );
+  return msd->rx.result;
+}
+
+
+// --------------------------------------------------------------------------
+// Perform a synchronous receive and wait for it to complete
+//
+static cyg_int32
+usbs_msd_rx(usbs_msd* msd, void* buf, cyg_int32 n)
+{
+  usbs_msd_start_rx( msd, buf, n );
+  return usbs_msd_wait_for_rx( msd );
+}
+
+
+// --------------------------------------------------------------------------
+// Halt end-point
+//
+static void
+usbs_msd_set_ep_halted( usbs_msd* msd , usbs_msd_ep_t ep, cyg_bool state )
+{
+  if( ep == CYG_USBS_EP_RX )
+    usbs_set_rx_endpoint_halted( msd->rx_ep , state );
+  else if( ep == CYG_USBS_EP_TX )
+    usbs_set_tx_endpoint_halted( msd->tx_ep , state );
+}
+
+
+// --------------------------------------------------------------------------
+// Perform a synchronous end-point halt and wait for host to restart it
+//
+static cyg_int32
+usbs_msd_ep_stall(usbs_msd* msd, usbs_msd_ep_t ep )
+{
+  cyg_sem_t *ready;
+  cyg_int32 *result;
+
+#if !defined(CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE)
+   return 1;
+#endif
+
+  if( ep == CYG_USBS_EP_RX )
+  {
+    ready    = &msd->rx.ready;
+    result   = &msd->rx.result;
+  }
+  else if( ep == CYG_USBS_EP_TX )
+  {
+    ready    = &msd->tx.ready;
+    result   = &msd->tx.result;
+  }
+  else
+    return 0;
+
+  // Halt End-point
+  usbs_msd_set_ep_halted( msd, ep , 1 );
+
+  // Wait
+  if( ep == CYG_USBS_EP_RX )
+    usbs_start_rx_endpoint_wait( msd->rx_ep, usbs_msd_rx_complete, msd );
+  else if( ep == CYG_USBS_EP_TX )
+    usbs_start_tx_endpoint_wait( msd->tx_ep, usbs_msd_tx_complete, msd );
+
+  cyg_semaphore_wait( ready );
+
+  return ( *result );
+
+}
+
+
+// --------------------------------------------------------------------------
+// Initialize a Mass Storage Device structure
+//
+static bool
+usbs_msd_init( usbs_msd* msd )
+{
+  cyg_io_handle_t handle;
+  cyg_uint8 i = 0;
+
+  if( msd->ctrl_ep == NULL )
+    return false;
+
+  // Lookup storage devices
+  msd->lun->max_lun = 0;
+  for (i = 0; i < USBS_MSD_CBW_MAX_LUN; i++)
+  {
+    if ( msd->lun->name[i] != NULL )
+    {
+      DBG("USB Slave MSD: Lookup %s \n", msd->lun->name[i] );
+      if( cyg_io_lookup( msd->lun->name[i] , &handle ) != ENOERR )
+        return false;
+      msd->lun->handle[i] = handle;
+      msd->lun->max_lun++;
+    }
+  }
+
+  msd->tx.result =  0;
+  msd->rx.result =  0;
+
+  // Initialize TX and RX semaphore
+  cyg_semaphore_init( &msd->tx.ready, 0 );
+  cyg_semaphore_init( &msd->rx.ready, 0 );
+
+  cyg_mutex_init( &msd->lock );
+
+  cyg_cond_init( &msd->state_cond, &msd->lock );
+
+  // Make USB string descriptors
+  usbs_msd_create_str_descriptor( \
+                     msd->enum_mfg_str,\
+                     msd->mfg_str );
+  usbs_msd_create_str_descriptor( \
+                     msd->enum_product_str,\
+                     msd->product_str );
+  usbs_msd_create_str_descriptor( \
+                     msd->enum_serial_str,\
+                     msd->serial_str );
+
+  // Set up enumeration & USB call-backs
+  msd->usb_state = msd->ctrl_ep->state;
+
+  msd->ctrl_ep->enumeration_data = msd->enum_data;
+
+  if ( msd->ctrl_ep->state_change_fn )
+    msd->app_state_change_fn = msd->ctrl_ep->state_change_fn;
+
+  msd->ctrl_ep->state_change_fn    = usbs_msd_state_change_handler;
+  msd->ctrl_ep->state_change_data  = (void*) msd;
+  msd->ctrl_ep->class_control_fn   = usbs_msd_class_handler;
+  msd->ctrl_ep->class_control_data = (void*) msd;
+
+  if ( msd->handler_init )
+     msd->handler_init( &msd->handler_data );
+
+  msd->send    = usbs_msd_tx;
+  msd->receive = usbs_msd_rx;
+  msd->stall   = usbs_msd_ep_stall;
+
+  // Setup initial state
+  msd->state = CYG_USBS_MSD_WAIT;
+
+  return true;
+}
+
+
+// --------------------------------------------------------------------------
+// Initialize a Mass Storage Device structure
+//
+static void
+usbs_msd_start_service(usbs_msd* msd)
+{
+
+  cyg_thread_create( USBS_MSD_THREAD_STACK_PRIORITY , &usbs_msd_handler, \
+                     (cyg_addrword_t) msd, msd->serv_name, msd->serv_stack,  \
+                     USBS_MSD_THREAD_STACK_SIZE, &msd->serv_handle, \
+                     &msd->serv_thread);
+
+  cyg_thread_resume( msd->serv_handle );
+
+}
+
+
+// --------------------------------------------------------------------------
+// Start the USB subsystem
+//
+bool
+usbs_msd_start(void)
+{
+
+#ifdef CYGPKG_IO_USB_SLAVE_MSD0
+
+  DBG("USB Slave Mass-Storage 0 starts\n");
+
+  if ( usbs_msd_init( &msd0 ) == false )
+  {
+    DBG("USB Slave Mass-Storage 0 startup failed\n");
+    return false;
+  }
+
+  // ----- Start USB subsystem -----
+  //
+  usbs_start( msd0.ctrl_ep );
+
+  usbs_msd_start_service( &msd0 );
+
+#endif
+
+  return true;
+}
+
+
+
+
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/src/usbs_msd_handler.c
@@ -0,0 +1,266 @@
+//==========================================================================
+//
+//      usbs_msd_handler.c
+//
+//      Support for slave-side USB mass storage devices.
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand
+//
+// Date:         2010-06-02
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_endian.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/kernel/kapi.h>
+
+#include <pkgconf/io_usb_slave_msd.h>
+#include <cyg/io/usb/usbs_msd.h>
+
+#include <stdio.h> // for memcpy
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_DEBUG)
+#define DBG diag_printf
+#else
+#define DBG (1) ? (void)0 : diag_printf
+#endif
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_TRACE)
+#define TRACE diag_printf
+#else
+#define TRACE (1) ? (void)0 : diag_printf
+#endif
+
+#define CONSTRUCT_CSW( _csw_, _tag_ ) \
+{ \
+   _csw_.tag = _tag_; \
+   _csw_.signature = USBS_MSD_CSW_SIGNATURE; \
+};
+
+
+// Validate a command block wrapper
+// CBW is sent from host in little endian format, hence it
+// must be converted to the CPU endianness
+//
+static inline bool
+usbs_msd_validate_cbw(usbs_msd_cbw *cbw, cyg_int32 len)
+{
+
+  // Convert to CPU endianness
+  cbw->signature = CYG_LE32_TO_CPU( cbw->signature );
+  cbw->tag       = CYG_LE32_TO_CPU( cbw->tag );
+  cbw->data_transfert_len = CYG_LE32_TO_CPU( cbw->data_transfert_len );
+
+  if( len != sizeof( usbs_msd_cbw ) ||
+     cbw->signature != USBS_MSD_CBW_SIGNATURE )
+  {
+    DBG("USB Slave MSD: CBW signature %x, len %d\n\r", \
+      cbw->signature, len);
+    return false;
+  }
+  else
+    return true;
+}
+
+
+// Validate a command block wrapper content
+//
+static inline bool
+usbs_msd_validate_cbw_data(usbs_msd_cbw *cbw)
+{
+  if( ( cbw->lun < USBS_MSD_CBW_MAX_LUN ) && \
+      ( cbw->cb.len <= USBS_MSD_CBW_MAX_SCSI_CMD_LEN ) && \
+      ( cbw->cb.len >= USBS_MSD_CBW_MIN_SCSI_CMD_LEN ) && \
+      ( ( cbw->flags == USBS_MSD_CBW_HOST2DEVICE ) || \
+        ( cbw->flags == USBS_MSD_CBW_DEVICE2HOST ) ) )
+  {
+    return true;
+  }
+  else
+  {
+    DBG("USB Slave MSD: CBW Invalid data, LUN %d, len %d, flag %x\n\r", \
+        cbw->lun, cbw->cb.len, cbw->flags);
+  }
+  return false;
+}
+
+
+// Send Command Status Wrapper
+//
+static inline cyg_int32
+usbs_msd_send_csw( usbs_msd* msd )
+{
+  // Convert to host endianness
+  msd->csw.signature = CYG_CPU_TO_LE32( msd->csw.signature );
+  msd->csw.tag       = CYG_CPU_TO_LE32( msd->csw.tag );
+  msd->csw.data_residue = CYG_CPU_TO_LE32( msd->csw.data_residue );
+
+  return msd->send( msd, &msd->csw, sizeof( usbs_msd_csw ));
+}
+
+
+// Receive Command Status Wrapper
+//
+static cyg_int32
+usbs_msd_wait_for_cbw( usbs_msd *msd )
+{
+  cyg_uint8 cbw[sizeof( usbs_msd_cbw ) + 1];
+  cyg_int32 n;
+
+  TRACE("USB Slave MSD: Wait for CBW\n\r");
+  n = msd->receive( msd, cbw, sizeof( cbw ) );
+
+  TRACE("USB Slave MSD: CBW received, len %d\n\r", n);
+
+  if ( n < 0)
+    return n;
+
+  memcpy(&msd->cbw, cbw, sizeof( usbs_msd_cbw ));
+
+  if ( ( true == usbs_msd_validate_cbw( &msd->cbw, n ) ) && \
+          ( true == usbs_msd_validate_cbw_data( &msd->cbw ) ) )
+  {
+    CONSTRUCT_CSW( msd->csw , msd->cbw.tag );
+
+    if( msd->cbw.flags == USBS_MSD_CBW_DEVICE2HOST )
+    {
+      msd->state = CYG_USBS_MSD_DATA_OUT;
+    }
+    else if ( msd->cbw.flags == USBS_MSD_CBW_HOST2DEVICE )
+    {
+      msd->state = CYG_USBS_MSD_DATA_IN;
+    }
+  }
+
+  return n;
+}
+
+// USB slave side Mass-Storage Handler
+//
+void
+usbs_msd_handler( cyg_addrword_t data )
+{
+  usbs_msd* msd = (usbs_msd*) data;
+  cyg_int32 transfered = 0;
+  cyg_int32 received   = 0;
+
+  while(1)
+  {
+
+    // Wait for device to be configured
+    DBG("USB Slave MSD: Wait for device configuration\n\r");
+    usbs_msd_wait_until_configured( msd );
+    cyg_thread_delay( (cyg_tick_count_t) 10 );
+
+    while(1)
+    {
+
+      switch( msd->state )
+      {
+         case CYG_USBS_MSD_WAIT:
+            // FIXME, check for return values
+            // For the time being, -EPIPE and -EAGAIN triggers the
+            // driver to wait for the device to be configured again.
+            received = usbs_msd_wait_for_cbw( msd );
+            if ( received < 0 )
+              break;
+            // Fall through
+
+         case CYG_USBS_MSD_DATA_IN:
+         case CYG_USBS_MSD_DATA_OUT:
+            // Handle data transfer IN and OUT
+            transfered = msd->handler_cmd( msd );
+
+            // Data transfer failed because of -EPIPE or -EAGAIN. For
+            // the time being just wait for the device to be re-configured
+            if(transfered < 0)
+            {
+              DBG("USB Slave MSD: Data transfer error\n\r");
+              msd->state = CYG_USBS_MSD_WAIT;
+              break;
+            }
+
+            // Compute the data residue value to be recorded in the
+            // Command Status Wrapper
+            msd->csw.data_residue = msd->cbw.data_transfert_len - transfered;
+
+            // Check if all data has been transfered / received to / from
+            // the host
+            if( msd->csw.data_residue != 0 )
+            {
+              DBG("USB Slave MSD: Transfer not complete %d / %d\n\r", \
+                        msd->cbw.data_transfert_len, transfered);
+
+              // Stall endpoint, this is a waiting call until the host has
+              // cleared the stall. AT91 USB driver does not seem to handle
+              // it!
+              msd->stall( msd, CYG_USBS_EP_TX );
+#if defined(CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE)
+              TRACE("USB Slave MSD: Stall completed\n\r");
+#endif
+            }
+
+            // Complete the transaction by sending the command status
+            usbs_msd_send_csw( msd );
+
+            TRACE("USB Slave MSD: CSW sent\n\r");
+
+            // Wait for next command
+            msd->state = CYG_USBS_MSD_WAIT;
+            break;
+
+         default:
+            DBG("USB Slave MSD: Invalid state\n\r");
+            break;
+      }
+
+      if( ( transfered < 0 ) || ( received < 0 ) )
+        break;
+
+    }
+  }
+}
+
+
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/src/usbs_msd_scsi.c
@@ -0,0 +1,510 @@
+//==========================================================================
+//
+//      usbs_msd_scsi.c
+//
+//      Support for slave-side USB mass storage SCSI devices.
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand <ccoutand@stmi.com>
+//
+// Date:         2010-06-02
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/kernel/kapi.h>
+#include <cyg/infra/diag.h>
+
+#include <pkgconf/io_usb_slave_msd.h>
+#include <cyg/io/usb/usbs_msd.h>
+
+#include <cyg/io/usb/usbs_msd_opcode.h>
+#include <cyg/io/usb/usbs_msd_scsi.h>
+
+#include <cyg/io/disk.h>
+
+#include <stdio.h> // for memcpy
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_DEBUG)
+#define DBG diag_printf
+#else
+#define DBG (1) ? (void)0 : diag_printf
+#endif
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_TRACE)
+#define TRACE diag_printf
+#else
+#define TRACE (1) ? (void)0 : diag_printf
+#endif
+
+
+const msd_scsi_inq_resp inq_resp = {
+   USBS_SCSI_DIRECT_ACCESS_BLOCK_DEVICE, // Direct Access Block device
+   USBS_SCSI_REMOVABLE_DEVICE,           // Device is removable
+   0x04,                                 // Comply with SPC-2
+   0x02,                                 // Standard format
+   0x20,                                 // Response is 0x20 + 4 bytes
+   0x00,
+   0x00,
+   0x00,
+   {'e','C','o','s',' ',' ',' ',' '},
+   {'M','a','s','s',' ','S','t','o','r','a','g','e',' ',' ',' ',' '},
+   {'0','.','0','1'},
+};
+
+
+// Handle Mode Sense Command
+//
+static inline void
+usbs_msd_scsi_update_sense(msd_scsi_req_sense_resp *sense, \
+                                cyg_uint8 asc, cyg_uint8 ascq, cyg_uint8 key )
+{
+   USBS_MSD_SCSI_SET_SENSE_ASC( sense->byte , asc );
+   USBS_MSD_SCSI_SET_SENSE_ASCQ( sense->byte , ascq );
+   USBS_MSD_SCSI_SET_SENSE_KEY( sense->byte , key );
+}
+
+
+// Handle Inquiry Request Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_inquiry( usbs_msd * msd )
+{
+   cyg_int32 tx_bytes = sizeof(msd_scsi_inq_resp);
+
+   TRACE("USB Slave MSD: SCSI inquiry\n\r");
+
+   // Copy over to message buffer
+   memcpy( msd->buffer, (cyg_uint8 *) &inq_resp, tx_bytes );
+
+   tx_bytes = msd->send( msd, msd->buffer, tx_bytes );
+
+   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+
+   return tx_bytes;
+}
+
+
+// Handle Read Capacity Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_capacity( usbs_msd * msd )
+{
+   cyg_disk_info_t disk_info;
+   cyg_int32 tx_bytes = sizeof(cyg_uint32) << 1;
+   cyg_uint32 len     = sizeof(cyg_disk_info_t);
+   cyg_uint32 key     = CYG_IO_GET_CONFIG_DISK_INFO;
+   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
+
+   TRACE("USB Slave MSD: SCSI capacity\n\r");
+
+   // Get the configuration of a device
+   cyg_io_get_config( lun, key, &disk_info, &len );
+
+   msd->buffer[0] = BYTE3_32( disk_info.blocks_num );
+   msd->buffer[1] = BYTE2_32( disk_info.blocks_num );
+   msd->buffer[2] = BYTE1_32( disk_info.blocks_num );
+   msd->buffer[3] = BYTE0_32( disk_info.blocks_num );
+
+   msd->buffer[4] = BYTE3_32( disk_info.block_size );
+   msd->buffer[5] = BYTE2_32( disk_info.block_size );
+   msd->buffer[6] = BYTE1_32( disk_info.block_size );
+   msd->buffer[7] = BYTE0_32( disk_info.block_size );
+
+   tx_bytes = msd->send( msd, msd->buffer, tx_bytes );
+
+   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+
+   return tx_bytes;
+}
+
+
+// Handle Read Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_read( usbs_msd * msd, msd_scsi_req_sense_resp *sense )
+{
+   Cyg_ErrNo ret;
+   cyg_uint32 transfert_len = 0, pos = 0, len = 1;
+   cyg_int32 ret_len = 0;
+   cyg_int32 tx_byte = 0;
+   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
+
+   TRACE("USB Slave MSD: SCSI read\n\r");
+
+   pos = ( msd->cbw.cb.data[2] << 24 ) | \
+         ( msd->cbw.cb.data[3] << 16 ) | \
+         ( msd->cbw.cb.data[4] <<  8 ) | \
+           msd->cbw.cb.data[5];
+
+   transfert_len = ( msd->cbw.cb.data[7] << 8 ) | msd->cbw.cb.data[8];
+
+   // Read data from a block device
+   while ( transfert_len > 0 ) {
+     if( ( ret = cyg_io_bread( lun, msd->buffer, &len, pos)) != ENOERR )
+       break;
+     tx_byte = msd->send( msd, msd->buffer, (USBS_MSD_DISK_SECTOR_SIZE) );
+     TRACE("USB Slave MSD: Read %d block, %d bytes\n\r", transfert_len, tx_byte);
+     ret_len += tx_byte;
+     // Substract 1 sector
+     transfert_len -= 1;
+     pos += 1;
+   }
+
+   if ( ret == ENOERR )
+   {
+      msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+   }
+   else
+   {
+     msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
+     usbs_msd_scsi_update_sense( sense, \
+             USBS_MSD_SCSI_SENSE_ASC_UNRECOVERED_READ_ERROR, \
+             USBS_MSD_SCSI_SENSE_ASCQ_UNRECOVERED_READ_ERROR, \
+             USBS_MSD_SCSI_SENSE_MEDIUM_ERROR );
+   }
+
+   return ret_len;
+}
+
+
+// Handle Write Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_write( usbs_msd * msd , msd_scsi_req_sense_resp *sense )
+{
+   Cyg_ErrNo ret;
+   cyg_uint32 transfert_len = 0, pos = 0, len = 1;
+   cyg_int32 ret_len = 0;
+   cyg_int32 rx_byte = 0;
+   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
+
+   DBG("USB Slave MSD: SCSI Write\n\r");
+
+   pos = ( msd->cbw.cb.data[2] << 24 ) | \
+             ( msd->cbw.cb.data[3] << 16 ) | \
+             ( msd->cbw.cb.data[4] <<  8 ) | \
+               msd->cbw.cb.data[5];
+
+   transfert_len = ( msd->cbw.cb.data[7] << 8 ) | msd->cbw.cb.data[8];
+
+   // Read data from a block device
+   while ( transfert_len > 0 ) {
+     rx_byte = msd->receive( msd, msd->buffer, (USBS_MSD_DISK_SECTOR_SIZE) );
+     if( ( ret = cyg_io_bwrite( lun, msd->buffer, &len, pos)) != ENOERR )
+       break;
+     TRACE("USB Slave MSD: Write %d block, %d bytes\n\r", transfert_len, rx_byte);
+     ret_len += ( rx_byte );
+     // Substract 1 sector
+     transfert_len -= 1;
+     pos += 1;
+   }
+
+   if ( ret == ENOERR )
+   {
+     msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+   }
+   else
+   {
+     msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
+     usbs_msd_scsi_update_sense( sense, \
+             USBS_MSD_SCSI_SENSE_ASC_WRITE_ERROR, \
+             USBS_MSD_SCSI_SENSE_ASCQ_WRITE_ERROR, \
+             USBS_MSD_SCSI_SENSE_MEDIUM_ERROR );
+   }
+
+   return ret_len;
+}
+
+
+// Handle Request Sense Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_req_sense( usbs_msd * msd,  \
+                                      msd_scsi_req_sense_resp *sense )
+{
+   cyg_uint8 i = 0;
+   cyg_int32 tx_bytes = sizeof(msd_scsi_req_sense_resp);
+
+   TRACE("USB Slave MSD: SCSI request sense\n\r");
+
+   // Copy over to message buffer
+   for(i = 0 ; i < tx_bytes ; i++)
+       msd->buffer[i] = sense->byte[i];
+
+   tx_bytes = msd->send( msd, msd->buffer, tx_bytes );
+
+   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+
+   return tx_bytes;
+}
+
+
+// Handle Mode Sense Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_sense( usbs_msd * msd,  \
+                           msd_scsi_req_sense_resp *sense )
+{
+   cyg_int32 tx_bytes = 0x0;
+   DBG("USB Slave MSD: SCSI sense\n\r");
+
+   msd->buffer[0] = 0x03; // Number of byte in the following message
+   msd->buffer[1] = 0x00; // Media type
+   msd->buffer[2] = 0x00; // Not Write protected, no cache-control-bit support
+   msd->buffer[3] = 0x00; // No Mode parameter
+
+   // FIXME : handle different option correctly. For the time being,
+   // just respond with minimum data
+   if( ( msd->cbw.cb.data[2] & 0x3F ) == \
+        USBS_MSD_SCSI_MODE_PAGE_CODE_ALL )
+   {
+     DBG("USB Slave MSD: SCSI sense all\n\r");
+
+     tx_bytes = msd->send( msd, msd->buffer, 4 );
+
+     msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+   }
+   else
+   {
+     DBG("USB Slave MSD: SCSI sense page: %x\n\r", \
+             msd->cbw.cb.data[2]);
+
+     tx_bytes = msd->send( msd, msd->buffer, 4 );
+
+     msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
+   }
+
+   return tx_bytes;
+}
+
+
+// Handle Test Unit Ready Command
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_test_unit_ready( usbs_msd * msd , \
+                                         msd_scsi_req_sense_resp *sense )
+{
+   cyg_disk_info_t disk_info;
+   Cyg_ErrNo ret;
+   cyg_uint32 len = sizeof(cyg_disk_info_t);
+   cyg_uint32 key = CYG_IO_GET_CONFIG_DISK_INFO;
+   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
+
+   TRACE("USB Slave MSD: SCSI test unit ready\n\r");
+
+   // Get the configuration of a device
+   ret = cyg_io_get_config( lun, key, &disk_info, &len);
+
+   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+
+   USBS_MSD_SCSI_INIT_SENSE_DATA( sense->byte );
+
+   // check if disk is connected / mounted here
+   if( disk_info.connected == false )
+   {
+      DBG("USB Slave MSD: Disk not mounted \n\r");
+      usbs_msd_scsi_update_sense( sense, \
+             USBS_MSD_SCSI_SENSE_ASC_MEDIUM_NOT_PRESENT, \
+             USBS_MSD_SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT, \
+             USBS_MSD_SCSI_SENSE_UNIT_ATTENTION);
+
+      msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
+   }
+
+   // No data to transfer
+   return 0;
+}
+
+
+// Windows host operating system uses this command. Usually if
+// a command is not supported, the CSW should return failure.
+// Since no data is sent in the data transfer phase, the TX
+// endpoint shall be stalled. Since some USB driver in eCos
+// do not support endpoint stall, is it required to respond
+// with some data, otherwise the driver would freeze. In the
+// following case, we fill the data structure but report
+// failure in the CSW.
+#if !defined(CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE)
+// Handle Read Format Capacities
+//
+static inline cyg_int32
+usbs_msd_scsi_read_format_capacities( usbs_msd * msd )
+{
+   cyg_int32 i = 0;
+   DBG("USB Slave MSD: SCSI read format capacities\n\r");
+
+   for(i = 0 ; i < msd->cbw.data_transfert_len; i++)
+   {
+     msd->buffer[i] = 0;
+   }
+
+   i = msd->send( msd, msd->buffer, i );
+
+   msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
+
+   return i;
+}
+#endif
+
+
+// Handle Verify
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_verify( usbs_msd * msd )
+{
+   DBG("USB Slave MSD: SCSI test unit verify\n\r");
+
+   // FIXME: Should do something here?
+   // Return success, command is optional
+   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+
+   // No data to transfer
+   return 0;
+}
+
+
+// Handle Medium Removal
+//
+static inline cyg_int32
+usbs_msd_scsi_handle_removal( usbs_msd * msd )
+{
+   DBG("USB Slave MSD: SCSI Prevent / Allow device removal, LUN %d, flag %d %d\n\r",
+          ( msd->cbw.cb.data[1] & 0xf0 >> 4 ) , ( msd->cbw.cb.data[4] & 0x01 ),
+            msd->cbw.data_transfert_len );
+
+   // Support for this command is not mandatory.
+   // No specific handling of this command is implemented.
+   // Maybe mount / umount the disc?
+   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
+
+   // No data to transfer
+   return 0;
+}
+
+
+// Handle SCSI command
+//
+cyg_int32
+usbs_msd_scsi_handle_cmd( usbs_msd * msd )
+{
+   bool ret;
+   cyg_uint8 cmd = msd->cbw.cb.data[0];
+   msd_scsi_req_sense_resp *sense = (msd_scsi_req_sense_resp *) msd->handler_data;
+
+   switch( cmd )
+   {
+     case USBS_SCSI_INQUIRY:
+        ret = usbs_msd_scsi_handle_inquiry( msd );
+        break;
+
+     case USBS_SCSI_READ_CAPACITY:
+        ret = usbs_msd_scsi_handle_capacity( msd );
+        break;
+
+     case USBS_SCSI_READ_10:
+        ret = usbs_msd_scsi_handle_read(msd , sense );
+        break;
+
+     case USBS_SCSI_WRITE_10:
+        ret = usbs_msd_scsi_handle_write( msd , sense );
+        break;
+
+     case USBS_SCSI_REQUEST_SENSE:
+        ret = usbs_msd_scsi_handle_req_sense( msd , sense );
+        break;
+
+     case USBS_SCSI_SENSE_6:
+        ret = usbs_msd_scsi_handle_sense( msd , sense);
+        break;
+
+     case USBS_SCSI_TEST_UNIT_READY:
+        ret = usbs_msd_scsi_handle_test_unit_ready( msd , sense );
+        break;
+
+     case USBS_SCSI_VERIFY_10:
+        ret = usbs_msd_scsi_handle_verify( msd );
+        break;
+
+#if !defined(CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE)
+     case USBS_SCSI_READ_FORMAT_CAPACITIES:
+        ret = usbs_msd_scsi_read_format_capacities( msd );
+        break;
+#endif
+
+     case USBS_SCSI_PREVENT_ALLOW_REMOVAL:
+        ret = usbs_msd_scsi_handle_removal( msd );
+        break;
+
+     default:
+        // Use for all commands not implemented, not
+        // supported
+        DBG("USB Slave MSD: SCSI illegal request %x \n\r", cmd );
+        USBS_MSD_SCSI_INIT_SENSE_DATA( sense->byte );
+        usbs_msd_scsi_update_sense( sense, \
+                USBS_MSD_SCSI_SENSE_ASC_INVALID_OPCODE, \
+                USBS_MSD_SCSI_SENSE_ASCQ_INVALID_OPCODE, \
+                USBS_MSD_SCSI_SENSE_ILLEGAL_REQUEST);
+        msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
+        ret = 0;
+        break;
+
+   }
+
+   return ret;
+
+}
+
+// SCSI initialization
+//
+bool
+usbs_msd_scsi_init( void ** ctxt )
+{
+  static msd_scsi_req_sense_resp sense;
+
+  DBG("USB Slave MSD: SCSI init %p\n", &sense);
+
+  USBS_MSD_SCSI_INIT_SENSE_DATA( sense.byte );
+
+  *ctxt = &sense;
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/packages/io/usb/msd/slave/current/tests/usbs_test_ramdisk.c
@@ -0,0 +1,738 @@
+//==========================================================================
+//
+//      usb_test_ramdisk.c
+//
+//      Example application for the USB MSD layer in eCos.
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    ccoutand
+// Contributors:
+// Date:         2010-06-27
+// Description:  USB Slave Mass Storage example application.
+//
+//####DESCRIPTIONEND####
+//===========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+
+#if defined(CYGPKG_FS_FAT)
+#include <pkgconf/io_fileio.h>
+#include <pkgconf/fs_fat.h>
+#endif
+
+#include <pkgconf/io_usb_slave_msd.h>
+#include <pkgconf/kernel.h>
+#include <cyg/kernel/kapi.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/infra/diag.h>
+#include <cyg/io/usb/usbs_msd_io.h>
+#include <cyg/io/io.h>
+#include <cyg/io/devtab.h>
+#include <cyg/io/disk.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(CYGPKG_FS_FAT)
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/testcase.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <cyg/fileio/fileio.h>
+#include <cyg/fs/fatfs.h>
+#endif
+
+#if defined(CYGBLD_IO_USB_SLAVE_MSD_DEBUG)
+#define DBG diag_printf
+#else
+#define DBG (1) ? (void)0 : diag_printf
+#endif
+
+// ----------------------------------------------------------------------------
+// FAT12 file-system FBR, FAT and ROOT directory entries are hardcoded
+// and later copied over to the RAM disk
+//
+
+#define USBS_MSD_RAMDISK_BLOCKLEN   512
+#define USBS_MSD_RAMDISK_NUM_BLOCK   32
+
+// Allocate space for the RAM disk
+static char ram_disk[ USBS_MSD_RAMDISK_BLOCKLEN * USBS_MSD_RAMDISK_NUM_BLOCK ] __attribute__((aligned(4)));
+
+// FAT12 Boot Record
+const char fat12_br[] = {
+   0xEB, 0x3C, 0x90,                               // Field for Bootable Media
+   0x4D, 0x53, 0x57, 0x49, 0x4E, 0x34, 0x2E, 0x31, // MSWIN4.1
+   0x00, 0x02,                                     // 512 bytes sector
+   0x01,                                           // 1 sector per cluster
+   0x01, 0x00,                                     // 1 reserved sector (including MBR)
+   0x02,                                           // 2 FATs
+   0x40, 0x00,                                     // 64 entries
+   USBS_MSD_RAMDISK_NUM_BLOCK, 0x00,               // Number of sectors is less than 32K: 32 sectors
+   0xF0,                                           // Removable media
+   0x01, 0x00,                                     // 1sector per FAT
+   0x00, 0x00,                                     // Sector per track (not used in LBA)
+   0x00, 0x00,                                     // Number of Heads (not used in LBA)
+   0x00, 0x00, 0x00, 0x00,                         // Hidden sector
+   0x00, 0x00, 0x00, 0x00,                         // Number of sectors is more than 32K
+   0x00,                                           // Logical drive number
+   0x00,                                           // Reserved
+   0x29,                                           // Extended boot signature
+   0x04, 0x03, 0x02, 0x01,                         // Serial Number
+   0x65, 0x43, 0x6F, 0x73, 0x20, 0x64, 0x69, 0x73, // VOLUME: eCos disk
+   0x6B, 0x20, 0x20,
+   0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20  // FAT12
+};
+
+// MBR and Volume sector signature
+const char mbr_signature[] = {
+   0x55, 0xAA
+};
+
+// Partition table
+const char partition_tbl[] = {
+   // First (FAT12)
+   0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+   0x01, 0x00, 0x00, 0x00, (USBS_MSD_RAMDISK_NUM_BLOCK-1), 0x00, 0x00, 0x00,
+   // Second
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   // Third
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   // Fourth
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// Root directory (eCos-3.0)
+const char root_dir[] = {
+   0x65, 0x43, 0x6F, 0x73, 0x2d, 0x33, 0x2e, 0x30,
+   0x20, 0x20, 0x20, 0x28, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x9e,
+   0x65, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// File-system Allocation Table
+const char fat[] = {
+  0xF0, 0xff, 0xff
+};
+
+// Initialize FAT12
+static void
+init_fat12_disk( char *start_addr )
+{
+  char * dst = start_addr;
+
+  // Copy partition table
+  dst = start_addr + 446;
+  memcpy(dst, partition_tbl, 64);
+
+  // Copy signature
+  dst = start_addr + (USBS_MSD_RAMDISK_BLOCKLEN - 2 );
+  memcpy(dst, mbr_signature, 2);
+
+  // Copy FBR
+  dst = start_addr + USBS_MSD_RAMDISK_BLOCKLEN;
+  memcpy(dst, fat12_br, 62);
+
+  // Copy signature
+  dst = start_addr + (( USBS_MSD_RAMDISK_BLOCKLEN * 2 ) - 2 );
+  memcpy(dst, mbr_signature, 2);
+
+  // Copy FAT0
+  dst = start_addr + ( USBS_MSD_RAMDISK_BLOCKLEN * 2);
+  memcpy(dst, fat, 3);
+
+  // Copy FAT1
+  dst = start_addr + ( USBS_MSD_RAMDISK_BLOCKLEN * 3);
+  memcpy(dst, fat, 3);
+
+  // Copy Root directory
+  dst = start_addr + ( USBS_MSD_RAMDISK_BLOCKLEN * 4);
+  memcpy(dst, root_dir, 32);
+
+}
+
+
+// ----------------------------------------------------------------------------
+// Create a tiny "RAM disk" device
+//
+//
+
+#define RAM_DISK_NAME "/dev/ramdisk0/"
+
+typedef struct {
+    volatile cyg_uint8 *base;
+    cyg_uint16 size;
+} ram_disk_info_t;
+
+static cyg_bool ram_disk_init(struct cyg_devtab_entry *tab);
+
+static Cyg_ErrNo ram_disk_bread(disk_channel *chan,
+                              void         *buf,
+                              cyg_uint32    len,
+                              cyg_uint32    block_num);
+
+
+static Cyg_ErrNo ram_disk_bwrite(disk_channel *chan,
+                               const void   *buf,
+                               cyg_uint32    len,
+                               cyg_uint32    block_num);
+
+static Cyg_ErrNo ram_disk_get_config(disk_channel *chan,
+                               cyg_uint32    key,
+                               const void   *xbuf,
+                               cyg_uint32   *len);
+
+static Cyg_ErrNo ram_disk_set_config(disk_channel *chan,
+                               cyg_uint32    key,
+                               const void   *xbuf,
+                               cyg_uint32   *len);
+
+static Cyg_ErrNo ram_disk_lookup(struct cyg_devtab_entry **tab,
+                                struct cyg_devtab_entry  *sub_tab,
+                                const char               *name);
+
+DISK_FUNS(ram_disk_funs,
+          ram_disk_bread,
+          ram_disk_bwrite,
+          ram_disk_get_config,
+          ram_disk_set_config
+);
+
+DISK_CONTROLLER(ram_disk_controller, ram_disk_controller);
+
+#define RAM_DISK_INSTANCE(_number_,_base_,_mbr_supp_,_name_)    \
+static ram_disk_info_t ram_disk_info##_number_ = {              \
+    base: (volatile cyg_uint8 *)_base_,                         \
+};                                                              \
+DISK_CHANNEL(ram_disk_channel##_number_,                        \
+             ram_disk_funs,                                     \
+             ram_disk_info##_number_,                           \
+             ram_disk_controller,                               \
+             _mbr_supp_,                                        \
+             1                                                  \
+);                                                              \
+BLOCK_DEVTAB_ENTRY(ram_disk_io##_number_,                       \
+             _name_,                                            \
+             0,                                                 \
+             &cyg_io_disk_devio,                                \
+             ram_disk_init,                                     \
+             ram_disk_lookup,                                   \
+             &ram_disk_channel##_number_                        \
+);
+
+RAM_DISK_INSTANCE(0, 0, true, RAM_DISK_NAME);
+
+
+// ----------------------------------------------------------------------------
+static void
+read_data(volatile cyg_uint8  *base,
+          void                *buf,
+          cyg_uint32           len)
+{
+    cyg_uint8 *dst = (cyg_uint8 *)buf;
+    cyg_uint8 *src = (cyg_uint8 *)base;
+    cyg_uint32 i = 0;
+
+    for (i = 0; i < len; i += 1)
+    {
+        *dst = *src;
+        dst = dst + 1; src = src + 1;
+    }
+
+}
+
+static void
+write_data(volatile cyg_uint8  *base,
+           const void          *buf,
+           cyg_uint16           len)
+{
+    cyg_uint8 *dst = (cyg_uint8 *)base;
+    cyg_uint8 *src = (cyg_uint8 *)buf;
+    cyg_uint32 i = 0;
+
+    for (i = 0; i < len; i += 1)
+    {
+        *dst = *src;
+         dst = dst + 1; src = src + 1;
+    }
+}
+
+// ----------------------------------------------------------------------------
+static cyg_bool
+ram_disk_init(struct cyg_devtab_entry *tab)
+{
+    disk_channel           *chan = (disk_channel *) tab->priv;
+    ram_disk_info_t         *info = (ram_disk_info_t *) chan->dev_priv;
+    cyg_disk_identify_t     ident;
+
+    if (chan->init)
+        return true;
+
+    info->base = (volatile cyg_uint8 *) &ram_disk[0];
+    info->size = USBS_MSD_RAMDISK_BLOCKLEN * USBS_MSD_RAMDISK_NUM_BLOCK;
+
+    DBG("RAM DISK ( %p ) init\n", info->base);
+
+    init_fat12_disk( &ram_disk[0] );
+
+    ident.cylinders_num   =  0;
+    ident.heads_num       =  0;
+    ident.lba_sectors_num = USBS_MSD_RAMDISK_NUM_BLOCK-2;
+    ident.phys_block_size = USBS_MSD_RAMDISK_BLOCKLEN;
+    ident.max_transfer    = USBS_MSD_RAMDISK_BLOCKLEN;
+
+    if (!(chan->callbacks->disk_init)(tab))
+        return false;
+
+    if (ENOERR != (chan->callbacks->disk_connected)(tab, &ident))
+        return false;
+
+    return true;
+}
+
+static Cyg_ErrNo
+ram_disk_lookup(struct cyg_devtab_entry **tab,
+               struct cyg_devtab_entry  *sub_tab,
+               const char *name)
+{
+    disk_channel *chan = (disk_channel *) (*tab)->priv;
+    return (chan->callbacks->disk_lookup)(tab, sub_tab, name);
+}
+
+static Cyg_ErrNo
+ram_disk_bread(disk_channel *chan,
+             void         *buf,
+             cyg_uint32    len,
+             cyg_uint32    block_num)
+{
+    ram_disk_info_t *info = (ram_disk_info_t *)chan->dev_priv;
+    volatile cyg_uint8 *src = info->base + USBS_MSD_RAMDISK_BLOCKLEN * block_num;
+    cyg_uint32 len_byte = len * USBS_MSD_RAMDISK_BLOCKLEN;
+
+    if ( len_byte == 0 )
+      return EINVAL;
+
+    read_data(src, buf, len_byte);
+
+    return ENOERR;
+}
+
+static Cyg_ErrNo
+ram_disk_bwrite(disk_channel *chan,
+              const void   *buf,
+              cyg_uint32    len,
+              cyg_uint32    block_num)
+{
+    ram_disk_info_t *info = (ram_disk_info_t *)chan->dev_priv;
+    volatile cyg_uint8 *dst = info->base + USBS_MSD_RAMDISK_BLOCKLEN * block_num;
+    cyg_uint32 len_byte = len * USBS_MSD_RAMDISK_BLOCKLEN;
+
+    if ( len_byte == 0 )
+      return EINVAL;
+
+    write_data(dst, buf, len_byte);
+
+    return ENOERR;
+}
+
+static Cyg_ErrNo
+ram_disk_get_config(disk_channel *chan,
+                   cyg_uint32    key,
+                   const void   *xbuf,
+                   cyg_uint32   *len)
+{
+    return -EINVAL;
+}
+
+static Cyg_ErrNo
+ram_disk_set_config(disk_channel *chan,
+                   cyg_uint32    key,
+                   const void   *xbuf,
+                   cyg_uint32   *len)
+{
+    return -EINVAL;
+}
+
+
+// ----------------------------------------------------------------------------
+// In case FAT file-system package is included, this application will try
+// to play with the file-system before it is mounted as a mass storage device.
+// The following code is a copy of the fatfs1.c from the fs/test directory
+//
+#if defined(CYGPKG_FS_FAT)
+
+#define SHOW_RESULT( _fn, _res ) \
+  DBG("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
+
+#define IOSIZE  100
+
+//==========================================================================
+
+void checkcwd( const char *cwd )
+{
+    static char cwdbuf[PATH_MAX];
+    char *ret;
+
+    ret = getcwd( cwdbuf, sizeof(cwdbuf));
+    if( ret == NULL ) SHOW_RESULT( getcwd, (int)ret );
+
+    if( strcmp( cwdbuf, cwd ) != 0 )
+    {
+        DBG( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+        CYG_TEST_FAIL( "Current directory mismatch");
+    }
+}
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot )
+{
+    int err;
+    DIR *dirp;
+    int num=0;
+
+    DBG("<INFO>: reading directory %s\n",name);
+
+    dirp = opendir( name );
+    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+    for(;;)
+    {
+        struct dirent *entry = readdir( dirp );
+
+        if( entry == NULL )
+            break;
+        num++;
+        DBG("<INFO>: entry %14s",entry->d_name);
+#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE
+        DBG(" d_type %2x", entry->d_type);
+#endif
+        if( statp )
+        {
+            char fullname[PATH_MAX];
+            struct stat sbuf;
+
+            if( name[0] )
+            {
+                strcpy(fullname, name );
+                if( !(name[0] == '/' && name[1] == 0 ) )
+                    strcat(fullname, "/" );
+            }
+            else fullname[0] = 0;
+
+            strcat(fullname, entry->d_name );
+
+            err = stat( fullname, &sbuf );
+            if( err < 0 )
+            {
+                if( errno == ENOSYS )
+                    DBG(" <no status available>");
+                else SHOW_RESULT( stat, err );
+            }
+            else
+            {
+                DBG(" [mode %08x ino %08x nlink %d size %ld]",
+                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,(long)sbuf.st_size);
+            }
+#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE
+            if ((entry->d_type & S_IFMT) != (sbuf.st_mode & S_IFMT))
+              CYG_TEST_FAIL("File mode's don't match between dirent and stat");
+#endif
+        }
+
+        DBG("\n");
+    }
+
+    err = closedir( dirp );
+    if( err < 0 ) SHOW_RESULT( stat, err );
+    if (numexpected >= 0 && num != numexpected)
+        CYG_TEST_FAIL("Wrong number of dir entries\n");
+    if ( numgot != NULL )
+        *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t size )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+
+    DBG("<INFO>: create file %s size %zd \n",name,size);
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    while( size > 0 )
+    {
+        ssize_t len = size;
+        if ( len > IOSIZE ) len = IOSIZE;
+
+        wrote = write( fd, buf, len );
+        if( wrote != len ) SHOW_RESULT( write, (int)wrote );
+
+        size -= wrote;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void checkfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t done;
+    int i;
+    int err;
+    off_t pos = 0;
+
+    DBG("<INFO>: check file %s\n",name);
+
+    err = access( name, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd = open( name, O_RDONLY );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    for(;;)
+    {
+        done = read( fd, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, (int)done );
+
+        if( done == 0 ) break;
+
+        for( i = 0; i < done; i++ )
+            if( buf[i] != i%256 )
+            {
+                DBG("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256);
+                CYG_TEST_FAIL("Data read not equal to data written\n");
+            }
+
+        pos += done;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void copyfile( char *name2, char *name1 )
+{
+
+    int err;
+    char buf[IOSIZE];
+    int fd1, fd2;
+    ssize_t done, wrote;
+
+    DBG("<INFO>: copy file %s -> %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    err = access( name2, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd1 = open( name1, O_WRONLY|O_CREAT );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+
+    for(;;)
+    {
+        done = read( fd2, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, (int)done );
+
+        if( done == 0 ) break;
+
+        wrote = write( fd1, buf, done );
+        if( wrote != done ) SHOW_RESULT( write, (int) wrote );
+
+        if( wrote != done ) break;
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+}
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1 )
+{
+    int err;
+    char buf1[IOSIZE];
+    char buf2[IOSIZE];
+    int fd1, fd2;
+    ssize_t done1, done2;
+    int i;
+
+    DBG("<INFO>: compare files %s == %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd1 = open( name1, O_RDONLY );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+
+    for(;;)
+    {
+        done1 = read( fd1, buf1, IOSIZE );
+        if( done1 < 0 ) SHOW_RESULT( read, (int)done1 );
+
+        done2 = read( fd2, buf2, IOSIZE );
+        if( done2 < 0 ) SHOW_RESULT( read, (int)done2 );
+
+        if( done1 != done2 )
+            DBG("Files different sizes\n");
+
+        if( done1 == 0 ) break;
+
+        for( i = 0; i < done1; i++ )
+            if( buf1[i] != buf2[i] )
+            {
+                DBG("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+                CYG_TEST_FAIL("Data in files not equal\n");
+            }
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+}
+
+#endif
+
+
+
+// ----------------------------------------------------------------------------
+// Entry point of the test application. If the FAT file-system package is
+// included, the file-system is mounted and tested before the USB Mass Storage
+// service is started.
+//
+// Once the mass storage device is mounted on the host computer, 2 files
+// (foo and fee) and one directory (bar) should appear in the device
+//
+
+int cyg_start(void)
+{
+#if defined(CYGPKG_FS_FAT)
+  int err;
+  int existingdirents=-1;
+#endif
+
+  DBG("Start USB MSD application\n\r");
+
+#if defined(CYGPKG_FS_FAT)
+
+  // Mount RAM disk partition 1
+  err = mount( "/dev/ramdisk0/1", "/", "fatfs" );
+
+  if( err < 0 )
+     SHOW_RESULT( mount, err );
+
+  err = chdir( "/" );
+  if( err < 0 )
+     SHOW_RESULT( chdir, err );
+
+  checkcwd( "/" );
+
+  // Display list of all files/directories from root
+  listdir( "/", true, -1, &existingdirents );
+
+  // Play around with the file-system, create / copy /
+  // compare files
+  createfile( "/foo", 1000 );
+  checkfile( "foo" );
+  copyfile( "foo", "fee" );
+  checkfile( "fee" );
+  comparefiles( "foo", "/fee" );
+  DBG("<INFO>: mkdir bar\n");
+
+  // Create new directory
+  err = mkdir( "/bar", 0 );
+  if( err < 0 )
+     SHOW_RESULT( mkdir, err );
+
+  // Display list of all files/directories from root
+  listdir( "/" , true, existingdirents+3, NULL );
+
+  // Umount file-system
+  err = umount( "/" );
+
+  if( err < 0 )
+     SHOW_RESULT( umount, err );
+
+#endif
+
+  // Start Mass Storage Service
+  usbs_msd_start();
+
+  // Start scheduler
+  cyg_scheduler_start();
+
+}