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

文档信息

前言

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

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

2.  Oracle Solaris 内核和设备树

3.  多线程

4.  属性

设备属性

设备属性名称

创建和更新属性

查找属性

prop_op() 入口点

5.  管理事件和排队任务

6.  驱动程序自动配置

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

8.  中断处理程序

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

10.  映射设备和内核内存

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.  Solaris DDI/DKI 服务汇总

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

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

E.  pci.conf 文件

索引

设备属性

设备特性 (attribute) 信息可由称为属性 (property) 的名称-值对表示法表示。

例如,设备寄存器和板载内存可由 reg 属性表示。reg 属性是描述设备硬件寄存器的软件抽象术语。reg 属性的值对设备寄存器地址位置和大小进行编码。驱动程序使用 reg 属性访问设备寄存器。

另外一个示例是 interrupt 属性。interrupt 属性表示设备中断。interrupt 属性的值对设备中断 PIN 进行编码。

可以为属性指定五种类型的值:

没有值的属性被视为布尔属性。对于布尔属性,如果存在,则值为 True;如果不存在,则值为 False。

设备属性名称

严格地说,DDI/DKI 软件属性名称没有限制。但建议使用某些限制。IEEE 1275-1994 Standard for Boot Firmware 引导固件标准按如下方法定义属性:

属性是由 1 到 31 个可列显字符组成的人工可读文本字符串。属性名称不能包含大写字符或字符 "/"、"\"、":"、 "["、"]" 和 "@"。以字符 "+" 开头的属性名称保留供 IEEE 1275-1994 的将来修订使用。

根据约定,属性名称中不能使用下划线。可使用连字符 (-)。根据约定,以问号字符 (?) 结尾的属性名称包含字符串值(通常为 TRUE 或 FALSE),例如 auto-boot?

有关在驱动程序配置文件中添加属性的讨论,请参见 driver.conf(4) 手册页。pm(9P)pm-components(9P) 手册页说明了如何在电源管理中使用属性。有关应该如何在设备驱动程序手册页中介绍属性的示例,请阅读 sd(7D) 手册页。

创建和更新属性

要为驱动程序创建属性,或者更新现有属性,请将 DDI 驱动程序更新接口(如 ddi_prop_update_int(9F)ddi_prop_update_string(9F))中的一个接口与相应的属性类型一起使用。有关可用属性接口的列表,请参见表 4-1。这些接口通常从驱动程序的 attach(9E) 入口点调用。在以下示例中,ddi_prop_update_string() 创建一个名为 pm-hardware-state 且值为 needs-suspend-resume 的字符串属性。

     /* The following code is to tell cpr that this device
     * needs to be suspended and resumed.
     */
    (void) ddi_prop_update_string(device, dip,
         "pm-hardware-state", "needs-suspend-resume");

在大多数情况下,使用 ddi_prop_update() 例程即可满足更新属性的要求。但是,有时更新经常更改的属性值的系统开销可能会导致性能问题。有关使用属性值的本地实例以避免使用 ddi_prop_update() 的说明,请参见prop_op() 入口点

查找属性

驱动程序可以请求其父级的属性,而后者又可以请求其父级。驱动程序可以控制是否将请求传递到其父级以上。

例如,以下示例中的 esp 驱动程序为每个目标维护一个名为 targetx-sync-speed 的整数属性。targetx-sync-speed 中的 x 表示目标编号。prtconf(1M) 命令以详细模式显示驱动程序属性。以下示例列出了 esp 驱动程序的部分内容。

% prtconf -v
...
       esp, instance #0
            Driver software properties:
                name <target2-sync-speed> length <4>
                    value <0x00000fa0>.
...

下表汇总了属性接口。

表 4-1 属性接口用法

系列
属性接口
说明
ddi_prop_lookup
查找属性,如果该属性存在,则成功返回。如果该属性不存在,则失败。
查找并返回整数属性
查找并返回 64 位整数属性
查找并返回整数数组属性
查找并返回 64 位整数数组属性
查找并返回字符串属性
查找并返回字符串数组属性
查找并返回字节数组属性
ddi_prop_update
更新或创建整数属性
更新或创建单个 64 位整数属性
更新或创建整数数组属性
更新或创建字符串属性
更新或创建字符串数组属性
更新或创建 64 位整数数组属性
更新或创建字节数组属性
ddi_prop_remove
删除单个属性
删除与设备关联的所有属性

尽可能使用 64 位版本的 int 属性接口(如 ddi_prop_update_int64(9F)),而不要使用 32 位版本(如 ddi_prop_update_int(9F))。

prop_op() 入口点

向系统报告设备属性或驱动程序属性通常需要使用 prop_op(9E) 入口点。如果驱动程序无需创建或管理其自己的属性,则 ddi_prop_op(9F) 函数可用于此入口点。

如果在驱动程序的 cb_ops(9S) 结构中定义了 ddi_prop_op(),则 ddi_prop_op(9F) 可用作设备驱动程序的 prop_op(9E) 入口点。ddi_prop_op() 使叶设备可以搜索设备的属性列表以及从其中获取属性值。

如果驱动程序需要维护其值经常更改的属性,则应在 cb_ops() 结构中定义特定于驱动程序的 prop_op 例程,而不是调用 ddi_prop_op()。此方法可避免由于重复使用 ddi_prop_update() 而造成的效率低下。然后,驱动程序应在其软状态结构或驱动程序变量中维护属性值的副本。

prop_op(9E) 入口点向系统报告特定驱动程序属性的值和设备属性的值。在许多情况下,ddi_prop_op(9F) 例程在 cb_ops(9S) 结构中可用作驱动程序的 prop_op() 入口点。ddi_prop_op() 会执行所有必需的处理。对于处理设备属性请求时不需要进行特殊处理的驱动程序,ddi_prop_op() 即可满足要求。

但是,有时驱动程序必须提供 prop_op() 入口点。例如,如果驱动程序维护其值经常更改的属性,则针对每次更改使用 ddi_prop_update(9F) 更新属性便不能满足要求。相反,驱动程序应在实例的软状态下维护属性的阴影副本。然后,驱动程序可在值发生变化时更新阴影副本,而无需使用任何 ddi_prop_update() 例程。prop_op() 入口点必须拦截对此属性的请求,并使用 ddi_prop_update() 例程之一更新属性的值,然后将请求传递到 ddi_prop_op() 以处理属性请求。

在以下示例中,prop_op() 拦截 temperature 属性的请求。属性发生变化时,驱动程序将更新状态结构中的变量。但是,仅当发出请求时才会更新该属性。然后,驱动程序使用 ddi_prop_op() 处理该属性请求。如果属性请求不特定于某个设备,则驱动程序不会拦截该请求。dev 参数的值等于 DDI_DEV_T_ANY(通配符设备编号)时即是这种情况。

示例 4-1 prop_op() 例程

static int
xx_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
    int flags, char *name, caddr_t valuep, int *lengthp)
{
        minor_t instance;
        struct xxstate *xsp;
        if (dev != DDI_DEV_T_ANY) {
                return (ddi_prop_op(dev, dip, prop_op, flags, name,
                    valuep, lengthp));
        }

        instance = getminor(dev);
        xsp = ddi_get_soft_state(statep, instance);
        if (xsp == NULL)
                return (DDI_PROP_NOTFOUND);
        if (strcmp(name, "temperature") == 0) {
                ddi_prop_update_int(dev, dip, name, temperature);
        }

        /* other cases */    
}