diff mbox

[U-Boot,RFC,1/7] dm: usb: Add a uclass for USB controllers

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

Commit Message

Simon Glass Jan. 30, 2015, 7:04 p.m. UTC
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

Comments

Marek Vasut Feb. 9, 2015, 8:59 p.m. UTC | #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
Vivek Gautam March 9, 2015, 6:20 a.m. UTC | #2
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
Vivek Gautam March 9, 2015, 6:32 a.m. UTC | #3
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.
diff mbox

Patch

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,