![LINUX设备驱动之PCI设备驱动_第1页](http://file3.renrendoc.com/fileroot_temp3/2021-12/27/8f63ba14-efb4-4bf6-b5cf-54d858a1654e/8f63ba14-efb4-4bf6-b5cf-54d858a1654e1.gif)
![LINUX设备驱动之PCI设备驱动_第2页](http://file3.renrendoc.com/fileroot_temp3/2021-12/27/8f63ba14-efb4-4bf6-b5cf-54d858a1654e/8f63ba14-efb4-4bf6-b5cf-54d858a1654e2.gif)
![LINUX设备驱动之PCI设备驱动_第3页](http://file3.renrendoc.com/fileroot_temp3/2021-12/27/8f63ba14-efb4-4bf6-b5cf-54d858a1654e/8f63ba14-efb4-4bf6-b5cf-54d858a1654e3.gif)
![LINUX设备驱动之PCI设备驱动_第4页](http://file3.renrendoc.com/fileroot_temp3/2021-12/27/8f63ba14-efb4-4bf6-b5cf-54d858a1654e/8f63ba14-efb4-4bf6-b5cf-54d858a1654e4.gif)
![LINUX设备驱动之PCI设备驱动_第5页](http://file3.renrendoc.com/fileroot_temp3/2021-12/27/8f63ba14-efb4-4bf6-b5cf-54d858a1654e/8f63ba14-efb4-4bf6-b5cf-54d858a1654e5.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、LINUX设备驱动之PCI设备wan gxy该文档是整理PCI驱动时参考网上资料编写,供大家参考交流学习。1) PCI总线总线由电气接口和编程接口组成。先介绍PCI总线的电气接口。该总线具有 以下特性: 总线位宽为32位,可扩充到64位,数据总线和地址总线复用。 总线的时钟频率为33MHz随着PCI总线的发展,总线的时钟频率在提 高,PCI-X 1.0 总线的时钟频率为 66MHz/100MHz/133MH到 PCI-X 2.0 的时候,总线的时钟频率发展到 266MHz/533MHz/1066M,不过PCI总 线和PCI-X总线硬件结构上完全兼容。 支持全自动配置,资源分配,即插即用。 总线
2、规范独立于微处理器,通用性好。 PCI设备可以完全作为主控设备控制总线。 采用中央集中式总线仲裁。2) PCI设备引脚介绍AID|i AR|PARPAH.M付扩充(RbVD卜、£1丄IDSELSIX*Ni:伸尿(只有总it匸拧同iltvtCLKH5T11)1Tlx、TCKTKsT图(一) PCI兼容设备引脚示意图在一个PCI应用系统中,如果某个PCI设备获得了 PCI总线的控制权,就称 该设备是主设备,被主设备选中以进行数据传输的PCI设备称为从设备,对于PCI兼容设备的引脚主要分为两部分:必需引脚和可选引脚。对应主设 备至少需要49个引脚,对应从设备至少需要 47个引脚。必需部分对
3、应图(一) 中的左侧部分,可选部分对应图(一)中右侧部分。PCI兼容设备引脚共有100根,下面对这些信号进行 介绍,介绍前先对 引脚信号的类型做一个简介。PCI引脚信号按照数据传输的方向和电路驱动的特 性分为五种类型。 in:输入信号 out:输出信号 t/s:双向三态I/O驱动信号(三态:高电平、低电平和高阻抗) s/t/s:持续双向三态I/O驱动信号,表示持续且低电平有效的三态信号。在某个时刻只可属于一个主设备,并被其驱动。这种信号从低电平到高阻 抗之前,必需保证至少在一个时钟周期处于高电平状态,即低电平-> 至少一个时钟周期高电平-> 高阻抗。另一个主设备要驱动该信号,至少要
4、 等该信号的原有驱动者将其释放(变为高阻抗状态)一个时钟周期后,才能 开始。如果这种信号处于非驱动状态,在有新主设备驱动它之前应采取上拉措施, o/d:漏极开路即高阻状态,适用于输入/输出,其可独立输入/输出低电 平和高阻状态,若需要产生高电平,则需使用外部上拉电阻。可作线或,允许多个设备共同使用。F面对各个引脚信号做介绍信号标识信号名称信号类型概述CLK时钟in为PCI兼容设备上的接口提供时钟信 号及总线的仲裁提供时序,PCI-2.2规 范中最高时钟频率33MHz,除了 RST 和四个中断引脚外,其它引脚信号都 是在CLK上升沿采样,所有的时间参 数都是基于这个上升沿而定义的。CLK最小频率
5、0Hz。RST复位信号in使PCI特定的寄存器、配置寄存器和 定时器相关的信号置于一个固定的状 态。所有的PCI引脚信号驱动到它的 起始状态。通常情况下,意味着这些引脚处 于高阻态,SERR被浮空,REQ和GNT 都必须是高阻态,如果不能提供高阻 态输出的话,就把SBO和SDONE驱 动到低电平状态。为防止数据地址线 ADxx、C/BEx、PAR 引脚在复位 期间被浮空,如果要使用,也只能驱 动到低电平。REQ64在复位结束后有 效。AD31-0地址数据线t/s在FRAME有效时,是地址周期, AD31-0包含一个总线地址,对于配 置空间和储存器空间,这是一个双字 地址,对于I/O空间,这是一
6、个字节 地址,高位 AD31-24低位 AD7-0; 在IRDY和TRDY同时有效时,是数据周期,一次PCI总线的传输中包含 了一个地址信号周期和1个数据周 期。C/BE3-0总线命令和 字节使能信 号t/s在地址周期内,这四条线上传输的是 总线命令,在数据周期,传输的是字 节使能信号,表示在整个数据周期, AD31-0上哪些字节为有效数据。PAR奇偶校验 信号t/sAD31-0和C/BE3-0上的数据奇偶 校验,通常PCI传输时要求奇偶校验。PAR与AD31-0有相同的时序,但延 时一个时钟周期,在地址周期后一个 时钟周期,PAR稳定且有效。对于数 据周期,在写传输过程中,PAR在IRDY有
7、效后延迟一个时钟周期稳定 且有效,一旦PAR有效,在数据周期 完成后的一个时钟周期内它必须保持 有效。在读传输中,PAR在TRDY有 效后延迟一个时钟周期稳定且有效, 一旦PAR有效,在数据周期完成后的 一个时钟周期内它必须保持有效。 在地址周期和写数据周期,总线的主 设备驱动PAR,在读数据周期,目标 设备驱动PAR。FRAME帧周期信号s/t/s由总线的主设备驱动,表示一次 PCI 传输的开始和持续时间,FRAME有 效表示总线传输开始,当FRAME持 续有效说明总线传输继续进行。当 FRAME无效表示正在传输的最后一 个字节。IRDY主设备准备 好信号s/t/s该信号有效表明主设备已经具
8、有完成 一次PCI传输的能力,该信号需与 TRDY信号配合使用,这二者都有效 才能进行数据传输,否则即为等待周 期,在写周期,该信号有效表示 AD31-0线上数据已经建立,在读周 期,该信号有效表示主设备已经准备 好接收数据。TRDY从设备准备 好信号s/t/s该信号有效表明从设备已经做好完成 当前数据传输的准备工作,同样该信 号需与IRDY配合使用,二者同时有 效才能进行数据传输,在写周期,该 信号有效表示从设备做好接收数据准 备,在读周期,该信号有效表示数据 已经送到AD31-0线上,同理,二者任何一个无效时都为等待周期。STOP从设备要求 停止当前数 据传输信号s/t/s该信号有效,表示
9、从设备要求主设备 停止当前数据传输操作。LOCK总线锁定信 号s/t/s锁定操作只针对PCI桥设备,锁定表 明一个需要多次传输才能完成的原子 操作。该信号有效,对一个没有处于 锁疋状态的PCI桥设备来说表示 个 非独占的传输正在进行。在PCI总线 上,允许开始一次传输并不代表拥有 对LOCK信号的控 制权。取得对 LOCK信号的控制权要遵循一些协议 和GNT信号的配合。DEVSEL从设备选中信号s/t/s该信号有效,从设备已经解码主设备 发出的地址。IDSEL初始化设备 选择信号in配置空间读写时的片选信号。PERR数据奇偶校 验错误报告 信号s/t/s该引脚只用于反馈在除特殊周期外的 其它传
10、输过程中的数据奇偶校验错 误,PERR维持三态,在检测到传输 数据中的奇偶校验错误后,在传输数 据结束后的两个时钟周期内,由接收 数据的单元驱动PERR有效,至少要 持续一个时钟周期。在被释放到三态 前,PERR必须驱动到高电平一个时 钟周期,只有发出DEVSEL的单元才 能发出PERR。SERR系统出错信 号o/d用于反馈地址奇偶错误、特殊周期命 令中的数据奇偶错误和将引起重大事 故的其它灾难行的系统错误,如果一 个设备不想产生不可屏蔽(NMI),就 可以用SERR信号反馈给总线。SERR 是单纯的漏极开路信号,由反馈错误 的设备驱动,在一个总线时钟周期内 有效,SERR与总线时钟同步,并满
11、 足所有总线信号的建立与保持时间的 要求,SERR信号释放到无效状态由 系统设计者提供上拉电阻实现,从无 效状态恢复到有效状态需2-3个时钟 周期,支持SERR的设备在采样到 SERR有效时,就向操作系统报告系 统错误。REQ总线请求信 号t/s该信号只对主设备有效,是一个点对 点信号,用于向仲裁器说明某个主设备想使用总线。GNT总线允许信 号t/s该信号仅对主设备有效,也是一个点 对点信号,仲裁器想申请总线的主设 备说明其对总线的操作已经得到批 准。INTA中断A信号o/d常用于单一功能设备请求一次中断。INTB中断B信号o/d用于多功能设备请求一次中断。备注一INTC中断C信号o/d:用于
12、多功能设备请求一次中断。INTD中断D信号o/d用于多功能设备请求一次中断。SBO监视补偿信 号in /out该信号有效,说明对某修改行的一次 命中,所访问的数据无效,当SBO信 号无效而SDONE信号有效,说明PCI 主设备正在访冋存储器的有效行并可 进行高速缓存的操作。SDONE监视完成信 号in /out表示处理器CACHE对主存的监视状 态,无效表示监视仍在进行,否则便 是监视已完成。AD63-32地址数据复 用硬件t/s提供32个附加位,在地址周期(使用 DAC指令且REQ64已有效)传输64 位地址的咼32位,如果没有咼32位 地址,这些引脚就被保留,其上的数 据是稳疋的,但值是不
13、确疋的,在数 据周期,当REQ64和ACK64都有效 时,传输64位数据中的高32位。C/BE7-4总线命令和 字节允许复 用信号t/s在一个地址周期(使用DAC指令且 REQ64已有效)在C/BE7-4传输的是 有效的总线命令;如无,这些引脚被 保留,其值不确定,在数据周期当REQ64和 ACK64都有效时, C/BE7-4是字节允许,说明哪些字节上含有有效数据。REQ64请求传输 64位数据 信号t/s当其被当前总线的主设备有效驱动 时,说明该总线的主设备想做64位的 传输,REQ64和FRAME有相同的时 序,复位结束后,若REQ64有效,该 设备就已连接64位通道上,否则无。ACK64
14、64位传输 的应答信号s/t/s从设备驱动该信号,说明从设备能够 进行64位数据传输,ACK64和 DEVSEL有相同的时序。PAR64高偶校验信 号t/s是 AD63-32和 C/BE7-4的偶校验 位,当REQ64有效且C/BE7-4上有DAC命令时,第一地址周期后的一个 时钟周期PAR64有效,DAC命令的 第二个地址周期后的那一个时钟周期PAR64也有效,在数据周期中,当 REQ64和ACK64都有效时,读操作 中,TRDY有效后,PAR64稳定且有 效,在写操作中,IRDY有效后,PAR64 稳定且有效。一旦PAR64 有效,必须 保持有效指导数据周期完成后一个时 钟周期的时间。(P
15、AR64时序与 AD63-32相同但延迟一个时钟周 期),在地址周期和写数据周期内,总 线主设备驱动PAR64,在读数据周期 内,从设备驱动 PAR64。备注二TDI测试数据输 入信号in将测试数据和测试指令串行移入到设 备中。TDO测试输出信 号out将测试数据和测试指令串行移出到设 备。TCK测试时钟信 号in记录状态信息和测试设备的输入输出 数据。TMS测试模式选 择in控制设备中的JTAG控制器状态。TRST测试复位信 号in异步初始化JTAG控制器备注一多功能设备的任何一种功能都能连接到任何一条中短线上,中断引脚寄存器决定该功能用那一条中断线去请求中断。如果一个设备只用了一条中断线,
16、就是用INTA,如果用两条就使用INTA和INTB,依,此类推。对于多功能设备,可以是所有功能用一条中断线,也可以每种功能使用自己的中断线,最多四种 功能。备注二在总线主设备和从设备之间,64位传输是动态协商的,在每个地址周期进行一次,而且,只有主存命令支持64位传输,总线主设备使 REQ64有效,从设备则通过使 ACK64有效加以应答,REQ64和ACK64都 是外部上拉的,保证 64位和32位单元混用,一旦64位传输建立,就一直保持到这次传输结束。3) PCI总线上的操作总线命令总线命令是由主设备发向从设备,其作用是规定主设备正在请求的传输类型,在地址周期,被编码的总线命它出现在C/BE3
17、-0引脚上,从设备的地址出现在AD地址数据复用引脚上。C/BE3-0命令类型命令作用0000中断应答是一个读命令,主设备从申请中断的从设备中读取中断向量。0001特殊周期通报处理器状态或在各个从设备之间传递信息。0010I/O读从一个映射到I/O地址空间的设备中读取数据。0011I/O写向一个映射到I/O地址空间的设备中读取数据。0100保留留作将来使用,任何设备也不允许对保留命令做出反应。0101保留留作将来使用,任何设备也不允许对保留命令做出反应。0110存储器读从一个映射到内存空间的设备上读取数据。0111存储器写向一个映射到内存空间的设备上写入数据。1000保留留作将来使用,任何设备也
18、不允许对保留命令做出反应。1001保留留作将来使用,任何设备也不允许对保留命令做出反应。1010配置读从每个设备的配置空间读取数据。1011配置写向每个设备的配置空间写入数据。1100储存器多行读试图在主设备断开连接之前读取多行高速缓存的数据,内存控制器应保证,只要FRAM有效,就连续不断地发内存读取请求,该命令预定用于大块连续数据的传输。1101双地址周期该命令用于传输 64位地址给支持64位寻址的设备,只支持 32位寻址的设备 不对该命令做岀反应。1110存储器一行读该命令与内存读命令不同之处在于它还表示主设备要求读取多于2个32位的数据周期,即一次读取缓存范围内一行上的所有数据。1111
19、存储器写和无效该命令与内存写命令的不同之处是它要保证最小的传输量是一个高速缓存行, 主设备要在一次PCI传输中,写完被寻址的高速缓存行的全部字节。命令的使用规则所有PCI设备都是配置(读和写)命令的目标设备,必须做出应答。对 其他的命令则有选择余地,I/O读或写命令是可选的。命令执行规则 保证I/O读或写命令的执行顺序。有重定位功能或寄存器的目标设备 要求能通过配置寄存器映射到存储器空间,并响应基本的存储器读或 写命令,这就为没有I/O空间(仅X86处理器有)设备的使用提供了一 种选择。当这种映射实现时,无论设备映射到I/O空间还是存储器命令执行规则都由系统设计者来保证。总线主设备可以根据需要
20、使用任选指令,从设备也可根据需要而选 用指令,但如果选用了基本指令,就必须支持所有存储器命令,包括 高速缓存写命令、高速缓存行读命令和存储器多行读命令。如果不能 全部使用,这些为优化性能而设的命令必需转化为基本的存储器命令。例如,一个从设备可以不实现存储器行读命令,但是它必须能接 受该命令的请求 ,并按存储器读命令来处理。同理,一个从设备可 以不实现存储器写但它必须能接受该命令的请求, 并按存储器写命令 来处理。对于进/ 出系统存储器的块数据传输,对能支持高速缓存写和高速 缓存行读命令的主设备,建议采用这两天命令,如果由于某种原因, 总线主设备不能使用性能已优化的命令, 就用存储器读和存储器写
21、命 令。对于使用存储器读命令的总线主设备,对所有命令都可作任意长 度的操作, 但最优方法如下, 如果高速缓存写命令要求实现高速缓存 行范围寄存器,存储器读命令也使用它, 使用高速缓存行范围寄存器时的最优方法: 存储器读命令:当突发传输少于半条高速缓存行数据时使用。 高速缓存行存储器读命令: 当突发传输半条到三条高速缓存行数据时 使用。 存储器重复读命令:当突发传输三条以上高速缓存行数据时使用。 不使用高速缓存行范围寄存器时的最优方法: 存储器读命令:当突发传输两个或更少数据时使用。 高速缓存行存储器读命令:当突发传输三到 12 个数据时使用。 存储器重复读命令:长突发传输数据时使用。PCI 协
22、议基础在 PCI 总线上, 总线的基本传输机制是突发传输, 一个突发传输由一 个地址周期和大于等于一个数据周期组成。 PCI 总线支持内存空间和I/O地址空间的突发传输。PCJ pr*durlCompofinri &«3b F maiq5V 32-bil PCI Cardc3 3V&1U PCI Card】ii川川 iriiiiiiiiiii【川川汕川iiiiiiiiiiiiiii川riiuiiiiiiiiiiiii川jmumu miuminimm F5V &4-W PCi CardLw mnmnim umiUnivsal I3 3V & 5V) 64
23、巾ii PCI Cax川iiniiL川丄一;iru小ii川川hi川川3.3V 34-btl PClSlol5V 32-brt PCI Slot5V54-bi1 PCI Slot编程接口:每个PCI设备由一个总线编号、一个设备编号及一个功能编号来标识, PCI规范 允许单个系统拥有高达256个总线,linux目前支持PCI域,每个PCI域可拥有 最多256个总线,每个总线可支持32个设备,每个设备可具有最多8个功能。每种功能都可以在硬件级由一个16位的地址来标识。驱 动程序使用pci_dev 数据结构来访问设备。总线上每个外设拥有三个地址空间:内存位置、I/O端口和配置寄存器,内存位 置和I/O
24、端口由同一 PCI总线上的所有设备共享,大多数PCI总线上的外设会把寄存器映射到某个内存地址区段,此时的内存地址 区段就是I/O内存。分析I/O端口和I/O内存的区别:MIPS、ARM和 PowerPC等平台的I/O和主存采用的是统一编址的方式,它们将 I/O空间映射到内存,采用与内存相同的汇编指令(load和store)来读写设备, 这种方式称为I/O内存;x86平台的I/O和主存采用的是独立编址的方式,CPU 有专门的线路来访问I/O,而且有专门的汇编 指令(in和out)来读写设备,这 种方式称为I/O端口。每种外设都是通过读写寄存器进行控制。 在硬件层,内存区域和I/O区域没有概 念上
25、的区别,他们都是通过向地址总线和控制总线发送电平信号进行访问, 再通 过数据总线读写数据。每个PCI槽有四个中断引脚,每个外设功能可使用一个,中断线共享,PCI总线中的I/O空间使用32位地址总线,PCI配置空间中每个设备功能有256个字节组成(PCI-E有4KB的配置空间),配置寄存器的布 局是标准化的(64)注意是小端模式。vendorlD :用于表示硬件制造商的16位寄存器。Device ID :由制造商选择,该ID通常与Ven dor ID生成一个唯一的32位硬件 设备标识符,class :每个外设都属于一个类.类寄存器是一个16-位值,它的高8位标识" 基类"(或
26、者群).例如,"ethernet" 和"token ring" 是2个类都属于"network" 群,而"serial" 和"parallel"属于"communication"群.一些驱动可支持几个类似的设备,每个都有一个不同的签名但是都属于同样的类;这些驱动可依赖类 寄存器标识它们的外设。subsystem ven dorIDsubsystem deviceID这些字段可用来进一步标识一个设备.如果芯片对于本地总线是一个通 用接口芯片,它常常被用在几个完全不同的地方,并且
27、驱动必须标识出 它在与之通话的实际设备.子系统标志用作此目的.使用这些不同的标识符,一个PCI驱动可告知内核它支持什么类型的设备. struct pci_device_id结构被用来定义一个驱动支持的不同类型PCI设备的列表这个结构包含不同的成员:u32 ven dor;u32 device;这些指定一个设备的PCI供应商和设备ID.如果驱动可处理任何供应 商或者设备ID,值PCI_ANY_ID应当用作这些成员上.u32 subvendor;u32 subdevice;这些指定一个设备的 PCI 子系统供应商和子系统设备 ID. 如果驱动可 处理任何类型的子系统 ID, 值 PCI_ANY_I
28、D 应当用作这些成员上 ._u32 class;_u32 class_mask;这 2 个值允许驱动来指定它支持一类 PCI 类设备 . 不同的 PCI 设备类 ( 一个 VAG 控制器是一个例子 ) 在 PCI 规范里被描述 . 如果一个驱动 可处理任何子系统 ID, 值 PCI_ANY_ID 应当用作这些字段 .kernel_ulong_t driver_data;这个值不用来匹配一个设备 , 但是用来持有信息 , PCI 驱动可用来区分 不同的设备 , 如果它想这样 .有 2 个帮助宏定义应当被用来初始化一个 struct pci_device_id 结构 :PCI_DEVICE(ven
29、dor, device)这个创建一个 struct pci_device_id ,它只匹配特定的供应商和设备ID. 这个宏设置这个结构的子供应商和子设备成员为 PCI_ANY_ID.PCI_DEVICE_CLASS(device_class, device_class_mask)这个创建一个 struct pci_device_id, 它匹配一个特定的 PCI 类.一个使用这些宏来定义一个驱动支持的设备类型的例子 , 在下面的内核 文件中可找到 :drivers/usb/host/ehci-hcd.c:static const struct pci_device_id pci_ids = /*
30、 handle any USB 2.0 EHCI controller */PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB << 8) | 0x20), 0), .driver_data = (unsigned long) &ehci_driver, /* end: all zeroes */ ;drivers/i2c/busses/i2c-i810.c: static struct pci_device_id i810_ids = PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810
31、_IG1) , PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3) , PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG) , PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC) , PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG) , 0, , ;这些例子创建一个 struct pci_device
32、_id 结构的列表 , 列表中最后一 个是被设置为全零的的空结构 . 这个 ID 的数组用在 struct pci_driver ( 下面讲述 ), 并且它还用来告诉用户空间这个特定的驱动支 持哪个设备 .这个 pci_device_id 结构需要被输出到用户空间 , 来允许热插拔和模块 加载系统知道什么模块使用什么硬件设备宏MODULE_DEVICE_TAB完E 成这个.例如:MODULE_DEVICE_TABLE(pci, i810_ids);这个语句创建一个局部变量称为 _mod_pci_device_table,它指向struct pci_device_id 的列表. 稍后在内核建立过
33、程中 , depmod 程序在 所有的模块中寻找 _mod_pci_device_table.如果找到这个符号 , 它将数据拉出模块并且添加到文件 /lib/modules/KERNEL_VERSION/modules.pcimap. 在 depmod 完成后 , 所有的被内核中的模块支持的 PCI 设备被列出 , 带有它们的模块名子 , 在那个文件中 . 当内核告知热插拔系统有新的 PCI 设备已找到 , 热插拔 系统使用 moudles.pcimap 文件来找到正确的驱动来加载 .注册一个 PCI 驱动为了被正确注册到内核 , 所有的 PCI 驱动必须创建的主结构是 struct pci_
34、driver 结构 . 这个结构包含许多函数回调和变量 , 来描述 PCI 驱 动给 PCI 核心 . 这里是这个结构的一个 PCI 驱动需要知道的成员 :const char *name;驱动的名子 . 它必须是唯一的 , 在内核中所有 PCI 驱动里面 . 通常被设 置为和驱动模块名子相同的名子 . 它显示在 sysfs 中在 /sys/bus/pci/drivers/下, 当驱动在内核时 .const struct pci_device_id *id_table;指向 struct pci_device_id 表的指针 , 在本章后面描述它 .int (*probe) (struct p
35、ci_dev *dev, const struct pci_device_id *id);指向 PCI 驱动中 probe 函数的指针 . 这个函数被 PCI 核心调用 , 当它 有一个它认为这个驱动想控制的 struct pci_dev 时. 一个指向 struct pci_device_id 的指针 , PCI 核心用来做这个决定的 , 也被传递给这个 函数. 如果这个 PCI 驱动需要这个传递给它的 struct pci_dev, 它应 当正确初始化这个设备并且返回 0. 如果这个驱动不想拥有这个设备 , 或者产生一个错误 , 它应当返回一个负的错误值 . 关于这个函数的更多 的细节在本
36、章后面 .void (*remove) (struct pci_dev *dev);指向 PCI 核心在 struct pci_dev被从系统中去除时调用的函数的指针或者当 PCI 驱动被从内核中卸载时 . 关于这个函数的更多的细节在本章 后面.int (*suspend) (struct pci_dev *dev, u32 state);当 struct pci_dev 被挂起时 PCI 核心调用的函数的指针 . 挂起状态在 state 变量里传递 . 这个函数是可选的 ; 一个驱动不必提供它 .int (*resume) (struct pci_dev *dev);当 pci_dev 被恢
37、复时 PCI 核心调用的函数的指针 . 它一直被调用在调 用挂起之后 . 这个函数时可选的 ; 一个驱动不必提供它 .总之, 为创建一个正确的 struct pci_driver 结构, 只有 4 个字段需 要被初始化 :例如:static struct pci_device_id wctdm_pci_tbl = 0xe159, 0x0001, 0xb100, PCI_ANY_ID, 0, 0, (unsigned long)&wctdmi , 0 ;MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl);static struct pci_driver wct
38、dm_driver = .name = "ax4g",.probe = wctdm_init_one,.remove =_devexit_p(wctdm_remove_one),.suspend = NULL,.resume = NULL,.id_table = wctdm_pci_tbl,;注册驱动程序, 注意 , pci_register_driver函数要么返回一个负的错误码, 要么是 0 当所有都成功注册 . 它不返回绑定到驱动上的设备号 , 或 者一个错误码如果没有设备被绑定到驱动上。static int _ _init wctdm_init(void) int
39、res;res = pci_register_driver(&wctdm_driver); if (res)return -ENODEV;return 0;注销驱动程序,当 PCI 驱动被卸载 , struct pci_drive 需要从内核中注 销. 这通过调用 pci_unregister_driver完成 . 当发生这个调用 , 任何当前绑定到这个驱动的 PCI 设备都被去除 , 并且这个 PCI 驱动的 remove 函数在 pci_unregister_driver 函数返回之前被调用 .static void _exit wctdm_cleanup(void) pci_un
40、register_driver(&wctdm_driver); 在 PCI 驱动的探测函数中 , 驱动可存取 PCI 设备的任何设备资源 (I/O 区或者 中断) 前, 驱动必须调用 pci_enable_device 函数:int pci_enable_device(struct pci_dev *dev);这个函数实际上使能设备 . 它唤醒设备以及在某些情况下也分配它的中 断线和 I/O 区 .在驱动已探测到设备后 , 它常常需要读或写 3 个地址空间 : 内存 , 端口, 和配置 . 特别地, 存取配置空间对驱动是至关重要的 , 因为这是唯一的 找到设备被映射到内存和 I/O 空
41、间的位置的方法 .因为微处理器无法直接存取配置空间 , 计算机供应商不得不提供一个方 法来完成它 . 为存取配置空间 , CPU 必须写和读 PCI 控制器中的寄存器 , 但是确切的实现是依赖于供应商的 , 并且和这个讨论无关 , 因为 Linux 提供了一个标准接口来存取配置空间 .对于驱动, 配置空间可通过 8-位, 16- 位, 或者 32- 位数据传输来存取 . 相关的函数原型定义于 <linux/pci.h>:int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val); int pci_read_co
42、nfig_word(struct pci_dev *dev, int where, u16 *val);int pci_read_config_dword(struct pci_dev *dev, int where, u32*val);从由 dev 所标识出的设备的配置空间读 1 个, 2 个或者 4 个字节. where 参数是从配置空间开始的字节偏移 . 从配置空间取得的值通过 val 指针返回 , 并且这个函数的返回值是一个错误码 . word 和 dword 函数转换刚刚读的值从小端到处理器的本地字节序 , 因此你不必处理字 节序.int pci_write_config_byte(
43、struct pci_dev *dev, int where, u8 val); int pci_write_config_word(struct pci_dev *dev, int where, u16 val);int pci_write_config_dword(struct pci_dev *dev, int where, u32val);写 1 个 , 2 个或者 4 个字节到配置空间 . 象通常一样 , 设备由 dev 所 标识, 并且象通常一样被写的值被传递 . word 和 dword 函数转换这个 值到小端 , 在写到外设之前 .所有的之前的函数被实现为真正调用下列函数的内联
44、函数 . 可自由使用 这些函数代替上面这些 , 如果这个驱动在任何特别时刻不能及时存取 struct pci_dev :int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);int pci_bus_read_config_word (struct pci_bus *bus, unsigned intdevfn, int where, u16 *val);int pci_bus_read_config_dword (struct pci_bus *bus, unsign
45、ed intdevfn, int where, u32 *val);就象 pci_read_function 一样 , 但是 struct pci_bus * 和 devfn 变量 需要来代替 struct pci_dev *.int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val);int pci_bus_write_c on fig_word (struct pci_bus *bus, un sig ned int devfn, int where, u16 val);int pci_bus_write_config_dword(struct pci_bus *bus, unsigned intdevfn, int where, u32 val);如同pci_write_ 函数,但是struct pci_bus * 和devfn 变量需要来 替代 struct pci_dev *使用pci_read_函数寻址配置变量的最好方法是通过定义在<linux/pci.h>中的符号名.例如,下面的小函数获取一个设
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025合同模板中外来料加工合同范本
- 2025年个人贷款担保合同模板(三篇)
- 2025企业管理资料劳动合同书样本文档范本
- 2025年个人房屋包工包料装修合同标准版本(三篇)
- 2025年个人房屋简单租赁合同(2篇)
- 2025年中外来料加工合同标准样本(2篇)
- 个体工商户 劳动合同纠纷
- 2025年中小企业人员劳动合同(三篇)
- 个人承包工程合同范本
- 玩具制造企业玩具设计与生产合同模板
- 2024年微生物检测试剂行业商业计划书
- 河南开封介绍课件
- 通信设备售后服务方案
- 高中英语选择性必修一单词表
- 初中生物校本课程纲要
- 物业公司介绍
- 卖花生混声合唱简谱
- 数学方法在物理中的应用
- 【永辉超市公司员工招聘问题及优化(12000字论文)】
- 心肺复苏指南
- 《智能物联网导论》AIoT导论-第2章课件
评论
0/150
提交评论