Writing Device Drivers

devmap_map()

int xxdevmap_map(devmap_cookie_t handle, dev_t dev, u_int flags,
 	offset_t offset, size_t len, void **new_devprivate);

This entry point is called after the driver returns from its devmap(9E) entry point and the system has established the user mapping to the device memory. The devmap_map(9E) entry point enables a driver to perform additional processing or to allocate mapping specific private data. For example, in order to support context switching, the driver has to allocate a context structure and associate it with the mapping.

The system expects the driver to return a pointer to the allocated private data in *new_devprivate. The driver must store offset and len, which define the range of the mapping, in its private data. Later, when the system calls devmap_unmap(9E), the driver will use offset and len stored in new_devprivate to check if the entire mapping, or just a part of it, is being unmapped.

flags indicates whether the driver should allocate a private context for the mapping. For example, a driver may allocate a memory region to store the device context if flags is set to MAP_PRIVATE, or it might return a pointer to a shared region if MAP_SHARED is set.

Example 12-2 shows an example of a devmap_map(9E) entry point. The driver allocates a new context structure and saves relevant parameters passed in by the entry point. Then the mapping is assigned a new context by either allocating a new one or attaching it to an already existing shared context. The minimum time interval that the mapping should have access to the device is set to one millisecond.


Example 12-2 devmap_map(9E) Routine

static int
int xxdevmap_map(devmap_cookie_t handle, dev_t dev, u_int flags,
	offset_t offset, size_t len, void **new_devprivate)
{
 	struct xxstate *xsp = ddi_get_soft_state(statep,
                        getminor(dev));
 	struct xxctx *newctx;

 	/* create a new context structure */
 	newctx = kmem_alloc(sizeof (struct xxctx), KM_SLEEP);
 	newctx->xsp = xsp;
 	newctx->handle = handle;
 	newctx->offset = offset;
 	newctx->flags = flags;
 	newctx->len = len;
 	mutex_enter(&xsp->ctx_lock);
 	if (flags & MAP_PRIVATE) {
	    	/* allocate a private context and initialize it */
	    	newctx->context = kmem_alloc(XXCTX_SIZE, KM_SLEEP);
	    	xxctxinit(newctx);
 	} else {
	    	/* set a pointer to the shared context */
	    	newctx->context = xsp->ctx_shared;
 	}
 	mutex_exit(&xsp->ctx_lock);
 	/* give at least 1 ms access before context switching */
 	devmap_set_ctx_timeout(handle, drv_usectohz(1000));
 	/* return the context strcuture */
 	*new_devprivate = newctx;
 	return(0);
}