
This function returns NULL on error at present. Adjust it so that we can return a real error, as is needed with driver model. Also improve the error handling in its caller, usb_hub_port_connect_change(), and adjust the code order to prepare for driver model.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
common/usb.c | 17 ++++++++--------- common/usb_hub.c | 41 ++++++++++++++++++++++++++--------------- include/usb.h | 20 ++++++++++++++++++-- 3 files changed, 52 insertions(+), 26 deletions(-)
diff --git a/common/usb.c b/common/usb.c index 32e15cd..f87c6a5 100644 --- a/common/usb.c +++ b/common/usb.c @@ -94,12 +94,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) @@ -827,16 +827,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(struct udevice *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 +843,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 +853,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(struct udevice *controller) { dev_index--; debug("Freeing device node: %d\n", dev_index); diff --git a/common/usb_hub.c b/common/usb_hub.c index 66b4a72..7199e25 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -24,6 +24,7 @@
#include <common.h> #include <command.h> +#include <errno.h> #include <asm/processor.h> #include <asm/unaligned.h> #include <linux/ctype.h> @@ -206,16 +207,18 @@ int hub_port_reset(struct usb_device *dev, int port, }
-void usb_hub_port_connect_change(struct usb_device *dev, int port) +int 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, speed;
/* Check status */ - if (usb_get_port_status(dev, port + 1, portsts) < 0) { + ret = usb_get_port_status(dev, port + 1, portsts); + if (ret < 0) { debug("get_port_status failed\n"); - return; + return ret; }
portstatus = le16_to_cpu(portsts->wPortStatus); @@ -233,47 +236,55 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) debug("usb_disconnect(&hub->children[port]);\n"); /* Return now if nothing is connected */ if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return; + return -ENOTCONN; } mdelay(200);
/* Reset the port */ - if (hub_port_reset(dev, port, &portstatus) < 0) { + ret = hub_port_reset(dev, port, &portstatus); + if (ret < 0) { printf("cannot reset port %i!?\n", port + 1); - return; + return ret; }
mdelay(200);
- /* Allocate a new device struct for it */ - usb = usb_alloc_new_device(dev->controller); - switch (portstatus & USB_PORT_STAT_SPEED_MASK) { case USB_PORT_STAT_SUPER_SPEED: - usb->speed = USB_SPEED_SUPER; + speed = USB_SPEED_SUPER; break; case USB_PORT_STAT_HIGH_SPEED: - usb->speed = USB_SPEED_HIGH; + speed = USB_SPEED_HIGH; break; case USB_PORT_STAT_LOW_SPEED: - usb->speed = USB_SPEED_LOW; + speed = USB_SPEED_LOW; break; default: - usb->speed = USB_SPEED_FULL; + speed = USB_SPEED_FULL; break; }
+ ret = usb_alloc_new_device(dev->controller, &usb); + if (ret) { + printf("cannot create new device: ret=%d", ret); + return ret; + } + dev->children[port] = usb; + usb->speed = speed; usb->parent = dev; usb->portnr = port + 1; /* Run it through the hoops (find a driver, etc) */ - if (usb_new_device(usb)) { + ret = usb_new_device(usb); + if (ret < 0) { /* 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); } + + return ret; }
diff --git a/include/usb.h b/include/usb.h index 0e1c16a..11ff5ab 100644 --- a/include/usb.h +++ b/include/usb.h @@ -703,10 +703,26 @@ 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); +/** + * usb_alloc_new_device() - Allocate a new device + * + * @devp: returns a pointer of a new device structure. With driver model this + * is a device pointer, but with legacy USB this pointer is + * driver-specific. + * @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); + +/** + * usb_free_device() - Free a partially-inited device + * + * This is an internal function. It is used to reverse the action of + * usb_alloc_new_device() when we hit a problem during init. + */ +void usb_free_device(struct udevice *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_ */