
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,