The QNX Device Manager (Dev) is the interface between processes and terminal devices. These terminal devices are located in the I/O namespace with names starting with /dev. For example, a console device on QNX would have a name such as: /dev/con1.
QNX programs access terminal devices using the standard read(), write(), open(), and close() functions. A terminal device is presented to a QNX process as a bidirectional stream of bytes that can be read or written by the process. The Device Manager regulates the flow of data between an application and the device. Some processing of this data is performed by Dev according to parameters in a terminal control structure (called termios), which exists for each device. Users can query and/or change parameters by using the stty utility; programs can use the tcgetattr() and tcsetattr() functions. The termios parameters control low-level fuctionality such as:
Some auxiliary services provided by the Device Manager:
The most significant mode ofdevice processing is controlled by the ICANON bit in the termios control structure. If this control bit is set, the Device Manager performs line-editing functions on received characters. Thus, only when line is entered (typically when a carriage return is received) will the processed data be made available to applications. This mode of operation is referred to as edited, canonical, or cooked mode. Line editing characters vary from terminal to terminal. The QNX console always starts out with a full set of editing keys defined.
If a terminal is connected to QNX via a serial channel, it is necessary to define the editing characters that apply to that particular terminal. T do this, you can use stty utility.
When ICANON is not set, the device is said to be in raw mode. In this mode, no input editing is performed, and any received data is made immediately available to QNX processes. When reading from a raw device, the application is capable of specifying underwhat conditions an input is to be satisfied. The criteria used for accepting raw input data are based on two members of the termios control structure: MIN and TIME. The application can specify a further qualifier of accepting input data when it issues its read request via dev_read(). This qualifier, TIMEOUT, is useful when writing protocols or realtime applications. TIMEOUT is always 0 for read(). When a QNX process issues a read request for n bytes of data, these three paraeters define when that read request is to be satisfied:
MIN | TIME | TIMEOUT | Description |
|
|
| Return immediately with as many bytes as are currently available (up to n bytes). |
|
|
| Return with up to n bytes only, when at least M bytes are available. |
|
|
| Return with up to n bytes when at least one byte is available, or Tx0.1 second has expired. |
|
|
| Return with up to n bytes when either M bytes are available or at least one byte has been received and the interbyte time between any subsequently received characters exceeds Tx0.1 second. |
|
|
| Reserved. |
|
|
| Return with up to n bytes when tx0.1 second has expired, or M bytes are available. |
|
|
| Reserved. |
|
|
| Return with up to n bytes when M bytes are available, or tx0.1 second has expired and no characters are received, or at least one byte has been received and the interbyte time between any subsequently received characters exceeds Tx0.1 second. |
The hardware interface is managed by individual driver processes. Data flows between Dev and its drivers through a set of shared memory queues for each terminal device. Because shared memory queues are used, it is necessary that Dev and all of its drivers reside on the same physical CPU. Three queues are used for each device. Each queue is implemented using a first-in, first-out mechanism. A control structure is also associated with each queue.
Received data is placed into the raw input queue by the driver and is consumed by Dev only when application process request data. Interrupt handlers within drivers typically call a trusted library routine within Dev to add data to this queue. Dev places output data into the output queue; the data is consumed by the driver as characters are physically transmitted to the device. Dev calls a trusted routine within the driver process each time new data is added so it can "kick" the driver into operation. Since output queues are used, Dev implements full write-behind for all terminal devices. Only when the output buffers are full will Dev cause a process to block while writing.
The canonical queue is managed by Dev and is used while processing input data in edited mode. The size of this queue determines the maximum edited input line that can be processes for a particular device. The sizes of all these queues are configurable; the only restriction is that the sum of all three queues can not exceed 64K.
Device drivers simply add received data to the raw input queue or consume and transmit data from the output queue. Dev decides when and if output transmission is to be suspended, how and if received data is echoed, etc. Low-level device control is implemented with a far call into an ioctl entry point within each driver. A common set of ioctl commands are supported by most drivers used directly by Dev. Device-specific ioctl commands can also be sent through Dev to the drivers by QNX processes (via the qnx_ioctl() C function).