📜 ⬆️ ⬇️

USB support in KolibriOS: what's inside? Part 1: general scheme

The USB architecture contains several levels. At the lowest level, a specially trained hardware, called the host controller , communicates with the USB device with special signals. Signals encode bits, bits add up into packets, packets form transactions , transactions make up transfers .

I’m talking about USB software support, so the levels below are almost uninteresting: the host controller is responsible for them. But it is important which interface represents the host controller software. Three interfaces are now distributed, and the fourth is gradually spreading:
Abbr.Interface nameVersionCode support controller in KolibriOS
UhciUniversal Host Controller InterfaceUSB 1.1kernel / trunk / bus / usb / uhci.inc
OHCIOpen Host Controller InterfaceUSB 1.1kernel / trunk / bus / usb / ohci.inc
EHCIEnhanced Host Controller InterfaceUSB 2.0kernel / trunk / bus / usb / ehci.inc
XhcieXtensible Host Controller Interface (new)USB 3.0Not supported in KolibriOS
At the same level of interaction with controllers, there are files kernel / trunk / bus / usb / hccommon.inc , where some functions common to all controllers are implemented, and kernel / trunk / bus / usb / init.inc , which starts the whole subsystem. However, do not rush into the code yet - firstly, I haven’t told yet what higher levels are expected of it, and secondly, after showing the general scheme, I will return to the individual components with details.


Some theory


From a software point of view, any USB device is a set of endpoints to which you can open pipes and organize transfers of various types. Each endpoint has its own number, from 0 to 15. Two endpoints can have one number only if they are both unidirectional, one of which is intended for transmissions from host to device, and the other in the opposite direction.

Depending on the type of gear being processed, there are four types of end points.



USB bus time is measured in frames or microframes . Frames appeared in USB1, one frame - one millisecond. Microframes appeared in USB2, in one frame 8 microframes. The USB infrastructure plans interrupt and isochronous transfers to specific (micro) frames so as to guarantee the requested time interval between transfers. Planning has no right to use more than 90% of the frame or more than 80% of the microframe. The remaining time (at least 10% / 20%, although it may be more, if not all the time is planned) is occupied by active control transmissions and, by residual, transmission of data arrays.

Channel Support Level


The file kernel / trunk / bus / usb / pipe.inc contains the implementation of channel handling functions. Enough detailed documentation is in kernel / trunk / docs / usbapi.txt . Now 4 functions are implemented. The first two of them are:

The channel support level also handles a device shutdown event, closing all channels associated with the device. So explicitly closing the channel is optional. The attentive reader may be indignant here: “So, the channel may suddenly close by itself?” But you should not worry - the device disconnect event, in addition to processing at the current level, is also broadcast “upward”. The channel is finally closed only after everyone has a chance to handle the device disconnect event. More precisely, the channel handle can be used at least up to the moment when the handlers “from above” finish their work. The handler in the driver is described in the documentation as DeviceDisconnected, although the real name can be any — the driver provides a pointer to this function.
')
Before introducing the following two functions, I should note the following. Each channel has its own transmission queue . In the same queue can be several transmissions at the same time, but only one of them can be active - the one that is in the head of the queue. The next transfer will begin only after the active transfer is fully successful. If any transfer fails, the queue will stop. Why do I need a queue? For efficiency: software processing of the completed transfer may take some time, the host controller may well not wait for the handler's reaction, and in the meantime, proceed further. Queues of different channels are independent, transmissions for different channels are performed in parallel.

The attentive reader, no doubt, noticed a lack of functions. I'm working on it.
The channel support level also includes the file kernel / trunk / bus / usb / scheduler.inc ; he is responsible for scheduling gears that are time sensitive.

Logic level


In the theory summary, I have already said that any USB device must have a zero control endpoint, through which the infrastructure polls the device and performs the initial configuration. The file kernel / trunk / bus / usb / protocol.inc is exactly what it does, based on the level of support for the channels. The result of this level: a loaded device driver that received a call to the function described in the documentation as AddDevice . Then everything is in the hands of the driver. The first argument to the AddDevice function is the handle of the channel open to the null endpoint. Using it, the driver can open the additional channels needed by him, as well as make additional tuning through the zero end point. The return value of AddDevice — either zero on error, or an abstract parameter that the USB infrastructure does not interpret, except for a comparison with zero — stores it inside the device information and then passes it to the DeviceDisconnected function, which I already mentioned .
To describe the two remaining parameters of the AddDevice function , I will need a little more theory.
2 * PS / 2 adapter - & gt;  USB
A single physical device can provide multiple interfaces that can be programmed to one degree or another independently. In particular, each interface has its own set of endpoints. A good example is the numerous PS / 2 to USB adapters that provide two inputs for mouse and keyboard; This USB device provides two unlinked interfaces. A less obvious, but more common example: USB-keyboards with special buttons are often presented as two independent interfaces, one is a keyboard with standard buttons, the other is additional buttons.
A USB device is required to support a request for various descriptors , in particular, a configuration descriptor . In response to a request for a configuration descriptor, the device also returns a lot of related information, including descriptors for all interfaces and all endpoints associated with the interface. The endpoint descriptor contains all the information necessary to open a channel to it.
The second argument to the AddDevice function is a pointer to the data associated with the configuration descriptor, starting with the configuration descriptor itself; one of its fields is the total data length. The third argument to the AddDevice function is a pointer to an interface handle for which the driver is responsible.
If a device implements multiple interfaces, then the logic device level will trigger the driver — or several drivers — several times. The responsibility of one AddDevice call extends from the interface descriptor that was transferred to it, to the next interface descriptor, or to the end of the data; On this interval are descriptors of all end points of this interface.

Device drivers


This is the highest level in USB architecture. Device drivers use the API level support channels and information collected by the level of the logic device to support the desired functionality, depending on the device itself.
Among the drivers, the hub driver kernel / trunk / bus / usb / hub.inc stands out because in some aspects it is close to the support level of the host controller and is an integral part of the USB infrastructure. The USB specification allocates the part of the host controller responsible for controlling USB ports to the root hub in a special entity; The root hub is related to the individual hubs interface for other levels, but they are fundamentally different in terms of programming.
Hub support code interface: when a device is connected, the code informs the host device support code of the new device; when the device is disconnected, the code transmits information about this level of channel support; for the logic device level, the code provides the AddDevice + DeviceDisconnected functions , which in the source text are called usb_hub_init and usb_hub_disconnect respectively, as well as the function of blocking the port to which the new device is connected.
Mice and keyboards are supported by the kernel / trunk / drivers / usbhid.asm driver . The flash driver is supported by the kernel / trunk / drivers / usbstor.asm driver .

Host Controllers Support Code Interface


Finally, I am ready to explain the entire interface provided by the host controllers support code to other levels. When a new device is connected, the usb_new_device function of the usb_new_device level is called. Here I should note the following: usb_new_device will try to open the channel to zero point. But the channel open function requires an already open channel, from where it copies the characteristics of the device. For this to work, the host controller level creates a pseudo-channel, in the structure of which it fills only the fields with the characteristics of the device. Opening a channel to the zero point will create a fully-fledged channel. When the host controller has reconciled itself with the thought of the disappearance of the channel, the function usb_pipe_closed the channel support level is called. In addition, the logic level during the initial setup changes the channel parameters; when the host controller confirms that the changes are accepted, one of the usb_after_set_address and usb_after_set_endpoint_size level usb_after_set_endpoint_size the logical unit is called. In more detail about why this is needed, I will describe in the framework of the analysis of the level of the logic device.

Functions specific to a particular host controller and called from another code are assembled into the usb_hardware_func structure from hccommon.inc . It includes:

All articles of the series


Part 1: general scheme
Part 2: Basics of working with host controllers
Part 3: Host Controller Support Code
Part 4: Channel Support Level
Part 5: logic level
Part 6: hub driver

PS If someone else does not know: we collect some money on Kickstarter to spend your Summer of Code. So far, 65% has been collected, and the fundraising ends May 31 (tomorrow). Article: habrahabr.ru/post/180197

Source: https://habr.com/ru/post/181586/


All Articles