diff --git a/nandwrite.c b/nandwrite.c
index b7cd72e..fc23e85 100644
--- a/nandwrite.c
+++ b/nandwrite.c
@@ -24,6 +24,8 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -74,7 +76,7 @@ static struct nand_oobinfo autoplace_oobinfo = {
 static void display_help (void)
 {
 	printf(
-"Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
+"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
 "Writes to the specified MTD device.\n"
 "\n"
 "  -a, --autoplace         Use auto oob layout\n"
@@ -110,6 +112,7 @@ static void display_version (void)
 	exit (EXIT_SUCCESS);
 }
 
+static const char	*standard_input = "-";
 static const char	*mtd_device, *img;
 static int		mtdoffset = 0;
 static bool		quiet = false;
@@ -198,16 +201,46 @@ static void process_options (int argc, char * const argv[])
 				blockalign = atoi (optarg);
 				break;
 			case '?':
-				error = 1;
+				error++;
 				break;
 		}
 	}
 
-	if ((argc - optind) != 2 || error)
+	if (mtdoffset < 0) {
+		fprintf(stderr, "Can't specify a negative device offset `%d'\n",
+				mtdoffset);
+		exit (EXIT_FAILURE);
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * There must be at least the MTD device node positional
+	 * argument remaining and, optionally, the input file.
+	 */
+
+	if (argc < 1 || argc > 2 || error)
 		display_help ();
 
-	mtd_device = argv[optind++];
-	img = argv[optind];
+	mtd_device = argv[0];
+
+	/*
+	 * Standard input may be specified either explictly as "-" or
+	 * implicity by simply omitting the second of the two
+	 * positional arguments.
+	 */
+
+	img = ((argc == 2) ? argv[1] : standard_input);
+}
+
+static void erase_buffer(void *buffer, size_t size)
+{
+	const uint8_t kEraseByte = 0xff;
+
+	if (buffer != NULL && size > 0) {
+		memset(buffer, kEraseByte, size);
+	}
 }
 
 /*
@@ -215,8 +248,12 @@ static void process_options (int argc, char * const argv[])
  */
 int main(int argc, char * const argv[])
 {
-	int cnt, fd, ifd, imglen = 0, pagelen, blockstart = -1;
+	int cnt = 0;
+	int fd = -1;
+	int ifd = -1;
+	int imglen = 0, pagelen;
 	bool baderaseblock = false;
+	int blockstart = -1;
 	struct mtd_info_user meminfo;
 	struct mtd_oob_buf oob;
 	loff_t offs;
@@ -226,7 +263,7 @@ int main(int argc, char * const argv[])
 
 	process_options(argc, argv);
 
-	memset(oobbuf, 0xff, sizeof(oobbuf));
+	erase_buffer(oobbuf, sizeof(oobbuf));
 
 	if (pad && writeoob) {
 		fprintf(stderr, "Can't pad when oob data is present.\n");
@@ -340,21 +377,48 @@ int main(int argc, char * const argv[])
 	oob.length = meminfo.oobsize;
 	oob.ptr = noecc ? oobreadbuf : oobbuf;
 
-	/* Open the input file */
-	if ((ifd = open(img, O_RDONLY)) == -1) {
+	/* Determine if we are reading from standard input or from a file. */
+	if (strcmp(img, standard_input) == 0) {
+		ifd = STDIN_FILENO;
+	} else {
+		ifd = open(img, O_RDONLY);
+	}
+
+	if (ifd == -1) {
 		perror(img);
 		goto restoreoob;
 	}
 
-	// get image length
-	imglen = lseek(ifd, 0, SEEK_END);
-	lseek (ifd, 0, SEEK_SET);
+	/* For now, don't allow writing oob when reading from standard input. */
+	if (ifd == STDIN_FILENO && writeoob) {
+		fprintf(stderr, "Can't write oob when reading from standard input.\n");
+		goto closeall;
+	}
 
 	pagelen = meminfo.writesize + ((writeoob) ? meminfo.oobsize : 0);
 
-	// Check, if file is pagealigned
+	/*
+	 * For the standard input case, the input size is merely an
+	 * invariant placeholder and is set to the write page
+	 * size. Otherwise, just use the input file size.
+	 *
+	 * TODO: Add support for the -l,--length=length option (see
+	 * previous discussion by Tommi Airikka <tommi.airikka@ericsson.com> at
+	 * <http://lists.infradead.org/pipermail/linux-mtd/2008-September/
+	 * 022913.html>
+	 */
+
+	if (ifd == STDIN_FILENO) {
+	    imglen = pagelen;
+	} else {
+	    imglen = lseek(ifd, 0, SEEK_END);
+	    lseek (ifd, 0, SEEK_SET);
+	}
+
+	// Check, if file is page-aligned
 	if ((!pad) && ((imglen % pagelen) != 0)) {
-		fprintf (stderr, "Input file is not page aligned\n");
+		fprintf (stderr, "Input file is not page-aligned. Use the padding "
+				 "option.\n");
 		goto closeall;
 	}
 
@@ -366,7 +430,13 @@ int main(int argc, char * const argv[])
 		goto closeall;
 	}
 
-	/* Get data from input and write to the device */
+	/*
+	 * Get data from input and write to the device while there is
+	 * still input to read and we are still within the device
+	 * bounds. Note that in the case of standard input, the input
+	 * length is simply a quasi-boolean flag whose values are page
+	 * length or zero.
+	 */
 	while (imglen && (mtdoffset < meminfo.size)) {
 		// new eraseblock , check for bad block(s)
 		// Stay in the loop to be sure if the mtdoffset changes because
@@ -379,7 +449,8 @@ int main(int argc, char * const argv[])
 			offs = blockstart;
 			baderaseblock = false;
 			if (!quiet)
-				fprintf (stdout, "Writing data to block %x\n", blockstart);
+				fprintf (stdout, "Writing data to block %d at offset 0x%x\n",
+						 blockstart / meminfo.erasesize, blockstart);
 
 			/* Check all the blocks in an erase block for bad blocks */
 			do {
@@ -404,18 +475,50 @@ int main(int argc, char * const argv[])
 		}
 
 		readlen = meminfo.writesize;
-		if (pad && (imglen < readlen))
-		{
-			readlen = imglen;
-			memset(writebuf + readlen, 0xff, meminfo.writesize - readlen);
-		}
 
-		/* Read Page Data from input file */
-		if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
-			if (cnt == 0)	// EOF
+		if (ifd != STDIN_FILENO) {
+			if (pad && (imglen < readlen))
+			{
+				readlen = imglen;
+				erase_buffer(writebuf + readlen, meminfo.writesize - readlen);
+			}
+
+			/* Read Page Data from input file */
+			if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
+				if (cnt == 0)	// EOF
+					break;
+				perror ("File I/O error on input file");
+				goto closeall;
+			}
+		} else {
+			int tinycnt = 0;
+
+			while(tinycnt < readlen) {
+				cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
+				if (cnt == 0) { // EOF
+					break;
+				} else if (cnt < 0) {
+					perror ("File I/O error on stdin");
+					goto closeall;
+				}
+				tinycnt += cnt;
+			}
+
+			/* No padding needed - we are done */
+			if (tinycnt == 0) {
+				imglen = 0;
 				break;
-			perror ("File I/O error on input file");
-			goto closeall;
+			}
+
+			/* No more bytes - we are done after writing the remaining bytes */
+			if (cnt == 0) {
+				imglen = 0;
+			}
+
+			/* Padding */
+			if (pad && (tinycnt < readlen)) {
+				erase_buffer(writebuf + tinycnt, meminfo.writesize - tinycnt);
+			}
 		}
 
 		if (writeoob) {
@@ -499,7 +602,9 @@ int main(int argc, char * const argv[])
 
 			continue;
 		}
-		imglen -= readlen;
+		if (ifd != STDIN_FILENO) {
+			imglen -= readlen;
+		}
 		mtdoffset += meminfo.writesize;
 	}
 
@@ -517,7 +622,7 @@ restoreoob:
 
 	close(fd);
 
-	if (imglen > 0) {
+	if ((ifd != STDIN_FILENO) && (imglen > 0)) {
 		perror ("Data was only partially written due to error\n");
 		exit (EXIT_FAILURE);
 	}
