The last piece of USB infrastructure is hubs. Although hubs are separate USB devices, they are closely related to other parts of the infrastructure so that the hub specification is part of the basic USB specification, and the support code is part of the kernel located in the bus / usb / hub.inc file .
SET_INTERFACE . The existence in nature of hubs that support the mode with different TT is not confirmed, as well as the benefits of this mode, so the hub driver does not even try to detect and enable it and simply uses the single TT mode, which is enabled by default.usb_hub_callbacks structure containing pointers to the usb_hub_init and usb_hub_disconnect driver functions. The driver operation begins when the logic device level calls usb_hub_init , and ends when the channel support level causes usb_hub_disconnect in response to the device disconnecting.usb_hub_init and continues in other functions as it usb_hub_init responses from the device. usb_hub_init opens a channel to the interrupt type endpoint, through which the hub will notify the driver about changes in the status of connected devices. Next, usb_hub_init sends a GET_DESCRIPTOR request to the hub handle .
29h ;32h=50 corresponds to 100 ms;usb_hub_init saves the endpoint packet size — it will be needed later — and requests 40 bytes of the hub descriptor, allowing a short response. After receiving the hub handle, usb_hub_got_config allocates and fills enough memory to store interesting data, plus two variables for each port: a pointer to the connected device and the device connection time.SET_FEATURE(PORT_POWER) . At the input, the command accepts a port number, counting from 1. Physically, the hub can support powering on and off for each port or be limited to two states “there is no power on all ports” and “power is on all ports” - the organization can be learned from the two lower bits of the attributes hub, 00 corresponds to the total power, 01 - separate, 10 and 11 are reserved. But in both cases, the hub maintains a separate logical state for each port and will not report events on ports with a power-off logic, so regardless of the physical organization, you need to turn on the power on each port. usb_hub_got_config and usb_hub_port_powered consistently usb_hub_port_powered a power-on command for all ports.usb_hub_process_deferred function. After the allotted interval usb_hub_process_deferred , usb_hub_process_deferred starts working with the hub.
usb_hub_wait_change , which requests data from the interrupt type endpoint. While there are no events requiring attention with the hub, the request waits without demanding CPU resources: the host controller periodically polls the endpoint without any intervention from the CPU to determine if there is any data. I remind you that the polling interval is encoded by the last byte of the endpoint descriptor and is set when the channel is opened. When the state of the hub has changed, the hub returns a bit mask indicating the ports whose state has changed, plus the low-order bit indicating whether the state of the hub itself has changed. If at the initialization of the hub some devices have already been connected to it, the first time the hub requests it, it will immediately return a change with respect to the “zero” state.usb_hub_init saved it, not limited to transferring to the channel open function.GET_STATUS , returning both the current status bits and the change bits, and CLEAR_FEATURE , one way to use which is to reset the specified change bit. Due to the fact that these are two different teams, the following situation is possible:GET_STATUS command and sees the device connection in the current state and in the state change,CLEAR_FEATURE command, the hub clears the change bit,GET_STATUS command, in GET_STATUS to find out what happened, and the CLEAR_FEATURE to clear the changes, you need to send the GET_STATUS command GET_STATUS to get the current status. It is possible that the second GET_STATUS command GET_STATUS again report changes in state after CLEAR_FEATURE ; although stopping processing at this point is correct - the next time the data is read from the end point of the interrupt type, the hub will immediately report a new change - more efficiently, since the host has learned about the change, update the host’s view of the world behind the hub and do a cycle: send a second CLEAR_FEATURE command and the third GET_STATUS and so on, until GET_STATUS reports no new changes.usb_hub_changed function. It looks at the state of which ports has changed, for each port it launches the above-described request-status-and-confirm-change cycle, accumulating incoming changes. The response to most changes is the corresponding debug print. It is necessary to process only device connection / disconnection notifications.usb_hub_changed remembers the connection time, after which usb_hub_process_deferred plans to wake up in 100 milliseconds. If within 100 milliseconds a signal arrives to disconnect a device on the same port, further actions are canceled. Unfortunately, the absence of such a signal does not mean that the device has been connected for all these 100 milliseconds - perhaps the polling interval is quite large and the signal has not reached yet. For reliability, after a 100 millisecond interval, usb_hub_process_deferred sends an explicit GET_STATUS request. If it shows that there was no change in the connection status, then further initialization is enabled. You cannot reset two devices on the same bus in parallel; if there is a reset of some other device connected to the same controller - not necessarily the same hub - then first the device is waiting for its turn to reset. The reset is activated by the SET_FEATURE(PORT_RESET) command SET_FEATURE(PORT_RESET) and is turned off by the hub automatically after 10 ms of the specified specification, which sets the reset status bit, which may or may not be noticed in time when reading the end point depending on the polling interval. Because of this uncertainty, usb_hub_process_deferred sends usb_hub_process_deferred independently after a set time and CLEAR_FEATURE , and the change processing code, if it still sees a change in the reset state, simply ignores it. The end of the reset in the hub at the same time includes broadcast traffic to the device. After resetting according to the usb_hub_process_deferred specification, another 10 milliseconds usb_hub_process_deferred , during which the device can adapt, and then passes control to the host controllers support code by calling usb_hardware_func.NewDevice . The device speed required for usb_hardware_func.NewDevice determined by the hub during the reset process and returned along with the other state of the device in response to GET_STATUS . A pointer to the connected device returned from usb_hardware_func.NewDevice is stored in the structure of the hub.usb_hub_changed device is disconnected, usb_hub_changed calls the usb_device_disconnected channel support function, passing the previously stored pointer from NewDevice . If the device was in the process of initialization, the process is terminated.usb_hub_disconnected handler, called when the hub is disconnected, calls usb_device_disconnected for all connected devices, advances the queue of devices waiting to be reset — if the device was reset when one of the devices was disconnected and frees the allocated memory for the hub structure.
Source: https://habr.com/ru/post/203918/
All Articles