Commit 7f1a07538f71b2b0f37744bdc899be294e0518b5
Committed by
Simon Glass
1 parent
f78a5c0774
Exists in
v2017.01-smarct4x
and in
34 other branches
dm: usb: Copy over usb_device values from usb_scan_device() to final usb_device
Currently we copy over a number of usb_device values stored in the on stack struct usb_device probed in usb_scan_device() to the final driver-model managed struct usb_device in usb_child_pre_probe() through usb_device_platdata, and then call usb_select_config() to fill in the rest. There are 3 problems with this approach: 1) It does not fill in enough fields before calling usb_select_config(), specifically it does not fill in ep0's maxpacketsize causing a div by zero exception in the ehci driver. 2) It unnecessarily redoes a number of usb requests making usb probing slower 3) Calling usb_select_config() a second time fails on some usb-1 devices plugged into usb-2 hubs, causing u-boot to not recognize these devices. This commit fixes these issues by removing (*) the usb_select_config() call from usb_child_pre_probe(), and instead of copying over things field by field through usb_device_platdata, store a pointer to the in stack usb_device (which is still valid when usb_child_pre_probe() gets called) and copy over the entire struct. *) Except for devices which are explictly instantiated through device-tree rather then discovered through usb_scan_device() such as emulated usb devices in the sandbox. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Simon Glass <sjg@chromium.org>
Showing 2 changed files with 38 additions and 22 deletions Side-by-side Diff
drivers/usb/host/usb-uclass.c
... | ... | @@ -533,11 +533,7 @@ |
533 | 533 | plat = dev_get_parent_platdata(dev); |
534 | 534 | debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat); |
535 | 535 | plat->devnum = udev->devnum; |
536 | - plat->speed = udev->speed; | |
537 | - plat->slot_id = udev->slot_id; | |
538 | - plat->portnr = port; | |
539 | - debug("** device '%s': stashing slot_id=%d\n", dev->name, | |
540 | - plat->slot_id); | |
536 | + plat->udev = udev; | |
541 | 537 | priv->next_addr++; |
542 | 538 | ret = device_probe(dev); |
543 | 539 | if (ret) { |
544 | 540 | |
... | ... | @@ -597,17 +593,34 @@ |
597 | 593 | struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); |
598 | 594 | int ret; |
599 | 595 | |
600 | - udev->controller_dev = usb_get_bus(dev); | |
601 | - udev->dev = dev; | |
602 | - udev->devnum = plat->devnum; | |
603 | - udev->slot_id = plat->slot_id; | |
604 | - udev->portnr = plat->portnr; | |
605 | - udev->speed = plat->speed; | |
606 | - debug("** device '%s': getting slot_id=%d\n", dev->name, plat->slot_id); | |
596 | + if (plat->udev) { | |
597 | + /* | |
598 | + * Copy over all the values set in the on stack struct | |
599 | + * usb_device in usb_scan_device() to our final struct | |
600 | + * usb_device for this dev. | |
601 | + */ | |
602 | + *udev = *(plat->udev); | |
603 | + /* And clear plat->udev as it will not be valid for long */ | |
604 | + plat->udev = NULL; | |
605 | + udev->dev = dev; | |
606 | + } else { | |
607 | + /* | |
608 | + * This happens with devices which are explicitly bound | |
609 | + * instead of being discovered through usb_scan_device() | |
610 | + * such as sandbox emul devices. | |
611 | + */ | |
612 | + udev->dev = dev; | |
613 | + udev->controller_dev = usb_get_bus(dev); | |
614 | + udev->devnum = plat->devnum; | |
607 | 615 | |
608 | - ret = usb_select_config(udev); | |
609 | - if (ret) | |
610 | - return ret; | |
616 | + /* | |
617 | + * udev did not go through usb_scan_device(), so we need to | |
618 | + * select the config and read the config descriptors. | |
619 | + */ | |
620 | + ret = usb_select_config(udev); | |
621 | + if (ret) | |
622 | + return ret; | |
623 | + } | |
611 | 624 | |
612 | 625 | return 0; |
613 | 626 | } |
include/usb.h
... | ... | @@ -571,20 +571,23 @@ |
571 | 571 | * This is used by sandbox to provide emulation data also. |
572 | 572 | * |
573 | 573 | * @id: ID used to match this device |
574 | - * @speed: Stores the speed associated with a USB device | |
575 | 574 | * @devnum: Device address on the USB bus |
576 | - * @slot_id: USB3 slot ID, which is separate from the device address | |
577 | - * @portnr: Port number of this device on its parent hub, numbered from 1 | |
578 | - * (0 mean this device is the root hub) | |
575 | + * @udev: usb-uclass internal use only do NOT use | |
579 | 576 | * @strings: List of descriptor strings (for sandbox emulation purposes) |
580 | 577 | * @desc_list: List of descriptors (for sandbox emulation purposes) |
581 | 578 | */ |
582 | 579 | struct usb_dev_platdata { |
583 | 580 | struct usb_device_id id; |
584 | - enum usb_device_speed speed; | |
585 | 581 | int devnum; |
586 | - int slot_id; | |
587 | - int portnr; /* Hub port number, 1..n */ | |
582 | + /* | |
583 | + * This pointer is used to pass the usb_device used in usb_scan_device, | |
584 | + * to get the usb descriptors before the driver is known, to the | |
585 | + * actual udevice once the driver is known and the udevice is created. | |
586 | + * This will be NULL except during probe, do NOT use. | |
587 | + * | |
588 | + * This should eventually go away. | |
589 | + */ | |
590 | + struct usb_device *udev; | |
588 | 591 | #ifdef CONFIG_SANDBOX |
589 | 592 | struct usb_string *strings; |
590 | 593 | /* NULL-terminated list of descriptor pointers */ |