The segmap(9E) entry point is responsible for setting up a memory mapping requested by an mmap(2) system call. Drivers for many memory-mapped devices use ddi_devmap_segmap(9F) as the entry point rather than defining their own segmap(9E) routine. By providing a segmap() entry point, a driver can take care of general tasks before or after creating the mapping. For example, the driver can check mapping permissions and allocate private mapping resources. The driver can also make adjustments to the mapping to accommodate non-page-aligned device buffers. The segmap() entry point must call the ddi_devmap_segmap(9F) function before returning. The ddi_devmap_segmap() function calls the driver's devmap(9E) entry point to perform the actual mapping.
The segmap() function has the following syntax:
int segmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp);
where:
Device whose memory is to be mapped.
Offset within device memory at which mapping begins.
Pointer to the address space into which the device memory should be mapped.
Note that this argument can be either a struct as *, as shown in Example 10–1, or a ddi_as_handle_t, as shown in Example 10–2. This is because ddidevmap.h includes the following declaration:
typedef struct as *ddi_as_handle_t
Pointer to the address in the address space to which the device memory should be mapped.
Length (in bytes) of the memory being mapped.
A bit field that specifies the protections. Possible settings are PROT_READ, PROT_WRITE, PROT_EXEC, PROT_USER, and PROT_ALL. See the man page for details.
Maximum protection flag possible for attempted mapping. The PROT_WRITE bit can be masked out if the user opened the special file read-only.
Flags that indicate the type of mapping. Possible values include MAP_SHARED and MAP_PRIVATE.
Pointer to the user credentials structure.
In the following example, the driver controls a frame buffer that allows write-only mappings. The driver returns EINVAL if the application tries to gain read access and then calls ddi_devmap_segmap(9F) to set up the user mapping.
static int xxsegmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp) { if (prot & PROT_READ) return (EINVAL); return (ddi_devmap_segmap(dev, off, as, addrp, len, prot, maxprot, flags, cred)); }
The following example shows how to handle a device that has a buffer that is not page-aligned in its register space. This example maps a buffer that starts at offset 0x800, so that mmap(2) returns an address that corresponds to the start of the buffer. The devmap_devmem_setup(9F) function maps entire pages, requires the mapping to be page aligned, and returns an address to the start of a page. If this address is passed through segmap(9E), or if no segmap() entry point is defined, mmap() returns the address that corresponds to the start of the page, not the address that corresponds to the start of the buffer. In this example, the buffer offset is added to the page-aligned address that was returned by devmap_devmem_setup so that the resulting address returned is the desired start of the buffer.
#define BUFFER_OFFSET 0x800 int xx_segmap(dev_t dev, off_t off, ddi_as_handle_t as, caddr_t *addrp, off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp) { int rval; unsigned long pagemask = ptob(1L) - 1L; if ((rval = ddi_devmap_segmap(dev, off, as, addrp, len, prot, maxprot, flags, credp)) == DDI_SUCCESS) { /* * The address returned by ddi_devmap_segmap is the start of the page * that contains the buffer. Add the offset of the buffer to get the * final address. */ *addrp += BUFFER_OFFSET & pagemask); } return (rval); }