[U-Boot] [RFC PATCH 0/7] RFC: dm: Add USB support

This series adds basic driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types. So far the absolute limit on the number of USB devices is only slightly relaxed.
Only USB controllers have a real driver model device. USB devices (including the hub in the controller) are not modelled as driver model devices. This is for two reasons:
- it is easier since we don't need to bind a whole lot of devices when scanning - the two main USB devices (block devices and Ethernet) don't have driver mode support yet anyway, so it would be pointless. However the recent network RFC has encouraged me to send this.
The basic approach is to set up the driver model structures in parallel to what already exists rather than to replace them. This allows both driver model and legacy to be used for USB, although not with the same board.
So far only XHCI is supported. As an example the Exynos XHCI driver is converted to driver model.
I would appreciate comments before going further.
Caveats: - sandbox code is incomplete and there are no tests - 'usb stop' does not remove existing devices (I have not yet settled on the best approach) - the usb.h changes need to be split correctly into the patches once they are final
This series is available at u-boot-dm/usb-working.
Simon Glass (7): dm: usb: Add a uclass for USB controllers dm: usb: Support driver model in exynos XHCI dm: usb: Adjust users of the USB stack to work with driver model dm: usb: WIP sandbox USB implementation dm: core: Add a function to get the uclass data for a device arm: Show relocated PC/LR in the register dump dm: exynos: Enable driver model for snow XHCI
Makefile | 1 + arch/arm/lib/interrupts.c | 13 +- arch/sandbox/dts/sandbox.dts | 20 +++ arch/sandbox/include/asm/processor.h | 0 common/cmd_usb.c | 74 ++++++++--- common/usb.c | 28 +++-- common/usb_hub.c | 13 +- common/usb_storage.c | 148 +++++++++++++--------- drivers/core/device.c | 10 ++ 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/eth/usb_ether.c | 46 +++++-- drivers/usb/host/Makefile | 5 + drivers/usb/host/usb-sandbox.c | 151 +++++++++++++++++++++++ drivers/usb/host/usb-uclass.c | 227 ++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-exynos5.c | 115 +++++++++++++++++- drivers/usb/host/xhci.c | 229 ++++++++++++++++++++++++++++------- drivers/usb/host/xhci.h | 24 ++++ include/configs/sandbox.h | 3 + include/configs/snow.h | 1 + include/dm/device.h | 10 ++ include/dm/uclass-id.h | 2 + include/usb.h | 76 +++++++++++- include/usb_defs.h | 14 ++- 26 files changed, 1294 insertions(+), 153 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 create mode 100644 drivers/usb/host/usb-uclass.c

Add a uclass that can represent a USB controller. For now we do not create devices for things attached to the controller.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/host/Makefile | 2 + drivers/usb/host/usb-uclass.c | 227 ++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 230 insertions(+) create mode 100644 drivers/usb/host/usb-uclass.c
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index c11b551..d0b890a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -5,6 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ #
+obj-$(CONFIG_DM_USB) += usb-uclass.o + # ohci obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o obj-$(CONFIG_USB_ATMEL) += ohci-at91.o diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c new file mode 100644 index 0000000..86564db --- /dev/null +++ b/drivers/usb/host/usb-uclass.c @@ -0,0 +1,227 @@ +/* + * (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 <errno.h> +#include <usb.h> +#include <dm/device-internal.h> + +static bool usb_started; /* flag for the started/stopped USB status */ +static bool asynch_allowed; + +int usb_disable_asynch(int disable) +{ + int old_value = asynch_allowed; + + asynch_allowed = !disable; + return old_value; +} + +int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, + int length, int interval) +{ + struct udevice *dev = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(dev); + + if (!ops->control) + return -ENOSYS; + + return ops->interrupt(dev, udev, pipe, buffer, length, interval); +} + +int submit_control_msg(struct usb_device *udev, unsigned long pipe, + void *buffer, int length, struct devrequest *setup) +{ + struct udevice *dev = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(dev); + + if (!ops->control) + return -ENOSYS; + + return ops->control(dev, udev, pipe, buffer, length, setup); +} + +int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer, + int length) +{ + struct udevice *dev = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(dev); + + if (!ops->control) + return -ENOSYS; + + return ops->bulk(dev, udev, pipe, buffer, length); +} + +int usb_alloc_device(struct usb_device *udev) +{ + struct udevice *dev = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(dev); + + if (!ops->alloc_device) + return -ENOSYS; + + return ops->alloc_device(dev, udev); +} + +int usb_stop(void) +{ + return 0; +} + +int usb_init(void) +{ + int controllers_initialized = 0; + struct usb_device *udev; + struct udevice *dev; + struct uclass *uc; + int count = 0; + int ret; + + asynch_allowed = 1; + ret = uclass_get(UCLASS_USB, &uc); + if (ret) + return ret; + uclass_foreach_dev(dev, uc) { + struct dm_usb_info *usb; + + /* init low_level USB */ + count++; + printf("USB"); + ret = device_probe(dev); + printf("%d: ", dev->seq); + if (ret == -ENODEV) { /* No such device. */ + puts("Port not available.\n"); + controllers_initialized++; + continue; + } + + if (ret) { /* Other error. */ + puts("probe failed\n"); + continue; + } + /* + * lowlevel init is OK, now scan the bus for devices + * i.e. search HUBs and configure them + */ + controllers_initialized++; + printf("scanning bus %d for devices... ", dev->seq); + ret = usb_alloc_new_device(dev, &udev); + /* + * device 0 is always present + * (root hub, so let it analyze) + */ + if (!ret) + usb_new_device(udev); + + usb = dev_get_uclass_priv(dev); + if (!usb->dev_index) + printf("No USB Device found\n"); + else + printf("%d USB Device(s) found\n", usb->dev_index); + + usb_started = true; + } + + debug("scan end\n"); + /* if we were not able to find at least one working bus, bail out */ + if (!count) + printf("No controllers found\n"); + else if (controllers_initialized == 0) + printf("USB error: all controllers failed lowlevel init\n"); + + return usb_started ? 0 : -1; +} + +#ifdef CONFIG_MUSB_HOST +int usb_reset_root_port(void) +{ + return -ENOSYS; +} +#endif + +int usb_alloc_new_device(struct udevice *controller, + struct usb_device **devp) +{ + struct dm_usb_info *usb = dev_get_uclass_priv(controller); + struct usb_device *udev; + + int i; + + debug("New Device %d\n", usb->dev_index); + if (usb->dev_index == USB_MAX_DEVICE) { + printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE); + return -ENOSPC; + } + /* default Address is 0, real addresses start with 1 */ + udev = &usb->usb_dev[usb->dev_index++]; + udev->devnum = usb->dev_index; + udev->maxchild = 0; + for (i = 0; i < USB_MAXCHILDREN; i++) + udev->children[i] = NULL; + udev->parent = NULL; + udev->controller_dev = controller; + udev->controller = usb->controller; + debug("%s: udev=%p\n", __func__, udev); + + *devp = udev; + return 0; +} + +struct usb_device *usb_get_dev_index(struct udevice *controller, int index) +{ + struct dm_usb_info *usb = dev_get_uclass_priv(controller); + struct usb_device *udev; + + if (index < 0 || index >= USB_MAX_DEVICE) + return NULL; + udev = &usb->usb_dev[index]; + + return udev->controller ? udev : NULL; +} + +/* +static int usb_child_pre_probe(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parentdata(dev); + + udev->controller = dev; + + return 0; +} +*/ +/* + * Free the newly created device node. + * Called in error cases where configuring a newly attached + * device fails for some reason. + */ +void usb_free_device(struct udevice *controller) +{ + struct dm_usb_info *usb = dev_get_uclass_priv(controller); + + usb->dev_index--; + debug("Freeing device node: %d\n", usb->dev_index); + memset(&usb->usb_dev[usb->dev_index], '\0', sizeof(struct usb_device)); + usb->usb_dev[usb->dev_index].devnum = -1; +} + +UCLASS_DRIVER(usb) = { + .id = UCLASS_USB, + .name = "usb", + .flags = DM_UC_FLAG_SEQ_ALIAS, +/* + .child_pre_probe = usb_child_pre_probe, + .post_probe = i2c_post_probe, +*/ + .per_device_auto_alloc_size = sizeof(struct dm_usb_info), +/* + .per_child_auto_alloc_size = sizeof(struct usb_device), + .per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip), + .child_post_bind = i2c_child_post_bind, +*/ +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..baab810 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_USB, /* USB bus */
UCLASS_COUNT, UCLASS_INVALID = -1,

On Friday, January 30, 2015 at 08:04:51 PM, Simon Glass wrote:
Add a uclass that can represent a USB controller. For now we do not create devices for things attached to the controller.
Signed-off-by: Simon Glass sjg@chromium.org
[...]
+UCLASS_DRIVER(usb) = {
- .id = UCLASS_USB,
- .name = "usb",
- .flags = DM_UC_FLAG_SEQ_ALIAS,
+/*
- .child_pre_probe = usb_child_pre_probe,
- .post_probe = i2c_post_probe,
Certainly this is USB, right ? ;-)
+*/
What's the reason for this commented-out stuff please ?
- .per_device_auto_alloc_size = sizeof(struct dm_usb_info),
+/*
- .per_child_auto_alloc_size = sizeof(struct usb_device),
- .per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
- .child_post_bind = i2c_child_post_bind,
+*/ +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..baab810 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_USB, /* USB bus */
UCLASS_COUNT, UCLASS_INVALID = -1,
Best regards, Marek Vasut

Hi Simon,
On Sat, Jan 31, 2015 at 12:34 AM, Simon Glass sjg@chromium.org wrote:
Add a uclass that can represent a USB controller. For now we do not create devices for things attached to the controller.
Signed-off-by: Simon Glass sjg@chromium.org
Please find my comments inline below.
drivers/usb/host/Makefile | 2 + drivers/usb/host/usb-uclass.c | 227 ++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 230 insertions(+) create mode 100644 drivers/usb/host/usb-uclass.c
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index c11b551..d0b890a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -5,6 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ #
+obj-$(CONFIG_DM_USB) += usb-uclass.o
# ohci obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o obj-$(CONFIG_USB_ATMEL) += ohci-at91.o diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c new file mode 100644 index 0000000..86564db --- /dev/null +++ b/drivers/usb/host/usb-uclass.c @@ -0,0 +1,227 @@ +/*
- (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 <errno.h> +#include <usb.h> +#include <dm/device-internal.h>
+static bool usb_started; /* flag for the started/stopped USB status */ +static bool asynch_allowed;
+int usb_disable_asynch(int disable) +{
int old_value = asynch_allowed;
asynch_allowed = !disable;
return old_value;
+}
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
int length, int interval)
+{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->control)
return -ENOSYS;
return ops->interrupt(dev, udev, pipe, buffer, length, interval);
+}
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
void *buffer, int length, struct devrequest *setup)
+{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->control)
return -ENOSYS;
return ops->control(dev, udev, pipe, buffer, length, setup);
+}
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
int length)
+{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->control)
return -ENOSYS;
return ops->bulk(dev, udev, pipe, buffer, length);
+}
+int usb_alloc_device(struct usb_device *udev) +{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->alloc_device)
return -ENOSYS;
return ops->alloc_device(dev, udev);
+}
+int usb_stop(void) +{
return 0;
+}
+int usb_init(void) +{
int controllers_initialized = 0;
struct usb_device *udev;
struct udevice *dev;
struct uclass *uc;
int count = 0;
int ret;
asynch_allowed = 1;
you may still want to do a usb_hub_reset() like usb_init() in common/usb.c does ?
Also make all devices unknown initially
ret = uclass_get(UCLASS_USB, &uc);
if (ret)
return ret;
nit: just add an extra line here.
uclass_foreach_dev(dev, uc) {
struct dm_usb_info *usb;
/* init low_level USB */
count++;
printf("USB");
ret = device_probe(dev);
printf("%d: ", dev->seq);
if (ret == -ENODEV) { /* No such device. */
puts("Port not available.\n");
controllers_initialized++;
continue;
}
if (ret) { /* Other error. */
puts("probe failed\n");
continue;
}
/*
* lowlevel init is OK, now scan the bus for devices
* i.e. search HUBs and configure them
*/
controllers_initialized++;
printf("scanning bus %d for devices... ", dev->seq);
ret = usb_alloc_new_device(dev, &udev);
/*
* device 0 is always present
* (root hub, so let it analyze)
*/
if (!ret)
usb_new_device(udev);
usb = dev_get_uclass_priv(dev);
if (!usb->dev_index)
printf("No USB Device found\n");
else
printf("%d USB Device(s) found\n", usb->dev_index);
usb_started = true;
}
debug("scan end\n");
/* if we were not able to find at least one working bus, bail out */
if (!count)
printf("No controllers found\n");
else if (controllers_initialized == 0)
printf("USB error: all controllers failed lowlevel init\n");
return usb_started ? 0 : -1;
+}
+#ifdef CONFIG_MUSB_HOST +int usb_reset_root_port(void) +{
return -ENOSYS;
+} +#endif
+int usb_alloc_new_device(struct udevice *controller,
struct usb_device **devp)
+{
struct dm_usb_info *usb = dev_get_uclass_priv(controller);
struct usb_device *udev;
int i;
debug("New Device %d\n", usb->dev_index);
if (usb->dev_index == USB_MAX_DEVICE) {
printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
return -ENOSPC;
}
/* default Address is 0, real addresses start with 1 */
udev = &usb->usb_dev[usb->dev_index++];
udev->devnum = usb->dev_index;
udev->maxchild = 0;
for (i = 0; i < USB_MAXCHILDREN; i++)
udev->children[i] = NULL;
udev->parent = NULL;
udev->controller_dev = controller;
udev->controller = usb->controller;
debug("%s: udev=%p\n", __func__, udev);
*devp = udev;
return 0;
+}
+struct usb_device *usb_get_dev_index(struct udevice *controller, int index) +{
struct dm_usb_info *usb = dev_get_uclass_priv(controller);
struct usb_device *udev;
if (index < 0 || index >= USB_MAX_DEVICE)
return NULL;
udev = &usb->usb_dev[index];
return udev->controller ? udev : NULL;
+}
+/* +static int usb_child_pre_probe(struct udevice *dev) +{
struct usb_device *udev = dev_get_parentdata(dev);
udev->controller = dev;
return 0;
+} +*/ +/*
- Free the newly created device node.
- Called in error cases where configuring a newly attached
- device fails for some reason.
- */
+void usb_free_device(struct udevice *controller) +{
struct dm_usb_info *usb = dev_get_uclass_priv(controller);
usb->dev_index--;
debug("Freeing device node: %d\n", usb->dev_index);
memset(&usb->usb_dev[usb->dev_index], '\0', sizeof(struct usb_device));
usb->usb_dev[usb->dev_index].devnum = -1;
+}
+UCLASS_DRIVER(usb) = {
.id = UCLASS_USB,
.name = "usb",
.flags = DM_UC_FLAG_SEQ_ALIAS,
+/*
.child_pre_probe = usb_child_pre_probe,
.post_probe = i2c_post_probe,
+*/
.per_device_auto_alloc_size = sizeof(struct dm_usb_info),
+/*
.per_child_auto_alloc_size = sizeof(struct usb_device),
.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_post_bind = i2c_child_post_bind,
+*/ +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..baab810 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_USB, /* USB bus */ UCLASS_COUNT, UCLASS_INVALID = -1,
-- 2.2.0.rc0.207.ga3a616c
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi,
On Mon, Mar 9, 2015 at 11:50 AM, Vivek Gautam gautamvivek1987@gmail.com wrote:
Sorry i was in the middle of adding comment and the message just got sent. I will add other comments here.
Hi Simon,
On Sat, Jan 31, 2015 at 12:34 AM, Simon Glass sjg@chromium.org wrote:
Add a uclass that can represent a USB controller. For now we do not create devices for things attached to the controller.
Signed-off-by: Simon Glass sjg@chromium.org
Please find my comments inline below.
drivers/usb/host/Makefile | 2 + drivers/usb/host/usb-uclass.c | 227 ++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 230 insertions(+) create mode 100644 drivers/usb/host/usb-uclass.c
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index c11b551..d0b890a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -5,6 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ #
+obj-$(CONFIG_DM_USB) += usb-uclass.o
# ohci obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o obj-$(CONFIG_USB_ATMEL) += ohci-at91.o diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c new file mode 100644 index 0000000..86564db --- /dev/null +++ b/drivers/usb/host/usb-uclass.c @@ -0,0 +1,227 @@ +/*
- (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 <errno.h> +#include <usb.h> +#include <dm/device-internal.h>
+static bool usb_started; /* flag for the started/stopped USB status */ +static bool asynch_allowed;
+int usb_disable_asynch(int disable) +{
int old_value = asynch_allowed;
asynch_allowed = !disable;
return old_value;
+}
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
int length, int interval)
+{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->control)
return -ENOSYS;
return ops->interrupt(dev, udev, pipe, buffer, length, interval);
+}
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
void *buffer, int length, struct devrequest *setup)
+{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->control)
return -ENOSYS;
return ops->control(dev, udev, pipe, buffer, length, setup);
+}
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
int length)
+{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->control)
return -ENOSYS;
return ops->bulk(dev, udev, pipe, buffer, length);
+}
+int usb_alloc_device(struct usb_device *udev) +{
struct udevice *dev = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(dev);
if (!ops->alloc_device)
return -ENOSYS;
return ops->alloc_device(dev, udev);
+}
+int usb_stop(void) +{
i think you are already planning to add "remove()" call for host controller here, alongwith freeing the device, usb_free_device().
return 0;
+}
+int usb_init(void) +{
int controllers_initialized = 0;
struct usb_device *udev;
struct udevice *dev;
struct uclass *uc;
int count = 0;
int ret;
asynch_allowed = 1;
you may still want to do a usb_hub_reset() like usb_init() in common/usb.c does ?
Also make all devices unknown initially
i think this may not be required.
ret = uclass_get(UCLASS_USB, &uc);
if (ret)
return ret;
nit: just add an extra line here.
uclass_foreach_dev(dev, uc) {
struct dm_usb_info *usb;
/* init low_level USB */
count++;
printf("USB");
ret = device_probe(dev);
printf("%d: ", dev->seq);
if (ret == -ENODEV) { /* No such device. */
puts("Port not available.\n");
controllers_initialized++;
continue;
}
if (ret) { /* Other error. */
puts("probe failed\n");
continue;
}
/*
* lowlevel init is OK, now scan the bus for devices
* i.e. search HUBs and configure them
*/
controllers_initialized++;
printf("scanning bus %d for devices... ", dev->seq);
ret = usb_alloc_new_device(dev, &udev);
/*
* device 0 is always present
* (root hub, so let it analyze)
*/
if (!ret)
usb_new_device(udev);
usb = dev_get_uclass_priv(dev);
if (!usb->dev_index)
printf("No USB Device found\n");
else
printf("%d USB Device(s) found\n", usb->dev_index);
usb_started = true;
}
debug("scan end\n");
/* if we were not able to find at least one working bus, bail out */
if (!count)
printf("No controllers found\n");
else if (controllers_initialized == 0)
printf("USB error: all controllers failed lowlevel init\n");
return usb_started ? 0 : -1;
+}
+#ifdef CONFIG_MUSB_HOST +int usb_reset_root_port(void) +{
return -ENOSYS;
+} +#endif
+int usb_alloc_new_device(struct udevice *controller,
struct usb_device **devp)
+{
struct dm_usb_info *usb = dev_get_uclass_priv(controller);
struct usb_device *udev;
int i;
debug("New Device %d\n", usb->dev_index);
if (usb->dev_index == USB_MAX_DEVICE) {
printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
return -ENOSPC;
}
/* default Address is 0, real addresses start with 1 */
udev = &usb->usb_dev[usb->dev_index++];
udev->devnum = usb->dev_index;
udev->maxchild = 0;
for (i = 0; i < USB_MAXCHILDREN; i++)
udev->children[i] = NULL;
udev->parent = NULL;
udev->controller_dev = controller;
udev->controller = usb->controller;
debug("%s: udev=%p\n", __func__, udev);
*devp = udev;
return 0;
+}
+struct usb_device *usb_get_dev_index(struct udevice *controller, int index) +{
struct dm_usb_info *usb = dev_get_uclass_priv(controller);
struct usb_device *udev;
if (index < 0 || index >= USB_MAX_DEVICE)
return NULL;
udev = &usb->usb_dev[index];
return udev->controller ? udev : NULL;
+}
+/* +static int usb_child_pre_probe(struct udevice *dev) +{
struct usb_device *udev = dev_get_parentdata(dev);
udev->controller = dev;
return 0;
+} +*/ +/*
- Free the newly created device node.
- Called in error cases where configuring a newly attached
- device fails for some reason.
- */
+void usb_free_device(struct udevice *controller) +{
struct dm_usb_info *usb = dev_get_uclass_priv(controller);
usb->dev_index--;
debug("Freeing device node: %d\n", usb->dev_index);
memset(&usb->usb_dev[usb->dev_index], '\0', sizeof(struct usb_device));
usb->usb_dev[usb->dev_index].devnum = -1;
+}
+UCLASS_DRIVER(usb) = {
.id = UCLASS_USB,
.name = "usb",
.flags = DM_UC_FLAG_SEQ_ALIAS,
+/*
.child_pre_probe = usb_child_pre_probe,
.post_probe = i2c_post_probe,
+*/
.per_device_auto_alloc_size = sizeof(struct dm_usb_info),
+/*
.per_child_auto_alloc_size = sizeof(struct usb_device),
.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_post_bind = i2c_child_post_bind,
+*/ +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..baab810 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_USB, /* USB bus */ UCLASS_COUNT, UCLASS_INVALID = -1,
-- 2.2.0.rc0.207.ga3a616c
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Rest looks fine to me.

(This patch will be split for submission)
Add driver model support to the XHCI framework, and move exynos over to use it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/host/xhci-exynos5.c | 115 +++++++++++++++++++- drivers/usb/host/xhci.c | 229 ++++++++++++++++++++++++++++++++-------- drivers/usb/host/xhci.h | 24 +++++ 3 files changed, 324 insertions(+), 44 deletions(-)
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c index a77c8bc..e61f39e 100644 --- a/drivers/usb/host/xhci-exynos5.c +++ b/drivers/usb/host/xhci-exynos5.c @@ -14,6 +14,7 @@ */
#include <common.h> +#include <dm.h> #include <fdtdec.h> #include <libfdt.h> #include <malloc.h> @@ -32,6 +33,12 @@ /* Declare global data pointer */ DECLARE_GLOBAL_DATA_PTR;
+struct exynos_xhci_platdata { + fdt_addr_t hcd_base; + fdt_addr_t phy_base; + struct gpio_desc vbus_gpio; +}; + /** * Contains pointers to register base addresses * for the usb controller. @@ -40,12 +47,56 @@ struct exynos_xhci { struct exynos_usb3_phy *usb3_phy; struct xhci_hccr *hcd; struct dwc3 *dwc3_reg; +#ifndef CONFIG_DM_USB struct gpio_desc vbus_gpio; +#endif };
+#ifndef CONFIG_DM_USB static struct exynos_xhci exynos; +#endif
-#ifdef CONFIG_OF_CONTROL +#ifdef CONFIG_DM_USB +static int xhci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct exynos_xhci_platdata *plat = dev_get_platdata(dev); + const void *blob = gd->fdt_blob; + unsigned int node; + int depth; + + /* + * Get the base address for XHCI controller from the device node + */ + plat->hcd_base = fdtdec_get_addr(blob, dev->of_offset, "reg"); + if (plat->hcd_base == FDT_ADDR_T_NONE) { + debug("Can't get the XHCI register base address\n"); + return -ENXIO; + } + + depth = 0; + node = fdtdec_next_compatible_subnode(blob, dev->of_offset, + COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth); + if (node <= 0) { + debug("XHCI: Can't get device node for usb3-phy controller\n"); + return -ENODEV; + } + + /* + * Get the base address for usbphy from the device node + */ + plat->phy_base = fdtdec_get_addr(blob, node, "reg"); + if (plat->phy_base == FDT_ADDR_T_NONE) { + debug("Can't get the usbphy register address\n"); + return -ENXIO; + } + + /* Vbus gpio */ + gpio_request_by_name(dev, "samsung,vbus-gpio", 0, + &plat->vbus_gpio, GPIOD_IS_OUT); + + return 0; +} +#else static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos) { fdt_addr_t addr; @@ -182,7 +233,7 @@ static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy) set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE); }
-void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) +static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG), @@ -283,6 +334,7 @@ static void exynos_xhci_core_exit(struct exynos_xhci *exynos) exynos5_usb3_phy_exit(exynos->usb3_phy); }
+#ifndef CONFIG_DM_USB int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) { struct exynos_xhci *ctx = &exynos; @@ -326,3 +378,62 @@ void xhci_hcd_stop(int index)
exynos_xhci_core_exit(ctx); } +#endif + +#ifdef CONFIG_DM_USB +static int xhci_usb_probe(struct udevice *dev) +{ + struct exynos_xhci_platdata *plat = dev_get_platdata(dev); + struct exynos_xhci *ctx = dev_get_priv(dev); + struct xhci_hcor *hcor; + int ret; + + ctx->hcd = (struct xhci_hccr *)plat->hcd_base; + ctx->usb3_phy = (struct exynos_usb3_phy *)plat->phy_base; + ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); + hcor = (struct xhci_hcor *)((uint32_t)ctx->hcd + + HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); + + /* setup the Vbus gpio here */ + if (dm_gpio_is_valid(&plat->vbus_gpio)) + dm_gpio_set_value(&plat->vbus_gpio, 1); + + ret = exynos_xhci_core_init(ctx); + if (ret) { + puts("XHCI: failed to initialize controller\n"); + return -EINVAL; + } + + return xhci_register(dev, ctx->hcd, hcor); +} + +static int xhci_usb_remove(struct udevice *dev) +{ + struct exynos_xhci *ctx = dev_get_priv(dev); + int ret; + + ret = xhci_deregister(dev); + if (ret) + return ret; + exynos_xhci_core_exit(ctx); + + return 0; +} + +static const struct udevice_id xhci_usb_ids[] = { + { .compatible = "samsung,exynos5250-xhci" }, + { } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "xhci_exynos", + .id = UCLASS_USB, + .of_match = xhci_usb_ids, + .ofdata_to_platdata = xhci_usb_ofdata_to_platdata, + .probe = xhci_usb_probe, + .remove = xhci_usb_remove, + .ops = &xhci_usb_ops, + .priv_auto_alloc_size = sizeof(struct exynos_xhci), + .platdata_auto_alloc_size = sizeof(struct exynos_xhci_platdata), +}; +#endif diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 87f2972..fa3a5c5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -21,6 +21,7 @@ */
#include <common.h> +#include <dm.h> #include <asm/byteorder.h> #include <usb.h> #include <malloc.h> @@ -108,7 +109,9 @@ static struct descriptor { }, };
+#ifndef CONFIG_DM_USB static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; +#endif
/** * Waits for as per specified amount of time @@ -461,10 +464,10 @@ static int xhci_address_device(struct usb_device *udev) * @param udev pointer to the Device Data Structure * @return Returns 0 on succes else return error code on failure */ -int usb_alloc_device(struct usb_device *udev) +int _xhci_alloc_device(struct usb_device *udev) { - union xhci_trb *event; struct xhci_ctrl *ctrl = udev->controller; + union xhci_trb *event; int ret;
/* @@ -499,6 +502,13 @@ int usb_alloc_device(struct usb_device *udev) return 0; }
+#ifndef CONFIG_DM_USB +int usb_alloc_device(struct usb_device *udev) +{ + return _xhci_alloc_device(udev); +} +#endif + /* * Full speed devices may have a max packet size greater than 8 bytes, but the * USB core doesn't know that until it reads the first 8 bytes of the @@ -858,9 +868,8 @@ unknown: * @param interval interval of the interrupt * @return 0 */ -int -submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, - int length, int interval) +static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe, + void *buffer, int length, int interval) { /* * TODO: Not addressing any interrupt type transfer requests @@ -878,9 +887,8 @@ submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, * @param length length of the buffer * @return returns 0 if successful else -1 on failure */ -int -submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer, - int length) +static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe, + void *buffer, int length) { if (usb_pipetype(pipe) != PIPE_BULK) { printf("non-bulk pipe (type=%lu)", usb_pipetype(pipe)); @@ -900,9 +908,9 @@ submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer, * @param setup Request type * @return returns 0 if successful else -1 on failure */ -int -submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer, - int length, struct devrequest *setup) +static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe, + void *buffer, int length, + struct devrequest *setup) { struct xhci_ctrl *ctrl = udev->controller; int ret = 0; @@ -929,33 +937,16 @@ submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer, return xhci_ctrl_tx(udev, pipe, setup, length, buffer); }
-/** - * Intialises the XHCI host controller - * and allocates the necessary data structures - * - * @param index index to the host controller data structure - * @return pointer to the intialised controller - */ -int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +static int xhci_lowlevel_init(struct xhci_ctrl *ctrl) { + struct xhci_hccr *hccr; + struct xhci_hcor *hcor; uint32_t val; uint32_t val2; uint32_t reg; - struct xhci_hccr *hccr; - struct xhci_hcor *hcor; - struct xhci_ctrl *ctrl; - - if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0) - return -ENODEV; - - if (xhci_reset(hcor) != 0) - return -ENODEV; - - ctrl = &xhcic[index]; - - ctrl->hccr = hccr; - ctrl->hcor = hcor;
+ hccr = ctrl->hccr; + hcor = ctrl->hcor; /* * Program the Number of Device Slots Enabled field in the CONFIG * register with the max value of slots the HC can handle. @@ -997,11 +988,75 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) reg = HC_VERSION(xhci_readl(&hccr->cr_capbase)); printf("USB XHCI %x.%02x\n", reg >> 8, reg & 0xff);
- *controller = &xhcic[index]; + return 0; +} + +static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl) +{ + u32 temp; + + xhci_reset(ctrl->hcor); + + debug("// Disabling event ring interrupts\n"); + temp = xhci_readl(&ctrl->hcor->or_usbsts); + xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT); + temp = xhci_readl(&ctrl->ir_set->irq_pending); + xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp));
return 0; }
+#ifndef CONFIG_DM_USB +int submit_control_msg(struct usb_device *udev, unsigned long pipe, + void *buffer, int length, struct devrequest *setup) +{ + return _xhci_submit_control_msg(udev, pipe, buffer, length, setup); +} + +int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer, + int length) +{ + return _xhci_submit_bulk_msg(udev, pipe, buffer, length); +} + +int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, + int length, int interval) +{ + return _xhci_submit_int_msg(udev, pipe, buffer, length, interval); +} + +/** + * Intialises the XHCI host controller + * and allocates the necessary data structures + * + * @param index index to the host controller data structure + * @return pointer to the intialised controller + */ +int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +{ + struct xhci_hccr *hccr; + struct xhci_hcor *hcor; + struct xhci_ctrl *ctrl; + int ret; + + if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0) + return -ENODEV; + + if (xhci_reset(hcor) != 0) + return -ENODEV; + + ctrl = &xhcic[index]; + + ctrl->hccr = hccr; + ctrl->hcor = hcor; + + ret = xhci_lowlevel_init(ctrl); + + *controller = &xhcic[index]; + + return ret; +} + /** * Stops the XHCI host controller * and cleans up all the related data structures @@ -1012,19 +1067,109 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) int usb_lowlevel_stop(int index) { struct xhci_ctrl *ctrl = (xhcic + index); - u32 temp;
- xhci_reset(ctrl->hcor); + xhci_lowlevel_stop(ctrl); + xhci_hcd_stop(index); + xhci_cleanup(ctrl);
- debug("// Disabling event ring interrupts\n"); - temp = xhci_readl(&ctrl->hcor->or_usbsts); - xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT); - temp = xhci_readl(&ctrl->ir_set->irq_pending); - xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp)); + return 0; +} +#endif /* CONFIG_DM_USB */
- xhci_hcd_stop(index); +#ifdef CONFIG_DM_USB +/* +static struct usb_device *get_usb_device(struct udevice *dev) +{ + struct usb_device *udev;
+ if (device_get_uclass_id(dev) == UCLASS_USB) + udev = dev_get_uclass_priv(dev); + else + udev = dev_get_parentdata(dev); + + return udev; +} +*/ +static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + struct devrequest *setup) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _xhci_submit_control_msg(udev, pipe, buffer, length, setup); +} + +static int xhci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _xhci_submit_bulk_msg(udev, pipe, buffer, length); +} + +static int xhci_submit_int_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + int interval) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _xhci_submit_int_msg(udev, pipe, buffer, length, interval); +} + +static int xhci_alloc_device(struct udevice *dev, struct usb_device *udev) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _xhci_alloc_device(udev); +} + +int xhci_register(struct udevice *dev, struct xhci_hccr *hccr, + struct xhci_hcor *hcor) +{ + struct dm_usb_info *usb = dev_get_uclass_priv(dev); + struct xhci_ctrl *ctrl; + int ret; + + debug("%s: dev='%s', hccr=%p, hcor=%p\n", __func__, dev->name, + hccr, hcor); + ctrl = calloc(1, sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + ctrl->dev = dev; + usb->dev = dev; + usb->controller = ctrl; + + ret = xhci_reset(hcor); + if (ret) + goto err; + + ctrl->hccr = hccr; + ctrl->hcor = hcor; + ret = xhci_lowlevel_init(ctrl); + if (ret) + goto err; + + return 0; +err: + free(ctrl); + debug("%s: failed, ret=%d\n", __func__, ret); + return ret; +} + +int xhci_deregister(struct udevice *dev) +{ + struct dm_usb_info *usb = dev_get_uclass_priv(dev); + struct xhci_ctrl *ctrl = usb->controller; + + xhci_lowlevel_stop(ctrl); xhci_cleanup(ctrl); + free(ctrl);
return 0; } + +struct dm_usb_ops xhci_usb_ops = { + .control = xhci_submit_control_msg, + .bulk = xhci_submit_bulk_msg, + .interrupt = xhci_submit_int_msg, + .alloc_device = xhci_alloc_device, +}; + +#endif diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6685ed2..f9fd99e 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1200,6 +1200,9 @@ void xhci_hcd_stop(int index); #define XHCI_STS_CNR (1 << 11)
struct xhci_ctrl { +#ifdef CONFIG_DM_USB + struct udevice *dev; +#endif struct xhci_hccr *hccr; /* R/O registers, not need for volatile */ struct xhci_hcor *hcor; struct xhci_doorbell_array *dba; @@ -1250,4 +1253,25 @@ int xhci_alloc_virt_device(struct usb_device *udev); int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr, struct xhci_hcor *hcor);
+/** + * xhci_deregister() - Unregister an XHCI controller + * + * @dev: Controller device + * @return 0 if registered, -ve on error + */ +int xhci_deregister(struct udevice *dev); + +/** + * xhci_register() - Register a new XHCI controller + * + * @dev: Controller device + * @hccr: Host controller control registers + * @hcor: Not sure what this means + * @return 0 if registered, -ve on error + */ +int xhci_register(struct udevice *dev, struct xhci_hccr *hccr, + struct xhci_hcor *hcor); + +extern struct dm_usb_ops xhci_usb_ops; + #endif /* HOST_XHCI_H_ */

While we currently don't have driver model support for block devices and Ethernet, we can still allow this to work when driver model is used for USB.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/cmd_usb.c | 74 ++++++++++++++++------ common/usb.c | 28 +++++---- common/usb_hub.c | 13 +++- common/usb_storage.c | 148 ++++++++++++++++++++++++++++---------------- drivers/usb/eth/usb_ether.c | 46 +++++++++++--- include/usb.h | 76 +++++++++++++++++++++-- 6 files changed, 286 insertions(+), 99 deletions(-)
diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 27813f0..b824634 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -10,6 +10,7 @@
#include <common.h> #include <command.h> +#include <dm.h> #include <asm/byteorder.h> #include <asm/unaligned.h> #include <part.h> @@ -254,16 +255,24 @@ static void usb_display_config(struct usb_device *dev)
static struct usb_device *usb_find_device(int devnum) { - struct usb_device *dev; +#ifdef CONFIG_DM_USB + struct udevice *dev; + + if (uclass_get_device_by_seq(UCLASS_USB, devnum, &dev)) + return NULL; + return dev_get_uclass_priv(dev); +#else + struct usb_device *udev; int d;
for (d = 0; d < USB_MAX_DEVICE; d++) { - dev = usb_get_dev_index(d); - if (dev == NULL) + udev = usb_get_dev_index(d); + if (udev == NULL) return NULL; - if (dev->devnum == devnum) - return dev; + if (udev->devnum == devnum) + return udev; } +#endif
return NULL; } @@ -466,9 +475,8 @@ static void do_usb_start(void) */ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - + struct usb_device *udev = NULL; int i; - struct usb_device *dev = NULL; extern char usb_started; #ifdef CONFIG_USB_STORAGE block_dev_desc_t *stor_dev; @@ -508,36 +516,64 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } if (strncmp(argv[1], "tree", 4) == 0) { puts("USB device tree:\n"); +#ifdef CONFIG_DM_USB + struct udevice *dev; + + for (uclass_first_device(UCLASS_USB, &dev); + dev; + uclass_next_device(&dev)) { + struct usb_device *udev = dev_get_uclass_priv(dev); + + usb_show_tree(udev); + } +#else for (i = 0; i < USB_MAX_DEVICE; i++) { + struct usb_device *dev; + dev = usb_get_dev_index(i); if (dev == NULL) break; if (dev->parent == NULL) usb_show_tree(dev); } +#endif return 0; } if (strncmp(argv[1], "inf", 3) == 0) { - int d; if (argc == 2) { +#ifdef CONFIG_DM_USB + struct udevice *dev; + + for (uclass_first_device(UCLASS_USB, &dev); + dev; + uclass_next_device(&dev)) { + struct usb_device *udev; + + udev = dev_get_uclass_priv(dev); + usb_display_desc(udev); + usb_display_config(udev); + } +#else + int d; for (d = 0; d < USB_MAX_DEVICE; d++) { - dev = usb_get_dev_index(d); - if (dev == NULL) + udev = usb_get_dev_index(d); + if (udev == NULL) break; - usb_display_desc(dev); - usb_display_config(dev); + usb_display_desc(udev); + usb_display_config(udev); } +#endif return 0; } else { i = simple_strtoul(argv[2], NULL, 10); printf("config for device %d\n", i); - dev = usb_find_device(i); - if (dev == NULL) { + udev = usb_find_device(i); + if (udev == NULL) { printf("*** No device available ***\n"); return 0; } else { - usb_display_desc(dev); - usb_display_config(dev); + usb_display_desc(udev); + usb_display_config(udev); } } return 0; @@ -546,13 +582,13 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (argc < 5) return CMD_RET_USAGE; i = simple_strtoul(argv[2], NULL, 10); - dev = usb_find_device(i); - if (dev == NULL) { + udev = usb_find_device(i); + if (udev == NULL) { printf("Device %d does not exist.\n", i); return 1; } i = simple_strtoul(argv[3], NULL, 10); - return usb_test(dev, i, argv[4]); + return usb_test(udev, i, argv[4]); } #ifdef CONFIG_USB_STORAGE if (strncmp(argv[1], "stor", 4) == 0) diff --git a/common/usb.c b/common/usb.c index 32e15cd..3ccf8a7 100644 --- a/common/usb.c +++ b/common/usb.c @@ -41,12 +41,13 @@
#define USB_BUFSIZ 512
-static struct usb_device usb_dev[USB_MAX_DEVICE]; -static int dev_index; static int asynch_allowed; - char usb_started; /* flag for the started/stopped USB status */
+#ifndef CONFIG_DM_USB +static struct usb_device usb_dev[USB_MAX_DEVICE]; +static int dev_index; + #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif @@ -94,12 +95,12 @@ int usb_init(void) controllers_initialized++; start_index = dev_index; printf("scanning bus %d for devices... ", i); - dev = usb_alloc_new_device(ctrl); + ret = usb_alloc_new_device(ctrl, &dev); /* * device 0 is always present * (root hub, so let it analyze) */ - if (dev) + if (!ret) usb_new_device(dev);
if (start_index == dev_index) @@ -152,6 +153,7 @@ int usb_disable_asynch(int disable) asynch_allowed = !disable; return old_value; } +#endif /* !CONFIG_DM_USB */
/*------------------------------------------------------------------- @@ -815,6 +817,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) * the USB device are static allocated [USB_MAX_DEVICE]. */
+#ifndef CONFIG_DM_USB
/* returns a pointer to the device with the index [index]. * if the device is not assigned (dev->devnum==-1) returns NULL @@ -827,16 +830,13 @@ struct usb_device *usb_get_dev_index(int index) return &usb_dev[index]; }
-/* returns a pointer of a new device structure or NULL, if - * no device struct is available - */ -struct usb_device *usb_alloc_new_device(void *controller) +int usb_alloc_new_device(void *controller, struct usb_device **devp) { int i; debug("New Device %d\n", dev_index); if (dev_index == USB_MAX_DEVICE) { printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE); - return NULL; + return -ENOSPC; } /* default Address is 0, real addresses start with 1 */ usb_dev[dev_index].devnum = dev_index + 1; @@ -846,7 +846,9 @@ struct usb_device *usb_alloc_new_device(void *controller) usb_dev[dev_index].parent = NULL; usb_dev[dev_index].controller = controller; dev_index++; - return &usb_dev[dev_index - 1]; + *devp = &usb_dev[dev_index - 1]; + + return 0; }
/* @@ -854,7 +856,7 @@ struct usb_device *usb_alloc_new_device(void *controller) * Called in error cases where configuring a newly attached * device fails for some reason. */ -void usb_free_device(void) +void usb_free_device(void *controller) { dev_index--; debug("Freeing device node: %d\n", dev_index); @@ -872,6 +874,8 @@ __weak int usb_alloc_device(struct usb_device *udev) { return 0; } +#endif /* !CONFIG_DM_USB */ + /* * By the time we get here, the device has gotten a new device ID * and is in the default state. We need to identify the thing and diff --git a/common/usb_hub.c b/common/usb_hub.c index 66b4a72..ccdf755 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -211,6 +211,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) struct usb_device *usb; ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus; + int ret;
/* Check status */ if (usb_get_port_status(dev, port + 1, portsts) < 0) { @@ -246,7 +247,15 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) mdelay(200);
/* Allocate a new device struct for it */ - usb = usb_alloc_new_device(dev->controller); +#ifdef CONFIG_DM_USB + ret = usb_alloc_new_device(dev->controller_dev, &usb); +#else + ret = usb_alloc_new_device(dev->controller, &usb); +#endif + if (ret) { + printf("cannot create new device: reg=%d", ret); + return; + }
switch (portstatus & USB_PORT_STAT_SPEED_MASK) { case USB_PORT_STAT_SUPER_SPEED: @@ -269,7 +278,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */ - usb_free_device(); + usb_free_device(dev->controller); dev->children[port] = NULL; debug("hub: disabling port %d\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); diff --git a/common/usb_storage.c b/common/usb_storage.c index 1411737..8fb2c18 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -33,9 +33,12 @@
#include <common.h> #include <command.h> +#include <dm.h> +#include <errno.h> #include <inttypes.h> #include <asm/byteorder.h> #include <asm/processor.h> +#include <dm/device-internal.h>
#include <part.h> #include <usb.h> @@ -158,7 +161,6 @@ unsigned long usb_stor_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer); unsigned long usb_stor_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer); -struct usb_device * usb_get_dev_index(int index); void uhci_show_temp_int_td(void);
#ifdef CONFIG_PARTITIONS @@ -208,6 +210,44 @@ static unsigned int usb_get_max_lun(struct us_data *us) return (len > 0) ? *result : 0; }
+static int usb_stor_probe_device(struct usb_device *dev) +{ + if (dev == NULL) + return -ENOENT; /* no more devices available */ + + if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) { + /* OK, it's a storage device. Iterate over its LUNs + * and populate `usb_dev_desc'. + */ + int lun, max_lun, start = usb_max_devs; + + max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]); + for (lun = 0; + lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV; + lun++) { + struct block_dev_desc *blkdev; + + blkdev = &usb_dev_desc[usb_max_devs]; + + if (usb_stor_get_info(dev, &usb_stor[start], + &usb_dev_desc[usb_max_devs]) == + 1) { + blkdev->lun = lun; + blkdev->priv = dev; + usb_max_devs++; + } + } + } + + /* if storage device */ + if (usb_max_devs == USB_MAX_STOR_DEV) { + printf("max USB Storage Device reached: %d stopping\n", + usb_max_devs); + return -ENOSPC; + } + + return 0; +} /******************************************************************************* * scan the usb and reports device info * to the user if mode = 1 @@ -215,8 +255,8 @@ static unsigned int usb_get_max_lun(struct us_data *us) */ int usb_stor_scan(int mode) { + struct block_dev_desc *blkdev; unsigned char i; - struct usb_device *dev;
if (mode == 1) printf(" scanning usb for storage devices... "); @@ -224,47 +264,55 @@ int usb_stor_scan(int mode) usb_disable_asynch(1); /* asynch transfer not allowed */
for (i = 0; i < USB_MAX_STOR_DEV; i++) { - memset(&usb_dev_desc[i], 0, sizeof(block_dev_desc_t)); - usb_dev_desc[i].if_type = IF_TYPE_USB; - usb_dev_desc[i].dev = i; - usb_dev_desc[i].part_type = PART_TYPE_UNKNOWN; - usb_dev_desc[i].target = 0xff; - usb_dev_desc[i].type = DEV_TYPE_UNKNOWN; - usb_dev_desc[i].block_read = usb_stor_read; - usb_dev_desc[i].block_write = usb_stor_write; + blkdev = &usb_dev_desc[i]; + memset(&blkdev, 0, sizeof(block_dev_desc_t)); + blkdev->if_type = IF_TYPE_USB; + blkdev->dev = i; + blkdev->part_type = PART_TYPE_UNKNOWN; + blkdev->target = 0xff; + blkdev->type = DEV_TYPE_UNKNOWN; + blkdev->block_read = usb_stor_read; + blkdev->block_write = usb_stor_write; }
usb_max_devs = 0; +#ifdef CONFIG_DM_USB + struct udevice *bus; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_USB, &uc); + if (ret) + return ret; + uclass_foreach_dev(bus, uc) { + struct udevice *dev; + + for (device_find_first_child(bus, &dev); + dev; + device_find_next_child(&dev)) { + ret = device_probe(dev); + if (!ret) { + struct usb_device *udev; + + udev = dev_get_parentdata(dev); + ret = usb_stor_probe_device(udev); + } + if (ret) { + printf("Device '%s' probe failed: %d\n", + dev->name, ret); + } + } + } +#else for (i = 0; i < USB_MAX_DEVICE; i++) { + struct usb_device *dev; + dev = usb_get_dev_index(i); /* get device */ debug("i=%d\n", i); - if (dev == NULL) - break; /* no more devices available */ - - if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) { - /* OK, it's a storage device. Iterate over its LUNs - * and populate `usb_dev_desc'. - */ - int lun, max_lun, start = usb_max_devs; - - max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]); - for (lun = 0; - lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV; - lun++) { - usb_dev_desc[usb_max_devs].lun = lun; - if (usb_stor_get_info(dev, &usb_stor[start], - &usb_dev_desc[usb_max_devs]) == 1) { - usb_max_devs++; - } - } - } - /* if storage device */ - if (usb_max_devs == USB_MAX_STOR_DEV) { - printf("max USB Storage Device reached: %d stopping\n", - usb_max_devs); + if (usb_stor_probe_device(dev)) break; - } } /* for */ +#endif
usb_disable_asynch(0); /* asynch transfer allowed */ printf("%d Storage Device(s) found\n", usb_max_devs); @@ -1046,7 +1094,7 @@ unsigned long usb_stor_read(int device, lbaint_t blknr, unsigned short smallblks; struct usb_device *dev; struct us_data *ss; - int retry, i; + int retry; ccb *srb = &usb_ccb;
if (blkcnt == 0) @@ -1054,15 +1102,10 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
device &= 0xff; /* Setup device */ - debug("\nusb_read: dev %d \n", device); - dev = NULL; - for (i = 0; i < USB_MAX_DEVICE; i++) { - dev = usb_get_dev_index(i); - if (dev == NULL) - return 0; - if (dev->devnum == usb_dev_desc[device].target) - break; - } + debug("\nusb_read: dev %d\n", device); + dev = usb_dev_desc[device].priv; + if (!dev) + return 0; ss = (struct us_data *)dev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */ @@ -1119,7 +1162,7 @@ unsigned long usb_stor_write(int device, lbaint_t blknr, unsigned short smallblks; struct usb_device *dev; struct us_data *ss; - int retry, i; + int retry; ccb *srb = &usb_ccb;
if (blkcnt == 0) @@ -1127,15 +1170,10 @@ unsigned long usb_stor_write(int device, lbaint_t blknr,
device &= 0xff; /* Setup device */ - debug("\nusb_write: dev %d \n", device); - dev = NULL; - for (i = 0; i < USB_MAX_DEVICE; i++) { - dev = usb_get_dev_index(i); - if (dev == NULL) - return 0; - if (dev->devnum == usb_dev_desc[device].target) - break; - } + debug("\nusb_write: dev %d\n", device); + dev = usb_dev_desc[device].priv; + if (!dev) + return 0; ss = (struct us_data *)dev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */ diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 7cb96e3..4334d16 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -5,7 +5,9 @@ */
#include <common.h> +#include <dm.h> #include <usb.h> +#include <dm/device-internal.h>
#include "usb_ether.h"
@@ -118,8 +120,6 @@ static void probe_valid_drivers(struct usb_device *dev) int usb_host_eth_scan(int mode) { int i, old_async; - struct usb_device *dev; -
if (mode == 1) printf(" scanning usb for ethernet devices... "); @@ -138,7 +138,38 @@ int usb_host_eth_scan(int mode) }
usb_max_eth_dev = 0; +#ifdef CONFIG_DM_USB + struct udevice *bus; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_USB, &uc); + if (ret) + return ret; + uclass_foreach_dev(bus, uc) { + for (i = 0; i < USB_MAX_DEVICE; i++) { + struct usb_device *dev; + + dev = usb_get_dev_index(bus, i); /* get device */ + debug("i=%d\n", i); + if (dev == NULL) + break; /* no more devices available */ + + /* + * find valid usb_ether driver for this device, + * if any + */ + probe_valid_drivers(dev); + + /* check limit */ + if (usb_max_eth_dev == USB_MAX_ETH_DEV) + break; + } /* for */ + } +#else for (i = 0; i < USB_MAX_DEVICE; i++) { + struct usb_device *dev; + dev = usb_get_dev_index(i); /* get device */ debug("i=%d\n", i); if (dev == NULL) @@ -148,13 +179,14 @@ int usb_host_eth_scan(int mode) probe_valid_drivers(dev);
/* check limit */ - if (usb_max_eth_dev == USB_MAX_ETH_DEV) { - printf("max USB Ethernet Device reached: %d stopping\n", - usb_max_eth_dev); + if (usb_max_eth_dev == USB_MAX_ETH_DEV) break; - } } /* for */ - +#endif + if (usb_max_eth_dev == USB_MAX_ETH_DEV) { + printf("max USB Ethernet Device reached: %d stopping\n", + usb_max_eth_dev); + } usb_disable_asynch(old_async); /* restore asynch value */ printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); if (usb_max_eth_dev > 0) diff --git a/include/usb.h b/include/usb.h index a8fee0b..ba80eb8 100644 --- a/include/usb.h +++ b/include/usb.h @@ -9,6 +9,7 @@ #ifndef _USB_H_ #define _USB_H_
+#include <fdtdec.h> #include <usb_defs.h> #include <linux/usb/ch9.h> #include <asm/cache.h> @@ -130,6 +131,10 @@ struct usb_device { void *controller; /* hardware controller private data */ /* slot_id - for xHCI enabled devices */ unsigned int slot_id; +#ifdef CONFIG_DM_USB + char **strings; + struct udevice *controller_dev; +#endif };
struct int_queue; @@ -245,7 +250,6 @@ int usb_stop(void); /* stop the USB Controller */ int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol); int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id); -struct usb_device *usb_get_dev_index(int index); int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned char request, unsigned char requesttype, unsigned short value, unsigned short index, @@ -423,15 +427,79 @@ struct usb_hub_device { struct usb_hub_descriptor desc; };
+#ifdef CONFIG_DM_USB + +/* This is attached to each controller */ +struct dm_usb_info { + struct usb_device usb_dev[USB_MAX_DEVICE]; + int dev_index; + struct udevice *dev; + void *controller; /* struct xhci_ctrl, etc. */ +}; + +struct dm_usb_ops { + int (*hcd_init)(struct udevice *dev, fdt_addr_t *hccrp, + fdt_addr_t *hcorp); + int (*control)(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + struct devrequest *setup); + int (*bulk)(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length); + int (*interrupt)(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + interval); + int (*alloc_device)(struct udevice *dev, struct usb_device *udev); +}; + +#define usb_get_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops) +#define usb_get_emul_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops) + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, int interval); + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int length, struct devrequest *setup); + +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length); + +#ifdef CONFIG_MUSB_HOST +int usb_reset_root_port(void); +#endif + +void usb_free_device(struct udevice *controller); +/** + * usb_alloc_new_device() - Allocate a new device + * + * @devp: returns a pointer of a new device structure + * @return 0 if OK, -ENOSPC if we have found out of room for new devices + */ +int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp); + +struct usb_device *usb_get_dev_index(struct udevice *controller, int index); + +#else + +void usb_free_device(void *controller); +/** + * usb_alloc_new_device() - Allocate a new device + * + * @devp: returns a pointer of a new device structure + * @return 0 if OK, -ENOSPC if we have found out of room for new devices + */ +int usb_alloc_new_device(void *controller, struct usb_device **devp); + +struct usb_device *usb_get_dev_index(int index); + +#endif + int usb_hub_probe(struct usb_device *dev, int ifnum); void usb_hub_reset(void); int hub_port_reset(struct usb_device *dev, int port, unsigned short *portstat);
-struct usb_device *usb_alloc_new_device(void *controller); - int usb_new_device(struct usb_device *dev); -void usb_free_device(void); + int usb_alloc_device(struct usb_device *dev);
#endif /*_USB_H_ */

On Sat, Jan 31, 2015 at 12:34 AM, Simon Glass sjg@chromium.org wrote:
While we currently don't have driver model support for block devices and Ethernet, we can still allow this to work when driver model is used for USB.
Signed-off-by: Simon Glass sjg@chromium.org
common/cmd_usb.c | 74 ++++++++++++++++------ common/usb.c | 28 +++++---- common/usb_hub.c | 13 +++- common/usb_storage.c | 148 ++++++++++++++++++++++++++++---------------- drivers/usb/eth/usb_ether.c | 46 +++++++++++--- include/usb.h | 76 +++++++++++++++++++++-- 6 files changed, 286 insertions(+), 99 deletions(-)
diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 27813f0..b824634 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -10,6 +10,7 @@
#include <common.h> #include <command.h> +#include <dm.h> #include <asm/byteorder.h> #include <asm/unaligned.h> #include <part.h> @@ -254,16 +255,24 @@ static void usb_display_config(struct usb_device *dev)
static struct usb_device *usb_find_device(int devnum) {
struct usb_device *dev;
+#ifdef CONFIG_DM_USB
struct udevice *dev;
if (uclass_get_device_by_seq(UCLASS_USB, devnum, &dev))
return NULL;
return dev_get_uclass_priv(dev);
+#else
struct usb_device *udev; int d; for (d = 0; d < USB_MAX_DEVICE; d++) {
dev = usb_get_dev_index(d);
if (dev == NULL)
udev = usb_get_dev_index(d);
if (udev == NULL) return NULL;
if (dev->devnum == devnum)
return dev;
if (udev->devnum == devnum)
return udev; }
+#endif
return NULL;
} @@ -466,9 +475,8 @@ static void do_usb_start(void) */ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
struct usb_device *udev = NULL; int i;
struct usb_device *dev = NULL; extern char usb_started;
#ifdef CONFIG_USB_STORAGE block_dev_desc_t *stor_dev; @@ -508,36 +516,64 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } if (strncmp(argv[1], "tree", 4) == 0) { puts("USB device tree:\n"); +#ifdef CONFIG_DM_USB
struct udevice *dev;
for (uclass_first_device(UCLASS_USB, &dev);
dev;
uclass_next_device(&dev)) {
struct usb_device *udev = dev_get_uclass_priv(dev);
usb_show_tree(udev);
}
+#else for (i = 0; i < USB_MAX_DEVICE; i++) {
struct usb_device *dev;
dev = usb_get_dev_index(i); if (dev == NULL) break; if (dev->parent == NULL) usb_show_tree(dev); }
+#endif return 0; } if (strncmp(argv[1], "inf", 3) == 0) {
int d; if (argc == 2) {
+#ifdef CONFIG_DM_USB
struct udevice *dev;
for (uclass_first_device(UCLASS_USB, &dev);
dev;
uclass_next_device(&dev)) {
struct usb_device *udev;
udev = dev_get_uclass_priv(dev);
usb_display_desc(udev);
usb_display_config(udev);
}
+#else
int d; for (d = 0; d < USB_MAX_DEVICE; d++) {
dev = usb_get_dev_index(d);
if (dev == NULL)
udev = usb_get_dev_index(d);
if (udev == NULL) break;
usb_display_desc(dev);
usb_display_config(dev);
usb_display_desc(udev);
usb_display_config(udev); }
+#endif return 0; } else { i = simple_strtoul(argv[2], NULL, 10); printf("config for device %d\n", i);
dev = usb_find_device(i);
if (dev == NULL) {
udev = usb_find_device(i);
if (udev == NULL) { printf("*** No device available ***\n"); return 0; } else {
usb_display_desc(dev);
usb_display_config(dev);
usb_display_desc(udev);
usb_display_config(udev); } } return 0;
@@ -546,13 +582,13 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (argc < 5) return CMD_RET_USAGE; i = simple_strtoul(argv[2], NULL, 10);
dev = usb_find_device(i);
if (dev == NULL) {
udev = usb_find_device(i);
if (udev == NULL) { printf("Device %d does not exist.\n", i); return 1; } i = simple_strtoul(argv[3], NULL, 10);
return usb_test(dev, i, argv[4]);
return usb_test(udev, i, argv[4]); }
#ifdef CONFIG_USB_STORAGE if (strncmp(argv[1], "stor", 4) == 0) diff --git a/common/usb.c b/common/usb.c index 32e15cd..3ccf8a7 100644 --- a/common/usb.c +++ b/common/usb.c @@ -41,12 +41,13 @@
#define USB_BUFSIZ 512
-static struct usb_device usb_dev[USB_MAX_DEVICE]; -static int dev_index; static int asynch_allowed;
char usb_started; /* flag for the started/stopped USB status */
+#ifndef CONFIG_DM_USB +static struct usb_device usb_dev[USB_MAX_DEVICE]; +static int dev_index;
#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif @@ -94,12 +95,12 @@ int usb_init(void) controllers_initialized++; start_index = dev_index; printf("scanning bus %d for devices... ", i);
dev = usb_alloc_new_device(ctrl);
ret = usb_alloc_new_device(ctrl, &dev); /* * device 0 is always present * (root hub, so let it analyze) */
if (dev)
if (!ret) usb_new_device(dev); if (start_index == dev_index)
@@ -152,6 +153,7 @@ int usb_disable_asynch(int disable) asynch_allowed = !disable; return old_value; } +#endif /* !CONFIG_DM_USB */
/*------------------------------------------------------------------- @@ -815,6 +817,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
- the USB device are static allocated [USB_MAX_DEVICE].
*/
+#ifndef CONFIG_DM_USB
/* returns a pointer to the device with the index [index].
- if the device is not assigned (dev->devnum==-1) returns NULL
@@ -827,16 +830,13 @@ struct usb_device *usb_get_dev_index(int index) return &usb_dev[index]; }
-/* returns a pointer of a new device structure or NULL, if
- no device struct is available
- */
-struct usb_device *usb_alloc_new_device(void *controller) +int usb_alloc_new_device(void *controller, struct usb_device **devp) { int i; debug("New Device %d\n", dev_index); if (dev_index == USB_MAX_DEVICE) { printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
return NULL;
return -ENOSPC; } /* default Address is 0, real addresses start with 1 */ usb_dev[dev_index].devnum = dev_index + 1;
@@ -846,7 +846,9 @@ struct usb_device *usb_alloc_new_device(void *controller) usb_dev[dev_index].parent = NULL; usb_dev[dev_index].controller = controller; dev_index++;
return &usb_dev[dev_index - 1];
*devp = &usb_dev[dev_index - 1];
return 0;
}
/* @@ -854,7 +856,7 @@ struct usb_device *usb_alloc_new_device(void *controller)
- Called in error cases where configuring a newly attached
- device fails for some reason.
*/ -void usb_free_device(void) +void usb_free_device(void *controller) { dev_index--; debug("Freeing device node: %d\n", dev_index); @@ -872,6 +874,8 @@ __weak int usb_alloc_device(struct usb_device *udev) { return 0; } +#endif /* !CONFIG_DM_USB */
/*
- By the time we get here, the device has gotten a new device ID
- and is in the default state. We need to identify the thing and
diff --git a/common/usb_hub.c b/common/usb_hub.c index 66b4a72..ccdf755 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -211,6 +211,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) struct usb_device *usb; ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus;
int ret; /* Check status */ if (usb_get_port_status(dev, port + 1, portsts) < 0) {
@@ -246,7 +247,15 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) mdelay(200);
/* Allocate a new device struct for it */
usb = usb_alloc_new_device(dev->controller);
+#ifdef CONFIG_DM_USB
ret = usb_alloc_new_device(dev->controller_dev, &usb);
+#else
ret = usb_alloc_new_device(dev->controller, &usb);
+#endif
if (ret) {
printf("cannot create new device: reg=%d", ret);
return;
} switch (portstatus & USB_PORT_STAT_SPEED_MASK) { case USB_PORT_STAT_SUPER_SPEED:
@@ -269,7 +278,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */
usb_free_device();
usb_free_device(dev->controller); dev->children[port] = NULL; debug("hub: disabling port %d\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
diff --git a/common/usb_storage.c b/common/usb_storage.c index 1411737..8fb2c18 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -33,9 +33,12 @@
#include <common.h> #include <command.h> +#include <dm.h> +#include <errno.h> #include <inttypes.h> #include <asm/byteorder.h> #include <asm/processor.h> +#include <dm/device-internal.h>
#include <part.h> #include <usb.h> @@ -158,7 +161,6 @@ unsigned long usb_stor_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer); unsigned long usb_stor_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer); -struct usb_device * usb_get_dev_index(int index); void uhci_show_temp_int_td(void);
#ifdef CONFIG_PARTITIONS @@ -208,6 +210,44 @@ static unsigned int usb_get_max_lun(struct us_data *us) return (len > 0) ? *result : 0; }
+static int usb_stor_probe_device(struct usb_device *dev) +{
if (dev == NULL)
return -ENOENT; /* no more devices available */
if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
/* OK, it's a storage device. Iterate over its LUNs
* and populate `usb_dev_desc'.
*/
int lun, max_lun, start = usb_max_devs;
max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
for (lun = 0;
lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
lun++) {
struct block_dev_desc *blkdev;
blkdev = &usb_dev_desc[usb_max_devs];
if (usb_stor_get_info(dev, &usb_stor[start],
&usb_dev_desc[usb_max_devs]) ==
1) {
blkdev->lun = lun;
blkdev->priv = dev;
usb_max_devs++;
}
}
}
/* if storage device */
if (usb_max_devs == USB_MAX_STOR_DEV) {
printf("max USB Storage Device reached: %d stopping\n",
usb_max_devs);
return -ENOSPC;
}
return 0;
+} /*******************************************************************************
- scan the usb and reports device info
- to the user if mode = 1
@@ -215,8 +255,8 @@ static unsigned int usb_get_max_lun(struct us_data *us) */ int usb_stor_scan(int mode) {
struct block_dev_desc *blkdev; unsigned char i;
struct usb_device *dev; if (mode == 1) printf(" scanning usb for storage devices... ");
@@ -224,47 +264,55 @@ int usb_stor_scan(int mode) usb_disable_asynch(1); /* asynch transfer not allowed */
for (i = 0; i < USB_MAX_STOR_DEV; i++) {
memset(&usb_dev_desc[i], 0, sizeof(block_dev_desc_t));
usb_dev_desc[i].if_type = IF_TYPE_USB;
usb_dev_desc[i].dev = i;
usb_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
usb_dev_desc[i].target = 0xff;
usb_dev_desc[i].type = DEV_TYPE_UNKNOWN;
usb_dev_desc[i].block_read = usb_stor_read;
usb_dev_desc[i].block_write = usb_stor_write;
blkdev = &usb_dev_desc[i];
memset(&blkdev, 0, sizeof(block_dev_desc_t));
blkdev->if_type = IF_TYPE_USB;
blkdev->dev = i;
blkdev->part_type = PART_TYPE_UNKNOWN;
blkdev->target = 0xff;
blkdev->type = DEV_TYPE_UNKNOWN;
blkdev->block_read = usb_stor_read;
blkdev->block_write = usb_stor_write; } usb_max_devs = 0;
+#ifdef CONFIG_DM_USB
struct udevice *bus;
struct uclass *uc;
int ret;
ret = uclass_get(UCLASS_USB, &uc);
if (ret)
return ret;
uclass_foreach_dev(bus, uc) {
struct udevice *dev;
for (device_find_first_child(bus, &dev);
dev;
device_find_next_child(&dev)) {
ret = device_probe(dev);
if (!ret) {
struct usb_device *udev;
udev = dev_get_parentdata(dev);
ret = usb_stor_probe_device(udev);
}
if (ret) {
printf("Device '%s' probe failed: %d\n",
dev->name, ret);
}
}
}
+#else for (i = 0; i < USB_MAX_DEVICE; i++) {
struct usb_device *dev;
dev = usb_get_dev_index(i); /* get device */ debug("i=%d\n", i);
if (dev == NULL)
break; /* no more devices available */
if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
/* OK, it's a storage device. Iterate over its LUNs
* and populate `usb_dev_desc'.
*/
int lun, max_lun, start = usb_max_devs;
max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
for (lun = 0;
lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
lun++) {
usb_dev_desc[usb_max_devs].lun = lun;
if (usb_stor_get_info(dev, &usb_stor[start],
&usb_dev_desc[usb_max_devs]) == 1) {
usb_max_devs++;
}
}
}
/* if storage device */
if (usb_max_devs == USB_MAX_STOR_DEV) {
printf("max USB Storage Device reached: %d stopping\n",
usb_max_devs);
if (usb_stor_probe_device(dev)) break;
} } /* for */
+#endif
usb_disable_asynch(0); /* asynch transfer allowed */ printf("%d Storage Device(s) found\n", usb_max_devs);
@@ -1046,7 +1094,7 @@ unsigned long usb_stor_read(int device, lbaint_t blknr, unsigned short smallblks; struct usb_device *dev; struct us_data *ss;
int retry, i;
int retry; ccb *srb = &usb_ccb; if (blkcnt == 0)
@@ -1054,15 +1102,10 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
device &= 0xff; /* Setup device */
debug("\nusb_read: dev %d \n", device);
dev = NULL;
for (i = 0; i < USB_MAX_DEVICE; i++) {
dev = usb_get_dev_index(i);
if (dev == NULL)
return 0;
if (dev->devnum == usb_dev_desc[device].target)
break;
}
debug("\nusb_read: dev %d\n", device);
dev = usb_dev_desc[device].priv;
if (!dev)
return 0; ss = (struct us_data *)dev->privptr; usb_disable_asynch(1); /* asynch transfer not allowed */
@@ -1119,7 +1162,7 @@ unsigned long usb_stor_write(int device, lbaint_t blknr, unsigned short smallblks; struct usb_device *dev; struct us_data *ss;
int retry, i;
int retry; ccb *srb = &usb_ccb; if (blkcnt == 0)
@@ -1127,15 +1170,10 @@ unsigned long usb_stor_write(int device, lbaint_t blknr,
device &= 0xff; /* Setup device */
debug("\nusb_write: dev %d \n", device);
dev = NULL;
for (i = 0; i < USB_MAX_DEVICE; i++) {
dev = usb_get_dev_index(i);
if (dev == NULL)
return 0;
if (dev->devnum == usb_dev_desc[device].target)
break;
}
debug("\nusb_write: dev %d\n", device);
dev = usb_dev_desc[device].priv;
if (!dev)
return 0; ss = (struct us_data *)dev->privptr; usb_disable_asynch(1); /* asynch transfer not allowed */
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 7cb96e3..4334d16 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -5,7 +5,9 @@ */
#include <common.h> +#include <dm.h> #include <usb.h> +#include <dm/device-internal.h>
#include "usb_ether.h"
@@ -118,8 +120,6 @@ static void probe_valid_drivers(struct usb_device *dev) int usb_host_eth_scan(int mode) { int i, old_async;
struct usb_device *dev;
if (mode == 1) printf(" scanning usb for ethernet devices... ");
@@ -138,7 +138,38 @@ int usb_host_eth_scan(int mode) }
usb_max_eth_dev = 0;
+#ifdef CONFIG_DM_USB
struct udevice *bus;
struct uclass *uc;
int ret;
ret = uclass_get(UCLASS_USB, &uc);
if (ret)
return ret;
uclass_foreach_dev(bus, uc) {
for (i = 0; i < USB_MAX_DEVICE; i++) {
struct usb_device *dev;
dev = usb_get_dev_index(bus, i); /* get device */
debug("i=%d\n", i);
if (dev == NULL)
break; /* no more devices available */
/*
* find valid usb_ether driver for this device,
* if any
*/
probe_valid_drivers(dev);
/* check limit */
if (usb_max_eth_dev == USB_MAX_ETH_DEV)
break;
} /* for */
}
+#else for (i = 0; i < USB_MAX_DEVICE; i++) {
struct usb_device *dev;
dev = usb_get_dev_index(i); /* get device */ debug("i=%d\n", i); if (dev == NULL)
@@ -148,13 +179,14 @@ int usb_host_eth_scan(int mode) probe_valid_drivers(dev);
/* check limit */
if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
printf("max USB Ethernet Device reached: %d stopping\n",
usb_max_eth_dev);
if (usb_max_eth_dev == USB_MAX_ETH_DEV) break;
} } /* for */
+#endif
if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
printf("max USB Ethernet Device reached: %d stopping\n",
usb_max_eth_dev);
} usb_disable_asynch(old_async); /* restore asynch value */ printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); if (usb_max_eth_dev > 0)
diff --git a/include/usb.h b/include/usb.h index a8fee0b..ba80eb8 100644 --- a/include/usb.h +++ b/include/usb.h @@ -9,6 +9,7 @@ #ifndef _USB_H_ #define _USB_H_
+#include <fdtdec.h> #include <usb_defs.h> #include <linux/usb/ch9.h> #include <asm/cache.h> @@ -130,6 +131,10 @@ struct usb_device { void *controller; /* hardware controller private data */ /* slot_id - for xHCI enabled devices */ unsigned int slot_id; +#ifdef CONFIG_DM_USB
char **strings;
struct udevice *controller_dev;
+#endif };
struct int_queue; @@ -245,7 +250,6 @@ int usb_stop(void); /* stop the USB Controller */ int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol); int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id); -struct usb_device *usb_get_dev_index(int index); int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned char request, unsigned char requesttype, unsigned short value, unsigned short index, @@ -423,15 +427,79 @@ struct usb_hub_device { struct usb_hub_descriptor desc; };
+#ifdef CONFIG_DM_USB
+/* This is attached to each controller */ +struct dm_usb_info {
struct usb_device usb_dev[USB_MAX_DEVICE];
int dev_index;
struct udevice *dev;
void *controller; /* struct xhci_ctrl, etc. */
+};
+struct dm_usb_ops {
int (*hcd_init)(struct udevice *dev, fdt_addr_t *hccrp,
fdt_addr_t *hcorp);
int (*control)(struct udevice *dev, struct usb_device *udev,
unsigned long pipe, void *buffer, int length,
struct devrequest *setup);
int (*bulk)(struct udevice *dev, struct usb_device *udev,
unsigned long pipe, void *buffer, int length);
int (*interrupt)(struct udevice *dev, struct usb_device *udev,
unsigned long pipe, void *buffer, int length,
interval);
data type required for "interval". It gives build error.
int (*alloc_device)(struct udevice *dev, struct usb_device *udev);
+};
+#define usb_get_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops) +#define usb_get_emul_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops)
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, int interval);
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int length, struct devrequest *setup);
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length);
+#ifdef CONFIG_MUSB_HOST +int usb_reset_root_port(void); +#endif
+void usb_free_device(struct udevice *controller); +/**
- usb_alloc_new_device() - Allocate a new device
- @devp: returns a pointer of a new device structure
- @return 0 if OK, -ENOSPC if we have found out of room for new devices
- */
+int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp);
+struct usb_device *usb_get_dev_index(struct udevice *controller, int index);
+#else
+void usb_free_device(void *controller); +/**
- usb_alloc_new_device() - Allocate a new device
- @devp: returns a pointer of a new device structure
- @return 0 if OK, -ENOSPC if we have found out of room for new devices
- */
+int usb_alloc_new_device(void *controller, struct usb_device **devp);
+struct usb_device *usb_get_dev_index(int index);
+#endif
int usb_hub_probe(struct usb_device *dev, int ifnum); void usb_hub_reset(void); int hub_port_reset(struct usb_device *dev, int port, unsigned short *portstat);
-struct usb_device *usb_alloc_new_device(void *controller);
int usb_new_device(struct usb_device *dev); -void usb_free_device(void);
int usb_alloc_device(struct usb_device *dev);
#endif /*_USB_H_ */
2.2.0.rc0.207.ga3a616c
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

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@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

This is a convenience function only so far. Eventually it could have some consistency checking added.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 10 ++++++++++ include/dm/device.h | 10 ++++++++++ 2 files changed, 20 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index b73d3b8..fbb377b 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -305,6 +305,16 @@ void *dev_get_priv(struct udevice *dev) return dev->priv; }
+void *dev_get_uclass_priv(struct udevice *dev) +{ + if (!dev) { + dm_warn("%s: null device\n", __func__); + return NULL; + } + + return dev->uclass_priv; +} + void *dev_get_parentdata(struct udevice *dev) { if (!dev) { diff --git a/include/dm/device.h b/include/dm/device.h index 81afa8c..511dbd9 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -229,6 +229,16 @@ void *dev_get_parentdata(struct udevice *dev); void *dev_get_priv(struct udevice *dev);
/** + * dev_get_uclass_priv() - Get the private data for a device's class + * + * This checks that dev is not NULL, but no other checks for now + * + * @dev Device to check + * @return uclass private data, or NULL if none + */ +void *dev_get_uclass_priv(struct udevice *dev); + +/** * struct dev_get_parent() - Get the parent of a device * * @child: Child to check

If we don't know the relocation address, the raw values are not very useful. Show the pre-relocation values as well as these can be looked up in System.map, etc.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/lib/interrupts.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c index 4dacfd9..06f4679 100644 --- a/arch/arm/lib/interrupts.c +++ b/arch/arm/lib/interrupts.c @@ -137,10 +137,15 @@ void show_regs (struct pt_regs *regs)
flags = condition_codes (regs);
- printf ("pc : [<%08lx>] lr : [<%08lx>]\n" - "sp : %08lx ip : %08lx fp : %08lx\n", - instruction_pointer (regs), - regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); + printf("pc : [<%08lx>] lr : [<%08lx>]\n", + instruction_pointer(regs), regs->ARM_lr); + if (gd->flags & GD_FLG_RELOC) { + printf("reloc pc : [<%08lx>] lr : [<%08lx>]\n", + instruction_pointer(regs) - gd->reloc_off, + regs->ARM_lr - gd->reloc_off); + } + printf("sp : %08lx ip : %08lx fp : %08lx\n", + regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); printf ("r10: %08lx r9 : %08lx r8 : %08lx\n", regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",

Hello Simon,
On Fri, 30 Jan 2015 12:04:56 -0700, Simon Glass sjg@chromium.org wrote:
If we don't know the relocation address, the raw values are not very useful. Show the pre-relocation values as well as these can be looked up in System.map, etc.
Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Albert ARIBAUD albert.u.boot@aribaud.net
Simon, I think this one go straight into the ARM tree despite being an RFC patch in a series -- it's useful, pretty much standalone and it won't prevent any target from booting.
Amicalement,

Hi Albert,
On 1 February 2015 at 01:45, Albert ARIBAUD albert.u.boot@aribaud.net wrote:
Hello Simon,
On Fri, 30 Jan 2015 12:04:56 -0700, Simon Glass sjg@chromium.org wrote:
If we don't know the relocation address, the raw values are not very useful. Show the pre-relocation values as well as these can be looked up in System.map, etc.
Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Albert ARIBAUD albert.u.boot@aribaud.net
Simon, I think this one go straight into the ARM tree despite being an RFC patch in a series -- it's useful, pretty much standalone and it won't prevent any target from booting.
Sure, I think it is safe.
Regards, Simon

Hello Simon,
On Fri, 30 Jan 2015 12:04:56 -0700, Simon Glass sjg@chromium.org wrote:
If we don't know the relocation address, the raw values are not very useful. Show the pre-relocation values as well as these can be looked up in System.map, etc.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/lib/interrupts.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c index 4dacfd9..06f4679 100644 --- a/arch/arm/lib/interrupts.c +++ b/arch/arm/lib/interrupts.c @@ -137,10 +137,15 @@ void show_regs (struct pt_regs *regs)
flags = condition_codes (regs);
- printf ("pc : [<%08lx>] lr : [<%08lx>]\n"
"sp : %08lx ip : %08lx fp : %08lx\n",
instruction_pointer (regs),
regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
- printf("pc : [<%08lx>] lr : [<%08lx>]\n",
instruction_pointer(regs), regs->ARM_lr);
- if (gd->flags & GD_FLG_RELOC) {
printf("reloc pc : [<%08lx>] lr : [<%08lx>]\n",
instruction_pointer(regs) - gd->reloc_off,
regs->ARM_lr - gd->reloc_off);
- }
- printf("sp : %08lx ip : %08lx fp : %08lx\n",
printf ("r10: %08lx r9 : %08lx r8 : %08lx\n", regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
-- 2.2.0.rc0.207.ga3a616c
Applied as a "bugfix" to u-boot-arm/master, thanks!
Amicalement,

Switch snow over to use driver model for USB.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/configs/snow.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/snow.h b/include/configs/snow.h index ce6676e..00bd646 100644 --- a/include/configs/snow.h +++ b/include/configs/snow.h @@ -27,6 +27,7 @@ #define CONFIG_BOARD_COMMON #define CONFIG_ARCH_EARLY_INIT_R
+#define CONFIG_DM_USB #define CONFIG_USB_XHCI #define CONFIG_USB_XHCI_EXYNOS

On Friday, January 30, 2015 at 08:04:50 PM, Simon Glass wrote:
This series adds basic driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types. So far the absolute limit on the number of USB devices is only slightly relaxed.
Only USB controllers have a real driver model device. USB devices (including the hub in the controller) are not modelled as driver model devices. This is for two reasons:
- it is easier since we don't need to bind a whole lot of devices when scanning
- the two main USB devices (block devices and Ethernet) don't have driver mode support yet anyway, so it would be pointless. However the recent network RFC has encouraged me to send this.
The basic approach is to set up the driver model structures in parallel to what already exists rather than to replace them. This allows both driver model and legacy to be used for USB, although not with the same board.
So far only XHCI is supported. As an example the Exynos XHCI driver is converted to driver model.
I would appreciate comments before going further.
Caveats:
- sandbox code is incomplete and there are no tests
- 'usb stop' does not remove existing devices (I have not yet settled on
the best approach)
- the usb.h changes need to be split correctly into the patches once they are final
This series is available at u-boot-dm/usb-working.
Hi!
I'll look at this by the end of next week, I will be free by then. It's not possible for me to do it earlier, sorry. Does this still work for you please?
Best regards, Marek Vasut

Hi Marek,
On 30 January 2015 at 15:16, Marek Vasut marex@denx.de wrote:
On Friday, January 30, 2015 at 08:04:50 PM, Simon Glass wrote:
This series adds basic driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types. So far the absolute limit on the number of USB devices is only slightly relaxed.
Only USB controllers have a real driver model device. USB devices (including the hub in the controller) are not modelled as driver model devices. This is for two reasons:
- it is easier since we don't need to bind a whole lot of devices when scanning
- the two main USB devices (block devices and Ethernet) don't have driver mode support yet anyway, so it would be pointless. However the recent network RFC has encouraged me to send this.
The basic approach is to set up the driver model structures in parallel to what already exists rather than to replace them. This allows both driver model and legacy to be used for USB, although not with the same board.
So far only XHCI is supported. As an example the Exynos XHCI driver is converted to driver model.
I would appreciate comments before going further.
Caveats:
- sandbox code is incomplete and there are no tests
- 'usb stop' does not remove existing devices (I have not yet settled on
the best approach)
- the usb.h changes need to be split correctly into the patches once they are final
This series is available at u-boot-dm/usb-working.
Hi!
I'll look at this by the end of next week, I will be free by then. It's not possible for me to do it earlier, sorry. Does this still work for you please?
Definitely, that sounds good. I was planning to leave it a week or two anyway, although I might fiddle more with the sandbox side in the meantime.
Regards, Simon

On Friday, January 30, 2015 at 11:41:33 PM, Simon Glass wrote:
Hi Marek,
Hi!
On 30 January 2015 at 15:16, Marek Vasut marex@denx.de wrote:
On Friday, January 30, 2015 at 08:04:50 PM, Simon Glass wrote:
This series adds basic driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types. So far the absolute limit on the number of USB devices is only slightly relaxed.
Only USB controllers have a real driver model device. USB devices (including the hub in the controller) are not modelled as driver model devices. This is for two reasons:
it is easier since we don't need to bind a whole lot of devices when
scanning
the two main USB devices (block devices and Ethernet) don't have
driver
mode support yet anyway, so it would be pointless. However the recent network RFC has encouraged me to send this.
The basic approach is to set up the driver model structures in parallel to what already exists rather than to replace them. This allows both driver model and legacy to be used for USB, although not with the same board.
So far only XHCI is supported. As an example the Exynos XHCI driver is converted to driver model.
I would appreciate comments before going further.
Caveats:
- sandbox code is incomplete and there are no tests
- 'usb stop' does not remove existing devices (I have not yet settled
on the best approach)
- the usb.h changes need to be split correctly into the patches once
they
are final
This series is available at u-boot-dm/usb-working.
Hi!
I'll look at this by the end of next week, I will be free by then. It's not possible for me to do it earlier, sorry. Does this still work for you please?
Definitely, that sounds good. I was planning to leave it a week or two anyway, although I might fiddle more with the sandbox side in the meantime.
I skimmed through the series finally, it looks mostly good for but a few minor coding style things. I would prefer if this went in for the next MW, what do you think please ?
Best regards, Marek Vasut

Hi Marek,
On 9 February 2015 at 14:02, Marek Vasut marex@denx.de wrote:
On Friday, January 30, 2015 at 11:41:33 PM, Simon Glass wrote:
Hi Marek,
Hi!
On 30 January 2015 at 15:16, Marek Vasut marex@denx.de wrote:
On Friday, January 30, 2015 at 08:04:50 PM, Simon Glass wrote:
This series adds basic driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types. So far the absolute limit on the number of USB devices is only slightly relaxed.
Only USB controllers have a real driver model device. USB devices (including the hub in the controller) are not modelled as driver model devices. This is for two reasons:
it is easier since we don't need to bind a whole lot of devices when
scanning
the two main USB devices (block devices and Ethernet) don't have
driver
mode support yet anyway, so it would be pointless. However the recent network RFC has encouraged me to send this.
The basic approach is to set up the driver model structures in parallel to what already exists rather than to replace them. This allows both driver model and legacy to be used for USB, although not with the same board.
So far only XHCI is supported. As an example the Exynos XHCI driver is converted to driver model.
I would appreciate comments before going further.
Caveats:
- sandbox code is incomplete and there are no tests
- 'usb stop' does not remove existing devices (I have not yet settled
on the best approach)
- the usb.h changes need to be split correctly into the patches once
they
are final
This series is available at u-boot-dm/usb-working.
Hi!
I'll look at this by the end of next week, I will be free by then. It's not possible for me to do it earlier, sorry. Does this still work for you please?
Definitely, that sounds good. I was planning to leave it a week or two anyway, although I might fiddle more with the sandbox side in the meantime.
I skimmed through the series finally, it looks mostly good for but a few minor coding style things. I would prefer if this went in for the next MW, what do you think please ?
Sounds good, hopefully we can bring in wider driver support too. I'd like to get this lot in before thinking too hard about how to deal with actual devices! Maybe we can target getting this series cleaned up and into u-boot-dm/next by end of Feb?
Regards, Simon

On Tuesday, February 10, 2015 at 06:28:30 AM, Simon Glass wrote:
Hi Marek,
Hi!
[...]
Hi!
I'll look at this by the end of next week, I will be free by then. It's not possible for me to do it earlier, sorry. Does this still work for you please?
Definitely, that sounds good. I was planning to leave it a week or two anyway, although I might fiddle more with the sandbox side in the meantime.
I skimmed through the series finally, it looks mostly good for but a few minor coding style things. I would prefer if this went in for the next MW, what do you think please ?
Sounds good, hopefully we can bring in wider driver support too. I'd like to get this lot in before thinking too hard about how to deal with actual devices! Maybe we can target getting this series cleaned up and into u-boot-dm/next by end of Feb?
I'll be happy to see it there, yes.
Thank you!
Best regards, Marek Vasut

Hi Simon,
On Sat, Jan 31, 2015 at 12:34 AM, Simon Glass sjg@chromium.org wrote:
This series adds basic driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types. So far the absolute limit on the number of USB devices is only slightly relaxed.
Only USB controllers have a real driver model device. USB devices (including the hub in the controller) are not modelled as driver model devices. This is for two reasons:
- it is easier since we don't need to bind a whole lot of devices when scanning
- the two main USB devices (block devices and Ethernet) don't have driver mode support yet anyway, so it would be pointless. However the recent network RFC has encouraged me to send this.
The basic approach is to set up the driver model structures in parallel to what already exists rather than to replace them. This allows both driver model and legacy to be used for USB, although not with the same board.
So far only XHCI is supported. As an example the Exynos XHCI driver is converted to driver model.
I would appreciate comments before going further.
Caveats:
- sandbox code is incomplete and there are no tests
- 'usb stop' does not remove existing devices (I have not yet settled on
the best approach)
- the usb.h changes need to be split correctly into the patches once they are final
This series is available at u-boot-dm/usb-working.
Just ran a quick test on smdk5250. I used Below is what i get :
-------------------------------------------------------------------------------------- SMDK5250 # usb start starting USB... USBRegister 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 0: scanning bus 0 for devices... cannot reset port 1!? 1 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found SMDK5250 # usb start starting USB... USB0: scanning bus 0 for devices... BUG: failure at drivers/usb/host/xhci-mem.c:666/xhci_setup_addressable_virt_dev()! BUG! resetting ... --------------------------------------------------------------------------------------
The first time when "scanning bus 0 for devices... cannot reset port 1!?" comes. This seems to be smdk issue only which i am looking into currently.
But the second time when i run usb start, the setup itself hits a NULL pointer it seems. However just tot of u-boot-dm doesn't give this issue. The device gets detected when "usb reset" is used after doing a "usb start" first time.
Even with my patch series, i hit a NULL pointer BUG, when doing a "usb reset"
-------------------------------------------------------------------------------------- SMDK5250 # usb reset resetting USB... Host not halted after 16000 microseconds. BUG: failure at drivers/usb/host/xhci-mem.c:83/xhci_ring_free()! BUG! resetting ... -------------------------------------------------------------------------------------- However i could understand why this is coming, since usb_lowlevel_stop() called in xhci.c; at that time xhci's data structures are not initialized, and we hit this BUG.
I will check further on snow.
Simon Glass (7): dm: usb: Add a uclass for USB controllers dm: usb: Support driver model in exynos XHCI dm: usb: Adjust users of the USB stack to work with driver model dm: usb: WIP sandbox USB implementation dm: core: Add a function to get the uclass data for a device arm: Show relocated PC/LR in the register dump dm: exynos: Enable driver model for snow XHCI
Makefile | 1 + arch/arm/lib/interrupts.c | 13 +- arch/sandbox/dts/sandbox.dts | 20 +++ arch/sandbox/include/asm/processor.h | 0 common/cmd_usb.c | 74 ++++++++--- common/usb.c | 28 +++-- common/usb_hub.c | 13 +- common/usb_storage.c | 148 +++++++++++++--------- drivers/core/device.c | 10 ++ 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/eth/usb_ether.c | 46 +++++-- drivers/usb/host/Makefile | 5 + drivers/usb/host/usb-sandbox.c | 151 +++++++++++++++++++++++ drivers/usb/host/usb-uclass.c | 227 ++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-exynos5.c | 115 +++++++++++++++++- drivers/usb/host/xhci.c | 229 ++++++++++++++++++++++++++++------- drivers/usb/host/xhci.h | 24 ++++ include/configs/sandbox.h | 3 + include/configs/snow.h | 1 + include/dm/device.h | 10 ++ include/dm/uclass-id.h | 2 + include/usb.h | 76 +++++++++++- include/usb_defs.h | 14 ++- 26 files changed, 1294 insertions(+), 153 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 create mode 100644 drivers/usb/host/usb-uclass.c
-- 2.2.0.rc0.207.ga3a616c
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
participants (4)
-
Albert ARIBAUD
-
Marek Vasut
-
Simon Glass
-
Vivek Gautam