Writing Device Drivers

Associating User Mappings With Driver Notifications

When a user process requests a mapping to a device with mmap(2), the driver`s segmap(9E) entry point is called. The driver must use ddi_devmap_segmap(9F) or devmap_setup(9F) when setting up the memory mapping if it needs to manage device contexts. Both functions will call the driver's devmap(9E) entry point, which uses devmap_devmem_setup(9F) to associate the device memory with the user mapping. See Chapter 12, Mapping Device and Kernel Memory for details on how to map device memory.

For the driver to get notifications on accesses to the user mapping, it has to inform the system of the devmap_callback_ctl(9S) entry points. It does this by providing a pointer to a devmap_callback_ctl(9S) structure to devmap_devmem_setup(9F). A devmap_callback_ctl(9S) structure describes a set of context management entry points that are called by the system to notify a device driver to manage events on the device mappings.

The system associates each mapping with a mapping handle. This handle is passed to each of the context management entry points. The mapping handle can be used to invalidate and validate the mapping translations. If the driver invalidates the mapping translations, it will be notified of any future access to the mapping. If the driver validates the mapping translations, it will no longer be notified of accesses to the mapping. Mappings are always created with the mapping translations invalidated so that the driver will be notified on first access to the mapping.

Example 13–6 shows how to set up a mapping using the device context management interfaces.


Example 13–6 devmap(9E) Entry Point With Context Management Support

static struct devmap_callback_ctl xx_callback_ctl = {
    DEVMAP_OPS_REV, xxdevmap_map, xxdevmap_access,
    xxdevmap_dup, xxdevmap_unmap
};

static int
xxdevmap(dev_t dev, devmap_cookie_t handle, offset_t off,
    size_t len, size_t *maplen, uint_t model)
{
        struct xxstate *xsp;
        uint_t rnumber;
        int    error;
    
        /* Setup data access attribute structure */
        struct ddi_device_acc_attr xx_acc_attr = {
            DDI_DEVICE_ATTR_V0,
            DDI_NEVERSWAP_ACC,
            DDI_STRICTORDER_ACC
        };
        xsp = ddi_get_soft_state(statep, getminor(dev));
        if (xsp == NULL)
                return (ENXIO);
        len = ptob(btopr(len));
        rnumber = 0;
        /* Set up the device mapping */
        error = devmap_devmem_setup(handle, xsp->dip, &xx_callback_ctl,
                rnumber, off, len, PROT_ALL, 0, &xx_acc_attr);
        *maplen = len;
        return (error);
}