diff --git a/ChangeLog b/ChangeLog
index 1fc07dc19bdf08a8165ca0a84e27a5ab15e5102d..da0c769ba620ab22b80e9b0e4f7461f76982cd9c 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -11175,4 +11175,5 @@
 	  statistics (2015-11-26).
 	* net/net_procfs.c:  Add basic support for networking entries in the
 	  procfs (2015-11-27).
-
+	* mtd/filemtd.c and smart.c:  Add support for a /dev/smart loop device.
+	  From Ken Petit (2015-11-28).
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 03f08fd0e7b059746553b01f51328df0cb950fdc..b3bd84d70304be03ed6ccff1bc0ce8a7fc19ece9 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -268,6 +268,28 @@ config RAMMTD_FLASHSIM
 
 endif
 
+config FILEMTD
+	bool "File-based MTD driver"
+	default n
+	---help---
+		Build support for a File-based MTD driver.
+
+if FILEMTD
+
+config FILEMTD_BLOCKSIZE
+	int "File MTD block size"
+	default 512
+
+config FILEMTD_ERASESIZE
+	int "File MTD erase block size"
+	default 4096
+
+config FILEMTD_ERASESTATE
+	hex "Simulated erase state"
+	default 0xff
+
+endif
+
 config MTD_AT24XX
 	bool "I2C-based AT24xx eeprom"
 	default n
@@ -479,6 +501,14 @@ config MTD_SMART
 
 if MTD_SMART
 
+config SMART_DEV_LOOP
+	bool "Enable SMART loop device"
+	select FILEMTD
+	default n
+	---help---
+		Supports a smart loop device that can be used to export a
+		file (or character device) as a SMART block device.
+
 config MTD_SMART_SECTOR_SIZE
 	int "SMART Device sector size"
 	default 1024
diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs
index bd284d6822d1d774ed61bb5cc6eca909845e679a..fdd77d3610b3ca19d7c9302ee1fc6f75090024f0 100644
--- a/drivers/mtd/Make.defs
+++ b/drivers/mtd/Make.defs
@@ -72,6 +72,10 @@ ifeq ($(CONFIG_RAMMTD),y)
 CSRCS += rammtd.c
 endif
 
+ifeq ($(CONFIG_FILEMTD),y)
+CSRCS += filemtd.c
+endif
+
 ifeq ($(CONFIG_MTD_AT24XX),y)
 CSRCS += at24xx.c
 endif
diff --git a/drivers/mtd/filemtd.c b/drivers/mtd/filemtd.c
index c4dee5db756f879f02e580fd79051fff7aef28d4..18b2e19e1a9d0a2d85c2b1e3f2cb55695c56cbb8 100644
--- a/drivers/mtd/filemtd.c
+++ b/drivers/mtd/filemtd.c
@@ -95,10 +95,12 @@
 
 struct file_dev_s
 {
-  struct mtd_dev_s mtd;      /* MTD device */
-  int              fd;       /* File descriptor of underlying file */
-  size_t           nblocks;  /* Number of erase blocks */
-  size_t           offset;   /* Offset from start of file */
+  struct mtd_dev_s mtd;        /* MTD device */
+  int              fd;         /* File descriptor of underlying file */
+  size_t           nblocks;    /* Number of erase blocks */
+  size_t           offset;     /* Offset from start of file */
+  size_t           erasesize;  /* Offset from start of file */
+  size_t           blocksize;  /* Offset from start of file */
 };
 
 /****************************************************************************
@@ -270,8 +272,8 @@ static int file_erase(FAR struct mtd_dev_s *dev, off_t startblock,
    * corresponding to the number of blocks.
    */
 
-  offset = startblock * CONFIG_FILEMTD_BLOCKSIZE;
-  nbytes = nblocks * CONFIG_FILEMTD_BLOCKSIZE;
+  offset = startblock * priv->blocksize;
+  nbytes = nblocks * priv->blocksize;
 
   /* Then erase the data in the file */
 
@@ -317,8 +319,8 @@ static ssize_t file_bread(FAR struct mtd_dev_s *dev, off_t startblock,
    * corresponding to the number of blocks.
    */
 
-  offset = startblock * CONFIG_FILEMTD_BLOCKSIZE;
-  nbytes = nblocks * CONFIG_FILEMTD_BLOCKSIZE;
+  offset = startblock * priv->blocksize;
+  nbytes = nblocks * priv->blocksize;
 
   /* Then read the data from the file */
 
@@ -357,8 +359,8 @@ static ssize_t file_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
    * corresponding to the number of blocks.
    */
 
-  offset = startblock * CONFIG_FILEMTD_BLOCKSIZE;
-  nbytes = nblocks * CONFIG_FILEMTD_BLOCKSIZE;
+  offset = startblock * priv->blocksize;
+  nbytes = nblocks * priv->blocksize;
 
   /* Then write the data to the file */
 
@@ -379,7 +381,7 @@ static ssize_t file_byteread(FAR struct mtd_dev_s *dev, off_t offset,
 
   /* Don't let read read past end of buffer */
 
-  if (offset + nbytes > priv->nblocks * CONFIG_FILEMTD_ERASESIZE)
+  if (offset + nbytes > priv->nblocks * priv->erasesize)
    {
      return 0;
    }
@@ -403,7 +405,7 @@ static ssize_t file_bytewrite(FAR struct mtd_dev_s *dev, off_t offset,
 
   /* Don't let the write exceed the original size of the file */
 
-  maxoffset = priv->nblocks * CONFIG_FILEMTD_ERASESIZE;
+  maxoffset = priv->nblocks * priv->erasesize;
   if (offset + nbytes > maxoffset)
     {
       return 0;
@@ -438,8 +440,8 @@ static int file_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
                * the capacity and how to access the device.
                */
 
-              geo->blocksize    = CONFIG_FILEMTD_BLOCKSIZE;
-              geo->erasesize    = CONFIG_FILEMTD_ERASESIZE;
+              geo->blocksize    = priv->blocksize;
+              geo->erasesize    = priv->erasesize;
               geo->neraseblocks = priv->nblocks;
               ret               = OK;
             }
@@ -482,7 +484,8 @@ static int file_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
  *
  ****************************************************************************/
 
-FAR struct mtd_dev_s *filemtd_initialize(FAR const char *path, size_t offset)
+FAR struct mtd_dev_s *filemtd_initialize(FAR const char *path, size_t offset,
+                            int16_t sectsize, int32_t erasesize)
 {
   FAR struct file_dev_s *priv;
   struct stat sb;
@@ -527,9 +530,31 @@ FAR struct mtd_dev_s *filemtd_initialize(FAR const char *path, size_t offset)
       return NULL;
     }
 
+  /* Set the block size based on the provided sectsize parameter */
+
+  if (sectsize <= 0)
+    {
+      priv->blocksize = CONFIG_FILEMTD_BLOCKSIZE;
+    }
+  else
+    {
+      priv->blocksize = sectsize;
+    }
+
+  /* Set the erase size based on the provided erasesize parameter */
+
+  if (erasesize <= 0)
+    {
+      priv->erasesize = CONFIG_FILEMTD_ERASESIZE;
+    }
+  else
+    {
+      priv->erasesize = erasesize;
+    }
+
   /* Force the size to be an even number of the erase block size */
 
-  nblocks = (filelen - offset) / CONFIG_FILEMTD_ERASESIZE;
+  nblocks = (filelen - offset) / priv->erasesize;
   if (nblocks < 3)
     {
       fdbg("Need to provide at least three full erase block\n");
@@ -591,3 +616,24 @@ void filemtd_teardown(FAR struct mtd_dev_s *dev)
 
   kmm_free(priv);
 }
+
+/****************************************************************************
+ * Name: filemtd_isfilemtd
+ *
+ * Description:
+ *   Tests if the provided mtd is a filemtd device.
+ *
+ * Input Parameters:
+ *   mtd - Pointer to the mtd.
+ *
+ ****************************************************************************/
+
+bool filemtd_isfilemtd(FAR struct mtd_dev_s *dev)
+{
+  FAR struct file_dev_s *priv = (FAR struct file_dev_s *) dev;
+
+  if (priv->mtd.erase == file_erase)
+    return 1;
+
+  return 0;
+}
diff --git a/drivers/mtd/smart.c b/drivers/mtd/smart.c
index c82a3af1127d7825e2f76379fe851bcc34db9710..cb188c1854656932a3064bbad758f0978a413e9c 100644
--- a/drivers/mtd/smart.c
+++ b/drivers/mtd/smart.c
@@ -43,6 +43,8 @@
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -385,6 +387,14 @@ static int smart_relocate_static_data(FAR struct smart_struct_s *dev, uint16_t b
 static int smart_relocate_sector(FAR struct smart_struct_s *dev,
                  uint16_t oldsector, uint16_t newsector);
 
+#ifdef CONFIG_SMART_DEV_LOOP
+static ssize_t smart_loop_read(FAR struct file *filep, FAR char *buffer,
+                 size_t buflen);
+static ssize_t smart_loop_write(FAR struct file *filep, FAR const char *buffer,
+                 size_t buflen);
+static int     smart_loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+#endif /* CONFIG_SMART_DEV_LOOP */
+
 /****************************************************************************
  * Private Data
  ****************************************************************************/
@@ -403,6 +413,21 @@ static const struct block_operations g_bops =
   smart_ioctl     /* ioctl    */
 };
 
+#ifdef CONFIG_SMART_DEV_LOOP
+static const struct file_operations g_fops =
+{
+  0,                /* open */
+  0,                /* close */
+  smart_loop_read,  /* read */
+  smart_loop_write, /* write */
+  0,                /* seek */
+  smart_loop_ioctl  /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+  , 0               /* poll */
+#endif
+};
+#endif /* CONFIG_SMART_DEV_LOOP */
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -5411,6 +5436,10 @@ int smart_initialize(int minor, FAR struct mtd_dev_s *mtd, FAR const char *partn
       smart_scan(dev);
     }
 
+#ifdef CONFIG_SMART_DEV_LOOP
+  (void)register_driver("/dev/smart", &g_fops, 0666, NULL);
+#endif
+
   return OK;
 
 errout:
@@ -5437,3 +5466,210 @@ errout:
   kmm_free(dev);
   return ret;
 }
+
+ /****************************************************************************
+ * Name: smart_losetup
+ *
+ * Description: Dynamically setups up a SMART enabled loop device that
+ *              is backed by a file.  The resulting loop device is a
+ *              MTD type block device vs. a generic block device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMART_DEV_LOOP
+static int smart_losetup(int minor, FAR const char *filename,
+                int sectsize, int erasesize, off_t offset, bool readonly)
+{
+  FAR struct mtd_dev_s *mtd;
+  struct stat           sb;
+  int                   x, ret;
+  char                  devpath[20];
+
+  /* Try to create a filemtd device using the filename provided */
+
+  mtd = filemtd_initialize(filename, offset, sectsize, erasesize);
+  if (mtd == NULL)
+    {
+      return -ENOENT;
+    }
+
+  /* Check if we need to dynamically assign a minor number */
+
+  if (minor == -1)
+    {
+      /* Start at zero and stat /dev/smartX until no entry found.
+       * Searching 0 to 256 should be sufficient.
+       */
+
+      for (x = 0; x < 256; x++)
+        {
+          snprintf(devpath, sizeof(devpath), "/dev/smart%d", x);
+          ret = stat(devpath, &sb);
+          if (ret != 0)
+            {
+              /* We can use this minor number */
+
+              minor = x;
+              break;
+            }
+        }
+    }
+
+  /* Now create a smart MTD using the filemtd backing it */
+
+  ret = smart_initialize(minor, mtd, NULL);
+
+  if (ret != OK)
+    {
+      filemtd_teardown(mtd);
+    }
+
+  return ret;
+}
+#endif /* CONFIG_SMART_DEV_LOOP */
+
+/****************************************************************************
+ * Name: loteardown
+ *
+ * Description:
+ *   Undo the setup performed by losetup
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMART_DEV_LOOP
+static int smart_loteardown(FAR const char *devname)
+{
+  FAR struct smart_struct_s *dev;
+  FAR struct inode *inode;
+  int ret;
+
+  /* Sanity check */
+
+#ifdef CONFIG_DEBUG
+  if (!devname)
+    {
+      return -EINVAL;
+    }
+#endif
+
+  /* Open the block driver associated with devname so that we can get the inode
+   * reference.
+   */
+
+  ret = open_blockdriver(devname, MS_RDONLY, &inode);
+  if (ret < 0)
+    {
+      dbg("Failed to open %s: %d\n", devname, -ret);
+      return ret;
+    }
+
+  /* Inode private data is a reference to the loop device structure */
+
+  dev = (FAR struct smart_struct_s *)inode->i_private;
+
+  /* Validate this is a filemtd backended device */
+
+  if (!filemtd_isfilemtd(dev->mtd))
+    {
+      fdbg("Device is not a SMART loop: %s\n", devname);
+      return -EINVAL;
+    }
+
+  close_blockdriver(inode);
+
+  /* Now teardown the filemtd */
+
+  filemtd_teardown(dev->mtd);
+  unregister_blockdriver(devname);
+
+  kmm_free(dev);
+
+  return OK;
+}
+#endif /* CONFIG_SMART_DEV_LOOP */
+
+/****************************************************************************
+ * Name: smart_loop_read
+ ****************************************************************************/
+
+#ifdef CONFIG_SMART_DEV_LOOP
+static ssize_t smart_loop_read(FAR struct file *filep, FAR char *buffer, size_t len)
+{
+  return 0; /* Return EOF */
+}
+#endif /* CONFIG_SMART_DEV_LOOP */
+
+/****************************************************************************
+ * Name: smart_loop_write
+ ****************************************************************************/
+
+#ifdef CONFIG_SMART_DEV_LOOP
+static ssize_t smart_loop_write(FAR struct file *filep, FAR const char *buffer, size_t len)
+{
+  return len; /* Say that everything was written */
+}
+#endif /* CONFIG_SMART_DEV_LOOP */
+
+/****************************************************************************
+ * Name: smart_loop_ioctl
+ ****************************************************************************/
+
+#ifdef CONFIG_SMART_DEV_LOOP
+static int smart_loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+  int ret;
+
+  switch (cmd)
+    {
+    /* Command:      LOOPIOC_SETUP
+     * Description:  Setup the loop device
+     * Argument:     A pointer to a read-only instance of struct losetup_s.
+     * Dependencies: The loop device must be enabled (CONFIG_DEV_LOOP=y)
+     */
+
+    case SMART_LOOPIOC_SETUP:
+      {
+         FAR struct smart_losetup_s *setup = (FAR struct smart_losetup_s *)((uintptr_t)arg);
+
+        if (setup == NULL)
+          {
+            ret = -EINVAL;
+          }
+        else
+          {
+            ret = smart_losetup(setup->minor, setup->filename, setup->sectsize,
+                         setup->erasesize, setup->offset, setup->readonly);
+          }
+      }
+      break;
+
+    /* Command:      LOOPIOC_TEARDOWN
+     * Description:  Teardown a loop device previously setup vis LOOPIOC_SETUP
+     * Argument:     A read-able pointer to the path of the device to be
+     *               torn down
+     * Dependencies: The loop device must be enabled (CONFIG_DEV_LOOP=y)
+     */
+
+    case SMART_LOOPIOC_TEARDOWN:
+      {
+        FAR const char *devname = (FAR const char *)((uintptr_t)arg);
+
+        if (devname == NULL)
+          {
+            ret = -EINVAL;
+          }
+        else
+          {
+            ret = smart_loteardown(devname);
+          }
+       }
+       break;
+
+     default:
+       ret = -ENOTTY;
+    }
+
+  return ret;
+}
+#endif /* CONFIG_SMART_DEV_LOOP */
+
diff --git a/include/nuttx/fs/smart.h b/include/nuttx/fs/smart.h
index f3bff10cb679663cba39ef49e62ce46498bf888e..ec217466aad6d81f31c10c78276a538c1d2d8ea5 100644
--- a/include/nuttx/fs/smart.h
+++ b/include/nuttx/fs/smart.h
@@ -45,6 +45,7 @@
 
 #include <sys/types.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -64,6 +65,27 @@
 #define SMARTFS_SECTOR_TYPE_DIR   1
 #define SMARTFS_SECTOR_TYPE_FILE  2
 
+#ifdef CONFIG_SMART_DEV_LOOP
+/* Loop device IOCTL commands */
+
+/* Command:      SMART_LOOPIOC_SETUP
+ * Description:  Setup the loop device
+ * Argument:     A pointer to a read-only instance of struct losetup_s.
+ * Dependencies: The loop device must be enabled (CONFIG_DEV_LOOP=y)
+ */
+
+/* Command:      SMART_LOOPIOC_TEARDOWN
+ * Description:  Teardown a loop device previously setup vis LOOPIOC_SETUP
+ * Argument:     A read-able pointer to the path of the device to be
+ *               torn down
+ * Dependencies: The loop device must be enabled (CONFIG_DEV_LOOP=y)
+ */
+
+#define SMART_LOOPIOC_SETUP     _LOOPIOC(0x0001)
+#define SMART_LOOPIOC_TEARDOWN  _LOOPIOC(0x0002)
+
+#endif
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -112,6 +134,22 @@ struct smart_procfs_data_s
 };
 #endif
 
+#ifdef CONFIG_SMART_DEV_LOOP
+/* This is the structure referred to in the argument to the LOOPIOC_SETUP
+ * IOCTL command.
+ */
+
+struct smart_losetup_s
+{
+  FAR const char *filename;     /* The file or character device to use */
+  int             minor;        /* The minor number of thedevice */
+  int             erasesize;    /* The erase size to use on the file */
+  int             sectsize;     /* The sector / page size of the file */
+  off_t           offset;       /* An offset that may be applied to the device */
+  bool            readonly;     /* True: Read access will be supported only */
+};
+#endif
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h
index 367fbad1b8a7dfdc7e5091b3ece1e3d1a0109577..39803509f81dbe932f0f883845100f6e04cbab18 100644
--- a/include/nuttx/mtd/mtd.h
+++ b/include/nuttx/mtd/mtd.h
@@ -525,17 +525,36 @@ FAR struct mtd_dev_s *s25fl1_initialize(FAR struct qspi_dev_s *qspi,
 FAR struct mtd_dev_s *up_flashinitialize(void);
 
 /****************************************************************************
- * Name: up_flashinitialize
+ * Name: filemtd_initialize
  *
  * Description:
  *   Create a file backed MTD device.
  *
  ****************************************************************************/
 
-FAR struct mtd_dev_s *filemtd_initialize(FAR const char *path, size_t offset);
+FAR struct mtd_dev_s *filemtd_initialize(FAR const char *path, size_t offset,
+                        int16_t sectsize, int32_t erasesize);
+
+/****************************************************************************
+ * Name: filemtd_teardown
+ *
+ * Description:
+ *   Tear down a filemtd device.
+ *
+ ****************************************************************************/
 
 void filemtd_teardown(FAR struct mtd_dev_s* mtd);
 
+/****************************************************************************
+ * Name: filemtd_isfilemtd
+ *
+ * Description:
+ *   Test if MTD is a filemtd device.
+ *
+ ****************************************************************************/
+
+bool filemtd_isfilemtd(FAR struct mtd_dev_s* mtd);
+
 /****************************************************************************
  * Name: mtd_register
  *