参考:
Linux是非常优秀
开源操作系统
有着十分广泛
应用
基于该操作系统设备驱动![]()
需求越来越多
PCI作为
种广泛采用
总线标准
在嵌入式系统中正被大量使用
而Linux
内核也能很好地支持PCI设备
为此
本文介绍了Linux下无配置信息PCI设备驱动![]()
设计开发方法
1 PCI总线及无配置信息PCI设备 1.1 PCI总线 PCI是外围设备互连(Peripheral ComponentInterconnect)
![]()
简称
![]()
是
![]()
种通用
![]()
总线接口标准
![]()
原先是应用于计算机系统
![]()
![]()
PCI提供了
![]()
组完整
![]()
总线接口规范
![]()
其目
![]()
是描述如何将计算机系统中
![]()
外围设备以
![]()
种结构化和可控化
![]()
方式连接在
![]()
起
![]()
该规范同时详细定义了计算机系统中各个不同部件之间应该如何正确地进行交互
![]()
在
![]()
般
![]()
计算机系统中
![]()
总线子系统与存储子系统被PCI总线分开
![]()
CPU通过
![]()
块称为PCI桥
![]()
设备来完成同总线子系统
![]()
交互
![]()
图1所示是
![]()
个PCI子系统
![]()
体系结构
![]()
尽管目前PCI设备大多采用32位数据总线
![]()
但PCI规范中已经给出了64位
![]()
扩展实现方案
![]()
从而使PCI总线能够更好地实现平台无关性
![]()
虽然PCI总线是由Intel公司提出
![]()
![]()
但它不局限于Intel系列
![]()
处理器
![]()
当今流行
![]()
其它处理器系列如Alpha、PowerPC、APARC
![]()
以及多处理器结构
![]()
下
![]()
代处理器都可以使用PCI总线
![]()
具体而言
![]()
PCI总线包含
![]()
特点可简要描述为高性能、线性突发传输、极小
![]()
存取延误、采用总线主控和同步操作、独立于处理器、兼容性强、预留了发展空间、低成本、高效益、软件透明等等
1.2 PCI设备
配置空间 标准
![]()
PCI设备上有三种地址空间:I/O空间、存储空间及配置空间
![]()
CPU可以访问PCI设备上
![]()
所有地址空间
![]()
其中I/O空间和存储空间提供给设备驱动
![]()
使用
![]()
主要用来实现PCI设备和Linux内核中设备驱动
![]()
之间
![]()
通讯
![]()
而配置空间则装载着PCI设备
![]()
配置信息
![]()
主要由Linux内核中
![]()
PCI
![]()
化代码使用
![]()
PCI设备
![]()
配置信息空间如图2所示
![]()
标准PCI设备配置信息空间
![]()
大小为256个字节
![]()
其中低64个字节称为头标区
![]()
这部分区域
![]()
格式是固定
![]()
![]()
内容包括PCI设备号、厂商识别号、命令寄存器、状态寄存器、基址寄存器等重要信息;其余
![]()
192个字节称为设备有关区
![]()
不同
![]()
设备可以对这部分寄存器进行不同
![]()
定义
1.3 无配置信息
PCI设备 目前
![]()
嵌入式系统往往会要求CPU和专用数据运算器之间以很高
![]()
速率通信
![]()
由于现行
![]()
总线规范中
![]()
PCI
![]()
高性能是最为突出
![]()
![]()
因此PCI总线
![]()
连接方式被大量采用
![]()
数据运算器往往是针对某
![]()
系统设计
![]()
![]()
通常会采用FPGA设计
![]()
即在FPGA中添加进PCI
![]()
接口设计
![]()
也就是把FPGA设计成为
![]()
块PCI设备
![]()
但是由于嵌入式系统
![]()
局限性
![]()
在某些FPGA
![]()
PCI接口设计中不能划分配置信息空间(I/O空间和存储空间是设备与CPU信息交互
![]()
基础
![]()
是必须存在
![]()
)
![]()
因此这个设计也就是
![]()
块无配置信息
![]()
PCI设备
2 Linux设备驱动
Linux
![]()
设备驱动
![]()
大致可以分为驱动
![]()
![]()
注册与注销、设备
![]()
打开与释放、设备
![]()
读写操作、设备
![]()
控制操作、设备
![]()
中断和轮询处理几个部分
2.1 设备
注册与注销 向系统增加
![]()
个驱动
![]()
就要赋予它
![]()
个主设备号
![]()
这
![]()
赋值过程应该在驱动
![]()
![]()
![]()
化中完成
![]()
它通过
![]()
![]()
register_chrdev
![]()
或reg-iste_blkdev
![]()
向内核注册
![]()
接下来就是给
![]()
![]()
个设备驱动
![]()
名
![]()
这个名字必须插入到/dev目录中
![]()
并与驱动
![]()
![]()
主设备号和次设备号相连
![]()
获得主设备号
![]()
方法是选择
![]()
个当前不用
![]()
设备号
![]()
或者在
![]()
register_chrdev时让参数ma-jor为0
![]()
这样
![]()
其返回值便是设备
![]()
主设备号
![]()
另外
![]()
在关闭
![]()
设备或块设备时
![]()
还需要通过unregisler_chrdev
![]()
或unregister_blkdev
![]()
从内核中注销设备
![]()
并释放主设备号
2.2 设备
打开与释放 打开设备可由open
![]()
完成
![]()
在大部分驱动
![]()
中
![]()
open主要用于检查设备相关

(如设备尚未准备好等)、识别次设备号(如有必要更新当前read/write位置f_ops指针)
![]()
以及分配和填写要放在file->private_data里
![]()
数据结构
释放设备由release
![]()
完成
![]()
release
![]()
作用与open相反
![]()
主要是释放file->private_data中open分配
![]()
内存
![]()
并在最后
![]()
次关闭操作时关闭设备
2.3 设备
读写操作 ![]()
设备使用各自
![]()
read
![]()
和write
![]()
来对设备进行数据读写
![]()
块设备则使用通用block_read
![]()
和block_write
![]()
来对设备进行数据读写
![]()
这两个通用
![]()
可以向请求表中增加读写请求
![]()
这样
![]()
内核就可以优化请求顺序
![]()
由于是对内存缓冲区而不是对设备进行操作
![]()
因而能加快读写请求
![]()
如果内存缓冲区内没有要读入
![]()
数据或者需要将写请求写入设备
![]()
那么就需要真正地执行数据传输
2.4 设备
控制操作和中断处理 除了读写操作外
![]()
有时还需要控制设备
![]()
这在操作时可以通过设备驱动
![]()
中
![]()
ioctl
![]()
来完成
![]()
另外
![]()
对于不支持中断
![]()
设备
![]()
读写时需要轮流查询设备状态
![]()
以决定是否继续进行数据传输
![]()
如果设备支持中断
![]()
则可按中断方式进行
3 无配置信息PCI设备驱动![]()
设计 无配置信息PCI设备驱动
![]()
设计
![]()
关键在于
![]()
化
![]()
其余部分与标准PCI设备驱动差别不大
![]()
其
![]()
化
![]()
方法有两种:
![]()
是选用外接
![]()
EEPROM来存储该设备
![]()
配置信息;二是直接在驱动
![]()
![]()
探测模块里注册设备
用外接EEPROM配置方式时
![]()
内核启动后会检测EEPROM
![]()
然后读出其中
![]()
配置信息
![]()
并将设备
![]()
信息注册到pci dev里
在实际
![]()
系统应用中
![]()
如果无法外接EEP-ROM
![]()
就必须直接在驱动
![]()
![]()
探测模块里注册设备
![]()
在这种方式下
![]()
若系统中没有其它
![]()
即插即用PCI设备
![]()
则可能会导致检测设备失败
![]()
但事实上已经注册了该PCI设备
![]()
因此完全可以正常运行
笔者开发
![]()
嵌入式TDMA卫星通信系统中
![]()
CPU采用MPC8250芯片
![]()
基带信号处理模块采用Xilinx公司
![]()
X3SC4000(FG676)
![]()
MPC8250是Mo-torola公司开发
![]()
![]()
款PowerPC系列嵌入式处理器
![]()
该处理器中有32位超标量体系结构Power-PC603e处理器内核
![]()
并集成有PCI桥、PCI仲裁器、存储器控制器等部件
![]()
FPGA
![]()
设计中则包括PCI接口、sdram控制器及编码调制运算模块
此操作系统采用Linux
![]()
内核版本为2.6
![]()
由于Linux能很好地支持PCI总线
![]()
本设计在CPU和FPGA之间采用了PCI总线连接方式
![]()
由于FPGA
![]()
设计要求
![]()
PCI总线
![]()
中断信号未被使用
![]()
而是另行设定了两条中断信号线通往MPC8250
![]()
通用设计口
该系统支持FPGA中bin文件
实时更新
因此没有采用配置EPROM来配置FPGA
而是把要下载到FPGA里
bin文件同Uboot、Linux内核及jffs2文件系统
起放在了FLASH里
然后通过MPC8250提供
SPI总线下载到FPGA中
实际上
如需要更新FPGA
.bin文件
则可通过以太网口将文件拷入FLASH中再下载
在系统上电启动后
![]()
由于Linux内核先于jffs2解压
![]()
而FPGA
![]()
文件又必须在jffs2解压完后才能释放到内核空间
![]()
然后再借助SPI总线下载到FP-GA中
![]()
因此无法在FPGA中创建PCI设备配置信息空间
![]()
所以
![]()
本设计采用在检测PCI设备时直接注册
![]()
方法
3.1 驱动![]()
总体框架 下面是笔者驱动
![]()
整体框架
![]()
从中可以很明显地看出几个模块是如何联系起来
![]()
:
![]()
3.2 具体模块
实现 由于本系统没有采用标准PCI总线提供
![]()
中断信号
![]()
因此驱动
![]()
中无中断处理模块
![]()
下面着重介绍对本设计比较重要
![]()
![]()
化设备过程以及打开设备模块、读写模块
![]()
设计方法
(1)
![]()
化设备过程
![]()
化设备过程也是本系统PCI设备驱动中最为关键
![]()
部分
![]()
由于本系统中允许PCI总线挂接其它
![]()
即插即用设备
![]()
因此
![]()
这部分
![]()
还需要保留
![]()
其部分代码及注释如下:
在2.4之前
![]()
内核版本中
![]()
需要手动
![]()
pci_find_device
![]()
![]()
来查找PCI设备
![]()
但在2.4版本后
![]()
则可以
![]()
probe探测
![]()
来完成对硬件
![]()
检测及信息获取工作
![]()
其部分代码如下:
在获取
![]()
PCI信息子
![]()
pci_rewin_pci_re-sources_claim
![]()
和注册设备子
![]()
pci_rewin_de-vice_register
![]()
里
![]()
笔者自己创建
![]()
PCI设备信息可以写人到pci_dev
![]()
然后由Liunx内核通过pci_register_drivet
![]()
将此PCI设备信息创建在PCI设备列表中
(2) 打开设备模块
打开设备模块主要用来检查设备号、开辟PCI总线映射空间
![]()
打开设备模块
![]()
部分代码及注释如下:
(3) 读写模块
读操作就是先通过memcpy_fromio
![]()
将PCI上传来
![]()
数据搬移到内核空间中
![]()
接收缓冲区
![]()
再用copy_to_user搬移到用户数据空间
![]()
接收缓冲区和接收数据散列表都要在
![]()
化模块中进行处理
![]()
读操作
![]()
部分代码及注释如下:
写操作与读操作正好相反
![]()
它先通过copy_from_user
![]()
将用户空间
![]()
数据搬移到内核空间中
![]()
发送缓冲区
![]()
再通过memcpy
![]()
搬移到PCI总线上
![]()
由于发送
![]()
数据长度是可变
![]()
![]()
所以每次发送都需要构造不同
![]()
发送散列表(发送缓冲区可以再
![]()
化时分配)
![]()
写操作
![]()
代码与读操作类似
![]()
故此省略
值得注意
![]()
是
![]()
在PCI设备用I/O方式读写
![]()
时候
![]()
CPU将被迫停止工作以等待PCI设备完成此操作
![]()
且每次只允许
![]()
个设备访问
![]()
这个策略不利于提升系统性能
![]()
但利用MPC8250芯片提供
![]()
DMA(直接内存访问)机制则可大大提高PCI总线
![]()
性能
![]()
这也是笔者下
![]()
步需要改进
![]()
地方
4 结束语 本文讨论了Linux2.6版本下开发设备驱动
![]()
![]()
原理和相关知识
![]()
着重介绍了无配置信息PCI设备驱动
![]()
![]()
开发方法
![]()
该驱动开发方法可成功应用于嵌入式TDMA卫星通信系统
![]()
测试证明:本系统可稳定有效工作
![]()
今后
![]()
工作将着重是提升系统性能并进行改进.
阅读(1639) | 评论(0) | 转发(0) |