From: Bin Meng Date: Thu, 18 Jul 2019 07:34:01 +0000 (-0700) Subject: doc: driver-model: Convert usb-info.txt to reST X-Git-Tag: v2019.10-rc1~16^2~34 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a077bae3723c58efee3b8c99ac5291aef505a37d;p=platform%2Fkernel%2Fu-boot.git doc: driver-model: Convert usb-info.txt to reST Convert plain text documentation to reStructuredText format and add it to Sphinx TOC tree. No essential content change. Signed-off-by: Bin Meng --- diff --git a/doc/driver-model/index.rst b/doc/driver-model/index.rst index 64151bd165..ea32c36335 100644 --- a/doc/driver-model/index.rst +++ b/doc/driver-model/index.rst @@ -18,3 +18,4 @@ Driver Model remoteproc-framework serial-howto spi-howto + usb-info diff --git a/doc/driver-model/usb-info.rst b/doc/driver-model/usb-info.rst new file mode 100644 index 0000000000..1817df420f --- /dev/null +++ b/doc/driver-model/usb-info.rst @@ -0,0 +1,423 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +How USB works with driver model +=============================== + +Introduction +------------ + +Driver model USB support makes use of existing features but changes how +drivers are found. This document provides some information intended to help +understand how things work with USB in U-Boot when driver model is enabled. + + +Enabling driver model for USB +----------------------------- + +A new CONFIG_DM_USB option is provided to enable driver model for USB. This +causes the USB uclass to be included, and drops the equivalent code in +usb.c. In particular the usb_init() function is then implemented by the +uclass. + + +Support for EHCI and XHCI +------------------------- + +So far OHCI is not supported. Both EHCI and XHCI drivers should be declared +as drivers in the USB uclass. For example: + +.. code-block:: c + + static const struct udevice_id ehci_usb_ids[] = { + { .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 }, + { .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 }, + { .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 }, + { } + }; + + U_BOOT_DRIVER(usb_ehci) = { + .name = "ehci_tegra", + .id = UCLASS_USB, + .of_match = ehci_usb_ids, + .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, + .probe = tegra_ehci_usb_probe, + .remove = tegra_ehci_usb_remove, + .ops = &ehci_usb_ops, + .platdata_auto_alloc_size = sizeof(struct usb_platdata), + .priv_auto_alloc_size = sizeof(struct fdt_usb), + .flags = DM_FLAG_ALLOC_PRIV_DMA, + }; + +Here ehci_usb_ids is used to list the controllers that the driver supports. +Each has its own data value. Controllers must be in the UCLASS_USB uclass. + +The ofdata_to_platdata() method allows the controller driver to grab any +necessary settings from the device tree. + +The ops here are ehci_usb_ops. All EHCI drivers will use these same ops in +most cases, since they are all EHCI-compatible. For EHCI there are also some +special operations that can be overridden when calling ehci_register(). + +The driver can use priv_auto_alloc_size to set the size of its private data. +This can hold run-time information needed by the driver for operation. It +exists when the device is probed (not when it is bound) and is removed when +the driver is removed. + +Note that usb_platdata is currently only used to deal with setting up a bus +in USB device mode (OTG operation). It can be omitted if that is not +supported. + +The driver's probe() method should do the basic controller init and then +call ehci_register() to register itself as an EHCI device. It should call +ehci_deregister() in the remove() method. Registering a new EHCI device +does not by itself cause the bus to be scanned. + +The old ehci_hcd_init() function is no-longer used. Nor is it necessary to +set up the USB controllers from board init code. When 'usb start' is used, +each controller will be probed and its bus scanned. + +XHCI works in a similar way. + + +Data structures +--------------- + +The following primary data structures are in use: + +- struct usb_device: + This holds information about a device on the bus. All devices have + this structure, even the root hub. The controller itself does not + have this structure. You can access it for a device 'dev' with + dev_get_parent_priv(dev). It matches the old structure except that the + parent and child information is not present (since driver model + handles that). Once the device is set up, you can find the device + descriptor and current configuration descriptor in this structure. + +- struct usb_platdata: + This holds platform data for a controller. So far this is only used + as a work-around for controllers which can act as USB devices in OTG + mode, since the gadget framework does not use driver model. + +- struct usb_dev_platdata: + This holds platform data for a device. You can access it for a + device 'dev' with dev_get_parent_platdata(dev). It holds the device + address and speed - anything that can be determined before the device + driver is actually set up. When probing the bus this structure is + used to provide essential information to the device driver. + +- struct usb_bus_priv: + This is private information for each controller, maintained by the + controller uclass. It is mostly used to keep track of the next + device address to use. + +Of these, only struct usb_device was used prior to driver model. + + +USB buses +--------- + +Given a controller, you know the bus - it is the one attached to the +controller. Each controller handles exactly one bus. Every controller has a +root hub attached to it. This hub, which is itself a USB device, can provide +one or more 'ports' to which additional devices can be attached. It is +possible to power up a hub and find out which of its ports have devices +attached. + +Devices are given addresses starting at 1. The root hub is always address 1, +and from there the devices are numbered in sequence. The USB uclass takes +care of this numbering automatically during enumeration. + +USB devices are enumerated by finding a device on a particular hub, and +setting its address to the next available address. The USB bus stretches out +in a tree structure, potentially with multiple hubs each with several ports +and perhaps other hubs. Some hubs will have their own power since otherwise +the 5V 500mA power supplied by the controller will not be sufficient to run +very many devices. + +Enumeration in U-Boot takes a long time since devices are probed one at a +time, and each is given sufficient time to wake up and announce itself. The +timeouts are set for the slowest device. + +Up to 127 devices can be on each bus. USB has four bus speeds: low +(1.5Mbps), full (12Mbps), high (480Mbps) which is only available with USB2 +and newer (EHCI), and super (5Gbps) which is only available with USB3 and +newer (XHCI). If you connect a super-speed device to a high-speed hub, you +will only get high-speed. + + +USB operations +-------------- + +As before driver model, messages can be sent using submit_bulk_msg() and the +like. These are now implemented by the USB uclass and route through the +controller drivers. Note that messages are not sent to the driver of the +device itself - i.e. they don't pass down the stack to the controller. +U-Boot simply finds the controller to which the device is attached, and sends +the message there with an appropriate 'pipe' value so it can be addressed +properly. Having said that, the USB device which should receive the message +is passed in to the driver methods, for use by sandbox. This design decision +is open for review and the code impact of changing it is small since the +methods are typically implemented by the EHCI and XHCI stacks. + +Controller drivers (in UCLASS_USB) themselves provide methods for sending +each message type. For XHCI an additional alloc_device() method is provided +since XHCI needs to allocate a device context before it can even read the +device's descriptor. + +These methods use a 'pipe' which is a collection of bit fields used to +describe the type of message, direction of transfer and the intended +recipient (device number). + + +USB Devices +----------- + +USB devices are found using a simple algorithm which works through the +available hubs in a depth-first search. Devices can be in any uclass, but +are attached to a parent hub (or controller in the case of the root hub) and +so have parent data attached to them (this is struct usb_device). + +By the time the device's probe() method is called, it is enumerated and is +ready to talk to the host. + +The enumeration process needs to work out which driver to attach to each USB +device. It does this by examining the device class, interface class, vendor +ID, product ID, etc. See struct usb_driver_entry for how drivers are matched +with USB devices - you can use the USB_DEVICE() macro to declare a USB +driver. For example, usb_storage.c defines a USB_DEVICE() to handle storage +devices, and it will be used for all USB devices which match. + + + +Technical details on enumeration flow +------------------------------------- + +It is useful to understand precisely how a USB bus is enumerating to avoid +confusion when dealing with USB devices. + +Device initialisation happens roughly like this: + +- At some point the 'usb start' command is run +- This calls usb_init() which works through each controller in turn +- The controller is probed(). This does no enumeration. +- Then usb_scan_bus() is called. This calls usb_scan_device() to scan the + (only) device that is attached to the controller - a root hub +- usb_scan_device() sets up a fake struct usb_device and calls + usb_setup_device(), passing the port number to be scanned, in this case + port 0 +- usb_setup_device() first calls usb_prepare_device() to set the device + address, then usb_select_config() to select the first configuration +- at this point the device is enumerated but we do not have a real struct + udevice for it. But we do have the descriptor in struct usb_device so we can + use this to figure out what driver to use +- back in usb_scan_device(), we call usb_find_child() to try to find an + existing device which matches the one we just found on the bus. This can + happen if the device is mentioned in the device tree, or if we previously + scanned the bus and so the device was created before +- if usb_find_child() does not find an existing device, we call + usb_find_and_bind_driver() which tries to bind one +- usb_find_and_bind_driver() searches all available USB drivers (declared + with USB_DEVICE()). If it finds a match it binds that driver to create a + new device. +- If it does not, it binds a generic driver. A generic driver is good enough + to allow access to the device (sending it packets, etc.) but all + functionality will need to be implemented outside the driver model. +- in any case, when usb_find_child() and/or usb_find_and_bind_driver() are + done, we have a device with the correct uclass. At this point we want to + probe the device +- first we store basic information about the new device (address, port, + speed) in its parent platform data. We cannot store it its private data + since that will not exist until the device is probed. +- then we call device_probe() which probes the device +- the first probe step is actually the USB controller's (or USB hubs's) + child_pre_probe() method. This gets called before anything else and is + intended to set up a child device ready to be used with its parent bus. For + USB this calls usb_child_pre_probe() which grabs the information that was + stored in the parent platform data and stores it in the parent private data + (which is struct usb_device, a real one this time). It then calls + usb_select_config() again to make sure that everything about the device is + set up +- note that we have called usb_select_config() twice. This is inefficient + but the alternative is to store additional information in the platform data. + The time taken is minimal and this way is simpler +- at this point the device is set up and ready for use so far as the USB + subsystem is concerned +- the device's probe() method is then called. It can send messages and do + whatever else it wants to make the device work. + +Note that the first device is always a root hub, and this must be scanned to +find any devices. The above steps will have created a hub (UCLASS_USB_HUB), +given it address 1 and set the configuration. + +For hubs, the hub uclass has a post_probe() method. This means that after +any hub is probed, the uclass gets to do some processing. In this case +usb_hub_post_probe() is called, and the following steps take place: + +- usb_hub_post_probe() calls usb_hub_scan() to scan the hub, which in turn + calls usb_hub_configure() +- hub power is enabled +- we loop through each port on the hub, performing the same steps for each +- first, check if there is a device present. This happens in + usb_hub_port_connect_change(). If so, then usb_scan_device() is called to + scan the device, passing the appropriate port number. +- you will recognise usb_scan_device() from the steps above. It sets up the + device ready for use. If it is a hub, it will scan that hub before it + continues here (recursively, depth-first) +- once all hub ports are scanned in this way, the hub is ready for use and + all of its downstream devices also +- additional controllers are scanned in the same way + +The above method has some nice properties: + +- the bus enumeration happens by virtue of driver model's natural device flow +- most logic is in the USB controller and hub uclasses; the actual device + drivers do not need to know they are on a USB bus, at least so far as + enumeration goes +- hub scanning happens automatically after a hub is probed + + +Hubs +---- + +USB hubs are scanned as in the section above. While hubs have their own +uclass, they share some common elements with controllers: + +- they both attach private data to their children (struct usb_device, + accessible for a child with dev_get_parent_priv(child)) +- they both use usb_child_pre_probe() to set up their children as proper USB + devices + + +Example - Mass Storage +---------------------- + +As an example of a USB device driver, see usb_storage.c. It uses its own +uclass and declares itself as follows: + +.. code-block:: c + + U_BOOT_DRIVER(usb_mass_storage) = { + .name = "usb_mass_storage", + .id = UCLASS_MASS_STORAGE, + .of_match = usb_mass_storage_ids, + .probe = usb_mass_storage_probe, + }; + + static const struct usb_device_id mass_storage_id_table[] = { + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_CLASS_MASS_STORAGE}, + { } /* Terminating entry */ + }; + + USB_DEVICE(usb_mass_storage, mass_storage_id_table); + +The USB_DEVICE() macro attaches the given table of matching information to +the given driver. Note that the driver is declared in U_BOOT_DRIVER() as +'usb_mass_storage' and this must match the first parameter of USB_DEVICE. + +When usb_find_and_bind_driver() is called on a USB device with the +bInterfaceClass value of USB_CLASS_MASS_STORAGE, it will automatically find +this driver and use it. + + +Counter-example: USB Ethernet +----------------------------- + +As an example of the old way of doing things, see usb_ether.c. When the bus +is scanned, all Ethernet devices will be created as generic USB devices (in +uclass UCLASS_USB_DEV_GENERIC). Then, when the scan is completed, +usb_host_eth_scan() will be called. This looks through all the devices on +each bus and manually figures out which are Ethernet devices in the ways of +yore. + +In fact, usb_ether should be moved to driver model. Each USB Ethernet driver +(e.g drivers/usb/eth/asix.c) should include a USB_DEVICE() declaration, so +that it will be found as part of normal USB enumeration. Then, instead of a +generic USB driver, a real (driver-model-aware) driver will be used. Since +Ethernet now supports driver model, this should be fairly easy to achieve, +and then usb_ether.c and the usb_host_eth_scan() will melt away. + + +Sandbox +------- + +All driver model uclasses must have tests and USB is no exception. To +achieve this, a sandbox USB controller is provided. This can make use of +emulation drivers which pretend to be USB devices. Emulations are provided +for a hub and a flash stick. These are enough to create a pretend USB bus +(defined by the sandbox device tree sandbox.dts) which can be scanned and +used. + +Tests in test/dm/usb.c make use of this feature. It allows much of the USB +stack to be tested without real hardware being needed. + +Here is an example device tree fragment: + +.. code-block:: none + + usb@1 { + compatible = "sandbox,usb"; + hub { + compatible = "usb-hub"; + usb,device-class = ; + hub-emul { + compatible = "sandbox,usb-hub"; + #address-cells = <1>; + #size-cells = <0>; + flash-stick { + reg = <0>; + compatible = "sandbox,usb-flash"; + sandbox,filepath = "flash.bin"; + }; + }; + }; + }; + +This defines a single controller, containing a root hub (which is required). +The hub is emulated by a hub emulator, and the emulated hub has a single +flash stick to emulate on one of its ports. + +When 'usb start' is used, the following 'dm tree' output will be available:: + + usb [ + ] `-- usb@1 + usb_hub [ + ] `-- hub + usb_emul [ + ] |-- hub-emul + usb_emul [ + ] | `-- flash-stick + usb_mass_st [ + ] `-- usb_mass_storage + + +This may look confusing. Most of it mirrors the device tree, but the +'usb_mass_storage' device is not in the device tree. This is created by +usb_find_and_bind_driver() based on the USB_DRIVER in usb_storage.c. While +'flash-stick' is the emulation device, 'usb_mass_storage' is the real U-Boot +USB device driver that talks to it. + + +Future work +----------- + +It is pretty uncommon to have a large USB bus with lots of hubs on an +embedded system. In fact anything other than a root hub is uncommon. Still +it would be possible to speed up enumeration in two ways: + +- breadth-first search would allow devices to be reset and probed in + parallel to some extent +- enumeration could be lazy, in the sense that we could enumerate just the + root hub at first, then only progress to the next 'level' when a device is + used that we cannot find. This could be made easier if the devices were + statically declared in the device tree (which is acceptable for production + boards where the same, known, things are on each bus). + +But in common cases the current algorithm is sufficient. + +Other things that need doing: +- Convert usb_ether to use driver model as described above +- Test that keyboards work (and convert to driver model) +- Move the USB gadget framework to driver model +- Implement OHCI in driver model +- Implement USB PHYs in driver model +- Work out a clever way to provide lazy init for USB devices + + +.. Simon Glass +.. 23-Mar-15 diff --git a/doc/driver-model/usb-info.txt b/doc/driver-model/usb-info.txt deleted file mode 100644 index e07e5ba261..0000000000 --- a/doc/driver-model/usb-info.txt +++ /dev/null @@ -1,415 +0,0 @@ -How USB works with driver model -=============================== - -Introduction ------------- - -Driver model USB support makes use of existing features but changes how -drivers are found. This document provides some information intended to help -understand how things work with USB in U-Boot when driver model is enabled. - - -Enabling driver model for USB ------------------------------ - -A new CONFIG_DM_USB option is provided to enable driver model for USB. This -causes the USB uclass to be included, and drops the equivalent code in -usb.c. In particular the usb_init() function is then implemented by the -uclass. - - -Support for EHCI and XHCI -------------------------- - -So far OHCI is not supported. Both EHCI and XHCI drivers should be declared -as drivers in the USB uclass. For example: - -static const struct udevice_id ehci_usb_ids[] = { - { .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 }, - { .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 }, - { .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 }, - { } -}; - -U_BOOT_DRIVER(usb_ehci) = { - .name = "ehci_tegra", - .id = UCLASS_USB, - .of_match = ehci_usb_ids, - .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, - .probe = tegra_ehci_usb_probe, - .remove = tegra_ehci_usb_remove, - .ops = &ehci_usb_ops, - .platdata_auto_alloc_size = sizeof(struct usb_platdata), - .priv_auto_alloc_size = sizeof(struct fdt_usb), - .flags = DM_FLAG_ALLOC_PRIV_DMA, -}; - -Here ehci_usb_ids is used to list the controllers that the driver supports. -Each has its own data value. Controllers must be in the UCLASS_USB uclass. - -The ofdata_to_platdata() method allows the controller driver to grab any -necessary settings from the device tree. - -The ops here are ehci_usb_ops. All EHCI drivers will use these same ops in -most cases, since they are all EHCI-compatible. For EHCI there are also some -special operations that can be overridden when calling ehci_register(). - -The driver can use priv_auto_alloc_size to set the size of its private data. -This can hold run-time information needed by the driver for operation. It -exists when the device is probed (not when it is bound) and is removed when -the driver is removed. - -Note that usb_platdata is currently only used to deal with setting up a bus -in USB device mode (OTG operation). It can be omitted if that is not -supported. - -The driver's probe() method should do the basic controller init and then -call ehci_register() to register itself as an EHCI device. It should call -ehci_deregister() in the remove() method. Registering a new EHCI device -does not by itself cause the bus to be scanned. - -The old ehci_hcd_init() function is no-longer used. Nor is it necessary to -set up the USB controllers from board init code. When 'usb start' is used, -each controller will be probed and its bus scanned. - -XHCI works in a similar way. - - -Data structures ---------------- - -The following primary data structures are in use: - -- struct usb_device - This holds information about a device on the bus. All devices have - this structure, even the root hub. The controller itself does not - have this structure. You can access it for a device 'dev' with - dev_get_parent_priv(dev). It matches the old structure except that the - parent and child information is not present (since driver model - handles that). Once the device is set up, you can find the device - descriptor and current configuration descriptor in this structure. - -- struct usb_platdata - This holds platform data for a controller. So far this is only used - as a work-around for controllers which can act as USB devices in OTG - mode, since the gadget framework does not use driver model. - -- struct usb_dev_platdata - This holds platform data for a device. You can access it for a - device 'dev' with dev_get_parent_platdata(dev). It holds the device - address and speed - anything that can be determined before the device - driver is actually set up. When probing the bus this structure is - used to provide essential information to the device driver. - -- struct usb_bus_priv - This is private information for each controller, maintained by the - controller uclass. It is mostly used to keep track of the next - device address to use. - -Of these, only struct usb_device was used prior to driver model. - - -USB buses ---------- - -Given a controller, you know the bus - it is the one attached to the -controller. Each controller handles exactly one bus. Every controller has a -root hub attached to it. This hub, which is itself a USB device, can provide -one or more 'ports' to which additional devices can be attached. It is -possible to power up a hub and find out which of its ports have devices -attached. - -Devices are given addresses starting at 1. The root hub is always address 1, -and from there the devices are numbered in sequence. The USB uclass takes -care of this numbering automatically during enumeration. - -USB devices are enumerated by finding a device on a particular hub, and -setting its address to the next available address. The USB bus stretches out -in a tree structure, potentially with multiple hubs each with several ports -and perhaps other hubs. Some hubs will have their own power since otherwise -the 5V 500mA power supplied by the controller will not be sufficient to run -very many devices. - -Enumeration in U-Boot takes a long time since devices are probed one at a -time, and each is given sufficient time to wake up and announce itself. The -timeouts are set for the slowest device. - -Up to 127 devices can be on each bus. USB has four bus speeds: low -(1.5Mbps), full (12Mbps), high (480Mbps) which is only available with USB2 -and newer (EHCI), and super (5Gbps) which is only available with USB3 and -newer (XHCI). If you connect a super-speed device to a high-speed hub, you -will only get high-speed. - - -USB operations --------------- - -As before driver model, messages can be sent using submit_bulk_msg() and the -like. These are now implemented by the USB uclass and route through the -controller drivers. Note that messages are not sent to the driver of the -device itself - i.e. they don't pass down the stack to the controller. -U-Boot simply finds the controller to which the device is attached, and sends -the message there with an appropriate 'pipe' value so it can be addressed -properly. Having said that, the USB device which should receive the message -is passed in to the driver methods, for use by sandbox. This design decision -is open for review and the code impact of changing it is small since the -methods are typically implemented by the EHCI and XHCI stacks. - -Controller drivers (in UCLASS_USB) themselves provide methods for sending -each message type. For XHCI an additional alloc_device() method is provided -since XHCI needs to allocate a device context before it can even read the -device's descriptor. - -These methods use a 'pipe' which is a collection of bit fields used to -describe the type of message, direction of transfer and the intended -recipient (device number). - - -USB Devices ------------ - -USB devices are found using a simple algorithm which works through the -available hubs in a depth-first search. Devices can be in any uclass, but -are attached to a parent hub (or controller in the case of the root hub) and -so have parent data attached to them (this is struct usb_device). - -By the time the device's probe() method is called, it is enumerated and is -ready to talk to the host. - -The enumeration process needs to work out which driver to attach to each USB -device. It does this by examining the device class, interface class, vendor -ID, product ID, etc. See struct usb_driver_entry for how drivers are matched -with USB devices - you can use the USB_DEVICE() macro to declare a USB -driver. For example, usb_storage.c defines a USB_DEVICE() to handle storage -devices, and it will be used for all USB devices which match. - - - -Technical details on enumeration flow -------------------------------------- - -It is useful to understand precisely how a USB bus is enumerating to avoid -confusion when dealing with USB devices. - -Device initialisation happens roughly like this: - -- At some point the 'usb start' command is run -- This calls usb_init() which works through each controller in turn -- The controller is probed(). This does no enumeration. -- Then usb_scan_bus() is called. This calls usb_scan_device() to scan the -(only) device that is attached to the controller - a root hub -- usb_scan_device() sets up a fake struct usb_device and calls -usb_setup_device(), passing the port number to be scanned, in this case port -0 -- usb_setup_device() first calls usb_prepare_device() to set the device -address, then usb_select_config() to select the first configuration -- at this point the device is enumerated but we do not have a real struct -udevice for it. But we do have the descriptor in struct usb_device so we can -use this to figure out what driver to use -- back in usb_scan_device(), we call usb_find_child() to try to find an -existing device which matches the one we just found on the bus. This can -happen if the device is mentioned in the device tree, or if we previously -scanned the bus and so the device was created before -- if usb_find_child() does not find an existing device, we call -usb_find_and_bind_driver() which tries to bind one -- usb_find_and_bind_driver() searches all available USB drivers (declared -with USB_DEVICE()). If it finds a match it binds that driver to create a new -device. -- If it does not, it binds a generic driver. A generic driver is good enough -to allow access to the device (sending it packets, etc.) but all -functionality will need to be implemented outside the driver model. -- in any case, when usb_find_child() and/or usb_find_and_bind_driver() are -done, we have a device with the correct uclass. At this point we want to -probe the device -- first we store basic information about the new device (address, port, -speed) in its parent platform data. We cannot store it its private data -since that will not exist until the device is probed. -- then we call device_probe() which probes the device -- the first probe step is actually the USB controller's (or USB hubs's) -child_pre_probe() method. This gets called before anything else and is -intended to set up a child device ready to be used with its parent bus. For -USB this calls usb_child_pre_probe() which grabs the information that was -stored in the parent platform data and stores it in the parent private data -(which is struct usb_device, a real one this time). It then calls -usb_select_config() again to make sure that everything about the device is -set up -- note that we have called usb_select_config() twice. This is inefficient -but the alternative is to store additional information in the platform data. -The time taken is minimal and this way is simpler -- at this point the device is set up and ready for use so far as the USB -subsystem is concerned -- the device's probe() method is then called. It can send messages and do -whatever else it wants to make the device work. - -Note that the first device is always a root hub, and this must be scanned to -find any devices. The above steps will have created a hub (UCLASS_USB_HUB), -given it address 1 and set the configuration. - -For hubs, the hub uclass has a post_probe() method. This means that after -any hub is probed, the uclass gets to do some processing. In this case -usb_hub_post_probe() is called, and the following steps take place: - -- usb_hub_post_probe() calls usb_hub_scan() to scan the hub, which in turn -calls usb_hub_configure() -- hub power is enabled -- we loop through each port on the hub, performing the same steps for each -- first, check if there is a device present. This happens in -usb_hub_port_connect_change(). If so, then usb_scan_device() is called to -scan the device, passing the appropriate port number. -- you will recognise usb_scan_device() from the steps above. It sets up the -device ready for use. If it is a hub, it will scan that hub before it -continues here (recursively, depth-first) -- once all hub ports are scanned in this way, the hub is ready for use and -all of its downstream devices also -- additional controllers are scanned in the same way - -The above method has some nice properties: - -- the bus enumeration happens by virtue of driver model's natural device flow -- most logic is in the USB controller and hub uclasses; the actual device -drivers do not need to know they are on a USB bus, at least so far as -enumeration goes -- hub scanning happens automatically after a hub is probed - - -Hubs ----- - -USB hubs are scanned as in the section above. While hubs have their own -uclass, they share some common elements with controllers: - -- they both attach private data to their children (struct usb_device, -accessible for a child with dev_get_parent_priv(child)) -- they both use usb_child_pre_probe() to set up their children as proper USB -devices - - -Example - Mass Storage ----------------------- - -As an example of a USB device driver, see usb_storage.c. It uses its own -uclass and declares itself as follows: - -U_BOOT_DRIVER(usb_mass_storage) = { - .name = "usb_mass_storage", - .id = UCLASS_MASS_STORAGE, - .of_match = usb_mass_storage_ids, - .probe = usb_mass_storage_probe, -}; - -static const struct usb_device_id mass_storage_id_table[] = { - { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, - .bInterfaceClass = USB_CLASS_MASS_STORAGE}, - { } /* Terminating entry */ -}; - -USB_DEVICE(usb_mass_storage, mass_storage_id_table); - -The USB_DEVICE() macro attaches the given table of matching information to -the given driver. Note that the driver is declared in U_BOOT_DRIVER() as -'usb_mass_storage' and this must match the first parameter of USB_DEVICE. - -When usb_find_and_bind_driver() is called on a USB device with the -bInterfaceClass value of USB_CLASS_MASS_STORAGE, it will automatically find -this driver and use it. - - -Counter-example: USB Ethernet ------------------------------ - -As an example of the old way of doing things, see usb_ether.c. When the bus -is scanned, all Ethernet devices will be created as generic USB devices (in -uclass UCLASS_USB_DEV_GENERIC). Then, when the scan is completed, -usb_host_eth_scan() will be called. This looks through all the devices on -each bus and manually figures out which are Ethernet devices in the ways of -yore. - -In fact, usb_ether should be moved to driver model. Each USB Ethernet driver -(e.g drivers/usb/eth/asix.c) should include a USB_DEVICE() declaration, so -that it will be found as part of normal USB enumeration. Then, instead of a -generic USB driver, a real (driver-model-aware) driver will be used. Since -Ethernet now supports driver model, this should be fairly easy to achieve, -and then usb_ether.c and the usb_host_eth_scan() will melt away. - - -Sandbox -------- - -All driver model uclasses must have tests and USB is no exception. To -achieve this, a sandbox USB controller is provided. This can make use of -emulation drivers which pretend to be USB devices. Emulations are provided -for a hub and a flash stick. These are enough to create a pretend USB bus -(defined by the sandbox device tree sandbox.dts) which can be scanned and -used. - -Tests in test/dm/usb.c make use of this feature. It allows much of the USB -stack to be tested without real hardware being needed. - -Here is an example device tree fragment: - - usb@1 { - compatible = "sandbox,usb"; - hub { - compatible = "usb-hub"; - usb,device-class = ; - hub-emul { - compatible = "sandbox,usb-hub"; - #address-cells = <1>; - #size-cells = <0>; - flash-stick { - reg = <0>; - compatible = "sandbox,usb-flash"; - sandbox,filepath = "flash.bin"; - }; - }; - }; - }; - -This defines a single controller, containing a root hub (which is required). -The hub is emulated by a hub emulator, and the emulated hub has a single -flash stick to emulate on one of its ports. - -When 'usb start' is used, the following 'dm tree' output will be available: - - usb [ + ] `-- usb@1 - usb_hub [ + ] `-- hub - usb_emul [ + ] |-- hub-emul - usb_emul [ + ] | `-- flash-stick - usb_mass_st [ + ] `-- usb_mass_storage - - -This may look confusing. Most of it mirrors the device tree, but the -'usb_mass_storage' device is not in the device tree. This is created by -usb_find_and_bind_driver() based on the USB_DRIVER in usb_storage.c. While -'flash-stick' is the emulation device, 'usb_mass_storage' is the real U-Boot -USB device driver that talks to it. - - -Future work ------------ - -It is pretty uncommon to have a large USB bus with lots of hubs on an -embedded system. In fact anything other than a root hub is uncommon. Still -it would be possible to speed up enumeration in two ways: - -- breadth-first search would allow devices to be reset and probed in -parallel to some extent -- enumeration could be lazy, in the sense that we could enumerate just the -root hub at first, then only progress to the next 'level' when a device is -used that we cannot find. This could be made easier if the devices were -statically declared in the device tree (which is acceptable for production -boards where the same, known, things are on each bus). - -But in common cases the current algorithm is sufficient. - -Other things that need doing: -- Convert usb_ether to use driver model as described above -- Test that keyboards work (and convert to driver model) -- Move the USB gadget framework to driver model -- Implement OHCI in driver model -- Implement USB PHYs in driver model -- Work out a clever way to provide lazy init for USB devices - --- -Simon Glass -23-Mar-15