编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

segmap(9E) 入口点

segmap(9E) 入口点负责设置 mmap(2) 系统调用所请求的内存映射。许多内存映射设备的驱动程序使用 ddi_devmap_segmap(9F) 作为入口点,而不是定义自己的 segmap(9E) 例程。通过提供 segmap () 入口点,驱动程序能够在创建映射之前或之后管理常规任务。例如,驱动程序可以检查映射权限并分配专用映射资源。驱动程序还可以调整映射,以适应非按页对齐的设备缓冲区。segmap() 入口点在返回之前必须调用 ddi_devmap_segmap(9F) 函数。ddi_devmap_segmap() 函数调用驱动程序的 devmap(9E) 入口点以执行实际映射。

segmap() 函数的语法如下所示:

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);

其中:

dev

要映射其内存的设备。

off

设备内存中的偏移,映射将从此位置开始。

asp

指向设备内存将要映射到的地址空间的指针。

请注意,此参数可以是 struct as *(如Example 10–1中所示),也可以是 ddi_as_handle_t(如Example 10–2中所示)。这是因为 ddidevmap.h 包括以下声明:

typedef struct as *ddi_as_handle_t
addrp

指向设备内存将要映射到的地址空间中的地址的指针。

len

所映射的内存的长度(字节)。

prot

指定保护的位字段。可能的设置有 PROT_READ、PROT_WRITE、PROT_EXEC、PROT_USER 和 PROT_ALL。有关详细信息,请参见手册页。

maxprot

尝试的映射可用的最大保护标志。如果用户打开只读的特殊文件,则 PROT_WRITE 位可能会被屏蔽。

flags

指示映射类型的标志。可能的值包括 MAP_SHARED 和 MAP_PRIVATE。

credp

指向用户凭证结构的指针。

在以下示例中,驱动程序控制允许只写映射的帧缓存器。如果应用程序尝试进行读取访问,并随后调用 ddi_devmap_segmap(9F) 来设置用户映射,则驱动程序返回 EINVAL。

示例 10-1  segmap(9E) 例程
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));
}

以下示例说明如何处理其缓冲区未在寄存器空间中按页对齐的设备。本示例将映射从偏移 0x800 开始的缓冲区,因此 mmap(2) 会返回与该缓冲区起始位置对应的地址。devmap_devmem_setup(9F) 函数映射整页,要求映射按页对齐,并返回页起始位置的地址。如果此地址是通过 segmap(9E) 传递的,或者未定义 segmap() 入口点,则 mmap() 将返回对应于页起始位置的地址,而不是对应于缓冲区起始位置的地址。在本示例中,缓冲区偏移将与 devmap_devmem_setup 返回的按页对齐地址相加,因此,得到的返回地址就是所需的缓冲区起始地址。

示例 10-2  使用 segmap() 函数更改 mmap() 调用返回的地址
#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);
}