Writing Device Drivers

devmap_unmap(9E)

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);

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

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. new_handle1 may be NULL.

new_devprivate1

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

new_handle2

Handle that the system uses to describe the new region that begins at off + len. new_handle2 may 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. It is ignored if new_handle2 is NULL.

The devmap_unmap(9E) 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 only a part of the mapping is being unmapped, the driver must allocate a new private data for the remaining mapping before freeing the old private data. There is no need to call devmap_unload(9F) on the handle of the mapping being freed, even if it is the mapping with the valid translations. However, to prevent future problems in devmap_access(9E), the device driver should make sure that its representation of the current mapping is set to "no current mapping".

Example 13-5 shows an example of a devmap_unmap(9E) routine.


Example 13-5 devmap_unmap(9E) 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));
}