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

文档信息

前言

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

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

设备驱动程序基础知识

什么是设备驱动程序?

什么是设备驱动程序入口点?

设备驱动程序入口点

通用于所有驱动程序的入口点

设备访问入口点

可装入模块入口点

自动配置入口点

内核统计信息入口点

电源管理入口点

通用入口点汇总

用于块设备驱动程序的入口点

用于字符设备驱动程序的入口点

用于 STREAMS 设备驱动程序的入口点

用于内存映射设备的入口点

网络设备驱动程序入口点

用于 SCSI HBA 驱动程序的入口点

用于 PC 卡驱动程序的入口点

设备驱动程序设计注意事项

DDI/DKI 功能

设备 ID

设备属性

中断处理

回调函数

软件状态管理

程控 I/O 设备访问

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

分层驱动程序接口

驱动程序上下文

返回错误

动态内存分配

热插拔

2.  Oracle Solaris 内核和设备树

3.  多线程

4.  属性

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 文件

索引

设备驱动程序设计注意事项

从服务的使用方和提供方角度来看,设备驱动程序都必须与 Oracle Solaris OS 兼容。本节所讨论的以下问题是设计设备驱动程序过程中需要考虑的问题:

DDI/DKI 功能

为了使驱动程序具有可移植性,提供了 Oracle Solaris DDI/DKI 接口。利用 DDI/DKI,开发者可采用标准方式编写驱动程序代码,而不必担心硬件或平台差异。本节介绍 DDI/DKI 接口的各个方面。

设备 ID

利用 DDI 接口,驱动程序可以为设备提供永久、唯一的标识符。可以使用设备 ID 标识或查找设备。此 ID 与设备的名称或编号 (dev_t) 无关。应用程序可以使用 libdevid(3LIB) 中定义的函数来读取和处理由驱动程序注册的设备 ID。

设备属性

设备或设备驱动程序的特性 (attribute) 通过属性 (property) 指定。属性是一个名称/值对。名称是标识具有关联值的属性的字符串。属性可以由自标识设备的 FCode、硬件配置文件(请参见 driver.conf(4) 手册页)或驱动程序自身使用 ddi_prop_update(9F) 系列例程进行定义。

中断处理

DDI/DKI 解决了设备中断处理的以下方面的问题:

设备中断源包含在称为 interrupt 的属性中,此属性既可由自标识设备的 PROM(位于硬件配置文件中)提供,也可由 x86 平台上的引导系统提供。

回调函数

某些 DDI 机制提供回调机制。DDI 函数提供一种在满足某个条件时调度回调的机制。在以下典型的情况下,可以使用回调函数:

回调函数在某种程度上与入口点(例如,中断处理程序)类似。允许回调的 DDI 函数期望回调函数执行特定任务。如果使用 DMA 例程,则回调函数必须返回一个值,指示是否需要在出现故障时重新调度此函数。

回调函数作为单独的中断线程执行。回调必须处理所有常见的多线程问题。


注 - 驱动程序在分离设备之前必须先取消所有已调度的回调函数。


软件状态管理

为了帮助设备驱动程序编写人员分配状态结构,DDI/DKI 提供了一组称为软件状态管理例程的内存管理例程,也称为软状态例程。这些例程可动态分配、检索以及销毁指定大小的内存项,并可隐藏列表管理的详细信息。可使用实例编号来标识所需内存项。此编号通常为系统指定的实例编号。

这些例程用于实现以下任务:

有关如何使用这些例程的示例,请参见可装入驱动程序接口

程控 I/O 设备访问

程控 I/O 设备访问是指通过主机 CPU 读/写设备寄存器或设备内存的行为。Oracle Solaris DDI 提供通过内核映射设备寄存器或内存的接口,以及从驱动程序读/写设备内存的接口。使用这些接口,通过自动管理设备和主机字节存储顺序中的任何差异,以及强制执行设备所强加的任何内存存储顺序要求,可以开发与平台和总线无关的驱动程序。

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

Oracle Solaris 平台可定义与体系结构无关的高级模型,以支持具备 DMA 功能的设备。Oracle Solaris DDI 可防止驱动程序使用特定于平台的详细信息。使用此概念,通用驱动程序可以在多个平台和体系结构上运行。

分层驱动程序接口

DDI/DKI 提供一组称为分层设备接口 (layered device interface, LDI) 的接口。利用这些接口,可以从 Oracle Solaris 内核中访问设备。该功能使开发者可以编写查看内核设备使用情况的应用程序。例如,prtconf(1M)fuser(1M) 命令都可以使用 LDI,以便使系统管理员可以跟踪设备使用情况的各方面。第 14 章 对 LDI 进行了更详细的说明。

驱动程序上下文

驱动程序上下文是指驱动程序的当前运行环境。上下文会限制驱动程序可执行的操作。驱动程序上下文取决于调用的执行代码。驱动程序代码在以下四种上下文中执行:

手册页的第 9F 节介绍了每个函数所允许的上下文。例如,在内核上下文中,驱动程序不得调用 copyin(9F)

返回错误

除列显数据损坏之类的意外错误外,设备驱动程序通常不会列显消息。相反,驱动程序入口点应返回错误代码,以便应用程序可以确定如何处理错误。可以使用 cmn_err(9F) 函数将消息写入随后会在控制台上显示的系统日志中。

cmn_err(9F) 解释的格式字符串说明符与 printf(3C) 格式字符串说明符类似,前者还添加了可列显位字段的格式 %b。格式字符串的第一个字符可能具有特殊意义。在对 cmn_err(9F) 的调用中,还会指定消息 level,用于指示要列显的严重性标签。有关更多详细信息,请参见 cmn_err(9F) 手册页。

级别 CE_PANIC 具有使系统崩溃的负面影响。仅当系统处于不稳定状态以至继续运行将导致更多问题时,才应使用此级别。此外,调试时可以使用此级别来获取系统核心转储。不应使用 CE_PANIC 生成设备驱动程序。

动态内存分配

必须将设备驱动程序设计为可以同时处理驱动程序声明要驱动的所有连接设备。驱动程序处理的设备数不应受到限制。必须动态分配所有每设备信息。

void *kmem_alloc(size_t size, int flag);

标准内核内存分配例程为 kmem_alloc(9F)kmem_alloc() 与 C 库例程 malloc(3C) 类似,前者添加了 flag 参数。flag 参数可以是 KM_SLEEPKM_NOSLEEP,用于指示没有所需大小的内存空间时调用方是否要阻塞。如果设置了 KM_NOSLEEP 并且内存不可用,kmem_alloc(9F) 将返回 NULL

kmem_zalloc(9F)kmem_alloc(9F) 类似,但前者还可以清除已分配内存的内容。


注 - 内核内存是有限资源,并且不可分页,它还会与用户应用程序和内核其余部分争用物理内存。分配大量内核内存的驱动程序可导致系统性能降低。


void kmem_free(void *cp, size_t size);

可使用 kmem_free(9F) 将通过 kmem_alloc(9F)kmem_zalloc(9F) 分配的内存返回到系统。kmem_free() 与 C 库例程 free(3C) 类似,但前者添加了 size 参数。驱动程序必须跟踪每个已分配对象的大小,以便在以后调用 kmem_free(9F)

热插拔

本手册没有重点介绍热插拔信息。如果按照本书中介绍的规则和建议编写设备驱动程序,则您的应用程序应该能够处理热插拔。需要特别指出的是,请确保您的驱动程序中的自动配置(请参见第 6 章)和 detach(9E) 都能正常工作。此外,如果要设计使用电源管理的驱动程序,则应遵循第 12 章中介绍的信息。SCSI HBA 驱动程序可能需要向其 dev_ops 结构中添加 cb_ops 结构(请参见第 18 章),以利用热插拔功能。

早期版本的 Oracle Solaris OS 要求可热插拔的驱动程序包括 DT_HOTPLUG 属性,但现在已不再需要该属性。不过,驱动程序编写者可视情况自由加入和使用 DT_HOTPLUG 属性。