Writing Device Drivers

Associating Device Memory With User Mappings

devmap_devmem_setup(9F) is provided to export device memory to user applications. devmap_devmem_setup(9F) has to be called from the driver's devmap(9E) entry point:

int devmap_devmem_setup(devmap_cookie_t handle,
 		dev_info_t *dip,
 		struct devmap_callback_ctl *callbackops,
 		u_int rnumber, offset_t roff,
 		size_t len, u_int maxprot, u_int flags,
 		ddi_device_acc_attr_t *accattrp);

handle is an opaque device-mapping handle that the system uses to identify the mapping. It is passed in by the devmap(9E) entry point. dip is a pointer to the device's dev_info structure. dip is stored by the driver in its private data structure during attach(9E). callbackops is a pointer to a devmap_callback_ctl(9S) structure that allows the driver to be notified of user events on the mapping. See Chapter 12, Device Context Managementfor a complete description of devmap_callback_ctl(9S).

roff and len describe a range within the device memory specified by the register set rnumber. roff is the offset into the device memory, and len is the length in bytes that is exported. The register specifications referred to by rnumber are described by the reg property (see driver.conf(4), isa(4), eisa(4), mca(4), sysbus(4), vme(4), sbus(4) and pci(4)). For devices with only one register set, pass zero for rnumber. The range described by roff and len are made accessible to the user's application mapping at the offset passed in by the devmap(9E) entry point. Usually the driver will pass the devmap(9E) offset directly to devmap_devmem_setup(9F). The return address of mmap(2) will then map to the beginning of the register set.

maxprot allows the driver to specify different protections for different regions within the exported device memory. For example, one region might not allow write access by only setting PROT_READ and PROT_USER.

flags must be set to DEVMAP_DEFAULTS. accattrp is a pointer to a ddi_device_acc_attr(9S) structure.

Example 11-1 shows how to export device memory to an application. The driver first determines whether the requested mapping falls within the device memory region. The size of the device memory is determined using ddi_dev_regsize(9F). The length of the mapping is rounded up to a multiple of a page size using ptob(9F) and btopr(9F), and devmap_devmem_setup(9F) is called to export the device memory to the application.


Example 11-1 devmap_devmem_setup(9F) Routine

static int
xxdevmap(dev_t dev, devmap_cookie_t handle, offset_t off,
	size_t len, size_t *maplen, uint_t model)
{
	struct xxstate *xsp;
	int	error, rnumber;
	off_t regsize;
	
	/* Set up data access attribute structure */
	struct ddi_device_acc_attr xx_acc_attr = {
		    DDI_DEVICE_ATTR_V0,
	    	DDI_NEVERSWAP_ACC,
	    	DDI_STRICTORDER_ACC
	};
	xsp = ddi_get_soft_state(statep, getminor(dev));
	if (xsp == NULL)
	    	return (ENXIO);
	/* use register set 0 */
	rnumber = 0;
	/* get size of register set */
	if (ddi_dev_regsize(xsp->dip, rnumber, &regsize) !=
DDI_SUCCESS)
	    	return (ENXIO);
	/* round up len to a multiple of a page size */
	len = ptob(btopr(len));
	if (off + len > regsize)
	    	return (ENXIO);
	/* Set up the device mapping */
	error = devmap_devmem_setup(handle, xsp->dip, NULL, rnumber
				off, len, PROT_ALL, DEVMAP_DEFAULTS, &xx_acc_attr);
	/* acknowledge the entire range */
	*maplen = len;
	return (error);
}