DEVMAP(9E)                   Driver Entry Points                  DEVMAP(9E)
NAME
       devmap - validate and translate virtual mapping for memory mapped
       device
SYNOPSIS
       #include <sys/ddi.h>
       #include <sys/sunddi.h>       
int prefixdevmap(
dev_t dev, 
devmap_cookie_t dhp, 
offset_t off,            
size_t len, 
size_t *maplen, 
uint_t model);
INTERFACE LEVEL
       illumos DDI specific (illumos DDI).
PARAMETERS
       dev                  Device whose memory is to be mapped.       
dhp                  An opaque mapping handle that the system uses to describe
                  the mapping.       
off                  User offset within the logical device memory at which the
                  mapping begins.       
len                  Length (in bytes) of the mapping to be mapped.       
maplen                  Pointer to length (in bytes) of mapping that has been
                  validated. 
maplen is less than or equal to  
len.       
model                  The data model type of the current thread.
DESCRIPTION
       devmap() is a required entry point for character drivers supporting
       memory-mapped devices if the drivers use the devmap framework to set
       up the mapping. A memory mapped device has memory  that can be mapped
       into a process's address space. The 
mmap(2) system call, when applied
       to a character special file, allows this device memory to be mapped
       into user space for direct access by the user applications.
       As a result of a 
mmap(2) system call, the system calls the 
devmap()       entry point during the mapping setup when 
D_DEVMAP is set in the       
cb_flag field of the 
cb_ops(9S) structure, and any of the following
       conditions apply:
           o      
ddi_devmap_segmap(9F) is used as the 
segmap(9E) entry
                  point.
           o      
segmap(9E) entry point is set to 
NULL.           o      
mmap(9E) entry point is set to 
NULL.       Otherwise 
EINVAL will be returned to 
mmap(2).
       Device drivers should use 
devmap() to validate the user mappings to
       the device, to translate the logical offset,  
off, to the
       corresponding physical offset within the device address space, and to
       pass the mapping information to the system for setting up the
       mapping.       
dhp is a device mapping handle that the system uses to describe a
       mapping to a memory that is either contiguous in physical address
       space or in kernel virtual address space. The system may create
       multiple mapping  handles in one 
mmap(2) system call (for example, if
       the mapping contains multiple physically discontiguous memory
       regions).       
model returns the C Language Type Model which the current thread
       expects.  It is set to 
DDI_MODEL_ILP32 if the current thread expects
       32-bit ( 
ILP32) semantics, or 
DDI_MODEL_LP64 if the current thread
       expects 64-bit ( 
LP64) semantics. 
model is used in combination with       
ddi_model_convert_from(9F) to determine whether there is a data model
       mismatch between the current thread and the device driver. The device
       driver might have to adjust the shape of data structures before
       exporting them to a user thread which supports a different data
       model.       
devmap() should return 
EINVAL if the logical offset, 
off, is out of
       the range of memory exported by the device to user space. If 
off +       
len exceeds the range of the contiguous memory, 
devmap() should
       return the length from  
off to the end of the contiguous memory
       region.  The system will repeatedly call 
devmap() until the original
       mapping length is satisfied. The driver sets 
*maplen to the validated
       length which must be either less than or equal to 
len.
       The 
devmap() entry point must initialize the mapping parameters
       before passing them to the system through either       
devmap_devmem_setup(9F) (if the memory being mapped is device memory)
       or 
devmap_umem_setup(9F) (if the memory being mapped is kernel
       memory). The 
devmap() entry point initializes the mapping parameters
       by mapping the control callback structure (see       
devmap_callback_ctl(9S)), the device access attributes, mapping
       length, maximum protection possible for the mapping, and optional
       mapping flags. See 
devmap_devmem_setup(9F) and 
devmap_umem_setup(9F)       for further information on initializing the mapping parameters.
       The system will copy the driver's 
devmap_callback_ctl(9S) data into
       its private memory so the drivers do not need to keep the data
       structure after the return from either 
devmap_devmem_setup(9F) or       
devmap_umem_setup(9F).
       For device mappings, the system establishes the mapping to the
       physical address that corresponds to 
off by passing the register
       number and the offset within the register address space to       
devmap_devmem_setup(9F).
       For kernel memory mapping, the system selects a user virtual address
       that is aligned with the kernel address being mapped for cache
       coherence.
RETURN VALUES
       0                   Successful completion.       
Non-zero                   An error occurred.
EXAMPLES
       Example 1: Implementing the devmap() Entry Point
       The following is an example of the implementation for the 
devmap()       entry point. For mapping device memory, 
devmap() calls       
devmap_devmem_setup(9F) with the register number, 
rnumber, and the
       offset within the register, 
roff. For mapping kernel memory, the
       driver must first allocate the kernel memory using       
ddi_umem_alloc(9F). For example, 
ddi_umem_alloc(9F) can be called in
       the 
attach(9E) routine. The resulting kernel memory cookie is stored
       in the driver soft state structure, which is accessible from the       
devmap() entry point. See 
ddi_soft_state(9F). 
devmap() passes the
       cookie obtained from 
ddi_umem_alloc(9F) and the offset within the
       allocated kernel memory to 
devmap_umem_setup(9F). The corresponding       
ddi_umem_free(9F) can be made in the 
detach(9E) routine to free up
       the kernel memory.
         ...
         #define MAPPING_SIZE 0x2000        /* size of the mapping */
         #define MAPPING_START 0x70000000   /* logical offset at beginning
                                               of the mapping */
         static
         struct devmap_callback_ctl xxmap_ops = {
                 DEVMAP_OPS_REV,                /* devmap_ops version number */
                 xxmap_map,                     /* devmap_ops map routine */
                 xxmap_access,                  /* devmap_ops access routine */
                 xxmap_dup,                     /* devmap_ops dup routine */
                 xxmap_unmap,                   /* devmap_ops unmap routine  */
         };
         static int
         xxdevmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
            size_t *maplen, uint_t model)
         {
            int    instance;
            struct xxstate *xsp;
            struct ddi_device_acc_attr *endian_attr;
            struct devmap_callback_ctl *callbackops = NULL;
            ddi_umem_cookie_t cookie;
            dev_info_t *dip;
            offset_t   roff;
            offset_t   koff;
            uint_t rnumber;
            uint_t maxprot;
            uint_t flags = 0;
            size_t length;
            int    err;
            /* get device soft state */
            instance = getminor(dev);
            xsp = ddi_get_soft_state(statep, instance);
            if (xsp == NULL)
               return (-1);
            dip = xsp->dip;
            /* check for a valid offset */
            if ( 
off is invalid )
               return (-1);
            /* check if len is within the range of contiguous memory */
            if ( 
(off + len) is contiguous.)                length = len;
            else
                length = MAPPING_START + MAPPING_SIZE - off;
            /* device access attributes */
            endian_attr = xsp->endian_attr;
            if (  
off is referring to a device memory.  ) {
                                          /* assign register related parameters */
               rnumber = XXX;             /* index to register set at off */
               roff = XXX;                /* offset of rnumber at local bus */
               callbackops = &xxmap_ops;  /* do all callbacks for this mapping */
               maxprot = PROT_ALL;        /* allowing all access */
               if ((err = devmap_devmem_setup(dhp, dip, callbackops, rnumber, roff,
                        length, maxprot, flags, endian_attr)) < 0)
                   return (err);
            } else if ( 
off is referring to a kernel memory.) {
               cookie = xsp->cookie;      /* cookie is obtained from                                             
ddi_umem_alloc(9F) */
               koff = XXX;                /* offset within the kernel memory. */
               callbackops = NULL;        /* don't do callback for this mapping */
               maxprot = PROT_ALL;        /* allowing all access */
               if ((err = devmap_umem_setup(dhp, dip, callbackops, cookie, koff,
                        length, maxprot, flags, endian_attr)) < 0)
                  return (err);
           }
                  *maplen = length;
             return (0);
         }
SEE ALSO
       mmap(2), 
attach(9E), 
detach(9E), 
mmap(9E), 
segmap(9E),       
ddi_devmap_segmap(9F), 
ddi_model_convert_from(9F),       
ddi_soft_state(9F), 
ddi_umem_alloc(9F), 
ddi_umem_free(9F),       
devmap_devmem_setup(9F), 
devmap_setup(9F), 
devmap_umem_setup(9F),       
cb_ops(9S), 
devmap_callback_ctl(9S)       Writing Device Drivers                              January 15, 1997                    DEVMAP(9E)