USB support in KolibriOS: what's inside? Part 5: logical device level

  • Tutorial
The device connection processing started at the host controller support level has stopped, preparing the device’s zero endpoint for operation. The level of support for channels provided methods for working with channels. It's time to apply them to continue the initialization of the device: the function usb_new_devicefrom bus / usb / is turned on .

Now the device can do little: it has not yet received an address on the bus, has not yet been configured, can only use 100 mA of power from the bus. In general, all that a device can do is tell about itself in response to suitable questions. The device’s story about itself is organized in the form of descriptors . The team is considered a suitable issue.GET_DESCRIPTORsent to the zero endpoint; the descriptor type must be indicated in the command , descriptor serial number among all with this type, data length for transmission. Each command to the control endpoint occupies 8 bytes and may or may not have additional data; in some commands some fields are not used. The command structure by bytes and the fields used are described in Chapter 9 of the USB specification, here I will only describe the input and output data for the commands.

The logical device level has two tasks: first, configure the device; secondly, ask him, download the appropriate driver - or even the drivers - and inform the driver about the new device.

First steps

usb_new_devicestarts by creating a channel to the zero endpoint of the device. Host controller support code before callingusb_new_devicefilled the structure describing the device, it remains only to specify the parameters of the endpoint: number - zero - and the maximum packet size. The maximum packet size for the control endpoint can vary from 8 to 64 bytes and is recorded among the first 8 bytes of the device descriptor. However, to read the descriptor, you need an already open channel. Fortunately, you can get out of the dependency cycle: the maximum packet size is needed only to split one transfer into transactions; it is guaranteed that the maximum packet size for the control endpoint is at least 8 bytes; if at the initial stages of the configuration only data of 8 bytes or less is transmitted, the exact value of the maximum packet size is not important. Therefore, as a maximum value of the packet, you can set any number, not less than 8 bytes.

However, there is one problem: EHCI emulation in VirtualBox is not entirely correct and requires 64 bytes to work with HighSpeed ​​devices. Since there are no other requirements, the channel to the zero endpoint begins to exist with a maximum packet size of 64 bytes.

Until the device has received an address on the bus, it responds to the zero address and prevents the reset of subsequent devices - if the reset of another device ends right now, both devices will respond to packets with a zero address, which will lead to a mess on the bus. Therefore, the first thing that does usb_new_deviceafter opening the channel is to select the first unoccupied address and send a command SET_ADDRESS. At the input, the team has SET_ADDRESSan address, there is no output.

After the command is completed, SET_ADDRESScontrol receives a procedureusb_set_address_callback. If the device did not respond to the command or responded with an error, then the only option is to disconnect the device from the bus at the hub level. If the command is successful, it usb_set_address_callbackinforms the host controller support level that the address has changed; for the reasons that I mentioned in a previous article in the series , the change may take some time. In both cases, the zero address on the bus ceases to be busy, so you can begin to reset subsequent devices, if any; the challenge is responsible for this usb_test_pending_port.

When the host controller confirms the address change in the structure describing the device, the support code calls usb_after_set_address. Now the views of the host controller and device about the address on the bus are reconciled, you can continue to configure. Next teamusb_after_set_addresssends a question GET_DESCRIPTOR, asking for the first 8 bytes of the device descriptor - descriptor type 1, descriptor number 0. The last of these 8 bytes sets the maximum packet size for the zero endpoint - the last of what was not enough for full communication. The response handler usb_get_descr8_callbackpulls out the maximum packet size, reports it to the host controller, and waits for confirmation. After confirmation, a call occurs usb_after_set_endpoint_sizewhere the question GET_DESCRIPTORfor the device descriptor is repeated, now requesting the data completely.

Device descriptor

The figure shows the hexadecimal dumps of the descriptors of two different devices: on top - the virtual hub RMH, below - some mouse. A device descriptor consists of the following data in little-endian :
  • the first byte of any descriptor is its size, the second is its type, the device descriptor is type 1;
  • the version of the USB specification with which the device is compatible, in BCD , 110his version 1.1, 200his version 2.0;
  • the class, subclass, and protocol of the device as a whole; often there are zeros, then the data is set at the level of individual interfaces - more about them will be next;
  • maximum packet size for zero endpoint;
  • Vendor ID and Product ID of the device - the USB Implementers Forum association gives each manufacturer of USB devices a two-byte Vendor ID, sometimes not even one, the manufacturer assigns a separate two-byte Product ID to each of its products; for example, Vendor ID is 8087hassigned to Intel;
  • device version - an arbitrary number that the manufacturer wrote here:
  • three pointers to strings, each of which may be absent. The first two are texts for the user, description lines of the manufacturer and product, respectively, the last is the serial number. The strings themselves are stored in separate type 3 descriptors;
  • number of configurations.
Configurations are mutually exclusive modes of operation of the device, between which there is nothing in common. In theory, a USB device can have several different configurations, between which software should choose. The USB specification, as a somewhat contrived example, cites a modem that can provide either one channel at 128 Kbps or two independent channels at 64 Kbps. In practice, the vast majority of devices has exactly one configuration and uses other methods of selecting the operating mode. However, this one configuration still needs to be explicitly enabled, before that the device will remain non-functional and capable of only giving descriptors.

KolibriOS always chooses the first device configuration. The function usb_get_descr_callbackcalled after reading the device descriptor sends a commandGET_DESCRIPTORfor the first configuration descriptor, type 2, number 0.

Together with the configuration descriptor, the device returns many other descriptors that specify the configuration details. The total amount of data associated with the configuration descriptor is not known in advance, but is contained in the configuration descriptor itself. Therefore, the request proceeds in two stages - at the first stage, the function usb_get_descr_callbackrequests 8 bytes, at the second stage the function usb_know_length_callbackpulls the total size from the read bytes and requests it already.

Configuration descriptor

One of the simplest configurations is the virtual hub RMH, it is shown in the figure. Together with the configuration descriptor, the device returns the descriptors of all interfaces of this configuration; for each interface, the descriptors of all its endpoints. Other types of associated data include descriptors — for example, HID devices like mice and keyboards return an HID descriptor between an interface descriptor and an endpoint descriptor; their analysis is a matter of the driver.

The configuration descriptor consists of the following data:
  • size and type, as with all descriptors; the configuration descriptor is type 2;
  • the total size of all associated data, in the example with RMH it is 9 + 9 + 7 = 19h;
  • number of interfaces;
  • command byte parameter SET_CONFIGURATIONcorresponding to the described configuration;
  • index of the configuration description line for the user, usually absent - set to 0;
  • attribute byte - the most significant bit and the 5 least significant bits are reserved, the 5th bit means support for waking from a sleep state in response to some external action, the 6th bit means that the device has its own power supply independent of the USB bus;
  • the maximum bus power used in this configuration is 1 unit = 2 mA, a value of 50 corresponds to 100 mA.

Interface descriptor:
  • size and type, as with all descriptors; the configuration descriptor is type 4;
  • interface number and interface mode identifier. For some devices, one interface can work in several modes. An example is webcams: depending on the resolution of the picture and the codec, the data flow rate can vary significantly, different modes reserve different bandwidth of the endpoint transmitting the data. In such cases, for the same interface there are several descriptors in which the number field is the same, but the mode identifiers differ. By default, after selecting a configuration, the interfaces operate in zero mode, the driver can send a command SET_INTERFACEto switch the mode of one interface;
  • number of end points;
  • class, subclass, and interface protocol. Classes, in addition 0FFh, are defined by the USB Implementers Forum, their descriptions are collected on this page . For example, class 9 includes hubs. The class is 0FFhused for devices that do not fall into any other class;
  • the interface description line index for the user, usually absent - set to 0.

The endpoint descriptor sets the parameters necessary to open the channel:
  • size and type, as with all descriptors; endpoint descriptor is type 5;
  • direction - the most significant bit - and the number - 4 least significant bits - of the end point; for example, 81hmeans point number 1, transmitting data from the device to the host;
  • endpoint type: 0 = control, 1 = isochronous, 2 = data arrays, 3 = interruptions; for isochronous points, specifying parameters are packed in the same byte;
  • 11 bits of the maximum packet size for this endpoint, plus another 2 bits for HighSpeed ​​points, which specify the maximum number of transactions per microframe;
  • desired polling interval for isochronous points and interruption type points. For LowSpeed ​​/ FullSpeed ​​points of interrupt type, the interval is specified in milliseconds, for HighSpeed ​​points of interrupt type, the interval is 2 value-1 microframes. In the example RMH get 2 11 /8 ms = 0.256 seconds. For isochronous points, the interval is 2 value-1 in units of measure corresponding to speed: milliseconds for FullSpeed, microframes for HighSpeed.

The function usb_set_config_callback, having received the full data associated with the configuration descriptor, issues a command SET_CONFIGURATIONwith a parameter taken from the descriptor; this command has no output. After successful completion of the command, the device becomes fully functional. The last of the functions of the logical device level,, usb_got_config_callbackparses the received configuration data: makes sure that the device is not trying to cheat by changing the total data size between the teams GET_DESCRIPTOR; goes through the list of descriptors, ignoring everything except interface descriptors; for descriptors with zero mode, defines the driver by the device class, loads the driver and calls its functionAddDevice, passing a pointer to the configuration data and a pointer to the desired interface descriptor inside them. For further work with the device, the loaded driver is responsible. I will talk about the existing KolibriOS drivers in subsequent articles.

All articles in 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: logical device level
Part 6: hub driver

Also popular now: