1、收 稿 日 期 : 2005 - 10 - 16作 者 简 介 :王 斑 (1981 ) ,男 ,山 东 烟 台 人 ,工 学 硕 士 ,主 要 从事 嵌 入 式 系 统 研 究 ;苗 克 坚 (1962 ) , 男 , 辽 宁 人 ,教 授 ,主 要从 事 并 行 与 分 布 计 算 的 研 究 。QNX驱 动 程 序 的 编 写王 斑 , 苗 克 坚(西 北 工 业 大 学 计 算 机 学 院 , 陕 西 西 安 710072)摘 要 :简 要 介 绍 了 QNX的 特 点 ,论 述 了 QNX下 资 源 管 理 器 和 设 备 驱 动 程 序 的 关 系 ,在 此 基 础 上 ,详 细
2、阐述 了 QNX驱 动 程 序 编 写 的 特 点 以 及 一 般 步 骤 。关 键 词 : QNX;资 源 管 理 器 ;设 备 驱 动 程 序中 图 分 类 号 : TP393 文 献 标 识 码 : B 文 章 编 号 : 1000 - 8829 (2006) 06 - 0054 - 03Programm ing D ev ice D r iver for QNX O SWANG Ban, M IAO Ke2jian( Institute of Computer Science, Northwestern Polytechnical University, Xi an 710072, C
3、hina )Abstract: The characteristics of QNX and the relation between resource managers and device drivers are intro2duced. On the basis of this, the characteristics of p rogramm ing device driver of QNX are analysed and a generalmethod of p rogramm ing device driver of QNX is given.Key words: quantum
4、 software system s(QNX); resource manager; device driver1 QNX介 绍QNX是 一 个 分 布 、 嵌 入 式 ,可 规 模 扩 展 的 微 内 核实 时 操 作 系 统 。首 先 , QNX是 一 个 实 时 系 统 。 实 时 系 统 最 重 要 的特 点 就 是 实 时 性 ,即 系 统 的 正 确 性 不 仅 依 赖 于 计 算 结果 的 正 确 性 ,还 取 决 于 输 出 结 果 的 及 时 性 。再 者 , QNX是 一 个 标 准 的 分 布 式 系 统 ,支 持 不 同结 点 间 的 分 工 合 作 与 资 源 共 享
5、 。其 次 , QNX的 内 核 仅 提 供 4种 服 务 :进 程 通 信 、 进程 调 度 、 中 断 处 理 和 底 层 网 络 通 信 。 因 此 内 核 非 常 小 ,运 行 速 度 极 快 。 用 户 可 以 很 容 易 对 它 进 行 开 发 扩 展 以实 现 自 己 的 实 际 需 求 。2 设 备 驱 动 程 序 与 资 源 管 理 器在 QNX中 设 备 被 通 称 为 资 源 ,所 有 的 资 源 都 由 资源 管 理 器 管 理 , QNX的 资 源 管 理 器 负 责 给 不 同 类 型 的设 备 提 供 一 个 接 口 。 这 种 设 备 可 能 是 真 正 的 硬
6、 件 设 备或 者 是 虚 拟 设 备 。 其 他 操 作 系 统 中 ,这 一 功 能 是 与 设备 驱 动 程 序 相 关 的 。 但 是 QNX的 资 源 管 理 器 与 设 备驱 动 程 序 不 同 的 是 它 以 独 立 于 内 核 的 进 程 来 运 行 ,使之 就 像 一 个 普 通 的 应 用 程 序 。 除 此 之 外 ,二 者 并 没 有本 质 的 区 别 ,所 以 在 以 下 介 绍 中 ,驱 动 程 序 和 资 源 管 理器 两 个 概 念 可 以 混 合 使 用 。3 QNX驱 动 程 序 的 特 点QNX的 驱 动 程 序 是 开 放 型 的 ,没 有 什 么 特
7、定 的 框架 和 模 式 。 驱 动 程 序 的 根 本 目 的 就 是 实 现 硬 件 和 应 用程 序 的 交 互 。 QNX对 硬 件 的 操 作 非 常 方 便 快 捷 ,只 要通 过 系 统 命 令 pci2v就 可 以 查 找 到 硬 件 的 端 口 ,所 以 ,用 户 甚 至 可 以 跳 过 驱 动 直 接 对 硬 件 进 行 操 作 ,这 对 于用 户 来 说 是 非 常 方 便 的 。 QNX也 提 供 了 资 源 管 理 器来 支 持 驱 动 ,用 户 可 以 编 写 自 己 的 命 令 来 控 制 硬 件 。4 QNX驱 动 程 序 的 编 写驱 动 程 序 的 编 写
8、主 要 包 括 以 下 几 个 方 面 : 设 备 初 始 化 和 释 放 。 把 数 据 从 内 核 传 送 到 硬 件 和 从 硬 件 读 取 数 据 。 读 取 应 用 程 序 传 送 给 设 备 文 件 的 数 据 和 回 送 应用 程 序 请 求 的 数 据 。 检 测 和 处 理 设 备 出 现 的 错 误 。从 以 下 几 个 方 面 来 介 绍 QNX驱 动 程 序 编 写 的 步骤 :(1)设 备 的 硬 件 资 源 管 理 和 分 配 。首 先 在 驱 动 程 序 要 用 到 的 硬 件 资 源 主 要 包 括 内存 、 I/O端 口 和 中 断 ,如 果 用 到 DMA控
9、 制 器 的 话 ,还 要有 DMA通 道 。45 测 控 技 术 2006年 第 25卷 第 6期 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http:/一 个 线 程 如 果 想 要 对 端 口 进 行 I/O操 作 ,它 必 须具 有 适 当 的 权 限 ,必 须 调 用 这 个 函 数 来 保 证 线 程 可 以访 问 I/O端 口 。ThreadCtl( _NTO_TCTL_ IO, 0) ;如 果 不 调 用 这 个 函 数 ,系 统 就 会 对 其 提 供
10、默 认 的保 护 而 使 用 户 无 法 访 问 。得 到 权 限 之 后 ,还 必 须 通 过 mmap _device_ io ( )进行 I/0地 址 的 映 射 ,只 有 这 样 才 能 获 取 设 备 的 I/O资源 。在 QNX中 提 供 了 丰 富 的 PC I操 作 函 数 ,可 以 自 动的 查 找 资 源 ,读 写 PC I配 置 寄 存 器 。下 面 简 要 分 析 程 序 中 的 关 键 部 分 :pci_attach ( ) ;将 程 序 连 接 到 PC I server上 ,使 得 整 个 程 序 可 以 使 用 QNX系 统 提 供 的 pci_3 ( )函 数
11、 。doiRet = pci _ find _ device ( Deviceid, Vendorid, index + + ,if( iRet = = PC I_SUCCESS) then找 到 设 备 ;while ( iRet! = PC I_DEV ICE_NOT_FOUND) ;if( iRet! = PC I_SUCCESS) then不 能 找 到 设 备 ;查 找 PC I设 备 ,使 用 pci_find_device,传 给 该 函 数两 个 主 要 参 数 :设 备 号 和 厂 家 号 ,并 遍 历 查 找 所 有 的PC I插 槽 ,直 到 匹 配 为 止 。 找 到
12、设 备 以 后 可 以 利 用 pci_attach_device ( )函 数 把 pci_dev_ info ( )与 设 备 连 接 ,然 后 读 出 内 存 与 端 口 的 基 地 址 和 中 断 资 源 ,为 日 后 的操 作 做 准 备 。(2)建 立 与 资 源 管 理 器 的 交 互 机 制 并 初 始 化 消 息处 理 函 数 。dispatch_create ( )函 数 实 现 了 用 户 函 数 与 资 源 管理 器 的 交 互 。 通 过 这 个 函 数 资 源 管 理 器 可 以 作 为 服 务器 为 用 户 函 数 提 供 消 息 分 发 。QNX为 驱 动 程
13、序 开 发 者 提 供 了 可 靠 的 默 认 处 理函 数 ,但 是 用 户 也 可 以 根 据 需 要 定 义 自 己 的 消 息 处 理函 数 ,以 io_devctl为 例 :iofunc_func_init( _RESMGR_CONNECT_NFUNCS, io_funcs. devctl = io_devctl; / /用 户 将 使 用 自 己 的 io_devctl处 理 函 数 。(3)设 备 驱 动 程 序 与 应 用 程 序 的 接 口 。驱 动 程 序 不 但 要 完 成 对 硬 件 的 操 作 ,还 要 与 操 作系 统 进 行 数 据 的 传 输 ,在 驱 动 程
14、序 加 载 以 后 ,用 户 程 序就 可 以 像 操 作 文 件 一 样 操 作 设 备 ,比 较 简 单 快 捷 的 方法 是 使 用 devctl( )作 为 应 用 程 序 与 驱 动 程 序 的 接 口 。devctl( )函 数 的 格 式 是 :devctl ( int fd, int dcmd, void 3 data, size_t nbytes, int 3 return_info) ;下 面 的 值 直 接 映 射 _ IO_DEVCTL消 息 本 身 :struct _io_devctluint16_t type;uint16_t combine_len;int32_t
15、 dcmd;int32_t nbytes;int32_t zero;struct _io_devctl_rep lyuint32_t zero;int32_t ret_val;int32_t nbytes;int32_t zero2;typedef unionstruct _io_devctl i;struct _io_devctl_rep ly o; io_devctl_t;对 于 大 多 数 资 源 管 理 器 消 息 来 说 ,定 义 的 联 合 包括 输 入 结 构 (发 送 给 资 源 管 理 器 )和 输 出 结 构 (发 送 回客 户 端 )。 Io_devctl处 理 函 数
16、的 参 数 说 明 如 下 :io_devctl_t 3 m sg:指 向 包 含 消 息 的 联 合 。type:值 为 _ IO _DEVCTL。combine_len:只 对 混 合 消 息 有 意 义 。nbyte:是 传 递 给 devctl( )函 数 的 ,这 个 值 包 含 传 递给 驱 动 程 序 的 数 据 的 大 小 ,或 从 驱 动 程 序 接 受 的数 据 的 最 大 值 。dcmd:传 递 给 devctl( )函 数 的 ,这 个 命 令 是 使 用 定义 在 的 宏 形 成 的 。如 上 面 的 结 构 体 所 示 ,上 层 的 用 户 ,把 要 与 设 备 驱
17、动 程 序 通 信 的 数 据 填 入 结 构 体 中 ,再 由 系 统 进 行 重 新的 解 析 ,以 消 息 的 方 式 传 给 底 层 驱 动 程 序 ,驱 动 程 序 再把 消 息 中 的 功 能 号 和 要 传 递 的 参 数 取 出 使 用 。下 面 是 _ IO _DEVCTL 消 息 的 处 理 函 数 的 关 键 代码 :int io_devctl ( resmgr_ context_ t 3 ctp, io _ devctl_ t 3 m sg,RESMGR_OCB_T 3 ocb) union data_t data;int data32; 3 rx_data;if( (
18、 status = iofunc _ devctl_ default ( ctp, m sg, ocb) ) ! = _RESMGR_DEFAULT) return ( status) ; rx_data = _DEVCTL_DATA (m sg - i) ; / /从 消 息 中 取 得 数据 结 构/3 以 下 就 是 一 个 使 用 devctl的 操 作 ,完 成 从 驱 动 程 序 取一 些 数 据 传 给 应 用 程 序 中 ; 3 /switch (m sg - i. dcmd) case MY_DEVCTL_GETVAL:rx_data - data32 = global_in
19、teger;nbytes = sizeof( rx_data - data32) ;break;default:55QNX驱 动 程 序 的 编 写 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http:/return ( ENOSYS) ;/3 表 明 返 回 的 字 节 数 ,并 返 回 3 /m sg - o. nbytes = nbytes;return ( _RESMGR_PTR ( cp t, 还 有 一 些 需 要 说 明 :被 传 递 的 数 据 直 接 跟
20、 在 io _devctl_ t结 构 的 后 面 ,可 以 使 用 宏 _DEVCTL _DATA(m sg - i)得 到 这 个 位 置 的 指 针 。 不 过 这 并 不 适 用 于大 的 数 据 消 息 ,在 这 种 情 况 下 ,可 以 使 用 resmgr_m s2gread ( )从 客 户 程 序 中 读 取 消 息 。被 返 回 到 客 户 程 序 的 数 据 被 放 在 回 答 消 息 中 ,这和 输 入 数 据 的 机 制 是 相 同 的 ,所 以 使 用 _DEVCTL _DA2TA ( )函 数 来 得 到 这 个 位 置 的 指 针 。(4)返 回 与 回 答 的
21、 方 法 。从 处 理 函 数 返 回 到 设 备 驱 动 程 序 库 有 许 多 方 法 ,不 过 这 过 程 比 较 复 杂 ,需 要 填 写 正 确 的 结 构 ,以 下 介 绍几 种 方 法 : 返 回 错 误 :使 用 return ( ENOMEM )的 格 式 ,这 种格 式 同 样 可 用 在 像 read ( )这 样 的 函 数 ,至 于 返 回 的 错误 号 在 中 有 相 应 的 解 释 。 有 时 需 要 返 回 一 个 数 据 头 跟 着 N 个 缓 冲 区 ,使用 的 缓 冲 区 根 据 每 次 不 同 的 回 答 不 同 ,这 是 需 要 使 用一 个 IOV数
22、 组 ,用 这 个 数 据 的 元 素 指 针 指 向 数 据 头 和数 据 缓 冲 区 。 下 面 的 例 子 是 变 量 i包 含 要 返 回 的 缓 冲区 的 偏 移 量 。 在 _RESMGR_NPARTS(2)中 的 2告 诉 驱动 程 序 库 有 多 少 元 素 要 返 回 。my_header_t header;a_buffer_t buffersN ; .SETIOV ( SETIOV ( return ( _RESMGR_NPARTS(2) ) ; 返 回 成 功 但 并 不 包 含 数 据 , return ( EOK)或 re2turn ( _RESMGR_NPARTS(
23、0) )。 返 回 一 个 包 含 数 据 的 缓 冲 区 ,这 也 是 在 系 统 中使 用 最 多 的 一 种 方 法 ,可 以 使 用 两 种 方 法 :return ( _RESMGR_PTR ( ctp, buffer, nbytes) ) ;和 SETIOV ( ctp - iov, buffer, nbytes) ;return ( _RESMGR_NPARTS(1) )(5)设 备 的 中 断 处 理 。因 为 设 备 的 端 口 和 内 存 资 源 已 经 映 射 到 了 系 统中 ,所 以 只 需 使 用 相 应 的 函 数 就 可 以 完 成 读 写 。 在QNX中 提
24、供 了 许 多 库 函 数 来 支 持 驱 动 程 序 的 开 发 ,传统 的 方 法 是 把 ISR过 程 和 一 个 IRQ捆 绑 起 来 ,但 是 由于 ISR的 上 下 文 切 换 而 影 响 到 实 时 性 。 下 面 介 绍 一 种比 较 实 时 的 方 法 ,由 于 实 时 性 的 要 求 ,事 先 把 一 个 事 件的 结 构 和 一 个 IRQ捆 绑 起 来 ,这 样 系 统 停 留 在 中 断 里的 时 间 就 会 缩 短 ,所 以 在 驱 动 程 序 中 绑 定 一 个 中 断 注册 程 序 ,由 它 来 创 建 一 个 线 程 ,并 把 中 断 的 信 息 传 递 给线
25、 程 ,由 该 线 程 来 处 理 中 断 事 务 。 这 样 就 可 以 保 证 系统 能 够 很 快 地 响 应 中 断 ,又 不 会 长 时 间 驻 留 于 中 断 处理 程 序 而 不 响 应 其 他 的 中 断 。下 面 分 析 具 体 的 细 节 : if( (mypcip - chid = ChannelCreate ( _NTO_CHF_D ISCONNECT | _NTO _CHF _UNBLOCK) ) = = - 1 )then报 错 处 理 ; if( (mypcip - coid = ConnectA ttach (0, 0, mypcip- chid, 0, _NT
26、O_SIDE_CHANNEL) ) = - 1) then报错 处 理 ;填 写 必 要 的 属 性 结 构 体 如 事 件 : if( (mypcip - iid = Interrup tA ttachEvent(mypcip- int_line, if ( EOK! = p thread _ create ( 以 上 是 函 数 register_interrup t ( )中 的 主 体 部 分 ,说明 如 下 : 创 建 一 个 接 收 消 息 和 脉 冲 信 号 的 通 道 ,并 实 现将 它 与 线 程 的 绑 定 。 将 该 通 道 与 调 用 它 的 线 程 连 接 起 来 ,
27、通 过 参 数mypcip - chid指 向 通 道 ,实 现 连 接 。 进 行 一 系 列 的 初 始 化 后 ,通 过 内 核 调 用 函 数 In2terrputA ttachEvent,实 现 将 mypcip - int_line指 向 的 中断 服 务 程 序 与 设 备 连 接 起 来 。 这 一 步 创 建 线 程 mythread,由 该 线 程 处 理 中 断事 务 ,比 如 数 据 的 接 收 。当 中 断 来 临 时 ,由 主 函 数 进 入 注 册 中 断 的 函 数 ,创建 线 程 后 ,由 线 程 从 通 道 读 取 消 息 。5 结 束 语QNX的 驱 动
28、程 序 与 其 他 操 作 系 统 不 同 ,它 只 是 一个 普 通 的 线 程 ,可 以 随 时 停 止 ,随 时 配 置 ,这 极 大 地 方便 了 用 户 。 资 源 管 理 器 的 最 大 好 处 就 是 可 以 通 过POSIX函 数 进 行 访 问 ,从 而 做 到 应 用 程 序 的 设 备 无 关性 。参 考 文 献 : 1 QNX Soft System L td. . QNX neutrino realtime operating sys2tem architecture CP /DK. 2002. 2 QNX Soft System L td. . QNX neutri
29、no realtime operating sys2tem p rogrammer s guide CP /DK. 2002. 3 QNX驱 动 程 序 编 程 入 门 M /CD . 北 京 领 先 实 时 科 技 有限 责 任 公 司 , 2001. 4 QNX Neutrino实 时 编 程 入 门 M /CD . 北 京 领 先 实 时 科技 有 限 责 任 公 司 , 2001.65 测 控 技 术 2006年 第 25卷 第 6期 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http:/