diff mbox

[U-Boot,RFC,4/7] dm: usb: WIP sandbox USB implementation

Message ID 1422644697-3735-5-git-send-email-sjg@chromium.org
State RFC
Delegated to: Marek Vasut
Headers show

Commit Message

Simon Glass Jan. 30, 2015, 7:04 p.m. UTC
This shows the basic approach with a new directory containing sandbox
emulations of USB devices for testing. So far hubs are not supported.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 Makefile                             |   1 +
 arch/sandbox/dts/sandbox.dts         |  20 +++++
 arch/sandbox/include/asm/processor.h |   0
 drivers/usb/dev/Makefile             |  10 +++
 drivers/usb/dev/sandbox-flash.c      |  95 ++++++++++++++++++++++
 drivers/usb/dev/sandbox-hub.c        | 116 +++++++++++++++++++++++++++
 drivers/usb/dev/usb-emul-uclass.c    |  16 ++++
 drivers/usb/host/Makefile            |   3 +
 drivers/usb/host/usb-sandbox.c       | 151 +++++++++++++++++++++++++++++++++++
 include/configs/sandbox.h            |   3 +
 include/dm/uclass-id.h               |   1 +
 include/usb_defs.h                   |  14 ++--
 12 files changed, 424 insertions(+), 6 deletions(-)
 create mode 100644 arch/sandbox/include/asm/processor.h
 create mode 100644 drivers/usb/dev/Makefile
 create mode 100644 drivers/usb/dev/sandbox-flash.c
 create mode 100644 drivers/usb/dev/sandbox-hub.c
 create mode 100644 drivers/usb/dev/usb-emul-uclass.c
 create mode 100644 drivers/usb/host/usb-sandbox.c
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 9b406c8..836d93b 100644
--- a/Makefile
+++ b/Makefile
@@ -632,6 +632,7 @@  libs-y += drivers/spi/
 libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
 libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
 libs-y += drivers/serial/
+libs-y += drivers/usb/dev/
 libs-y += drivers/usb/eth/
 libs-y += drivers/usb/gadget/
 libs-y += drivers/usb/host/
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 9ce31bf..7d22920 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -181,4 +181,24 @@ 
 		};
 	};
 
+	usb@0 {
+		compatible = "sandbox,usb";
+		status = "disabled";
+		flash-stick {
+			compatible = "sandbox,usb-flash";
+		};
+	};
+
+	usb@1 {
+		compatible = "sandbox,usb";
+		flash-stick {
+			compatible = "sandbox,usb-hub";
+		};
+	};
+
+	usb@2 {
+		compatible = "sandbox,usb";
+		status = "disabled";
+	};
+
 };
diff --git a/arch/sandbox/include/asm/processor.h b/arch/sandbox/include/asm/processor.h
new file mode 100644
index 0000000..e69de29
diff --git a/drivers/usb/dev/Makefile b/drivers/usb/dev/Makefile
new file mode 100644
index 0000000..a741f45
--- /dev/null
+++ b/drivers/usb/dev/Makefile
@@ -0,0 +1,10 @@ 
+#
+# (C) Copyright 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_SANDBOX) += sandbox-flash.o
+obj-$(CONFIG_SANDBOX) += sandbox-hub.o
+obj-$(CONFIG_SANDBOX) += usb-emul-uclass.o
diff --git a/drivers/usb/dev/sandbox-flash.c b/drivers/usb/dev/sandbox-flash.c
new file mode 100644
index 0000000..51aec69
--- /dev/null
+++ b/drivers/usb/dev/sandbox-flash.c
@@ -0,0 +1,95 @@ 
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#define DEBUG
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+
+enum {
+	STRINGID_null,
+	STRINGID_manufacterer,
+	STRINGID_product,
+	STRINGID_serial,
+
+	STRINGID_count,
+};
+
+static char *usb_strings[] = {
+	"",
+	"sandbox",
+	"flash_emulator",
+	"1234",
+	NULL,
+};
+
+static int sandbox_flash_submit_control_msg(struct udevice *dev,
+					    unsigned long pipe,
+					    void *buffer, int length,
+					    struct devrequest *setup)
+{
+	struct usb_device *udev = dev_get_uclass_priv(dev);
+
+	if (pipe == usb_rcvctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case USB_REQ_GET_DESCRIPTOR:
+			memcpy(buffer, &udev->descriptor, length);
+			udev->status = 0;
+			udev->act_len = length;
+			return 0;
+		default:
+			debug("request=%x\n", setup->request);
+			break;
+		}
+	}
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+static int sandbox_flash_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_uclass_priv(dev);
+	struct usb_device_descriptor *desc;
+	struct usb_config_descriptor *cdesc;
+
+	udev->strings = usb_strings;
+	desc = &udev->descriptor;
+	desc->iManufacturer = STRINGID_manufacterer;
+	desc->iProduct = STRINGID_product;
+	desc->iSerialNumber = STRINGID_serial;
+
+	udev->maxpacketsize = PACKET_SIZE_64;
+
+	cdesc = &udev->config.desc;
+	cdesc->bLength = sizeof(*cdesc);
+	cdesc->bDescriptorType = USB_DT_CONFIG;
+	cdesc->wTotalLength = 100;
+	cdesc->bNumInterfaces = 1;
+	cdesc->bConfigurationValue = 1;
+	cdesc->iConfiguration = 0;
+	cdesc->bmAttributes = 1 << 7;
+	cdesc->bMaxPower = 50;
+
+	return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_flash_ops = {
+	.submit_control_msg	= sandbox_flash_submit_control_msg,
+};
+
+static const struct udevice_id sandbox_usb_flash_ids[] = {
+	{ .compatible = "sandbox,usb-flash" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox_flash) = {
+	.name	= "usb_sandbox_flash",
+	.id	= UCLASS_USB_EMUL,
+	.of_match = sandbox_usb_flash_ids,
+	.probe = sandbox_flash_probe,
+	.ops	= &sandbox_usb_flash_ops,
+};
diff --git a/drivers/usb/dev/sandbox-hub.c b/drivers/usb/dev/sandbox-hub.c
new file mode 100644
index 0000000..60ef64a
--- /dev/null
+++ b/drivers/usb/dev/sandbox-hub.c
@@ -0,0 +1,116 @@ 
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#define DEBUG
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+
+enum {
+	STRING_null,
+	STRING_MANUFACTURER,
+	STRING_PRODUCT,
+	STRING_SERIAL,
+
+	STRING_count,
+};
+
+static char *usb_strings[] = {
+	"",
+	"sandbox",
+	"hub",
+	"2345",
+	NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+	.bLength =		sizeof(device_desc),
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+
+	.bDeviceClass =		USB_CLASS_HUB,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
+
+	.idVendor =		__constant_cpu_to_le16(0x1234),
+	.idProduct =		__constant_cpu_to_le16(0x5678),
+	.iManufacturer =	STRING_MANUFACTURER,
+	.iProduct =		STRING_PRODUCT,
+	.iSerialNumber =	STRING_SERIAL,
+	.bNumConfigurations =	1,
+};
+
+static const struct usb_descriptor_header hub_desc[] = {
+};
+
+static int sandbox_hub_submit_control_msg(struct udevice *dev,
+					  unsigned long pipe,
+					  void *buffer, int length,
+					  struct devrequest *setup)
+{
+	struct usb_device *udev = dev_get_uclass_priv(dev);
+
+	if (pipe == usb_rcvctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case USB_REQ_GET_DESCRIPTOR:
+			memcpy(buffer, &udev->descriptor, length);
+			udev->status = 0;
+			udev->act_len = length;
+			return 0;
+		default:
+			debug("request=%x\n", setup->request);
+			break;
+		}
+	}
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+static int sandbox_hub_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_uclass_priv(dev);
+	struct usb_device_descriptor *desc;
+	struct usb_config_descriptor *cdesc;
+
+	udev->strings = usb_strings;
+	desc = &udev->descriptor;
+	desc->iManufacturer = STRING_MANUFACTURER;
+	desc->iProduct = STRING_PRODUCT;
+	desc->iSerialNumber = STRING_SERIAL;
+
+	udev->maxpacketsize = PACKET_SIZE_64;
+
+	cdesc = &udev->config.desc;
+	cdesc->bLength = sizeof(*cdesc);
+	cdesc->bDescriptorType = USB_DT_CONFIG;
+	cdesc->wTotalLength = 100;
+	cdesc->bNumInterfaces = 1;
+	cdesc->bConfigurationValue = 1;
+	cdesc->iConfiguration = 0;
+	cdesc->bmAttributes = 1 << 7;
+	cdesc->bMaxPower = 50;
+
+	return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_hub_ops = {
+	.submit_control_msg	= sandbox_hub_submit_control_msg,
+};
+
+static const struct udevice_id sandbox_usb_hub_ids[] = {
+	{ .compatible = "sandbox,usb-hub" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox_hub) = {
+	.name	= "usb_sandbox_hub",
+	.id	= UCLASS_USB_EMUL,
+	.of_match = sandbox_usb_hub_ids,
+	.probe = sandbox_hub_probe,
+	.ops	= &sandbox_usb_hub_ops,
+};
diff --git a/drivers/usb/dev/usb-emul-uclass.c b/drivers/usb/dev/usb-emul-uclass.c
new file mode 100644
index 0000000..4114df0
--- /dev/null
+++ b/drivers/usb/dev/usb-emul-uclass.c
@@ -0,0 +1,16 @@ 
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+
+UCLASS_DRIVER(usb_emul) = {
+	.id		= UCLASS_USB_EMUL,
+	.name		= "usb_emul",
+	.per_device_auto_alloc_size = sizeof(struct usb_device),
+};
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index d0b890a..de8354a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -6,6 +6,9 @@ 
 #
 
 obj-$(CONFIG_DM_USB) += usb-uclass.o
+ifdef CONFIG_DM_USB
+obj-$(CONFIG_SANDBOX) += usb-sandbox.o
+endif
 
 # ohci
 obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
diff --git a/drivers/usb/host/usb-sandbox.c b/drivers/usb/host/usb-sandbox.c
new file mode 100644
index 0000000..34bf06d
--- /dev/null
+++ b/drivers/usb/host/usb-sandbox.c
@@ -0,0 +1,151 @@ 
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#define DEBUG
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int copy_to_unicode(char *buff, int length, const char *str)
+{
+	int ptr;
+	int i;
+
+	if (length < 2)
+		return 0;
+	buff[1] = USB_DT_STRING;
+	for (ptr = 2, i = 0; ptr + 1 < length && *str; i++, ptr += 2) {
+		buff[ptr] = str[i];
+		buff[ptr + 1] = 0;
+	}
+	buff[0] = ptr;
+
+	return ptr;
+}
+
+static int sandbox_submit_control_msg(struct udevice *dev, unsigned long pipe,
+				      void *buffer, int length,
+				      struct devrequest *setup)
+{
+	struct usb_device *udev = dev_get_uclass_priv(dev);
+	struct usb_device *emul_udev;
+	struct udevice *emul;
+	int ret;
+
+	debug("ctrl %s: pipe=%lx, buffer=%p, length=%x, setup=%p\n",
+	      dev->name, pipe, buffer, length, setup);
+	ret = device_get_child(dev, 0, &emul);
+	if (ret)
+		return ret;
+	emul_udev = dev_get_uclass_priv(emul);
+	if (pipe == usb_rcvctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case USB_REQ_GET_DESCRIPTOR: {
+			int type = setup->value >> 8;
+			int index = setup->value & 0xff;
+
+			if (type == USB_DT_DEVICE && index == 0) {
+				memcpy(buffer, &emul_udev->descriptor, length);
+				udev->status = 0;
+				udev->act_len = length;
+				return 0;
+			} else if (type == USB_DT_CONFIG && index == 0) {
+				memcpy(buffer, &emul_udev->config.desc, length);
+				udev->status = 0;
+				udev->act_len = length;
+				return 0;
+			} else if (type == USB_DT_STRING) {
+				if (index == 0) {
+					char *desc = buffer;
+
+					desc[0] = 4;
+					desc[1] = USB_DT_STRING;
+					desc[2] = 0x09;
+					desc[3] = 0x14;
+					udev->status = 0;
+					udev->act_len = 4;
+					return 0;
+				} else {
+					char **ptr = emul_udev->strings;
+					int i;
+
+					for (i = 0; i < index; i++) {
+						if (!ptr[i])
+							break;
+					}
+					if (ptr[i]) {
+						udev->act_len = copy_to_unicode(
+							buffer, length, ptr[i]);
+						udev->status = 0;
+						return 0;
+					}
+				}
+			}
+			break;
+		}
+		default:
+			debug("requestrcv =%x\n", setup->request);
+			break;
+		}
+	} else if (pipe == usb_snddefctrl(udev)) {
+		switch (setup->request) {
+		case USB_REQ_SET_ADDRESS:
+			emul_udev->devnum = setup->value;
+			udev->status = 0;
+			udev->act_len = 0;
+			return 0;
+		default:
+			debug("requestsend =%x\n", setup->request);
+			break;
+		}
+	} else if (pipe == usb_sndctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case USB_REQ_SET_CONFIGURATION:
+			emul_udev->configno = setup->value;
+			udev->status = 0;
+			udev->act_len = 0;
+			return 0;
+		default:
+			debug("sndctrlpipe req=%x\n", setup->request);
+			break;
+		}
+	}
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+static int sandbox_usb_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static int sandbox_usb_bind(struct udevice *dev)
+{
+	/* Scan the bus for devices */
+	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+static const struct dm_usb_ops sandbox_usb_ops = {
+	.submit_control_msg	= sandbox_submit_control_msg,
+};
+
+static const struct udevice_id sandbox_usb_ids[] = {
+	{ .compatible = "sandbox,usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox) = {
+	.name	= "usb_sandbox",
+	.id	= UCLASS_USB,
+	.of_match = sandbox_usb_ids,
+	.probe = sandbox_usb_probe,
+	.bind = sandbox_usb_bind,
+	.ops	= &sandbox_usb_ops,
+};
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index e9d3f32..392a40f 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -201,4 +201,7 @@ 
 
 #define CONFIG_CMD_LZMADEC
 
+#define CONFIG_CMD_USB
+#define CONFIG_DM_USB
+
 #endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index baab810..1c33fa6 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -20,6 +20,7 @@  enum uclass_id {
 	UCLASS_TEST_BUS,
 	UCLASS_SPI_EMUL,	/* sandbox SPI device emulator */
 	UCLASS_I2C_EMUL,	/* sandbox I2C device emulator */
+	UCLASS_USB_EMUL,	/* sandbox USB bus device emulator */
 	UCLASS_SIMPLE_BUS,
 
 	/* U-Boot uclasses start here */
diff --git a/include/usb_defs.h b/include/usb_defs.h
index 236a5ec..b580bf0 100644
--- a/include/usb_defs.h
+++ b/include/usb_defs.h
@@ -165,12 +165,14 @@ 
 #define USB_TEST_MODE_FORCE_ENABLE  0x05
 
 
-/* "pipe" definitions */
-
-#define PIPE_ISOCHRONOUS    0
-#define PIPE_INTERRUPT      1
-#define PIPE_CONTROL        2
-#define PIPE_BULK           3
+/*
+ * "pipe" definitions, use unsigned so we can compare reliably, since this
+ * value is shifted up to bits 30/31.
+ */
+#define PIPE_ISOCHRONOUS    0U
+#define PIPE_INTERRUPT      1U
+#define PIPE_CONTROL        2U
+#define PIPE_BULK           3U
 #define PIPE_DEVEP_MASK     0x0007ff00
 
 #define USB_ISOCHRONOUS    0