USB is much more complex than e.g. a serial interface. The standard defines not only how the bits are transferred, but also how information about a device can be obtained by the host. Every USB device must comply to this basic protocol.
When you implement a USB device, you must decide how it should present itself to the host. The basics common to all classes are handled by the driver itself. For the rest, you can choose among various device classes and each class has its advantages and disadvantages:
Custom class devices
The most straight forward way to implement a device is by choosing class Custom, which basically means that you comply to no known class. Data can be transferred in blocks up to 254 bytes in both directions over the default control endpoint. An example for a very simple custom class device is PowerSwitch. If required, interrupt endpoints can be added for stream-type data or to send spontaneous notifications to the host. An example for this can be found in the RemoteSensor project.
- Easy to implement on the device.
- Easy to write host side software on Unix.
- On Windows, a driver DLL must be installed. This means that the host application can't be run without installation.
- You must provide software for the host to control the device.
Standard HID class device
You can design your device to look like a standard USB keyboard, mouse or joystick and every application will be interoperable with your device without additional drivers. Since you adhere to the class specification, the operating system's driver knows how to communicate with your device.
- No driver required on host.
- Can only be used for standardized Human Interface Devices like mice, keyboard, joystick, power source, point-of-sale equipment etc.
- A HID Report Descriptor must be constructed to describe the data sent to the host. This may be tedious.
Examples for standard HID class devices can be found here.
Custom HID class device
The HID class defines a kind of data description language where the data sent to or received from a device can be described. The description contains not only the data format, but also the meaning of the entries. However, it is possible to misuse reports to send and receive arbitrary blocks data to/from the device.
You may ask why we don't use a custom class device if we want to exchange arbitrary blocks of data? Well, you can circumvent shortcomings of Microsoft Windows with this technique. Since Windows has a DLL responsible for all kind of HID devices, you don't need your own driver DLL and hence no installation.
- Windows software needs no driver DLL and hence no installation.
- Since the structure of the data blocks must be described in Report Descriptors, only fixed length blocks can be transferred. (It is possible to circumvent this limitation with a protocol layer on top of some fixed size blocks, see the AVR-Doper project.)
- Some operating systems (notably BSD) automatically bind the HID driver to the device and limit access through libusb.
- Different driver API on Windows and Unix since libusb is used on Unix but not on Windows.
- Increased complexity.
Vendor type requests sent to custom HID class device
The advantages of a custom class and a HID device can be (kind of) combined. Libusb can access endpoint 0 of all devices, even those which already have a driver attached to them such as HID devices.
You can therefore create an HID class device with a simple report structure which is never used. This prevents the "New Device" dialog on Windows. Then access it with libusb or libusb-win32 as if it were a custom class device.
- Complexity of HID can be avoided.
- Same API can be used on Unix and Windows.
- Prevents the "New Device" dialog on Windows.
- On Windows, you still must ship libusb-win32 with your code. However, it's sufficient to have it in the same directory as your application.
CDC class devices
The USB CDC class is intended for modems and other communication devices. Implementing this class, it is possible to simulate a modem and thus a serial interface ("virtual com port"). Drivers for this class are included in all modern operating systems.
CDC requires bulk endpoints which are forbidden for low speed devices by the USB specification. However, most operating systems don't care and CDC works. There are still many drawbacks involved (see disadvantages below) and the main purpose of implementing this class is to simulate older devices which had a serial interface.
- Devices compatible to old serial gadgets can be built.
- Communication parameters (bit rate, parity etc.) can't be wrong because they are ignored.
- Host side programming interface is well known and understood by most hobbyists.
- Violates the standard.
- Does not work with some versions of Linux (in combination with particular USB host controllers).
- Consumes ca. 90% or more of the AVR's CPU time because bulk endpoints are polled aggressively by the host. Real-time applications on the AVR are close to impossible.
- May become unreliable if other interrupts are used on the AVR.
- Requires an INF file on Windows which binds the device to the CDC driver DLLs. These DLLs differ from Windows version to version.
Some versions of Linux try to map bulk endpoints to interrupt endpoints on low speed devices and this mapping is broken. You need a kernel patch (included in the newest vanilla kernels >=2.6.23) on these kernels. Windows Vista enforces the standard and you need a driver to map the bulk endpoints to interrupt endpoints. See Osamu Tamura's site for details.
- You can build class compliant devices. No driver required on host.
- Violates the standard.
- Does not work with newer versions of Windows. Patch needed.
V-USB can be used to implement other classes as well, of course. Please extend this section if you have more information.