JavaScript is required to for searching.
跳过导航链接
退出打印视图
编写设备驱动程序     Oracle Solaris 11.1 Information Library (简体中文)
为本文档评分
search filter icon
search icon

文档信息

前言

第 1 部分针对 Oracle Solaris 平台设计设备驱动程序

1.  Oracle Solaris 设备驱动程序概述

2.  Oracle Solaris 内核和设备树

3.  多线程

4.  属性

5.  管理事件和排队任务

6.  驱动程序自动配置

7.  设备访问:程控 I/O

8.  中断处理程序

9.  直接内存访问 (Direct Memory Access, DMA)

10.  映射设备和内核内存

内存映射概述

导出映射

segmap(9E) 入口点

devmap(9E) 入口点

将设备内存与用户映射相关联

将内核内存与用户映射相关联

为用户访问分配内核内存

将内核内存导出到应用程序

释放为用户访问导出的内核内存

11.  设备上下文管理

12.  电源管理

13.  强化 Oracle Solaris 驱动程序

14.  分层驱动程序接口 (Layered Driver Interface, LDI)

第 2 部分设计特定种类的设备驱动程序

15.  字符设备驱动程序

16.  块设备驱动程序

17.  SCSI 目标驱动程序

18.  SCSI 主机总线适配器驱动程序

19.  网络设备驱动程序

20.  USB 驱动程序

21.  SR-IOV 驱动程序

第 3 部分生成设备驱动程序

22.  编译、装入、打包和测试驱动程序

23.  调试、测试和调优设备驱动程序

24.  推荐的编码方法

第 4 部分附录

A.  硬件概述

B.  Oracle Solaris DDI/DKI 服务汇总

C.  使设备驱动程序支持 64 位

D.  控制台帧缓存器驱动程序

E.  pci.conf 文件

索引

请告诉我们如何提高我们的文档:
过于简略
不易阅读或难以理解
重要信息缺失
错误的内容
需要翻译的版本
其他
Your rating has been updated
感谢您的反馈!

您的反馈将非常有助于我们提供更好的文档。 您是否愿意参与我们的内容改进并提供进一步的意见?

导出映射

本节介绍如何使用 segmap(9E)devmap(9E) 入口点。

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 *(如示例 10-1 中所示),也可以是 ddi_as_handle_t(如示例 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);
}

devmap(9E) 入口点

devmap(9E) 入口点通过 segmap(9E) 入口点内部的 ddi_devmap_segmap(9F) 函数调用。

devmap(9E) 入口点是作为 mmap(2) 系统调用的结果调用的。调用 devmap(9E) 函数可将设备内存或内核内存导出到用户应用程序。devmap() 函数用于进行以下操作:

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

int devmap(dev_t dev, devmap_cookie_t handle, offset_t off,
     size_t len, size_t *maplen, uint_t model);

其中:

dev

要映射其内存的设备。

handle

系统创建的设备映射句柄,用来描述到设备或内核中的连续内存的映射。

off

应用程序映射中的逻辑偏移,必须通过驱动程序将其转换为设备或内核内存中的对应偏移。

len

所映射的内存的长度(以字节为单位)。

maplen

使驱动程序可将不同的内核内存区域或多个物理上不连续的内存区域与一个连续的用户应用程序映射相关联。

model

当前线程的数据模型类型。

系统在一次 mmap(2) 系统调用中将创建多个映射句柄。例如,映射可能包含多个物理上不连续的内存区域。

devmap(9E) 的首次调用使用参数 offlen 的初始值。应用程序将这些参数传递给 mmap(2)devmap(9E)*maplen 设置为从 off 到连续内存区域末尾之间的长度。*maplen 值必须向上进位为页面大小的倍数。 *maplen 值可被设置为小于原始映射长度 len。如果这样,系统将使用调整了 offlen 参数的新映射句柄反复调用 devmap(9E),直到达到初始映射长度为止。

如果一个驱动程序支持多个应用程序数据模型,则必须将 model 传递给 ddi_model_convert_from(9F)ddi_model_convert_from() 函数可以确定当前线程与设备驱动程序之间是否存在数据模型不匹配的情况。设备驱动程序可能必须调整数据结构的形状,然后才能将结构导出到支持不同数据模型的用户线程。有关更多详细信息,请参见附录 C

如果逻辑偏移 off 超出了驱动程序导出的内存范围,则 devmap(9E) 入口点必将返回 -1