Linux驱动与应用层通信,USB设备驱动层与应用层和硬件的通信过程.

1、USB设备驱动程序

(1)驱动程序的基本概念设备驱动程序是一个包含了许多操作系统可调用例程的软件容器,它可以使得应用程序访问硬件设备,这些例程可以使硬件设备执行相应的动作。也就是处理硬件设备连接到CPU通信的细节的代码。硬件设备可能是任何连接到计算机的电子电路。一个设备驱动应使得应用程序远离细节,使应用程序不必知道物理连接、信号和与一个设备通信需要的协议等。应用程序是用户运行的程序,包括支持自定义硬件的特殊用途的应用程序。设备驱动可以保证程序代码只通过外设句柄访问外设或者端口。应用程序不需要精确监视和控制外设需要的交换信号(忙、应答等)。设备驱动通过在应用层和硬件专用层专用代码之间的转化来完成它的任务。应用层代码一般使用一套操作系统支持的函数。硬件代码则处理那些访问外设电路的必要协议,包括检测状态信号和在合适的时间切换控制信号。

(2)WDM设备驱动简介在Windows98下运行的代码以以下两种模式之一运行:用户模式和内核模式。在访问内存和其它系统资源时,每种有不同的允许优先级。应用程序必须运行在用户模式下,其它很多驱动运行在内核模式下。

在用户模式下,Windows限制应用程序访问内存和其他系统资源,Windows不允许用户访问设定为被保护的内存区域。这使得PC机可同时运行多个应用程序,不会互相干扰从理论上讲,即使一个应用程序崩溃了,其它应用程序也不会受到影响。在内核模式下,代码不限制访问系统资源,包括执行内存管理指令和控制访问I/O端口。

每个应用程序和驱动使用自己的语言与操作系统通信。应用程序使用WIN32API函数。驱动通信使用称作U0请求包(IRP)的结构。Windows定义了一套驱动可以使用的IRP。每个IRP请求或执行一个单个的输入或输出动作。USB设备的设备驱动使用IRP传递总线通信,处理USB通信。总线驱动按顺序使用IRP传递临近总线的通信。在一系列通信中,最终的总线直接驱动硬件。总线驱动被包括在Windows系统里,且不需要我们编程。

当用户模式程序需要读取设备数据时,它就调用 Win32 API 函数, Win32 子系统模块 ( 如 KERNEL32.DLL) 通过调用平台相关的系统服务接口实现该 API, 而平台相关的系统服务将调用内核模式支持例程。调用首先到达系统 DLL 中的一个入口点,然后这个用户模式的函数接着调用系统服务接口,最后由系统服务接口调用内核模式中的服务例程 [39] 。服务例程运行在内核模式中,为应用程序请求提供服务,并以某种方式与设备交互。它们首先检查传递给它们的参数以保护系统安全或防止用户模式程序非法存取数据,然后创建一个 IRP 的数据结构,并把这个数据结构送到某个驱动程序的入口点。用户模式调用者得到一个返回值,表明该 IRP 代表的操作还没有完成。用户模式程序也许会继续其它工作然后等待操作完成,或者立即进入等待状态。不论哪种方式,设备驱动程序对该 IRP 的处理都与应用程序无关。执行 IRP 的设备驱动程序最后可能会访问硬件。驱动程序完成一个 Il0 操作后,通过调用一个特殊的内核模式服务例程来完成该 IRP 。完成操作是处理 IRP 的最后动作,它使等待的应用程序恢复运行。

(3) USB 设备驱动的总线驱动 与传统 PC 总线 ( 如 PCI 总线 ) 设备的驱动程序相比, USB 设备驱动程序从不直接与硬件对话。相反,它仅靠创建 URB(USB request blocks) ,并把 URB 提交到总线驱动程序就可完成硬件操作。

系统中的 USB 总线驱动程序完成许多的工作。实际上对于一些 HID( 人机接口 ) 的 USB 设备,象键盘,鼠标和游戏操纵杆之类的设备可以自动的被系统识别并且支持。而除此之外的设备就需要自己写一个驱动程序来完成硬件和软件之间的联系。在核心模式 (kernel mode) 下,驱动程序用内部 I/O 控制 (IOCTL) 来组织和操作一些由其他部分发过来的要求和命令。而 IOCTL 又是通过 URB 来实现数据的传送的。

可以把 USBD.SYS 看作是接受 URB 的实体,向 USBD 的调用被转化为带有主功能代码为 IRPwe MJee INTERNAL DEVICE_ CONTROL 的 IRP 。然后 USED 再调度总线时间,发出 URB 中指定的操作。

为了创建一个 URB ,首先应该为 URB 分配内存,然后调用初始化例程把 URB 结构中的各个域填入请求要求的内容,例如,当为响应 IRP START DEVICE请求而配置设备时,首要的任务就是读取该设备的设备描述符。还可以在系统堆上为 URB 动态地分配内存。创建完 URB 后,需要创建并发送一个 IOCTL 请求到 USBD 驱动程序, USBD 驱动程序位于驱动程序层次结构的低端。在大多数情况下,需要等待设备回应。 当提交一个 URB 到 USB 总线驱动程序时,最终将收到一个描述该操作结果的 NTSTATUS 代码。其间,总线驱动程序使用另一组类型名为 USBD_ STATUS 的状态代码。这些代码并不是 NTSTATUS 代码。当 USED 完成一个 URB 时,它就把 URB 的 UrbHeader.Status 域设置为某个 USBD_ STATUS 值。并没有特别的协议关于保留这个值以及把它传递回应用程序,可以随意处理这个值。

在使用总线驱动中有两个问题需要重点说明:

读取配置描述符 因为硬件不允许直接访问接口和端点描述符,所以必须把整个可变长结构读入一个连续的内存区。读配置描述符时使用的描述符索引来自于设备固件响应 GET DESCRIPTOR 控制请求的结果,而不受 USB 规范的限定 [4U) 。配置过程的下一步是创建 URB 并发送到设备。 除了创建 URB, USBD 还初始化 USBD_INTERFACE_ LIST 表项中的 Interface 成员,使其指向一个 USBD INTERFACE INFORMATION 结构。这个结构与 URB 在同一物理内存区,在释放 URB 时该结构一同被释放。其中管道信息结构是我们在此真正关心的,因为结构中的其它域是在提交 URB 后由 USBD 填充的。这样,我们己经有了一组 USBD_INTERFACE LIST 表项。

配置 USB 总线驱动程序自动检测新插入的 USB 设备。然后它读取设备内的设备描述符以查明插入的是何种设备,描述符中的厂商和产品标识以及其它描述符一同决定具体安装哪一个驱动程序。

配置管理器调用驱动程序的 AddDevice 函数。 AddDevice 做所有我们已知的任务:创建设备对象,把设备对象连接到驱动程序堆栈上等等。最后,配置管理器向驱动程序发送一个即插即用请求 IRP_MN_START_DEVICE 。现在在写驱动程序中 . 不必再为 USB 驱动程序的 I/O 资源担心,因为它们不用任何 I/O 资源。这里可以直接说配置设备而不是配置硬件,因为不再涉及 I/O 端口、中断、 DMA 适配器对象,或者任何其它面向资源的元素

USB 使用了许多方法来帮助操作系统定位驱动程序 ( 或驱动程序集 ) ,包括设备上的设备描述符、配置描述符,以及接口描述符。对于有厂商和产品标识的设备,配置管理器首先在注册表中查找具有相应 ID 号的设备。如果注册表中没有这个表项,配置管理器将触发“新硬件向导”来寻找该设备的 INF 文件。新硬件向导向用户询问 INF 文件的位置,然后安装驱动程序并填写注册表。一旦配置管理器找到了注册表表项,它就可以动态地装载驱动程序。

2.USB应用程序设计

在Win32系统中,把每一个设备都抽象为文件,此时的应用程序只需通过几条简单的文件操作API函数,就可以实现与驱动程序中某个设备通信。一个驱动程序可以驱动多个设备,并且此驱动可能为Windows已有的,也可能为用户安装的。 通常,这些Win32API函数有以下几种:

(1) 查找打开设备 CreatFile 函数。打开一个设备,返回一个与设备相关的句柄。该函数声明形式如下:

HANDLE CreatFile( LPCTSTR lpFileName , //所要打开的设备名

DWORD dwDesiredAccess , //访问模式

DWORD dwShareMode , //共享模式

LPSECURITY_ATTRIBUTES lpSecurityAttributes ,//通常为NULL

DWORD dwCreationDistribution , //创建模式

DWORD dwFlagsAndAttributes , //文件属性和标志

HANDLE hTemplateFile // 临时文件的句柄,通常为NULL ) ;

如果调用成功,那么函数返回打开设备的句柄。采用下面程序来实现:

HANDLE hCom HCom=CreatFile( “COM2” , //设备名

GENERIC_READ | GENERIC_WRITE , //容许读和写

0 , //独占方式 NULL ,OPEN_EXISTING , //打开而不是创建

FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //

重叠方式

NULL) ;

当COM2口存在且处于空闲时,CreateFile函数将返回该串口的句柄。然而在编写USB应用程序时,却没有这么简单。因为目前还不知道所要打开的USB端口的设备路径名,所以还要获取设备信息集,识别接口信息。

(2) 从设备中读、写数据 ReadFile 函数。从设备中读取数据。

该函数声明如下:

BOOL ReadFile( HANDLE hCOM , //设备句柄

LPVOID lpBuffer , //指向接收缓冲区的指针

DWORD nNumberOfBytesToRead , //指定所要的字节数

LPDWORD lpNumOfBytesRead , //指向调用该函数读出的字节数

LPOVERLAPPED lpOverlapped , //异步结构 ) ;

其中,参数hCom为CreateFile函数所打开的串口句柄。

WriteFile 函数。向设备写函数,该函数声明形式如下:

BOOL WriteFile ( HANDLE hCom , //设备句柄

LPVOID lpBuffer , //指向读数据缓冲区的指针

DWORD nNumberOfBytesToWrite , //所读的字节数

LPDWORD lpNumOfBytesWritten , //指向已读入的字节数

LPOVERLAPPED lpOverlapped , //异步结构 ) ;

其中,参数hCom为CreateFile函数所打开的串口句柄。

(3) 设备的控制操作 DeviceIoControl 函数。

对设备进行一些自定义的操作,比如更改设置等。该函数声明形式如下:

BOOL DeviceIoControl ( HANDLE hDevice , //设备句柄

WORD dwIoControlCode , //所要执行的操作命令码

LPVOID lpINBuffer , //输入缓冲区

DWORD nInBufferSize , //输入缓冲区空间大小

LPVOID lpOutBuffer , //接收缓冲区

DWORD nOutBufferSize , //接收缓冲区

LPDWORD lpBytesReturned , //实际所接收数据个数

LPOVERLAPPED lpOverlapped , //异步结构 ) ;

其中,参数hDevice为CreateFile函数所打开的串口句柄。

(3) 关闭设备 CloseFile 函数。关闭一个由CreatFile打开的设备。该函数声明形式如下:

BOOL CloseHandle(HANDLE hCom)

其中,参数hCom为CreateFile函数所打开的串口句柄。 这些API函数的执行,都对应着驱动程序的一些分发例程,表5.1是常用API函数和驱动程序的IRP对应关系表。例如,当应用程序调用函数CreateFile来打开设备对象时,操作系统代替应用程序,向驱动程序发送系统I/O控制消息IPR_MJ_CREATE,从而驱动程序响应这个消息,对应的例程被调用。如果驱动程序没有提供该例程,CreateFile调用就会失效。也许有这个疑问:当用CreateFile打开一个串口时,并没有编写驱动程序,为什么串口已有驱动程序?这是因为串口的驱动程序是不需自行编写的,它已包含在系统中。这样,编写好相应的USB驱动程序后,再编写应用程序就不是一件很困难的事情。

表5.1 常用API函数和驱动程序的IRP对应关系

API 函数 IRP 说 明

CreateFile IRP _MJ_CREATE 打开设备

ReadFile IRP_MJ_READ 从设备获取数据

WriteFile IRP_MJ_WRITE 向设备发送数据

CloseFile IRP_MJ_CLOSE 关闭设备

DeviceIoControl IRP_MJ_DEVICE_CONTROL 控制操作

应用层API(kernel32.dll)

驱动层的IRP

驱动层创建URB(USBD.SYS),同时创建并发送一个IOCTL请求到USBD 驱动程序

驱动将URB提交到总线驱动程序

总线驱动程序配置硬件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LINUX设备驱动第三版_ 前言 第一章 设备驱动程序简介 设备驱动程序的作用 内核功能划分 设备和模块的分类 安全问题 版本编号 许可证条款 加入内核开发社团 本书概要 第二章 构造和运行模块 设置测试系统 Hello World模块 核心模块与应用程序的对比 编译和装载 内核符号表 预备知识 初始化和关闭 模块参数 在用户空间编写驱动程序 快速参考 第三章 字符设备驱动程序 scull的设计 主设备号和次设备号 一些重要的数据结构 字符设备的注册 open和release scull的内存使用 read和write 试试新设备 快速参考 第四章 调试技术 内核中的调试支持 通过打印调试 通过查询调试 通过监视调试 调试系统故障 调试器和相关工具 第五章 并发和竞态 scull的缺陷 并发及其管理 信号量和互斥体 completion 自旋锁 锁陷阱 除了锁之外的办法 快速参考 第六章 高级字符驱动程序操作 ioctl 阻塞型I/O poll和select 异步通知 定位设备 设备文件的访问控制 快速参考 第七章 时间、延迟及延缓操作 度量时间差 获取当前时间 延迟执行 内核定时器 tasklet 工作队列 快速参考 第八章 分配内存 kmalloc函数的内幕 后备高速缓存 get_free_page和相关函数 vmalloc及其辅助函数 per-CPU变量 获取大的缓冲区 快速参考 第九章 与硬件通信 I/O端口和I/O内存 使用I/O端口 I/O端口示例 使用I/O内存 快速参考 第十章 中断处理 准备并口 安装中断处理例程 实现中断处理例程 顶半部和底半部 中断共享 中断驱动的I/O 快速参考 第十一章 内核的数据类型 使用标准C语言类型 为数据项分配确定的空间大小 接口特定的类型 其他有关移植性的问题 链表 快速参考 第十二章 PCI驱动程序 PCI接口 ISA回顾 PC/104和PC/104+ 其他的PC总线 SBus NuBus 外部总线 快速参考 第十三章 USB驱动程序 USB设备基础 USB和Sysfs USB urb 编写USB驱动程序 不使用urb的USB传输 快速参考 第十四章 Linux设备模型 kobject、kset和子系统 低sysfs操作 热插拔事件的产生 总线、设备驱动程序 类 各环节的整合 热插拔 处理固件 快速索引 第十五章 内存映射和DMA Linux的内存管理 mmap设备操作 执行直接I/O访问 直接内存访问 快速参考 第十六章 块设备驱动程序 注册 块设备操作 请求处理 其他一些细节 快速参考 第十七章 网络驱动程序 snull设计 连接到内核 net_device结构细节 打开和关闭 数据包传输 数据包的接收 中断处理例程 不使用接收中断 链路状态的改变 套接字缓冲区 MAC 地址解析 定制 ioctl 命令 统计信息 组播 其他知识点详解 快速参考 第十八章 TTY驱动程序 小型TTY驱动程序 tty_driver函数指针 TTY线路设置 ioctls proc和sysfs对TTY设备的处理 tty_driver结构详解 tty_operations结构详解 tty_struct结构详解 快速参考 参考书目 9112405-1_o.jpg (85.53 KB, 下载次数: 50)
摘 要:基于对Linux 下蓝牙协议栈BlueZ 源代码的分析,给出BlueZ的组织结构和特点。分析蓝牙USB 传输驱动机制和数据处理过程, 给出实现蓝牙设备驱动的重要数据结构和流程,并总结Linux 下开发蓝牙USB 设备驱动的一般方法和关键技术。 关键词:Linux 系统;蓝牙协议栈;设备驱动 USB Device Driver for Linux Bluetooth Stack LIANG Jun-xue, YU Bin (Institute of Electronic Technology, PLA Information Engineering University, Zhengzhou 450004) 【Abstract】This paper depicts the structure and characteristics of BlueZ based on analyzing the source code of Linux bluetooth stack BlueZ. It analyzes the implementation of bluetooth USB transport driver scheme and data processing procedure in detail, and gives the key data structure and implementation of bluetooth device driver. It summarizes the approach of developing Linux bluetooth USB device driver and the key technology. 【Key words】Linux system; bluetooth stack; device driver 计 算 机 工 程 Computer Engineering 第 34 卷 第 9 期 Vol.34 No.9 2008 年 5 月 May 2008 ·开发研究与设计技术· 文章编号:1000—3428(2008)09—0273—03 文献标识码:A 中图分类号:TP391 1 概述 蓝牙技术是开放式通信规范,而 Linux 是开放源码的操 作系统。廉价设备与免费软件的结合,促进了蓝牙技术和 Linux 的发展与融合。 Linux最早的蓝牙协议栈是由Axis Communication Inc在 1999 年发布的 OpenBT 协议栈。 随后, IBM 发布了 BlueDrekar 协议栈,但没有公开其源码。Qualcomm Incorporated 在 2001 年发布的 BlueZ 协议栈被接纳为 2.4.6 内核的一部分。此外, Rappore Technology 及 Nokia 的 Affix Bluetooth Stack 都是 Linux 系统下的蓝牙协议栈,应用在不同的设备和领域中。 BlueZ 是 Linux 的官方蓝牙协议栈,也是目前应用最广 泛的协议栈,几乎支持所有已通过认证的蓝牙设备。对于基 于主机的蓝牙应用,目前常见的硬件接口有 UART, USB 和 PC 卡等,USB 作为 PC 的标准外设接口,具有连接方便、兼 容性好和支持高速设备等特点,已广泛应用于蓝牙设备。 目前对 LinuxUSB 设备驱动的研究已较为广泛而深 入[1-4] ,但对 Linux 下的蓝牙设备驱动还没有专门的研究。本 文在分析 USB 设备驱动和蓝牙协议栈的基础上,总结了 Linux 下开发蓝牙 USB 驱动程序的一般方法,并深入剖析了 其关键技术。 2 Linux 蓝牙协议栈 BlueZ 简介 BlueZ 目前已成为一个开放性的源码工程。它可以很好 地在 Linux 支持的各种体系的硬件平台下运行,包括各种单 处理器平台、多处理器平台及超线程系统。 BlueZ 由多个独立的模块组成,内核空间主要包括设备 驱动、蓝牙核心及 HCI 、L2CAP 与 SCO 音频、 RFCOMM, BNEP, CMTP 与 HIDP 、通用蓝牙 SDP 库和后 台服务及面向所有的标准套接字接口;在用户空间提供了 蓝牙配置、测试及协议分析等工具。其组织结构如图 1 所示, BlueZ 没有实现专门的 SDP ,而是将其实现为运行在后台 的蓝牙服务库例程(图 1 没有描述该后台服务)。 RFOMM 支 持标准的套接口,并提供了串行仿真 TTY 接口,这使串行端 口应用程序和协议可以不加更改地运行在蓝牙设备上,例如 通过点对点协议 PPP 可实现基于 TCP/IP 协议簇的所有网络 应用。BNEP 实现了蓝牙的以太网仿真,TCP/IP 可以直接 运行于其上。 USB设备驱动 (hci_usb.o) L2CAP(l2cap.o) RFCOMM (rfcomm.o) BNEP (bnep.o) CMTP (cmtp.o) 串口设备驱动 (hci_uart.o) 虚拟串口设备驱动 (hci_vhci.o) 音频 socket RFCOMM socket BNEP socket CMTP socket L2CAP socket HCI socket 内核 空间 用户 空间 串口设备 CAPI设备 输入设备 网络设备 HDIP socket 音频设备 AF_BLUETOOTH socket 音频(sco.o) PPP TCP/IP AF_INET socket BNEP (bnep.o) 其他设备驱动 (bluecard_cs.o等) BlueZ工具和实用程序 HDIP (hdip.o) BlueZ核心 及HCI(bluez.o/bluetooth.o) 图 1 BlueZ 组织结构 3 蓝牙 USB 设备驱动 设备驱动程序在 Linux 内核中起着重要作用,它使某个 硬件能响应一个定义良好的内部编程接口。这些接口隐藏了 设备的工作细节,用户通过一组独立于特定驱动程序的标准 调用来操作设备。而将这些调用映射到作用于实际硬件设备 的特有操作上,则是驱动程序的任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值