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.  属性

5.  管理事件和排队任务

6.  驱动程序自动配置

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

8.  中断处理程序

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

10.  映射设备和内核内存

11.  设备上下文管理

12.  电源管理

13.  强化 Oracle Solaris 驱动程序

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

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

15.  字符设备驱动程序

字符驱动程序结构概述

字符设备自动配置

设备访问(字符驱动程序)

open() 入口点(字符驱动程序)

close() 入口点(字符驱动程序)

I/O 请求处理

用户地址

向量化的 I/O

同步 I/O 与异步 I/O 之间的差别

数据传输方法

程控 I/O 传输

DMA 传输(同步)

DMA 传输(异步)

minphys() 入口点

strategy() 入口点

映射设备内存

对文件描述符执行多路复用 I/O 操作

其他 I/O 控制

ioctl() 入口点(字符驱动程序)

对有 64 位处理能力的设备驱动程序的 I/O 控制支持

处理 copyout() 溢出

32 位和 64 位数据结构宏

结构宏如何工作?

何时使用结构宏

声明并初始化结构句柄

结构句柄的操作

其他操作

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

索引

对文件描述符执行多路复用 I/O 操作

一个线程有时需要处理多个文件描述符上的 I/O。需要从温度感应设备读取温度并将此温度报告给交互显示的应用程序就是一个示例。在与用户再次交互之前等待温度时,发出读取请求但没有可用数据的程序不会进入阻塞状态。

poll(2) 系统调用为用户提供了对一组引用打开的文件的文件描述符执行多路复用 I/O 操作的机制。poll(2) 识别那些在它们上面程序可以发送或接收数据而不会阻塞的文件描述符,或在它们上面特定事件已发生的文件描述符。

要允许程序轮询字符驱动程序,该驱动程序必须实现 chpoll(9E) 入口点。当用户进程对与设备相关的文件描述符发出 poll(2) 系统调用时,系统就会调用 chpoll(9E)。需要支持轮询的非 STREAMS 字符设备驱动程序使用 chpoll(9E) 入口点例程。

chpoll(9E) 函数使用以下语法:

int xxchpoll(dev_t dev, short events, int anyyet, short *reventsp,
     struct pollhead **phpp);

chpoll(9E) 入口点中,驱动程序必须遵循下列规则:

示例 15-10示例 15-11 说明了如何实现轮询规程以及如何使用 pollwakeup(9F)。

以下示例说明如何处理 POLLINPOLLERR 事件。首先,驱动程序读取状态寄存器以确定设备的当前状态。参数 events 指定驱动程序应该检查哪些条件。如果出现适当的条件,驱动程序会在 *reventsp 中设置相应的位。如果未出现任何条件并且没有设置 anyyet,则会在 *phpp 中返回 pollhead 结构的地址。

示例 15-10 chpoll(9E) 例程

static int
xxchpoll(dev_t dev, short events, int anyyet,
    short *reventsp, struct pollhead **phpp)
{
     uint8_t status;
     short revent;
     struct xxstate *xsp;

     xsp = ddi_get_soft_state(statep, getminor(dev));
     if (xsp == NULL)
         return (ENXIO);
     revent = 0;
     /*
    * Valid events are:
    * POLLIN | POLLOUT | POLLPRI | POLLHUP | POLLERR
    * This example checks only for POLLIN and POLLERR.
    */
     status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
     if ((events & POLLIN) && data available to read) {
        revent |= POLLIN;
     }
     if (status & DEVICE_ERROR) {
        revent |= POLLERR;
     }
     /* if nothing has occurred */
     if (revent == 0) {
        if (!anyyet) {
        *phpp = &xsp->pollhead;
        }
     }
       *reventsp = revent;
     return (0);
}

以下示例说明如何使用 pollwakeup(9F) 函数。当出现支持的条件时,通常会在中断例程中调用 pollwakeup(9F) 函数。中断例程从状态寄存器中读取状态并检查条件。然后,该例程为每个事件调用 pollwakeup(9F),以便有可能通知轮询线程再次进行检查。请注意,不能在持有任何锁定的情况下调用 pollwakeup(9F),这是因为如果另一个例程尝试进入 chpoll(9E) 并获取相同的锁,则会导致死锁。

示例 15-11 支持 chpoll(9E) 的中断例程

static u_int
xxintr(caddr_t arg)
{
     struct xxstate *xsp = (struct xxstate *)arg;
     uint8_t    status;
     /* normal interrupt processing */
     /* ... */
     status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
     if (status & DEVICE_ERROR) {
        pollwakeup(&xsp->pollhead, POLLERR);
     }
     if ( /* just completed a read */ ) {
        pollwakeup(&xsp->pollhead, POLLIN);
     }
     /* ... */
     return (DDI_INTR_CLAIMED);
}