• Keine Ergebnisse gefunden

9-1

9-3

9-4 9-4 9-6

9-8 9-9 9-10

9-12

9-15

This chapter describes the organization of a STREAMS driver, and discusses some of the processing typically required in drivers. Certain ele-ments of driver flow control are discussed. Procedures for handling user ioctls, common to modules and drivers, are described.

As discussed under "Stream Construction" in Chapter 5, driver and module organization are very similar. The call interfaces to all the driver procedures are identical to module interfaces and driver procedures must be reentrant. As described under "Environment" in Chapter 6, the driver put and service procedures have no user environment and cannot sleep. Other than with open and close, a driver interfaces with a user process by mes-sages, and indirectly, through flow control.

There are two significant differences between modules and drivers.

First, a device driver must also be accessible from an interrupt as well as from the Stream, and second, a driver can have multiple Streams connected to it. Multiple connections occur when more than one minor device uses the same driver and in the case of multiplexors (see Chapter 11). However, these particular differences are not recognized by the STREAMS mechanism:

They are handled by developer-provided code included in the driver pro-cedures.

Figure 9-1 shows multiple Streams (corresponding to minor devices), to a common driver. This depiction of two Streams connected to a single driver (also used in the Primer) is somewhat misleading. These are really two distinct Streams opened from the same cdevsw (i.e., same major device).

Consequently,-they have the same streamtab and the same driver pro-cedures. Modules opened from the same fmodsw might be depicted simi-larly if they had any reason to be cognizant, as do drivers, of common resources or alternate instantiations.

Multiple instantiations (minor devices) of the same driver are handled during the initial open for each device. Typically, the queue_t address is stored in a driver-private structure indexed by the minor device number.

The structure is typically pointed at by qytr (see Chapter 8). When the messages are received by the QUEUE, the calls to the driver put and service procedures pass the address of the queue_t, allowing the procedures to determine the associated device.

In addition to these differences, a driver is always at the end of a Stream. As a result, drivers must include standard processing for certain message types that a module might simply be able to pass to the next com-ponent.

Module(s) Module(s)

Port

o

Driver Procedures and Interrupt Code

Figure 9-1: Device Driver Streams

Port 1

The same utilities (described in Chapter 8), and mechanisms used for module flow control are used by drivers. However, they are typically used in a different manner in drivers, because a driver generally does not have a service procedure. The developer sets flow control values (mi_hiwat and miJowat) in the write side module_info structure, which STREAMS will copy into q_hiwat and qJowat in the queue_t structure of the QUEUE. A device driver typically has no write service procedure, but does maintain a write message queue. When a message is passed to the driver write side put procedure, the procedure will determine if device output is in progress. In the event output is busy, the put procedure cannot immediately send the message and calls the putq utility (see Appendix C) to queue the message.

(N ote that the driver might have elected to queue the message in all cases.) putq recognizes the absence of a service procedure and does not schedule the QUEUE.

When the message is queued, putq increments the value of q_count (approximately the enqueued character count, see the beginning of Chapter 8) by the size of the message and compares the result against the driver's write high water limit (q_hiwat) value. If the count exceeds q_hiwat, putq will set the internal FULL (see the section titled "Flow Control" in Chapter 6 of the Primer) indicator for the driver write QUEUE. This will cause mes-sages from upstream to be halted (can put returns FALSE) until the write queue count reaches qJowat. The driver messages waiting to be output are dequeued by the driver output interrupt routine with getq, which decre-ments the count. If the resulting count is below qJowat, getq will back-enable any upstream QUEUE that had been blocked. The above STREAMS processing also applies to modules on both write and read sides of the Stream.

Device drivers typically discard input when unable to send it to a user process. However, STREAMS allows flow control to be used on the driver read side, possibly to handle temporary upstream blocks. This is described in Chapter 13 in the section titled "Advanced Flow Control".

To some extent, a driver or module can control when its upstream transmission will become blocked. Control is available through the M_SETOPTS message (see Chapter 13 and Appendix B) to modify the Stream head read side flow control limits.

The example below shows how a simple interrupt-per-character line printer driver could be written. The driver is unidirectional and has no read side processing. It demonstrates some differences between module and driver programming, including the following:

Open handling A driver is passed a minor device number or is asked to select one (see next chapter).

Flush handling A driver must loop M_FLUSH messages back upstream.

Ioctl handling A driver must nak ioctl messages it does not under-stand. This is discussed under "Driver and Module Ioctls", below.

Write side flow control is also illustrated as described above.