USB serial drivers, Part 1
By artem on Nov 18, 2005
USB serial adapter is a USB device that tunnels asynchronous serial protocols, such as RS-232 and RS-485, through USB. It allows to add serial lines to computers with insufficient number of built-in serial ports. The most common need for these devices is on laptops to connect other machines' serial consoles, GPS devices, PDAs, etc.
Traditionally Solaris supported class devices only, such as printer class or mass storage class. A class driver can support devices from various vendors as long as they follow the class specification. Unfortunately, USB serial devices do not belong to any class: every device vendor has to invent a unique, often proprietary protocol, and therefore requires a separate driver.
Eventually a project was funded to support one type of USB serial adapters. We selected the Edgeport series from Inside-Out Networks. After a long break, drivers for Keyspan devices and those based on the Prolific PL2303 chip are coming soon to the next Solaris Express build. Due to the proprietary nature of device protocols, it may take some time for the driver sources to propagate to OpenSolaris.
This is the first in a series of articles about writing USB serial drivers for Solaris.
A typical USB serial device consists of a USB interface IC, firmware executed by an embedded CPU, and one or more UARTs (Universal Asynchronous Receiver-Transmitter). Firmware can be downloadable or upgradable by the driver. Firmware is responsible for bridging the two hardware interfaces, encoding outgoing and decoding incoming USB packets. At the other end, the driver similarly decodes/encodes USB packets and provides applications with the standard serial port API.
While each protocol is unique, functionality is largely the same: set serial parameters, such as baud rate and flow control, get modem status, set control lines, transmit and receive data. All these functions are available to applications via the standard UNIX termio(7I) programming interface.
The Solaris terminal subsystem, including the termio interface, is based on the STREAMS framework. STREAMS code is not easy to write, especially serial drivers, due to extreme asynchronicity and everything that it entails. It took some time for se(7D) and su(7D) to stabilize and we're still finding bugs in them once in a while.
It comes as no surprise that we decided to put USB termio implementation into a common module used by all USB serial drivers. We call it generic serial driver, GSD.
The bottom part of the driver that implements the vendor-specific USB protocol is called device-specific driver, DSD. The interface between these two parts is well-defined, we call it DSDI.
DSD in turn talks to the kernel USB framework, also known as USBA.
These layers are illustrated by the following diagram:
Note that GSD does not interact with USBA directly. In fact, GSD turned out generic enough to write any kind of serial driver, not just USB: it is possible, for example, to reimplement se(7D) and su(7D) using GSD. The only USB-specific features utilized in GSD are logging and hotplug events.
- GSD is a misc module:
/kernel/misc/usbser(and the 64-bit subdir).
- DSDs are driver modules:
/kernel/drv/usbs\*(and the 64-bit subdir)
- GSD sources:
- DSDI definition:
- DSDs should be located in