Writing Device Drivers

devmap_contextmgt() Entry Point

The syntax for devmap_contextmgt(9E) is:

int xxdevmap_contextmgt(devmap_cookie_t handle, void *devprivate,
    offset_t offset, size_t len, uint_t type, uint_t rw);

In general, devmap_contextmgt() should call devmap_unload(9F), with the handle of the mapping that currently has access to the device, to invalidate the translations for that mapping. This ensures that a call to devmap_access(9E) occurs for the current mapping the next time it is accessed. To validate the mapping translations for the mapping that caused the access event to occur, the driver must restore the device context for the process requesting access and call devmap_load(9F) on the handle of the mapping that generated the call to this entry point.

Accesses to portions of mappings that have had their mapping translations validated by a call to devmap_load() do not generate a call to devmap_access(). A subsequent call to devmap_unload() invalidates the mapping translations and allows devmap_access() to be called again.

If either devmap_load() or devmap_unload() returns an error, devmap_contextmgt() should immediately return that error. If the device driver encounters a hardware failure while restoring a device context, a -1 should be returned. Otherwise, after successfully handling the access request, devmap_contextmgt() should return zero. A return of other than zero from devmap_contextmgt() will cause a SIGBUS or SIGSEGV to be sent to the process.

Example 13–3 shows how to manage a one-page device context.


Note –

xxctxsave() and xxctxrestore() are device-dependent context save and restore functions. xxctxsave() reads data from the registers using the Solaris 9 DDI/DKI data access routines and saves it in the soft state structure. xxctxrestore() takes data saved in the soft state structure and writes it to device registers using the Solaris 9 DDI/DKI data access routines.



Example 13–3 devmap_contextmgt(9E) Routine

static int
xxdevmap_contextmgt(devmap_cookie_t handle, void *devprivate,
    offset_t off, size_t len, uint_t type, uint_t rw)
{
        int    error;
        struct xxctx *ctxp = devprivate;
        struct xxstate *xsp = ctxp->xsp;
        mutex_enter(&xsp->ctx_lock);
        /* unload mapping for current context */
        if (xsp->current_ctx != NULL) {
                if ((error = devmap_unload(xsp->current_ctx->handle,
                    off, len)) != 0) {
                        xsp->current_ctx = NULL;
                        mutex_exit(&xsp->ctx_lock);
                        return (error);
                }
        }
        /* Switch device context - device dependent */
        if (xxctxsave(xsp->current_ctx, off, len) < 0) {
                xsp->current_ctx = NULL;
                mutex_exit(&xsp->ctx_lock);
                return (-1);
        }
        if (xxctxrestore(ctxp, off, len) < 0){
                xsp->current_ctx = NULL;
                mutex_exit(&xsp->ctx_lock);
                return (-1);
        }
        xsp->current_ctx = ctxp;
        /* establish mapping for new context and return */
        error = devmap_load(handle, off, len, type, rw);
        if (error)
                xsp->current_ctx = NULL;
        mutex_exit(&xsp->ctx_lock);
        return (error);
}