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

Simon Glass
2015-01-30T19:04:54Z

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 --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 at 0 {
+ compatible = "sandbox,usb";
+ status = "disabled";
+ flash-stick {
+ compatible = "sandbox,usb-flash";
+ };
+ };
+
+ usb at 1 {
+ compatible = "sandbox,usb";
+ flash-stick {
+ compatible = "sandbox,usb-hub";
+ };
+ };
+
+ usb at 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
--
2.2.0.rc0.207.ga3a616c