52964.fb2
This chapter introduces the Universal Serial Bus (USB) by giving an overview of the technology, its low-level structure, and its device framework. The next chapter looks at how to write Windows device drivers using the USB Device Interface (USBDI). This chapter takes a brief look at the available classes of USB device that have common characteristics. The subsequent chapters look in detail at one of these classes for Human Input Devices (HID)[49].
The Universal Serial Bus (USB) is the recommended way to connect new low-speed or medium-speed external devices to PCs. It is simple for users to plug in a new USB device or remove one, even if the PC is switched on. The system configures itself automatically to accommodate the new device, prompting for the necessary driver.
The USB Specification defines all the basic physical, electrical, and logical characteristics of all USB systems. The Windows system drivers define the closely related USB Driver Interface (USBDI) for use by USB client device drivers. This chapter and the next look at both these USB models.
The USB specifications are available from the USB website at www.usb.org/developers/ in PDF format. I recommend that you also get the USB Compatibility Test software, usbcomp.exe. This includes the USBCheck tool to check whether a USB device meets some of the higher-level specifications. It also contains the HIDView program to inspect and test HID devices. The "Ignore hubs (Memphis only)" box should be checked for Windows 98. The Windows 2000 DDK also includes the UsbView tool that shows all the USB buses in the system and the devices that are connected to each USB bus.
Membership of USB Implementers forum costs $2500 per year including a free vendor ID. Alternatively, vendor IDs can be purchased separately for $200.
Some USB devices just exhibit basic USB features. However, USB goes on to specify several classes of devices, with common behavior and protocols. This makes it easier to write generic device drivers.
Table 20.1 shows the main USB device classes. The USB website has the full specifications for each class. The hub device class is specified in the standard USB Specification. I shall show later how the class constant (in the Interface descriptor) is sometimes used to identify the correct drivers for the device.
Table 20.1 Main USB device classes
Device class | Example device | Class constant |
---|---|---|
Audio | Speakers | USB_DEVICE_CLASS_AUDIO |
Communication | Modem | USB_DEVICE_CLASS_COMMUNICATIONS |
Human Input Device (HID) | Keyboard, Mouse | USB_DEVICE_CLASS_HUMAN_INTERFACE |
Display | Monitor | USB_DEVICE_CLASS_MONITOR |
Physical feedback devices | Force feedback joystick | USB_DEVICE_CLASS_PHYSICAL_INTERFACE |
Power | Uninterruptible power supply | USB_DEVICE_CLASS_POWER |
Printer | USB_DEVICE_CLASS_PRINTER | |
Mass storage | Hard drive | USB_DEVICE_CLASS_STORAGE |
Hub | USB_DEVICE_CLASS_HUB |
One of the USB device classes is for Human Input Devices (HID), described fully in Chapter 22. HID devices do not have to run on the USB, but they fit neatly into the USB device model.
HID provides an abstract model of input devices. A program that uses HID should not care how a device is connected, as long as a suitable HID minidriver is available for the interface. HID hides the implementation details.
Windows includes system HID drivers to interact with USB devices. If a USB device has an interface descriptor that says it is in the HID class, Windows loads the system HID drivers and the USB HID minidriver and reads the HID descriptors. You just need to write a HID client to do something with the device.
Figure 20.1 shows the logical structure of a USB device. The physical connection of the USB devices does not effect this logical view.
Figure 20.1 USB logical structure
Each device has one or more logical connection points inside it, called endpoints, each assigned one of the following transfer types: control, interrupt, bulk, and isochronous. All devices have an Endpoint 0 for transfers used to configure and control the device.
A connection between the host and a device's endpoint is called a pipe. The connection between the host USB system software and a device's Endpoint 0 is called the Default Pipe.
A device presents an appropriate set of endpoints to the host. A set of related endpoints is called an interface. A device with more than one interface is called a composite device.
Finally, a device may have more than one set of interfaces. Each set is called a configuration. Only one configuration can be active at a time. However, all interfaces (and their end-points) in the current configuration can be active at the same time. Most devices just have one configuration and one interface. Windows prompts you to choose the desired configuration when a device is first inserted.
The host reads various descriptors from a device to find out what configurations, interfaces, and endpoints are available. The host reads these descriptors when the device is first plugged in using the default pipe. Windows tries to set up a kernel device for each configuration or interface found.
The system USB drivers handle most of the hard work of connecting to a USB device. Indeed, some HID USB devices, such as keyboards, mice, and game devices are recognized automatically and do not need extra drivers.
However, most USB devices will need a new driver to talk to the device and respond to kernel or user application requests. At the kernel level, commands are issued by a client driver to the USB system using Internal IOCTLs. The most useful IOCTL allows you to issue USB Request Blocks (URBs) to the system USB driver. URBs let you issue a multitude of function calls to the USB system.
User mode USB utilities can also issue a few ordinary IOCTLs to a USB device, solely to get information about the connected devices.
Before I look at how to write USB device drivers using this USB Driver Interface (USBDI), it is necessary to explore the physical and logical structure of the USB system. The next chapter shows that Windows provides a fairly plain wrapper for the USB logical structure. The main USB concepts are reflected in the interface available to device driver writers.
At the USB level, a device can communicate in four different transfer types: control transfers, interrupt transfers, bulk transfers, and isochronous transfers. If designing a USB device from scratch, you will have to decide what transfer types are appropriate. As a driver writer, you may simply be told what transfer types to implement. Transfers are always initiated by the PC.
• Control transfers are used by the USB system and clients to send or receive relatively small amounts of data.
• Interrupt transfers signal input events from a device to the PC. Actually, the PC polls the device regularly (every 1ms–255ms) to get any available interrupt data.
• Bulk transfers are used — in either direction — for large amounts of data.
• Isochronous transfers happen regularly and are usually time-sensitive (e.g., for voice data coming from a telephone). USB divides its available bandwidth into frames, each nominally 1ms long. A device can do one isochronous transfer per frame.
The PC USB host juggles the pending transfer requests from various clients so that they fit into the available bandwidth within the frame structure. Isochronous and interrupt transfers can take up a maximum of ninety percent of the available frame bandwidth, leaving some room for control transfers. Most of the available bandwidth in each frame could be taken up by a regular isochronous transfer from one device. In this case, attaching another device that needs isochronous transfers might fail due to lack of bandwidth.
USB devices can be plugged into any USB ports on a PC. Some USB devices are hubs that allow further USB devices or hubs to be connected. A hub has one upstream connection towards the PC, and multiple downstream ports. Up to 127 devices can be connected in total. A hub counts as a device.
In USB-speak, the PC is called the host. Data is always transferred between the host and a device, or vice versa. Devices never talk to each other. The PC contains the root hub (or hubs), usually with a couple of downstream ports.
This arrangement leads to the star or branch architecture shown in Figure 20.2.
A device that does a useful job is called a function device. A USB compound device supports several functions. Internally, they consist of a hub with several downstream function devices.
Figure 20.2 shows an example USB physical layout. A USB keyboard is connected to one of a PC's USB ports. A USB hub is connected to the other PC port. The hub has two downstream ports. One is spare and the other has a compound USB device connected. Internally, the compound device has a hub and two function devices.
Figure 20.2 Example USB physical architecture
A PC has one or more USB host controllers built into it (e.g., each with two ports). There are two standard types of host controller: the USB Host Controller Interface (UHCI) and the Open Host Controller Interface (OHCI). The Windows USB class drivers have a miniclass driver for each of these controller types.
The USB cable has four wires. Two wires carry 5V power. Some devices may use this to power themselves, while others will be self-powered (i.e., battery or mains powered).
The other two USB wires carry the serial data. Data transfer is in one direction only at a time. Serial data is either transferred at full speed, 12 megabits per second (Mbs), or at low speed, 1.5 Mbs. All the serial data is at one of these speeds, so there is no rate conversion in hubs. A device is either a full-speed device or a low-speed device.
Note that there is no intention to uprate these communication speeds, unlike IEEE 1394. Move to IEEE 1394 if you need higher speed.
The USB protocol defines what appears on the serial bus. The host starts all transactions, but data transfer direction is switched, if necessary, during a transaction. The protocol allows devices to be plugged in at runtime and configured, and for devices to be unplugged at any time. Communication occurs only between the host and one device at a time.
Hubs repeat downstream data to all downstream ports (but not full-speed data to low-speed devices). For upstream data, hubs understand the protocol so they know which port (if any) to route upstream. Hubs do not buffer data.
The bus can be suspended by the host to reduce power, either globally or just for a specific device. If a device detects the suspended state then it must power down. The host can resume signalling on the bus to wake up all devices. Alternatively, a device can issue a remote wake-up to the host (e.g., for a telephone to indicate an incoming call).
The host can signal to a device that it should reset.
In some circumstances, communications on a pipe to a device can be stalled (e.g., if the data is corrupted). The host has to clear the problem via another pipe before normal communication can continue.
A hub detects electrically when a device is removed or plugged in, and whether it is a full-speed or low-speed device. How USB and Windows react after this is described later.
The USB protocol defines what happens on the serial data lines. The available data transmission time — the bandwidth — is divided up into frames, each 1ms long. At full speed a frame contains a maximum of 1500 bytes and, at low speed, 187 bytes.
Frames are primarily used as a means of allocating bandwidth to the different transfers that want to occur. The regular frame timing can also be used by devices to synchronize their activities to the USB bus. Frames are of particular interest to isochronous devices and drivers.
Packets
The smallest block of data transferred on the serial lines is called a packet. A packet is sent in only one direction, either from the host or to the host.
A packet consists of synchronization signals, a Packet ID (pid), possibly some data, and some CRC check bytes. There are 10 Packet IDs in four categories:
Token | OUT IN SOF SETUP |
Data | DATA0 DATA1 |
Handshake | ACK NAK STALL |
Special | PRE |
A transaction is a discrete interaction between the host and one device using one or more packets.
The host always starts a transaction with one of the Token type pids. A Data packet or packets may follow in either direction. Finally, a Handshake is sent back in the opposite direction to the data transfer.
The IN, OUT, and SETUP packets specify a USB address and endpoint, to specify the device and endpoint that should respond. One hundred and twenty-eight addresses are supported, with 0 being the default address on power-up or reset.
A SETUP packet includes eight data bytes to indicate what transaction is happening. USB defines standard control transactions, as described later. Other class and vendor specific SETUP control transactions are outside the basic USB spec.
The two different DATA pids are used to make it easier to detect if a complete data packet has been missed.
The ACK Handshake packet indicates that the transfer completed successfully, while NAK indicates that it did not (or that no data was available). A STALL Handshake return means that some serious error occurred in the device or endpoint, which the host must clear using another pipe.
When any of the previous packets are sent at low speed to a low-speed device, it is seen by a high-speed device as a PRE packet and so is ignored.
There are various limits on the packet size. DATA packets may be up to 1023 bytes long.
Start of Frame (SOF)
The SOF packet is sent by the host to indicate the start of a frame. This packet includes an 11-bit frame number, continuously going from 0 to 0x7FF (i.e., USBD_ISO_START_FRAME_RANGE–1) and rolling over to 0 again. SOF packets are seen by all high-speed devices. Note that SOF packets can be corrupted, as can any other packets.
Transaction Packet Structure
A control transfer involves the host sending the device a SETUP packet, zero or more DATA packets in either direction, and a Handshake.
An IN packet or an OUT packet starts all the other transfers. The definition of the device's endpoint determines whether it is an interrupt, bulk, or isochronous transfer.
The host starts Interrupt transfers regularly to see if the device endpoint has any data available. The device endpoint may return the data. Alternatively, the device might send NAK to indicate that there is no data available or that the state has not changed.
Similarly, bulk input requests may return data or NAK.
Remember that all pipes might stall.
When first reset, a device can draw 100mA (milliampere) from the bus. When configured, it can draw the power it asked for, up to the maximum of 500mA. If suspended, a device may only use 500µA (microampere).
This section shows how the low-level USB packets and transactions are used. The USB protocol defines how the USB system is set up and run, as well as how it may be used by clients.
The host works with the hubs to find all the devices on the bus. It uses standard control requests to set up a device. It reads various descriptors from the device, works out which drivers to load, and enables the device. A hub reports any new device insertions or removals through its Status Change endpoint.
After this, the USB system drivers control access to the bus, scheduling all the transfer requests to fit into the available bandwidth.
The PC host has to deal with USB device insertion and removal, both at power up and while running. Any hubs in the system help in this task. A hub is itself a device that talks to the system USB device driver usbhub.sys to inform it of any device insertions or removals.
The host knows when a device is inserted or removed. The hub tells it which port a new device is on. The host tells the hub to enable the port and issue a reset command to the device. The device initially responds at the default address of zero. The host reads the device's device descriptor and then allocates it a free USB address in the range 1-127.
The host can then read the rest of the device's descriptors. Eventually, the host selects one of the device configurations. This fully enables the device so that all the endpoints can be used.
The USB system will only let a device configuration be selected if there is enough bandwidth available.
Window inspects the configuration, interface, and endpoint descriptors and loads the appropriate drivers. In the unlikely case of a device with more than one configuration, Windows itself prompts the user to choose between them.
Root Hub
The PC host contains a root hub that it finds on its internal buses when the host is switched on. A USB host controller is usually found by the PCI enumerator. The host controller's PCI configuration space is accessed and set with appropriate values. The controller's registers are permanently mapped into memory. A USB host controller can usually take bus mastership to do its data transfers.
The PC talks directly to the root hub electronics embedded in the host controller. The root hub then reports any devices or further hubs that are attached. Any further hubs are enumerated in the same way until all the USB devices have been found.
If Windows finds two root hubs for example, it treats them as two separate USB buses.
Hub Functionality
A hub is a standard USB device of class HubClass, which must implement functions defined in the USB Specification. It has the necessary USB descriptors to describe its functionality.
A hub primarily consists of a signal repeater and controller. The repeater passes the USB signals in the correct direction. The controller understands the protocol and instructs the repeater. The hub controller is itself controlled by the host through two endpoints.
A hub is configured and interrogated through its standard Endpoint 0. This default pipe implements most of the standard control transactions and then goes on to implement various hub class specific control transactions (ClearHubFeature, ClearPortFeature, GetBusState, GetHubDescriptor, GetHubStatus, GetPortStatus, SetHubDescriptor, SetHubFeature, and SetPortFeature).
A hub also has a Status Change interrupt endpoint, used to inform the host of changes to each of its downstream ports. A port change bit is set if any of the following states change: device connected, port enabled, suspended, over-current indicated, reset, and powered. The host asks for the Status Change interrupt data every 255ms. The hub simply returns NAK if nothing has changed (e.g., if no devices have been added or removed).
The USB system uses standard control transactions to set up all devices. Further class and vendor specific requests can be defined.
A control transaction starts with a SETUP packet that includes eight data bytes in a customizable format, as shown in Table 20.2. Table 20.3 shows the bit definitions of the first byte, bmRequestType. The next byte is the request code.
Table 20.2 Control transfers
Field | Size | Description |
---|---|---|
bmRequestType | 1 | byte Request characteristics, see Table 20.3 |
bRequest | 1 | Request code, see Table 20.4 |
wValue | 2 | word parameter |
wIndex | 2 | index parameter |
wLength | 2 | Number of bytes to transfer |
Table 20.3 bmRequestType bit definitions
Bit 7 | Transfer direction | 0 = Host to device |
1 = Device to host | ||
Bits 6..5 | Type | 0 = Standard |
1 = Class | ||
2 = Vendor | ||
3 = Reserved | ||
Bits 4..0 | Recipient | 0 = Device |
1 = Interface | ||
2 = Endpoint | ||
3 = Other | ||
4..31 reserved |
The basic USB spec only defines the Standard type control transfers listed in Table 20.4. The table indicates the possible destinations, such as Device (D), Interface (I), or Endpoint (E).
Table 20.4 Standard USB SETUP transfer requests
Request code | Recipient | Description |
---|---|---|
CLEAR_FEATURE | DIE | Clears stall or remote wake-up and clears power states |
GET_CONFIGURATION | D | Get current configuration number (or 0 if not configured) |
GET_DESCRIPTOR | D | Get descriptor: Device, String or Configuration, Interface, and Endpoint. |
GET_INTERFACE | I | Get alternate setting for interface |
GET_STATUS | DIE | Get status, e.g., whether device is self-powered andwhether remote wake-up is signalled, or whether end-point is stalled. |
SET_ADDRESS | D | Set the device's address |
SET_CONFIGURATION | D | Set the configuration number |
SET_DESCRIPTOR | D | Set or add a descriptor |
SET_FEATURE | DIE | Sets stall or remote wake-up and sets power states |
SET_INTERFACE | I | Select an alternate interface setting |
SYNCH_FRAME | E | Used in isochronous transfers to indicate the start of a frame pattern. |
For example, the SET_ADDRESS request is sent to assign a USB address to a device. The device returns ACK when complete. A GET_DESCRIPTOR request asks for one of the descriptors. The descriptor is returned in one or more DATA packets.
Each device class usually has various control transfer requests defined. See the appropriate specification for details.
Table 20.5 shows the basic types of descriptor that a device should return, along with a summary of the information in each descriptor. Figure 20.1 gives a view of the relationship between the various descriptors. String descriptors are optional. Further class specific or vendor specific descriptors can be returned. Table 20.6 lists the standard descriptor type constants.
Configuration and endpoint descriptors must not include a descriptor for Endpoint 0.
An interface may have alternate settings that redefine the number or characteristics of the associated endpoints.
For isochronous requests, the endpoint maximum packet size reserves bus time.
Table 20.5 USB descriptor types and fields
Descriptor | Fields |
---|---|
Device | Vendor ID, Product ID, and Device release number. Device class, sub class, and protocol. Number of configurations |
Configuration | Number of interfaces. Attributes: bus-powered, self-powered, supports remote wake-up. Maximum power required |
Interface | Interface number, class, subclass, and protocol. Number of endpoints. |
Endpoint | Endpoint number, direction, transfer type, maximum packet size, and interrupt polling interval. |
String | String index 0: Language ID supported by device. Others: Unicode string and length |
Table 20.6 Standard descriptor type constants
USB_DEVICE_DESCRIPTOR_TYPE | 0x01 | |
USB_CONFIGURATION_DESCRIPTOR_TYPE | 0x02 | |
USB_STRING_DESCRIPTOR_TYPE | 0x03 | |
USB_INTERFACE_DESCRIPTOR_TYPE | 0x04 | |
USB_ENDPOINT_DESCRIPTOR_TYPE | 0x05 | |
USB_POWER_DESCRIPTOR_TYPE | 0x06 | W98 only |
USB_CONFIG_POWER_DESCRIPTOR_TYPE | 0x07 | W2000 only |
USB_INTERFACE_POWER_DESCRIPTOR_TYPE | 0x08 | W2000 only |
Windows uses values in the Device or Interface descriptors to choose which driver to load. Windows initially forms Hardware IDs using the Device descriptor vendor and product fields (idVendor, idProduct, and bcdDevice). If no installation INF file can be found with a model that matches the Hardware IDs, Windows forms Compatible IDs out of the Interface descriptor class fields (bInterfaceClass, bInterfaceSubClass, and bInterfaceProtocol). Windows then searches for an installation file that handles one of these Compatible IDs. If nothing can be found, it prompts the user for a new driver. The chosen installation file specifies the driver to load.
The Interface descriptor class field, bInterfaceClass, is zero for a basic USB device. If the interface meets one of the standard device class specifications, bInterfaceClass is one of the values listed earlier in Table 20.1.
Note that the Device descriptor class fields are not used in the driver selection process. Instead, the bDeviceProtocol field can be used to indicate which, if any, new features are supported, as described in the following text.
As mentioned earlier, the basic USB device framework is enhanced to provide specifications for several different classes of USB device. A Class constant is defined for each device class. Each class may then go on to define various Subclass and Protocol constants to further define the general type of functionality provided in the device.
These class constants are not given in the standard USB device descriptor, but set in the Interface descriptor, instead. If Windows cannot find a driver that matches the Device descriptor Hardware ID, it uses the Interface descriptor class constants to form a Compatible ID.
The USB class specifications define what interfaces and endpoints must appear in a particular class of device. A class may define one or more additional class-specific descriptors for the class device, interface, or endpoint. These devices still provide the standard device, configuration, interface, and endpoint descriptors.
Device classes typically also define a series of class specific request codes for control transactions. Bits 6 and 5 of the request code are set to 01 to indicate that these are class-specific requests. For example, the Hub class request ClearHubFeature has code 0x20.
Obtain the appropriate class specification from the USB website at www.usb.org/developers/. The HID class and its USB implementation are discussed in detail in Chapter 22. The power supply device class is defined purely as a HID device.
The class-specific descriptors are usually types of Interface descriptors. Class-specific descriptor IDs have the top three bits set to 001. Table 20.7 shows the first assigned class-specific descriptor IDs.
Table 20.7 Class-specific descriptor IDs
HID Class | HID descriptor | 0x21 |
Report descriptor | 0x22 | |
Physical Descriptor | 0x23 | |
Communications Class | CS_INTERFACE | 0x24 |
CS_ENDPOINT | 0x25 (not used yet) |
Printer Class
As an example of a USB class, it is worth looking here at the printer class. USB printers should resemble FPP or ECP parallel port printers, as defined in the IEEE 1284 specification. The format of the print data sent to the printer is not defined by this spec.
The printer class does not define any class-specific descriptors. The standard device descriptor has zeroes for its class, subclass, and protocol. The standard interface descriptor has constant USB_DEVICE_CLASS_PRINTER (0x07) in its bInterfaceClass field. bInterfaceSubClass is always set to 0x01 indicating a Printer. The bInterfaceProtocol field has 1 if the printer is unidirectional (i.e., it only accept incoming data) or 2 if bidirectional (i.e., it can return status information). A printer can have only one such interface, but it could perhaps switch between the two operating modes using an alternate interface setting.
A printer class device always has a Bulk OUT pipe for data sent to the printer. A bidirectional printer also has a Bulk IN pipe. These pipes are used to carry the relevant page control/description information and status.
A printer uses the default control pipe Endpoint 0 for standard USB purposes. However, it is also used for three printer class-specific requests. GET_DEVICE_ID (request 0) reads an IEEE 1284 device ID. GET_PORT_STATUS (1) gets a status byte that mimics the Centronics printer port status. SOFT_RESET (2) flushes all the buffers, resets the Bulk pipes, and clears all stall conditions.
USB continues to evolve, both to define new classes of devices and to make implementation of these devices easier. The USB Common class specification document firstly defines how new class specifications should be written. Then it goes on to describe new features that may be used to extend the basic USB functionality.
Table 20.8 lists the USB extensions. The Shared Endpoint extension is described in the next section.
Support for the USB enhancements is indicated in the device descriptor. The device bDeviceSubClass field is 0x00 and bDeviceProtocol is a bitmap of supported features. Shared endpoint support is indicated in bit 0.
Currently, there seems to be no indication that Windows supports any of these new features[50].
Table 20.8 USB new feature summary
Shared Endpoints | Allows one physical pipe to carry information from several logical pipes. |
Synchronization | Defines a standard way of reporting synchronization requirements for an endpoint. |
Dynamic Interfaces | Lets a device change its interface dynamically (e.g., a modem might receive either a voice call or a data call, and would want to change its interface accordingly). |
Associations | The ways in which different interfaces might be related (e.g., a modem data call might have voice and video information). Each interface requires a separate pipe. However, an association defines how the interfaces are related. |
Interface Power Management | An interface power descriptor might describe different: • power down states (apart from just suspended) or • methods of adjusting each interface's power. |
Default Notification. Pipe | A default notification pipe describes a common format for passing interrupt data to the host. |
Shared Endpoints
Designers of some devices might find that they need many endpoints and pipes, which might require lots of resources. The basic USB standard says that only the default pipe Endpoint 0 can be shared between interfaces.
The Shared Endpoint USB extension allows several logical pipes to be carried on one normal "physical" pipe. Such shared pipes must have the same transfer type (control, interrupt, bulk, or isochronous) and be in the same direction. Each logical pipe defines one or more logical packets for the data it might send.
Hosts and devices that handle shared pipes multiplex the data from each logical source on the physical pipe. For isochronous pipes, the combined maximum data packet size must fit into a frame. The software must ensure that a stall on one logical pipe does halt data flow on another logical pipe.
Flow control can optionally be implemented using a pipe in the opposite direction to data transfer. A source must not send data on a logical pipe until the target has provided a grant to send: a count of the number of logical packets it can receive.
This section briefly discusses options for both device firmware engineers and Windows device driver writers.
The different types of endpoint have different characteristics. Control transfers consist of messages or requests sent when the host dictates. Interrupt, bulk, and isochronous transfers are said to be stream pipes as they keep generating application defined data.
There is usually only one control pipe, for Endpoint 0. As well as carrying the USB set up and configuration standard transfers, you can use this pipe for the class-defined or your own vendor-defined requests. If need be, define any further control pipes.
Interrupt pipes are usually used for user input data, but they can also retrieve relatively infrequent data from the device. Interrupt pipes can be used in conjunction with isochronous pipes to provide feedback so that the data rate can be varied. As mentioned previously, a device can NAK an interrupt pipe request to indicate that no data has changed. Additionally, Chapter 23 shows that HID devices support the concept of an idle rate. This technique reduces the number of interrupt reports that are generated.
Devices that generate or consume data samples regularly will want to use isochronous transfers. Isochronous transfers can vary in length, and may be used in preference to bulk transfers as they reserve USB bus bandwidth. Isochronous transfers are not error checked, but a receiver can determine if a transmission error occurred by checking the frame number. Make sure that the application or device can cope with losing data. Bulk transfers are error checked, but they have the lowest priority on the bus.
Low-speed devices can only have two endpoints after Endpoint 0. Full-speed devices can have a maximum of 16 input and 16 output endpoints. Check that maximum packet size for your pipe type is acceptable.
Do not forget that if a pipe stalls, a control pipe request must be defined to clear the stall condition.
You might want to consider some of the new USB features, discussed earlier. Check that Windows supports the relevant feature.
Isochronous devices can represent quite a challenge to software designers. An isochronous input source usually generates a regular number of samples to represent their data, while an output sink receives samples and produces the relevant output.
A driver must firstly be able to handle the volume of data coming in and take appropriate steps if it cannot keep up. It is sometimes best if a set of samples can be left to build up for processing in one fell swoop, rather than processing each sample individually. Check that your application will survive this treatment.
Synchronizing a series of devices and processes is a more complicated issue. The clocks inside each device and inside the PC may all be running at different frequencies. Even if they are nominally at the same frequency, they may well drift or produce jitter.
A basic asynchronous source just sends any samples it has produced. A basic asynchronous sink might use a feedback interrupt pipe to tell the PC how many samples to send.
There are various techniques that devices and drivers can use to handle these difficulties. At the very least, some sort of rate adaptation or conversion may be necessary.
A common technique is to group the samples into service intervals and buffer the sample groups through the relevant processes. A driver might expect a set number of samples in a service interval. If not enough have arrived, a new sample or samples could be generated by interpolation. Similarly, if too many samples arrive, some should be dropped. This technique requires that you buffer up a set of samples for a service interval, one for each rate adaptation process. Check that the resultant delay through the system is acceptable, and that adding or dropping samples is satisfactory.
Another technique is to synchronize all activities to the 1kHz USB frame clock. An input source would generate the correct number of samples each frame, even if a different number had arrived. Make sure that your device copes if the USB Start of Frame (SOF) frame packet is corrupted.
An adaptive device interacts with the PC to tell it how many samples to send or receive. It might use an interrupt pipe to tell the host how to adjust its sample rate.
Frame Length Control
Another synchronization technique is for a device to obtain control of the USB frequency (i.e., take over mastership of the [SOF] packet rate). An SOF master adjusts the USB clock slightly to match its internal clock. However, only one device can take over USB bus master-snip, so a device should not rely on this technique.
There are Windows URB functions to request control of the USB frame length, and to get and set the current frame length. The frame length may be adjusted by only plus or minus one bit at a time. You can also get the current frame number.
Patterns
A final useful technique for isochronous transfers is to let the size of each transfer vary in a regular pattern to match the source data rate. The host and the endpoint must agree which frame begins the repeating pattern. One of the calls to the Windows USB drivers asks for the frame number which starts a pattern.
An audio signal could be sampled at 44.1kHz. This means that 44100 16 bit samples are generated every second. This corresponds to 44.1 samples every USB frame. Sending 45 samples per frame would be an acceptable solution, provided some special flag is used to indicate which frames have 45, rather than 44, samples. The recommended solution is to use a frame pattern. In this case, a pattern that repeats every 10ms should be used, consisting of nine frames of 44 samples and one frame of 45 samples. In total, exactly the right number of samples is sent, 44100 per second.
This chapter has looked at the background to the Universal Serial Bus (USB). An understanding of the USB low-level frame structure helps when writing device drivers. The Windows USB system drivers read the standard descriptors in each USB device to determine which drivers to load.
The next chapter looks at how to write a device driver that can talk to USB devices through the Windows USB Device Interface (USBDI).
Note that there are two uses of the word "class". Device drivers use the Windows USB class drivers to get access to the USB system. Each USB device can be categorized as a basic USB device, or as belonging to a class of USB devices such as HID, printer, etc.
The Windows 2000 DDK defines the Interface power descriptor structure. However, it is not apparent whether this information is used by the system USB class drivers.