Writing Device Drivers

Device Access

Access to a device by one or more application programs is controlled through the open(9E) and close(9E) entry points. The open(9E) routine of a character driver is always called whenever an open(2) system call is issued on a special file representing the device. For a particular minor device, open(9E) can be called many times, but the close(9E) routine is called only when the final reference to a device is removed. If the device is accessed through file descriptors, this is by a call to close(2) or exit(2). If the device is accessed through memory mapping, this could also be by a call to munmap(2).

open(9E)

int xxopen(dev_t *devp, int flag, int otyp, cred_t *credp);

The primary function of open(9E) is to verify that the open request is allowed. devp is a pointer to a device number. The open(9E) routine is passed a pointer so that the driver can change the minor number. This allows drivers to dynamically create minor instances of the device. An example of this might be a pseudo-terminal driver that creates a new pseudo-terminal whenever the driver is opened. A driver that dynamically chooses the minor number, normally creates only one minor device node in attach(9E) with ddi_create_minor_node(9F), then changes the minor number component of *devp using makedevice(9F) and getmajor(9F):

    *devp = makedevice(getmajor(*devp), new_minor);

The driver must keep track of available minor numbers internally.

otyp indicates how open(9E) was called. The driver must check that the value of otyp is appropriate for the device. For character drivers, otyp should be OTYP_CHR (see the open(9E) manual page).

flag contains bits indicating whether the device is being opened for reading (FREAD), writing (FWRITE), or both. User threads issuing the open(2) system call can also request exclusive access to the device (FEXCL) or specify that the open should not block for any reason (FNDELAY), but it is the driver's responsibility to enforce both cases. A driver for a write-only device such as a printer might consider an open for reading invalid.

credp is a pointer to a credential structure containing information about the caller, such as the user ID and group IDs. Drivers should not examine the structure directly, but should instead use drv_priv(9F) to check for the common case of root privileges. In this example, only root is allowed to open the device for writing.

Example 10-2 shows a character driver open(9E) routine.


Example 10-2 Character Driver open(9E) Routine

static int
xxopen(dev_t *devp, int flag, int otyp, cred_t *credp)
{
    minor_t            instance;

        if (getminor(*devp) is invalid)
                return (EINVAL);
        instance = getminor(*devp); /* one-to-one example mapping */
        /* Is the instance attached? */
        if (ddi_get_soft_state(statep, instance) == NULL)
                return (ENXIO);
        /* verify that otyp is appropriate */
        if (otyp != OTYP_CHR)
                return (EINVAL);
        if ((flag & FWRITE) && drv_priv(credp) == EPERM)
                return (EPERM);
        return (0);
}

close(9E)

int xxclose(dev_t dev, int flag, int otyp, cred_t *credp); 

close(9E) should perform any cleanup necessary to finish using the minor device, and prepare the device (and driver) to be opened again. For example, the open routine might have been invoked with the exclusive access (FEXCL) flag. A call to close(9E) would allow further opens to continue. Other functions that close(9E) might perform are: