Writing Device Drivers

devmap_unmap() Entry Point

The devmap_unmap(9E) entry point is called when a mapping is unmapped. Unmapping can be caused by a user process exiting or by calling the munmap(2) system call.

The syntax for devmap_unmap() is as follows:

void xxdevmap_unmap(devmap_cookie_t handle, void *devprivate,
    offset_t off, size_t len, devmap_cookie_t new-handle1,
    void **new-devprivate1, devmap_cookie_t new-handle2,
    void **new-devprivate2);

where:

handle

Mapping handle of the mapping being freed.

devprivate

Pointer to the driver private data associated with the mapping.

off

Offset within the logical device memory at which the unmapping begins.

len

Length in bytes of the memory being unmapped.

new-handle1

Handle that the system uses to describe the new region that ends at off - 1. The value of new-handle1 can be NULL.

new-devprivate1

Pointer to be filled in by the driver with the private driver mapping data for the new region that ends at off -1. new-devprivate1 is ignored if new-handle1 is NULL.

new-handle2

Handle that the system uses to describe the new region that begins at off + len. The value of new-handle2 can be NULL.

new-devprivate2

Pointer to be filled in by the driver with the driver private mapping data for the new region that begins at off + len. new-devprivate2 is ignored if new-handle2 is NULL.

The devmap_unmap() routine is expected to free any driver private resources that were allocated when this mapping was created, either by devmap_map(9E) or by devmap_dup(9E). If the mapping is only partially unmapped, the driver must allocate new private data for the remaining mapping before freeing the old private data. Calling devmap_unload(9F) on the handle of the freed mapping is not necessary, even if this handle points to the mapping with the valid translations. However, to prevent future devmap_access(9E) problems, the device driver should make sure the current mapping representation is set to “no current mapping”.

The following example shows a typical devmap_unmap() routine.


Example 11–5 Using the devmap_unmap() Routine

static void
xxdevmap_unmap(devmap_cookie_t handle, void *devprivate,
    offset_t off, size_t len, devmap_cookie_t new_handle1,
    void **new_devprivate1, devmap_cookie_t new_handle2,
    void **new_devprivate2)
{
    struct xxctx *ctxp = devprivate;
    struct xxstate *xsp = ctxp->xsp;
    mutex_enter(&xsp->ctx_lock);
    /*
     * If new_handle1 is not NULL, we are unmapping
     * at the end of the mapping.
     */
    if (new_handle1 != NULL) {
        /* Create a new context structure for the mapping */
        newctx = kmem_alloc(sizeof (struct xxctx), KM_SLEEP);
        newctx->xsp = xsp;
        if (ctxp->flags & MAP_PRIVATE) {
            /* allocate memory for the private context and copy it */
            newctx->context = kmem_alloc(XXCTX_SIZE, KM_SLEEP);
            bcopy(ctxp->context, newctx->context, XXCTX_SIZE);
        } else {
            /* point to the shared context */
            newctx->context = xsp->ctx_shared;
        }
        newctx->handle = new_handle1;
        newctx->offset = ctxp->offset;
        newctx->len = off - ctxp->offset;
        *new_devprivate1 = newctx;
    }
    /*
     * If new_handle2 is not NULL, we are unmapping
     * at the beginning of the mapping.
     */
    if (new_handle2 != NULL) {
        /* Create a new context for the mapping */
        newctx = kmem_alloc(sizeof (struct xxctx), KM_SLEEP);
        newctx->xsp = xsp;
        if (ctxp->flags & MAP_PRIVATE) {
            newctx->context = kmem_alloc(XXCTX_SIZE, KM_SLEEP);
            bcopy(ctxp->context, newctx->context, XXCTX_SIZE);
        } else {
            newctx->context = xsp->ctx_shared;
        }
        newctx->handle = new_handle2;
        newctx->offset = off + len;
        newctx->flags = ctxp->flags;
        newctx->len = ctxp->len - (off + len - ctxp->off);
        *new_devprivate2 = newctx;
    }
    if (xsp->current_ctx == ctxp)
        xsp->current_ctx = NULL;
    mutex_exit(&xsp->ctx_lock);
    if (ctxp->flags & MAP_PRIVATE)
        kmem_free(ctxp->context, XXCTX_SIZE);
    kmem_free(ctxp, sizeof (struct xxctx));
}