diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html
index a2a4a7c5b3f4f26f0e933bd91b2dae8eec138548..9418056eb9eddeb8c619ec8d6b5040bf2adce142 100644
--- a/Documentation/NuttShell.html
+++ b/Documentation/NuttShell.html
@@ -754,14 +754,50 @@ dd if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors
 </pre></ul>
 <p>
   <b>Synopsis</b>.
-  Copy blocks from &lt;infile&gt; to &lt;outfile&gt;.  As an example:
+  Copy blocks from &lt;infile&gt; to &lt;outfile&gt;.
+  &lt;infile&gt; or &lt;outfile&gt; may be the path to a standard file, a character device, or a block device.
+  Examples follow:
+</p>
+<ol>
+  <li>
+    Read from character device, write to regular file.
+    This will create a new file of the specified size filled with zero.
 <ul><pre>
+nsh&gt; ls -l /dev
+/dev:
+ crw-rw-rw-       0 zero
 nsh&gt; dd if=/dev/zero of=/tmp/zeros bs=64 count=16
 nsh&gt; ls -l /tmp
 /tmp:
  -rw-rw-rw-    1024 ZEROS
 </pre></ul>
-</p>
+  </li>
+  <li>
+    Read from character device, write to block device.
+    This will fill the entire block device with zeros.
+  </li>
+<ul><pre>
+nsh&gt; ls -l /dev
+/dev:
+ brw-rw-rw-       0 ram0
+ crw-rw-rw-       0 zero
+nsh&gt; dd if=/dev/zero of=/dev/ram0
+</pre></ul>
+  </li>
+  <li>
+    Read from a block devic, write to a character device.  This
+    will read the entire block device and dump the contents in
+    the bit bucket.
+  </li>
+<ul><pre>
+nsh&gt; ls -l /dev
+/dev:
+ crw-rw-rw-       0 null
+ brw-rw-rw-       0 ram0
+nsh&gt; dd if=/dev/ram0 of=/dev/null
+</pre></ul>
+  </li>
+</ol>
 
 <table width ="100%">
   <tr bgcolor="#e4e4e4">
diff --git a/drivers/bch/bchlib_read.c b/drivers/bch/bchlib_read.c
index 7af72ce8ad99cd373bf390752518ca527831664a..d2301d439263dc3f4fcaf31d5aaa0b16e3350b40 100644
--- a/drivers/bch/bchlib_read.c
+++ b/drivers/bch/bchlib_read.c
@@ -85,7 +85,7 @@
 
 ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t len)
 {
-  FAR struct bchlib_s *bch;
+  FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle;
   size_t nsectors;
   size_t sector;
   uint16 sectoffset;
@@ -202,135 +202,3 @@ ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t le
 
   return bytesread;
 }
-
-/****************************************************************************
- * Name: bchlib_write
- *
- * Description:
- *   Write to the block device set-up by bchlib_setup as if it were a character
- *   device.
- *
- ****************************************************************************/
-
-ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, size_t len)
-{
-  FAR struct bchlib_s *bch;
-  size_t nsectors;
-  size_t sector;
-  uint16 sectoffset;
-  size_t nbytes;
-  size_t byteswritten;
-  int    ret;
-
-  /* Get rid of this special case right away */
-
-  if (len < 1)
-    {
-      return 0;
-    }
-
-  /* Convert the file position into a sector number an offset. */
-
-  sector     = offset / bch->sectsize;
-  sectoffset = offset - sector * bch->sectsize;
-
-  if (sector >= bch->nsectors)
-    {
-      return -EFBIG;
-    }
-
-  /* Write the initial partial sector */
-
-  byteswritten = 0;
-  if (sectoffset > 0)
-    {
-      /* Read the full sector into the sector buffer */
-
-      bchlib_readsector(bch, sector);
-
-      /* Copy the tail end of the sector from the user buffer */
-
-      if (sectoffset + len > bch->sectsize)
-        {
-          nbytes = bch->sectsize - sectoffset;
-        }
-      else 
-        {
-          nbytes = len;
-        }
-
-      memcpy(&bch->buffer[sectoffset], buffer, nbytes);
-      bch->dirty = TRUE;
-
-      /* Adjust pointers and counts */
-
-      sectoffset    = 0;
-      sector++;
-
-      if (sector >= bch->nsectors)
-        {
-          return nbytes;
-        }
-
-      byteswritten  = nbytes;
-      buffer       += nbytes;
-      len          -= nbytes;
-    }
-
-  /* Then write all of the full sectors following the partial sector */
-
-  if (len >= bch->sectsize )
-    {
-      nsectors = len / bch->sectsize;
-      if (sector + nsectors > bch->nsectors)
-        {
-          nsectors = bch->nsectors - sector;
-        }
-
-      /* Write the contiguous sectors */
-
-      ret = bch->inode->u.i_bops->write(bch->inode, bch->buffer, sector, nsectors);
-      if (ret < 0)
-        {
-          fdbg("Write failed: %d\n");
-          return ret;
-        }
-
-      /* Adjust pointers and counts */
-
-      sectoffset    = 0;
-      sector       += nsectors;
-
-      nbytes        = nsectors * bch->sectsize;
-      byteswritten += nbytes;
-
-      if (sector >= bch->nsectors)
-        {
-          return byteswritten;
-        }
-
-      buffer    += nbytes;
-      len       -= nbytes;
-    }
-
-  /* Then write any partial final sector */
-
-  if (len > 0)
-    {
-      /* Read the sector into the sector buffer */
-
-      bchlib_readsector(bch, sector);
-
-      /* Copy the head end of the sector from the user buffer */
-
-      memcpy(bch->buffer, buffer, len);
-      bch->dirty = TRUE;
-
-      /* Adjust counts */
-
-      byteswritten += len;
-    }
-
-  return byteswritten;
-}
-
diff --git a/drivers/bch/bchlib_write.c b/drivers/bch/bchlib_write.c
index a897215ea4b343e9b13ff36a33470556e76b089b..ad0737faf35a3ee77acf02e1feda4c32c6a93773 100644
--- a/drivers/bch/bchlib_write.c
+++ b/drivers/bch/bchlib_write.c
@@ -85,7 +85,7 @@
 
 ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, size_t len)
 {
-  FAR struct bchlib_s *bch;
+  FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle;
   size_t nsectors;
   size_t sector;
   uint16 sectoffset;
diff --git a/examples/nsh/README.txt b/examples/nsh/README.txt
index 4b822e02e9ea4c88b0d3486e86e4ce64aa0f691a..9ea0464099371de9540576469c19f2399013a910 100644
--- a/examples/nsh/README.txt
+++ b/examples/nsh/README.txt
@@ -252,15 +252,38 @@ o cp <source-path> <dest-path>
 
 o dd if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>]
 
-  Copy blocks from <infile> to <outfile>.
+  Copy blocks from <infile> to <outfile>.  <nfile> or <outfile> may
+  be the path to a standard file, a character device, or a block device.
 
-  Example:
+  Examples:
+
+    1. Read from character device, write to regular file.  This will
+       create a new file of the specified size filled with zero.
 
     nsh> dd if=/dev/zero of=/tmp/zeros bs=64 count=16
     nsh> ls -l /tmp
     /tmp:
      -rw-rw-rw-    1024 ZEROS
 
+    2. Read from character device, write to block device.  This will
+       fill the entire block device with zeros.
+
+    nsh> ls -l /dev
+    /dev:
+     brw-rw-rw-       0 ram0
+     crw-rw-rw-       0 zero
+    nsh> dd if=/dev/zero of=/dev/ram0
+
+    3. Read from a block devic, write to a character device.  This
+       will read the entire block device and dump the contents in
+       the bit bucket.
+
+    nsh> ls -l /dev
+    /dev:
+     crw-rw-rw-       0 null
+     brw-rw-rw-       0 ram0
+    nsh> dd if=/dev/ram0 of=/dev/null
+
 o echo [<string|$name> [<string|$name>...]]
 
   Copy the sequence of strings and expanded environment variables to
diff --git a/examples/nsh/nsh_ddcmd.c b/examples/nsh/nsh_ddcmd.c
index 86f829f2be868df4d698dfc3f45a8fc9779b07ec..48cc822f101f6dfa18c9dfd00e593775607c903b 100644
--- a/examples/nsh/nsh_ddcmd.c
+++ b/examples/nsh/nsh_ddcmd.c
@@ -209,11 +209,24 @@ static int dd_writeblk(struct dd_s *dd)
   ssize_t nbytes;
   off_t   offset = (dd->sector - dd->skip) * dd->sectsize;
 
+  /* Write the sector at the specified offset */
+
   nbytes = bchlib_write(DD_OUTHANDLE, (char*)dd->buffer, offset, dd->sectsize);
   if (nbytes < 0)
     {
-      nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO);
-      return ERROR;
+      /* bchlib_write return -EFBIG on attempts to write past the end of
+       * the device.
+       */
+
+      if (nbytes == -EFBIG)
+        {
+          dd->eof = TRUE; /* Set end-of-file */
+        }
+      else
+        {
+          nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO_OF(-nbytes));
+          return ERROR;
+        }
     }
 
   return OK;
@@ -238,7 +251,7 @@ static int dd_writech(struct dd_s *dd)
       nbytes = write(DD_OUTFD, buffer, dd->sectsize - written);
       if (nbytes < 0)
         {
-           nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO);
+           nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO_OF(-nbytes));
            return ERROR;
         }
 
@@ -263,11 +276,14 @@ static int dd_readblk(struct dd_s *dd)
   nbytes = bchlib_read(DD_INHANDLE, (char*)dd->buffer, offset, dd->sectsize);
   if (nbytes < 0)
     {
-      nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_read", NSH_ERRNO);
+      nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_read", NSH_ERRNO_OF(-nbytes));
       return ERROR;
     }
 
+  /* bchlib_read return 0 on attempts to write past the end of the device. */
+
   dd->nbytes = nbytes;
+  dd->eof    = (nbytes == 0);
   return OK;
 }
 #endif
@@ -287,7 +303,7 @@ static int dd_readch(struct dd_s *dd)
       nbytes = read(DD_INFD, buffer, dd->sectsize - dd->nbytes);
       if (nbytes < 0)
         {
-           nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO);
+           nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO_OF(-nbytes));
            return ERROR;
         }
 
@@ -337,7 +353,7 @@ static inline int dd_infopen(const char *name, struct dd_s *dd)
   type = dd_filetype(name);
   if (type < 0)
     {
-      nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO);
+      nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO_OF(-type));
       return type;
     }
 
@@ -449,9 +465,9 @@ static inline int dd_outfopen(const char *name, struct dd_s *dd)
 int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
 {
   struct dd_s dd;
-  const char *infile = NULL;
-  const char *outfile = NULL;
-  int ret;
+  char *infile = NULL;
+  char *outfile = NULL;
+  int ret = ERROR;
   int i;
 
   /* Initialize the dd structure */
@@ -490,11 +506,11 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
     {
       if (strncmp(argv[i], "if=", 3) == 0)
         {
-          infile = &argv[i][3];
+          infile = nsh_getfullpath(vtbl, &argv[i][3]);
         }
       else if (strncmp(argv[i], "of=", 3) == 0)
         {
-          outfile = &argv[i][3];
+          outfile = nsh_getfullpath(vtbl, &argv[i][3]);
         }
       else if (strncmp(argv[i], "bs=", 3) == 0)
         {
@@ -514,14 +530,14 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
   if (!infile || !outfile)
     {
       nsh_output(vtbl, g_fmtargrequired, g_dd);
-      return ERROR;
+      goto errout_with_paths;
     }
 #endif
 
   if (dd.skip < 0 || dd.skip > dd.nsectors)
     {
       nsh_output(vtbl, g_fmtarginvalid, g_dd);
-      return ERROR;
+      goto errout_with_paths;
     }
 
   /* Allocate the I/O buffer */
@@ -530,7 +546,7 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
   if (!dd.buffer)
     {
       nsh_output(vtbl, g_fmtcmdoutofmemory, g_dd);
-      return ERROR;
+      goto errout_with_paths;
     }
 
   /* Open the input file */
@@ -538,7 +554,7 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
   ret = dd_infopen(infile, &dd);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_paths;
     }
 
   /* Open the output file */
@@ -562,38 +578,53 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
           goto errout_with_outf;
         }
 
-      /* Pad with zero if necessary (at the end of file only) */
+      /* Has the incoming data stream ended? */
 
-      for (i = dd.nbytes; i < dd.sectsize; i++)
+      if (!dd.eof)
         {
-          dd.buffer[i] = 0;
-        }
-
-      /* Write one sector to the output file */
+          /* Pad with zero if necessary (at the end of file only) */
 
-      if (dd.sector >= dd.skip)
-        {
-          ret = DD_WRITE(&dd);
-          if (ret < 0)
+          for (i = dd.nbytes; i < dd.sectsize; i++)
             {
-              goto errout_with_outf;
+              dd.buffer[i] = 0;
             }
 
-          /* Decrement to show that a sector was written */
+          /* Write one sector to the output file */
 
-          dd.nsectors--;
-        }
+          if (dd.sector >= dd.skip)
+            {
+              ret = DD_WRITE(&dd);
+              if (ret < 0)
+                {
+                  goto errout_with_outf;
+                }
+
+              /* Decrement to show that a sector was written */
 
-      /* Increment the sector number */
+              dd.nsectors--;
+            }
 
-      dd.sector++;
+          /* Increment the sector number */
+
+          dd.sector++;
+        }
     }
+  ret = OK;
 
 errout_with_outf:
   DD_INCLOSE(&dd);
 errout_with_inf:
   DD_OUTCLOSE(&dd);
   free(dd.buffer);
+errout_with_paths:
+  if (infile)
+    {
+      free(infile);
+    }
+  if (outfile)
+    {
+      free(outfile);
+    }
   return ret;
 }
 
diff --git a/include/nuttx/fs.h b/include/nuttx/fs.h
index 8a174b0117853075461c19e09c5832e3ec24dc46..ad979c5849daa4c89f9fa94033eefc1aec653a78 100644
--- a/include/nuttx/fs.h
+++ b/include/nuttx/fs.h
@@ -370,9 +370,10 @@ EXTERN int lib_flushall(FAR struct streamlist *list);
  * subdirectory
  */
 
-/* Register /dev/null */
+/* Register /dev/null and /dev/zero */
 
 EXTERN void devnull_register(void);
+EXTERN void devzero_register(void);
 
 /* Setup the loop device so that it exports the file referenced by 'filename'
  * as a block device.
@@ -382,12 +383,17 @@ EXTERN int losetup(const char *devname, const char *filename, uint16 sectsize,
                    off_t offset, boolean readonly);
 EXTERN int loteardown(const char *devname);
 
-/*   Setup so that the block driver referenced by 'blkdev' can be accessed
- *   similar to a character device.
+/* Setup so that the block driver referenced by 'blkdev' can be accessed
+ * similar to a character device.
+ *
+ * Access via a character device:
  */
 
 EXTERN int bchdev_register(const char *blkdev, const char *chardev, boolean readonly);
 EXTERN int bchdev_unregister(const char *chardev);
+
+/* Low level, direct access: */
+
 EXTERN int bchlib_setup(const char *blkdev, boolean readonly, FAR void **handle);
 EXTERN int bchlib_teardown(FAR void *handle);
 EXTERN ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t len);