Device Driver Tutorial

Reporting and Setting Device Size and Re-initializing the Device

The behavior of the ioctl(9E) entry point depends on the command value passed in to the entry point. These constants are defined in the new qotd.h header file. The qotd_ioctl() routine reports the size of the space allocated for the quotation, sets a new amount of space to allocate for the quotation, or resets the quotation back to its initial value.

If the request is to report the size of the space allocated for the quotation, then the qotd_ioctl() routine first sets a local size variable to the value of the quotation length in the state structure. If the device was not opened for reading, the qotd_ioctl() routine returns an error.

Because the qotd_ioctl() routine transfers data between kernel space and user space, the qotd_ioctl() routine must check whether both spaces are using the same data model. If the return value of the ddi_model_convert_from(9F) function is DDI_MODEL_ILP32, then the driver must convert to 32-bit data before calling ddi_copyout(9F) to transfer the current size of the quotation space. If the return value of the ddi_model_convert_from(9F) function is DDI_MODEL_NONE, then no data type conversion is necessary.

If the request is to set a new size for the space allocated for the quotation, then the qotd_ioctl() routine first sets local variables for the new size, the new quotation, and a new memory allocation cookie. If the device was not opened for writing, the qotd_ioctl() routine returns an error.

The qotd_ioctl() routine then checks again for data model mismatch. If the return value of the ddi_model_convert_from(9F) function is DDI_MODEL_ILP32, then the driver declares a 32-bit size variable to receive the new size from ddi_copyin(9F). When the new size is received, the size is converted to the data type of the kernel space.

If the new size is zero or is greater than QOTD_MAX_LEN, the qotd_ioctl() routine returns an error. If the new size is valid, then the qotd_ioctl() routine allocates new memory for the quotation and enters a mutex.

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

When the device is not busy, the qotd_ioctl() routine uses memcpy(9F) to copy the quotation from the driver's state structure to the new space. The qotd_ioctl() routine then frees the memory currently pointed to by the state structure, and updates the state structure members to the new values. The qotd_ioctl() routine then sets the QOTD_CHANGED flag, exits the mutex, and returns.

If the request is to discard the current quotation and reset to the initial quotation, then the qotd_ioctl() routine first sets local variables for the new quotation and a new memory allocation cookie. If the device was not opened for writing, the qotd_ioctl() routine returns an error. If the space allocated for the current quotation is different from the space allocated for the initial quotation, then the qotd_ioctl() routine allocates new memory that is the size of the initial space and enters a mutex.

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

When the device is not busy, the qotd_ioctl() routine frees the memory currently pointed to by the state structure, updates the memory state structure members to the new values, and resets the length to its initial value. If the size of the current quotation space was the same as the initial size and no new memory was allocated, then qotd_ioctl() calls bzero(9F) to clear the current quotation. The qotd_ioctl() routine then calls the strlcpy(9F) function to copy the initial quotation string to the quotation member of the state structure. The qotd_ioctl() routine then unsets the QOTD_CHANGED flag, exits the mutex, and returns.

Once the QOTD_CHANGED flag has been set, the only way to unset it is to run the qotdctl command with the -r option. See Exercising the Driver's I/O Controls for more information about the qotdctl command.