Writing Device Drivers

devmap_contextmgt()

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

In general, devmap_contextmgt(9E) 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(9F) do not generate a call to devmap_access(9E). A subsequent call to devmap_unload(9F) invalidates the mapping translations and allows devmap_access(9E) to be called again.

If either devmap_load(9F) or devmap_unload(9F) returns an error, devmap_contextmgt(9E) 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(9E) should return zero. A return of other than zero from devmap_contextmgt(9E) will cause a SIGBUS or SIGSEGV to be sent to the process.

Example 12-4 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 7 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 7 DDI/DKI data access routines.



Example 12-4 devmap_contextmgt(9E) Routine

static int
xxdevmap_contextmgt(devmap_cookie_t handle, void *devprivate,
     	offset_t off, size_t len, u_int type, u_int 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);
}