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 <s...@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@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 <s...@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 <s...@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 <s...@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 <s...@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 <s...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot