Merge branch 'master' of git://www.denx.de/git/u-boot-usb
diff --git a/README b/README
index 8e19aebb..a70475f 100644
--- a/README
+++ b/README
@@ -1367,6 +1367,13 @@
 			for your device
 			- CONFIG_USBD_PRODUCTID 0xFFFF
 
+		Some USB device drivers may need to check USB cable attachment.
+		In this case you can enable following config in BoardName.h:
+			CONFIG_USB_CABLE_CHECK
+			This enables function definition:
+			- usb_cable_connected() in include/usb.h
+			Implementation of this function is board-specific.
+
 - ULPI Layer Support:
 		The ULPI (UTMI Low Pin (count) Interface) PHYs are supported via
 		the generic ULPI layer. The generic layer accesses the ULPI PHY
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile
index ca7032c..501d974 100644
--- a/board/samsung/common/Makefile
+++ b/board/samsung/common/Makefile
@@ -7,3 +7,4 @@
 
 obj-$(CONFIG_SOFT_I2C_MULTI_BUS) += multi_i2c.o
 obj-$(CONFIG_THOR_FUNCTION) += thor.o
+obj-$(CONFIG_CMD_USB_MASS_STORAGE) += ums.o
diff --git a/board/samsung/common/ums.c b/board/samsung/common/ums.c
new file mode 100644
index 0000000..dc155ad
--- /dev/null
+++ b/board/samsung/common/ums.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <usb_mass_storage.h>
+#include <part.h>
+
+static int ums_read_sector(struct ums *ums_dev,
+			   ulong start, lbaint_t blkcnt, void *buf)
+{
+	block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
+	lbaint_t blkstart = start + ums_dev->start_sector;
+	int dev_num = block_dev->dev;
+
+	return block_dev->block_read(dev_num, blkstart, blkcnt, buf);
+}
+
+static int ums_write_sector(struct ums *ums_dev,
+			    ulong start, lbaint_t blkcnt, const void *buf)
+{
+	block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
+	lbaint_t blkstart = start + ums_dev->start_sector;
+	int dev_num = block_dev->dev;
+
+	return block_dev->block_write(dev_num, blkstart, blkcnt, buf);
+}
+
+static struct ums ums_dev = {
+	.read_sector = ums_read_sector,
+	.write_sector = ums_write_sector,
+	.name = "UMS disk",
+};
+
+static struct ums *ums_disk_init(struct mmc *mmc)
+{
+	uint64_t mmc_end_sector = mmc->capacity / SECTOR_SIZE;
+	uint64_t ums_end_sector = UMS_NUM_SECTORS + UMS_START_SECTOR;
+
+	if (!mmc_end_sector) {
+		error("MMC capacity is not valid");
+		return NULL;
+	}
+
+	ums_dev.mmc = mmc;
+
+	if (ums_end_sector <= mmc_end_sector) {
+		ums_dev.start_sector = UMS_START_SECTOR;
+		if (UMS_NUM_SECTORS)
+			ums_dev.num_sectors = UMS_NUM_SECTORS;
+		else
+			ums_dev.num_sectors = mmc_end_sector - UMS_START_SECTOR;
+	} else {
+		ums_dev.num_sectors = mmc_end_sector;
+		puts("UMS: defined bad disk parameters. Using default.\n");
+	}
+
+	printf("UMS: disk start sector: %#x, count: %#x\n",
+	       ums_dev.start_sector, ums_dev.num_sectors);
+
+	return &ums_dev;
+}
+
+struct ums *ums_init(unsigned int dev_num)
+{
+	struct mmc *mmc = NULL;
+
+	mmc = find_mmc_device(dev_num);
+	if (!mmc)
+		return NULL;
+
+	return ums_disk_init(mmc);
+}
diff --git a/board/samsung/trats/trats.c b/board/samsung/trats/trats.c
index d31d511..7012c13 100644
--- a/board/samsung/trats/trats.c
+++ b/board/samsung/trats/trats.c
@@ -772,65 +772,3 @@
 
 	setenv("lcdinfo", "lcd=s6e8ax0");
 }
-
-#ifdef CONFIG_USB_GADGET_MASS_STORAGE
-static int ums_read_sector(struct ums_device *ums_dev,
-			   ulong start, lbaint_t blkcnt, void *buf)
-{
-	if (ums_dev->mmc->block_dev.block_read(ums_dev->dev_num,
-			start + ums_dev->offset, blkcnt, buf) != blkcnt)
-		return -1;
-
-	return 0;
-}
-
-static int ums_write_sector(struct ums_device *ums_dev,
-			    ulong start, lbaint_t blkcnt, const void *buf)
-{
-	if (ums_dev->mmc->block_dev.block_write(ums_dev->dev_num,
-			start + ums_dev->offset, blkcnt, buf) != blkcnt)
-		return -1;
-
-	return 0;
-}
-
-static void ums_get_capacity(struct ums_device *ums_dev,
-			     long long int *capacity)
-{
-	long long int tmp_capacity;
-
-	tmp_capacity = (long long int) ((ums_dev->offset + ums_dev->part_size)
-					* SECTOR_SIZE);
-	*capacity = ums_dev->mmc->capacity - tmp_capacity;
-}
-
-static struct ums_board_info ums_board = {
-	.read_sector = ums_read_sector,
-	.write_sector = ums_write_sector,
-	.get_capacity = ums_get_capacity,
-	.name = "TRATS UMS disk",
-	.ums_dev = {
-		.mmc = NULL,
-		.dev_num = 0,
-		.offset = 0,
-		.part_size = 0.
-	},
-};
-
-struct ums_board_info *board_ums_init(unsigned int dev_num, unsigned int offset,
-				      unsigned int part_size)
-{
-	struct mmc *mmc;
-
-	mmc = find_mmc_device(dev_num);
-	if (!mmc)
-		return NULL;
-
-	ums_board.ums_dev.mmc = mmc;
-	ums_board.ums_dev.dev_num = dev_num;
-	ums_board.ums_dev.offset = offset;
-	ums_board.ums_dev.part_size = part_size;
-
-	return &ums_board;
-}
-#endif
diff --git a/common/cmd_usb_mass_storage.c b/common/cmd_usb_mass_storage.c
index f583caf..99487f4 100644
--- a/common/cmd_usb_mass_storage.c
+++ b/common/cmd_usb_mass_storage.c
@@ -5,6 +5,7 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#include <errno.h>
 #include <common.h>
 #include <command.h>
 #include <g_dnl.h>
@@ -20,55 +21,49 @@
 	const char *usb_controller = argv[1];
 	const char *mmc_devstring  = argv[2];
 
-	unsigned int dev_num = (unsigned int)(simple_strtoul(mmc_devstring,
-				NULL, 0));
-	if (dev_num) {
-		error("Set eMMC device to 0! - e.g. ums 0");
-		goto fail;
-	}
+	unsigned int dev_num = simple_strtoul(mmc_devstring, NULL, 0);
+
+	struct ums *ums = ums_init(dev_num);
+	if (!ums)
+		return CMD_RET_FAILURE;
 
 	unsigned int controller_index = (unsigned int)(simple_strtoul(
 					usb_controller,	NULL, 0));
 	if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
 		error("Couldn't init USB controller.");
-		goto fail;
-	}
-
-	struct ums_board_info *ums_info = board_ums_init(dev_num, 0, 0);
-	if (!ums_info) {
-		error("MMC: %d -> NOT available", dev_num);
-		goto fail;
+		return CMD_RET_FAILURE;
 	}
 
-	int rc = fsg_init(ums_info);
+	int rc = fsg_init(ums);
 	if (rc) {
 		error("fsg_init failed");
-		goto fail;
+		return CMD_RET_FAILURE;
 	}
 
 	g_dnl_register("ums");
 
 	while (1) {
-		/* Handle control-c and timeouts */
-		if (ctrlc()) {
-			error("The remote end did not respond in time.");
-			goto exit;
-		}
-
 		usb_gadget_handle_interrupts();
-		/* Check if USB cable has been detached */
-		if (fsg_main_thread(NULL) == EIO)
+
+		rc = fsg_main_thread(NULL);
+		if (rc) {
+			/* Check I/O error */
+			if (rc == -EIO)
+				printf("\rCheck USB cable connection\n");
+
+			/* Check CTRL+C */
+			if (rc == -EPIPE)
+				printf("\rCTRL+C - Operation aborted\n");
+
 			goto exit;
+		}
 	}
 exit:
 	g_dnl_unregister();
-	return 0;
-
-fail:
-	return -1;
+	return CMD_RET_SUCCESS;
 }
 
 U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage,
 	"Use the UMS [User Mass Storage]",
-	"<USB_controller> <mmc_dev>"
+	"ums <USB_controller> <mmc_dev>  e.g. ums 0 0"
 );
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 4a8804e..1eb92e5 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -229,6 +229,7 @@
 			dfu->crc = crc32(dfu->crc, buf, chunk);
 			dfu->i_buf += chunk;
 			dfu->b_left -= chunk;
+			dfu->r_left -= chunk;
 			size -= chunk;
 			buf += chunk;
 			readn += chunk;
@@ -287,7 +288,7 @@
 		dfu->offset = 0;
 		dfu->i_buf_end = dfu_get_buf() + dfu_buf_size;
 		dfu->i_buf = dfu->i_buf_start;
-		dfu->b_left = 0;
+		dfu->b_left = min(dfu_buf_size, dfu->r_left);
 
 		dfu->bad_skip = 0;
 
diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c
index edbf5a9..2d07097 100644
--- a/drivers/dfu/dfu_nand.c
+++ b/drivers/dfu/dfu_nand.c
@@ -121,6 +121,7 @@
 
 	switch (dfu->layout) {
 	case DFU_RAW_ADDR:
+		*len = dfu->data.nand.size;
 		ret = nand_block_read(dfu, offset, buf, len);
 		break;
 	default:
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 6ecdea3..b1fe8bd 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -243,6 +243,7 @@
 #include <config.h>
 #include <malloc.h>
 #include <common.h>
+#include <usb.h>
 
 #include <linux/err.h>
 #include <linux/usb/ch9.h>
@@ -441,7 +442,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-struct ums_board_info			*ums_info;
+struct ums *ums;
 struct fsg_common *the_fsg_common;
 
 static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
@@ -675,6 +676,18 @@
 			k++;
 		}
 
+		if (k == 10) {
+			/* Handle CTRL+C */
+			if (ctrlc())
+				return -EPIPE;
+#ifdef CONFIG_USB_CABLE_CHECK
+			/* Check cable connection */
+			if (!usb_cable_connected())
+				return -EIO;
+#endif
+			k = 0;
+		}
+
 		usb_gadget_handle_interrupts();
 	}
 	common->thread_wakeup_needed = 0;
@@ -757,14 +770,14 @@
 		}
 
 		/* Perform the read */
-		nread = 0;
-		rc = ums_info->read_sector(&(ums_info->ums_dev),
-					   file_offset / SECTOR_SIZE,
-					   amount / SECTOR_SIZE,
-					   (char __user *)bh->buf);
-		if (rc)
+		rc = ums->read_sector(ums,
+				      file_offset / SECTOR_SIZE,
+				      amount / SECTOR_SIZE,
+				      (char __user *)bh->buf);
+		if (!rc)
 			return -EIO;
-		nread = amount;
+
+		nread = rc * SECTOR_SIZE;
 
 		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
 				(unsigned long long) file_offset,
@@ -931,13 +944,13 @@
 			amount = bh->outreq->actual;
 
 			/* Perform the write */
-			rc = ums_info->write_sector(&(ums_info->ums_dev),
+			rc = ums->write_sector(ums,
 					       file_offset / SECTOR_SIZE,
 					       amount / SECTOR_SIZE,
 					       (char __user *)bh->buf);
-			if (rc)
+			if (!rc)
 				return -EIO;
-			nwritten = amount;
+			nwritten = rc * SECTOR_SIZE;
 
 			VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
 					(unsigned long long) file_offset,
@@ -959,6 +972,8 @@
 
 			/* If an error occurred, report it and its position */
 			if (nwritten < amount) {
+				printf("nwritten:%d amount:%d\n", nwritten,
+				       amount);
 				curlun->sense_data = SS_WRITE_ERROR;
 				curlun->info_valid = 1;
 				break;
@@ -1045,14 +1060,13 @@
 		}
 
 		/* Perform the read */
-		nread = 0;
-		rc = ums_info->read_sector(&(ums_info->ums_dev),
-					   file_offset / SECTOR_SIZE,
-					   amount / SECTOR_SIZE,
-					   (char __user *)bh->buf);
-		if (rc)
+		rc = ums->read_sector(ums,
+				      file_offset / SECTOR_SIZE,
+				      amount / SECTOR_SIZE,
+				      (char __user *)bh->buf);
+		if (!rc)
 			return -EIO;
-		nread = amount;
+		nread = rc * SECTOR_SIZE;
 
 		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
 				(unsigned long long) file_offset,
@@ -1100,7 +1114,7 @@
 	buf[4] = 31;		/* Additional length */
 				/* No special options */
 	sprintf((char *) (buf + 8), "%-8s%-16s%04x", (char*) vendor_id ,
-			ums_info->name, (u16) 0xffff);
+			ums->name, (u16) 0xffff);
 
 	return 36;
 }
@@ -2386,6 +2400,7 @@
 
 int fsg_main_thread(void *common_)
 {
+	int ret;
 	struct fsg_common	*common = the_fsg_common;
 	/* The main loop */
 	do {
@@ -2395,12 +2410,16 @@
 		}
 
 		if (!common->running) {
-			sleep_thread(common);
+			ret = sleep_thread(common);
+			if (ret)
+				return ret;
+
 			continue;
 		}
 
-		if (get_next_command(common))
-			continue;
+		ret = get_next_command(common);
+		if (ret)
+			return ret;
 
 		if (!exception_in_progress(common))
 			common->state = FSG_STATE_DATA_PHASE;
@@ -2753,9 +2772,9 @@
 	return fsg_bind_config(c->cdev, c, fsg_common);
 }
 
-int fsg_init(struct ums_board_info *ums)
+int fsg_init(struct ums *ums_dev)
 {
-	ums_info = ums;
+	ums = ums_dev;
 
 	return 0;
 }
diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
index 43f413a..8dc3d9f 100644
--- a/drivers/usb/gadget/g_dnl.c
+++ b/drivers/usb/gadget/g_dnl.c
@@ -33,6 +33,9 @@
 #define STRING_PRODUCT 2
 /* Index of String Descriptor describing this configuration */
 #define STRING_USBDOWN 2
+/* Index of String serial */
+#define STRING_SERIAL  3
+#define MAX_STRING_SERIAL	32
 /* Number of supported configurations */
 #define CONFIGURATION_NUMBER 1
 
@@ -40,8 +43,16 @@
 
 static const char shortname[] = "usb_dnl_";
 static const char product[] = "USB download gadget";
+static char g_dnl_serial[MAX_STRING_SERIAL];
 static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
 
+void g_dnl_set_serialnumber(char *s)
+{
+	memset(g_dnl_serial, 0, MAX_STRING_SERIAL);
+	if (strlen(s) < MAX_STRING_SERIAL)
+		strncpy(g_dnl_serial, s, strlen(s));
+}
+
 static struct usb_device_descriptor device_desc = {
 	.bLength = sizeof device_desc,
 	.bDescriptorType = USB_DT_DEVICE,
@@ -53,6 +64,7 @@
 	.idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM),
 	.idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM),
 	.iProduct = STRING_PRODUCT,
+	.iSerialNumber = STRING_SERIAL,
 	.bNumConfigurations = 1,
 };
 
@@ -63,6 +75,7 @@
 static struct usb_string g_dnl_string_defs[] = {
 	{.s = manufacturer},
 	{.s = product},
+	{.s = g_dnl_serial},
 	{ }		/* end of list */
 };
 
@@ -156,6 +169,13 @@
 	g_dnl_string_defs[1].id = id;
 	device_desc.iProduct = id;
 
+	id = usb_string_id(cdev);
+	if (id < 0)
+		return id;
+
+	g_dnl_string_defs[2].id = id;
+	device_desc.iSerialNumber = id;
+
 	g_dnl_bind_fixup(&device_desc, cdev->driver->name);
 	ret = g_dnl_config_register(cdev);
 	if (ret)
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 866e7c7..02803df 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -275,7 +275,6 @@
 #define ETOOSMALL	525
 
 #include <usb_mass_storage.h>
-extern struct ums_board_info		*ums_info;
 
 /*-------------------------------------------------------------------------*/
 
@@ -573,36 +572,16 @@
 static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 {
 	int				ro;
-	int				rc = -EINVAL;
-	loff_t				size;
-	loff_t				num_sectors;
-	loff_t				min_sectors;
 
 	/* R/W if we can, R/O if we must */
 	ro = curlun->initially_ro;
 
-	ums_info->get_capacity(&(ums_info->ums_dev), &size);
-	if (size < 0) {
-		printf("unable to find file size: %s\n", filename);
-		rc = (int) size;
-		goto out;
-	}
-	num_sectors = size >> 9;	/* File size in 512-byte blocks */
-	min_sectors = 1;
-	if (num_sectors < min_sectors) {
-		printf("file too small: %s\n", filename);
-		rc = -ETOOSMALL;
-		goto out;
-	}
-
 	curlun->ro = ro;
-	curlun->file_length = size;
-	curlun->num_sectors = num_sectors;
+	curlun->file_length = ums->num_sectors << 9;
+	curlun->num_sectors = ums->num_sectors;
 	debug("open backing file: %s\n", filename);
-	rc = 0;
 
-out:
-	return rc;
+	return 0;
 }
 
 static void fsg_lun_close(struct fsg_lun *curlun)
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 4ed07da..219d182 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1548,7 +1548,7 @@
 	}
 
 	dev->status = stat;
-	dev->act_len = transfer_len;
+	dev->act_len = urb->actual_length;
 
 #ifdef DEBUG
 	pkt_print(urb, dev, pipe, buffer, transfer_len,
diff --git a/include/configs/trats.h b/include/configs/trats.h
index 6ed3313..3d080c4 100644
--- a/include/configs/trats.h
+++ b/include/configs/trats.h
@@ -321,9 +321,7 @@
 #define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE ((500 * 120 * 4) + (1 << 12))
 
 #define CONFIG_CMD_USB_MASS_STORAGE
-#if defined(CONFIG_CMD_USB_MASS_STORAGE)
 #define CONFIG_USB_GADGET_MASS_STORAGE
-#endif
 
 /* Pass open firmware flat tree */
 #define CONFIG_OF_LIBFDT    1
diff --git a/include/g_dnl.h b/include/g_dnl.h
index de669fb..8f813c2 100644
--- a/include/g_dnl.h
+++ b/include/g_dnl.h
@@ -13,5 +13,6 @@
 int g_dnl_bind_fixup(struct usb_device_descriptor *, const char *);
 int g_dnl_register(const char *s);
 void g_dnl_unregister(void);
+void g_dnl_set_serialnumber(char *);
 
 #endif /* __G_DOWNLOAD_H_ */
diff --git a/include/usb.h b/include/usb.h
index d9fedee..736730e 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -197,6 +197,16 @@
  */
 int board_usb_cleanup(int index, enum usb_init_type init);
 
+/*
+ * If CONFIG_USB_CABLE_CHECK is set then this function
+ * should be defined in board file.
+ *
+ * @return 1 if cable is connected and 0 otherwise.
+ */
+#ifdef CONFIG_USB_CABLE_CHECK
+int usb_cable_connected(void);
+#endif
+
 #ifdef CONFIG_USB_STORAGE
 
 #define USB_MAX_STOR_DEV 5
diff --git a/include/usb_mass_storage.h b/include/usb_mass_storage.h
index 13f535c..9df3adc 100644
--- a/include/usb_mass_storage.h
+++ b/include/usb_mass_storage.h
@@ -9,32 +9,33 @@
 #define __USB_MASS_STORAGE_H__
 
 #define SECTOR_SIZE		0x200
-
 #include <mmc.h>
 #include <linux/usb/composite.h>
 
-struct ums_device {
-	struct mmc *mmc;
-	int dev_num;
-	int offset;
-	int part_size;
-};
+#ifndef UMS_START_SECTOR
+#define UMS_START_SECTOR	0
+#endif
 
-struct ums_board_info {
-	int (*read_sector)(struct ums_device *ums_dev,
+#ifndef UMS_NUM_SECTORS
+#define UMS_NUM_SECTORS		0
+#endif
+
+struct ums {
+	int (*read_sector)(struct ums *ums_dev,
 			   ulong start, lbaint_t blkcnt, void *buf);
-	int (*write_sector)(struct ums_device *ums_dev,
+	int (*write_sector)(struct ums *ums_dev,
 			    ulong start, lbaint_t blkcnt, const void *buf);
-	void (*get_capacity)(struct ums_device *ums_dev,
-			     long long int *capacity);
+	unsigned int start_sector;
+	unsigned int num_sectors;
 	const char *name;
-	struct ums_device ums_dev;
+	struct mmc *mmc;
 };
 
-int fsg_init(struct ums_board_info *);
+extern struct ums *ums;
+
+int fsg_init(struct ums *);
 void fsg_cleanup(void);
-struct ums_board_info *board_ums_init(unsigned int, unsigned int,
-				      unsigned int);
+struct ums *ums_init(unsigned int);
 int fsg_main_thread(void *);
 
 #ifdef CONFIG_USB_GADGET_MASS_STORAGE