Device Driver Tutorial

Writing New Data

The cb_ops(9S) structure for Version 3 of the Quote Of The Day driver declares two new entry points that support modifying the quotation. The two new entry points are write(9E) and ioctl(9E). The qotd_rw() routine is a third new routine in Version 3 of the driver. The qotd_rw() routine is called by both the read(9E) entry point and the write(9E) entry point.

The device state structure for Version 3 of the Quote Of The Day driver contains two new members that are used to modify the quotation. The qotd string holds the quotation for the current instance of the device. The qotd_len member holds the length in bytes of the current quotation.

Version 3 of the driver also defines two new constants that support modifying the quotation. In place of QOTD_MAXLEN, Version 3 of the driver defines QOTD_MAX_LEN. QOTD_MAX_LEN is used in the qotd_ioctl() entry point to test whether the user has entered a string that is too long. Version 3 of the driver also defines QOTD_CHANGED. The QOTD_CHANGED flag is set in the qotd_rw() routine and in the qotd_ioctl() entry point when a new quotation is copied from the user.

When the qotd_3 device is opened for writing, the kernel calls the qotd_write() entry point. The qotd_write() entry point then calls the qotd_rw() routine and passes a UIO_WRITE flag. The new qotd_read() entry point is exactly the same as the qotd_write() entry point, except that the qotd_read() entry point passes a UIO_READ flag. The qotd_rw() routine supports both reading and writing the device and thereby eliminates much duplicate code.

The qotd_rw() routine first gets the device soft state. Then the qotd_rw() routine checks the length of the I/O request in the uio(9S) I/O request structure. If this length is zero, the qotd_rw() routine returns zero. If this length is not zero, the qotd_rw() routine enters a mutex.

While the device is busy, the qotd_rw() routine checks whether the condition variable has been signaled or a signal(3C) is pending. If either of these conditions is true, the qotd_rw() routine exits the mutex and returns an error.

When the device is not busy, the qotd_rw() routine checks whether the data offset in the uio(9S) I/O request structure is valid. If the offset is not valid, the qotd_rw() routine exits the mutex and returns an error. If the offset is valid, the local length variable is set to the difference between the offset in the I/O request structure and the length in the device state structure. If this difference is zero, the qotd_rw() routine exits the mutex and returns. If the device was opened for writing, the qotd_rw() routine returns a space error. Otherwise, the qotd_rw() routine returns zero.

The qotd_rw() routine then sets the QOTD_BUSY flag in the flags member of the device state structure and exits the mutex. The qotd_rw() routine then calls the uiomove(9F) function to copy the quotation. If the rw argument is UIO_READ, then the quotation is transferred from the state structure to the I/O request structure. If the rw argument is UIO_WRITE, then the quotation is transferred from the I/O request structure to the state structure.

The qotd_rw() routine then enters a mutex again. If the device was opened for writing, the qotd_rw() routine sets the QOTD_CHANGED flag. The qotd_rw() routine then sets the device to not busy, calls cv_broadcast(9F) to unblock any threads that were blocked on this condition variable, and exits the mutex.

Finally, the qotd_rw() routine returns the quotation. The quotation is written to the device node.