设备特性 (attribute) 信息可由称为属性 (property) 的名称-值对表示法表示。
例如,设备寄存器和板载内存可由 reg 属性表示。reg 属性是描述设备硬件寄存器的软件抽象术语。reg 属性的值对设备寄存器地址位置和大小进行编码。驱动程序使用 reg 属性访问设备寄存器。
另外一个示例是 interrupt 属性。interrupt 属性表示设备中断。interrupt 属性的值对设备中断 PIN 进行编码。
可以为属性指定五种类型的值:
字节数组-任意长度的一系列字节
整数属性-整数值
整数数组属性-整数数组
字符串属性-以 null 结尾的字符串
字符串数组属性-以 null 结尾的字符串列表
没有值的属性被视为布尔属性。对于布尔属性,如果存在,则值为 True;如果不存在,则值为 False。
严格地说,DDI/DKI 软件属性名称没有限制。但建议使用某些限制。IEEE 1275-1994 Standard for Boot Firmware 引导固件标准按如下方法定义属性:
属性是由 1 到 31 个可列显字符组成的人工可读文本字符串。属性名称不能包含大写字符或字符 "/"、"\"、":"、 "["、"]" 和 "@"。以字符 "+" 开头的属性名称保留供 IEEE 1275-1994 的将来修订使用。
根据约定,属性名称中不能使用下划线。可使用连字符 (-)。根据约定,以问号字符 (?) 结尾的属性名称包含字符串值(通常为 TRUE 或 FALSE),例如 auto-boot?。
IEEE 1275 工作组的出版物中列出了预定义的属性名称。有关如何获取这些出版物的信息,请访问 http://playground.sun.com/1275/。有关在驱动程序配置文件中添加属性的讨论,请参见 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>. ... |
系列 |
属性接口 |
说明 |
---|---|---|
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(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(通配符设备编号)时即是这种情况。
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 */ }