驱动程序设计实用13篇

驱动程序设计
驱动程序设计篇1

TCD142D Driver Program Design

Xu Jing,Liang Hua

(Electronic&Information Institute of Nanchang Technology College,Nanchang330044,China)

Abstract:This research is mainly about the driver problems of TCD142D device using MCU.We use the KEIL software programs to compile and debug the program,achieving a better effect.

Keywords:TCD142D;Driver;CCD

一、绪论

TCD142D是一种电荷耦合器件(CCD,Charge Coupled Deviee),是一种以电荷包的形式存储和传递信息的固体成像器件。CCD作为一种光电转换器件,由于其具有精度高、分辨率好、性能稳定等特点,目前广泛应用于图像传感和非接触式测量领域。在CCD应用技术中,最关键的两个问题是CCD驱动时序的产生和CCD输出信号的处理。本文主要研究其驱动时序的产生问题。

由于在CCD应用系统中,一般都要用到微处理器,所以若采用“软件驱动”法,则无需增加硬件,在电路结构上最为简单,系统成本也最低,本文主要利用单片机,通过程序编程直接在I/O口上输出所需的各路驱动脉冲信号,是由程序指令的延时或者定时器中断产生,这种驱动时序产生方法的特点是调节时序灵活方便,编程简单,可在线调整驱动频率。

二、系统的设计

该系统由4部分组成:电源模块、单片机控制模块、电平转换模块、TCD142D电路。其中,电源系统在设计上选用常用的LM78/79系列三端稳压块来实现。单片机则选用常用的ATMEL公司生产的AT89S51单片机,对整个系统进行时序控制,编程输出的时序信号送入电平转换及驱动模块,该模块完成对TTL电平的转换,使得输出信号满足TCD142D的输入要求,该模块由高速驱动芯片DS0026来实现。TCD142D则只要负责接收前级输出的信号,并输出像元数据。

(一)TCD142D简介

TCD142D的驱动电路有4路脉冲,即SH、Ф1、Ф2、RS四路。SH是光电荷转移脉冲,其下跳沿即每幅图象输出的起始点。Ф1、Φ2为两相交变脉冲电压(相位差为90°),它们将转换到移位寄存器上的光电荷向输出极传递。RS为输出极复位脉冲,它可清除输出极输出一个单元的电荷后所剩电荷,以保证下一个单元的电荷电压的正确输出。

(二)TCD142D驱动脉冲的实现

在单片机89S51产生ΦSH、Φ1、Φ2、ΦRS四路驱动脉冲的作用下,TCD142D输出OS信号。显然,可以用单片机89C51的一个8位锁存输出口取其中的4位按照波形要求变化输出数据,这四位是1或者是0就决定了它们是高电平还是低电平,从而产生这四路驱动信号。

图1驱动信号波形的六个状态

图1中TCD142D 驱动信号波形图中把一个周期分为6个状态,在图中用虚线把各个状态转变点标记出来。可以看到,每经过1/6周期或者是1/3周期,单片机就要输出新的数据.既然使用单片机来驱动CCD,那么就要考虑单片机的输出脉冲频率与CCD工作脉冲的匹配问题.TCD142D的时钟范围是0.1~20MHz,可以看出时钟频率的最小值要求是0.1MHz。AT89S51单片机的最高工作频率是24MHz,可达到设计要求。仔细研究CCD时序的一个周期中的六次状态变化,安排好单片机口输出与CCD信号的对应关系。设计了如下的程序:

LOP:MOV P1,#0EH

NOP

NOP

NOP

CLR P1.1

MOV P1,#0BH

NOP

NOP

JBC P1.1,LOP

在程序中,执行完第一条指令后P1口输出时长为2μs的数据0EH,在其后的循环程序较多的使用了单机器周期指令和空操作指令,最后一条指令是双机器周期指令,这条指令既输出两个机器周期的0BH,又返回了循环程序。由TCD142D时序图可知,1061个移位脉冲周期后就要脱离循环,而进入下一过程,因此在程序中可以采用中断技术。把单片机内部的定时/计数器置成计数方式,计数初值设为1061,把Φ1的输出接至计数器输入端,对Φ1信号的下降沿进行计数。在计数器计满1061后便自动向单片机申请中断。

三、总结

用单片机产生的CCD驱动信号,在硬件设计上只需要在单片机的一个口的四位输出加上电平转换电路后接往CCD对应管脚.结构简单、可靠。其软件设计由于采用了循环程序及中断技术,总共只需要30多条指令,十分简单,这样产生的移位脉冲频率可达到200kHz左右,符合线阵TCD142D的工作要求。对于不同型号的线阵CCD,只要适当调整时序及程序即可得到需要的驱动时序。

驱动程序设计篇2

一、引言

嵌入式系统的硬件组成除了包括中心控制部件嵌入式系统处理器外,还有输入输出装置以及一些扩充装置开关、按键、传感器、模数转换器、LCD显示器、触摸屏及LED(发光二极管)等嵌入式硬件设备。嵌入式硬件环境是整个嵌入式操作系统和应用程序运行的硬件平台,不同的应用通常有不同的硬件环境[1]。硬件平台的多样性是嵌入式系统的一个主要特点。如何让这些设备工作起来,是嵌入式驱动程序的任务。由于I/O设备种类繁多,工作模式各不相同,驱动程序是整个嵌入式软件设计中最复杂、代码量最大、最繁琐的部分。

二、嵌入式驱动程序概述

外设驱动程序可以对系统提供访问设备的接口,把操作系统(软件)和设备(硬件)分离开来。当设备改变的时候,只需要更换相应的驱动程序,不必修改操作系统的内核以及运行在操作系统中的软件。系统的驱动程序要受控于相应的操作系统的多任务之间的同步机制。在操作系统中使用信号量、邮箱等机制进行协调。操作系统只和特定的驱动抽象层通讯,无论在抽象层下面对应的是什么类型的设备,对操作系统和用户的应用程序来说都是统一的接口[2]。驱动抽象层位置图如图1所示。

图1:驱动抽象层位置图

该部分包括基于ARM架构的串行口通讯、键盘驱动原理、I/O接口电路、A/D接口电路、LCD的驱动控制、触摸屏程序设计的内容。

三、嵌入式驱动程序设计研究

1.串行口通讯

通过监视串行口,把我们在程序中插入的想要反馈程序运行情况的串行口语句输出到显示器中的超级终端中。这样便可以实时监控程序的运行情况,方便调试程序。串行口组件设计是将接收到的字符再发送给串口(计算机与开发板是通过超级终端通讯的),即按PC键盘通过超级终端发送数据,开发板将接收到的数据再返送给PC,在超级终端上显示[3]。

要想设计好串行口驱动程序,需要做如下几步:

(1)熟悉串口通讯原理;

(2)查阅ARM串口寄存器文档,包括S3C2410控制、状态和数据寄存器;

(3)查阅电平转换芯片资料(max3232);

(4)设计硬件电路图;

(5)设计串口驱动(包括串口寄存器初始化,发送接收函数等)。

异步通信必须遵循的3项规定为:

(1)字符的格式

(2)波特率

(3)校验位

初始化时需要设置波特率、停止位、奇偶校验、数据位等参数。异步串行方式是将传输数据的每个字符一位接一位(例如先低位、后高位)地传送。数据的各不同位可以分时使用同一传输通道,因此串行I/O可以减少信号连线。如图2给出了异步串行通信中一个字符的传送格式。

图2:串行通信字符格式

开始前,线路处于空闲状态,送出连续“1”。传送开始时首先发一个“0”作为起始位,然后出现在通信线上的是字符的二进制编码数据。每个字符的数据位长可以约定为5位、6位、7位或8位,一般采用ASCII编码。后面是奇偶校验位,根据约定,用奇偶校验位将所传字符中为“1”的位数凑成奇数个或偶数个。也可以约定不要奇偶校验,这样就取消奇偶校验位。最后是表示停止位的“1”信号,这个停止位可以约定持续1位、1.5位或2位的时间宽度。至此一个字符传送完毕,线路又进入空闲,持续为“1”。经过一段随机的时间后,下一个字符开始传送才又发出起始位。

2.键盘驱动原理

键盘的设计是将一个瞬时接触开关放置在每一行与每一列的交叉点。矩阵所需的键的数目显然根据应用程序而不同。每一行由一个输出端口的一位驱动,而每一列由一个电阻器上拉且供给输入端口一位。键盘扫描过程就是让微处理器按有规律的时间间隔查看键盘矩阵,以确定是否有键被按下。一旦处理器判定有一个键按下,键盘扫描软件将过滤掉抖动并且判定哪个键被按下。每个键被分配一个称为扫描码的唯一标识符。应用程序利用该扫描码,根据按下的键来判定应该采取什么行动。如图3所示为逐行扫描法工作原理:逐根行线输出0电平,而其他行线保持高电平;同时检测列,列全1就没有键按下,0有键按下。行线和列线状态组合在一起就确定了是哪个键按下,如110 1110是0键按下,1010111是7键按下。

图3:逐行扫描法原理图

3.I/O接口电路

I/O系统的目标是对RTOS和应用程序员隐藏设备特定的信息,并且对系统的I/O设备提供一个统一的访问方法。下面是从不同角度看I/O系统:

(1)从系统软件开发者角度看,I/O操作意味着与设备的通信、对设备编程初始化和请示执行设备与系统之间的实际数据传输以及操作完成后通知请求者。系统软件工程师必须理解设备的物理特性,如寄存器的定义和设备的访问方法。

(2)从RTOS的角度看,I/O操作意味着对I/O请求定位正确的设备,对设备定位正确的设备驱动程序,并解决对设备驱动程序的请求。有时要求RTOS保证对设备的同步访问。RTOS必须进行抽象,对应用程序员隐含设备的特性。

(3)从应用程序员角度看,目标是找到一个简单、统一和精练的方法与系统中出现的所有类型的设备。

I/O接口的编址方式分为两种:

(1)I/O接口独立编址――端口映射方式

这种编址方式是将存储器地址空间和I/O接口地址空间分开设置,互不影响。设有专门的输入指令(IN)和输出指令(OUT)来完成I/O操作。

(2)I/O接口与存储器统一编址方式――内存映射这种编址方式不区分存储器地址空间和I/O接口地址空间,把所有的I/O接口的端口都当作是存储器的一个单元对待,每个接口芯片都安排一个或几个与存储器统一编号的地址号。也不设专门的输入/输出指令,所有传送和访问存储器的指令都可用来对I/O接口操作。

4.A/D接口电路

A/D转换器能将模拟量转换为数字量的电路;D/A转换器能将数字量转换为模拟量的电路。A/D转换器和D/A转换器是沟通模拟电路和数字电路的桥梁,也可称之为两者之间的接口。A/D 转换器是模拟信号源和CPU 之间联系的接口,它的任务是将连续变化的模拟信号转换为数字信号,以便计算机和数字系统进行处理、存储、控制和显示。一般A/D转换过程要经过采样、保持、量化和编码四个步骤。前两步在取样―保持电路中完成,后两步则在A/D转换器中完成。D/A转换器的基本原理是将输入的每一位二进制代码按其权的大小转换成相应的模拟量,然后将代表各位的模拟量相加,所得的总模拟量就与数字量成正比,这样便实现了从数字量到模拟量的转换。

A/D转换器较常用的是逐次逼近型,如图4所示。转换前,先将SAR寄存器各位清零。转换开始时,控制逻辑电路先设定SAR寄存器的最高位为“1”,其余位为“0”,此试探值经D/A转换成电压Vc,然后将Vc与模拟输入电压Vx比较。如果Vx≥Vc,说明SAR最高位的“1”应予保留;如果Vx

图4:逐次逼近式A/D转换原理图

5.LCD的驱动控制

LCD显示器的基本原理就是通过给不同的液晶单元供电,控制其光线的通过与否,从而达到显示的目的。因此,LCD的驱动控制归于对每个液晶单元的通断电的控制,每个液晶单元都对应着一个电极,对其通电,便可使光线通过。

液晶模块有两种工作模式:图形方式和文本方式。在图形方式下,模块上的缓冲区映射的是液晶屏上显示的图形点阵;在文本方式下,模块上的缓冲区对应的是液晶屏上显示的文本字符,包括英文字符和英文标点符号。因为汉字字库没有包含在液晶模块之中,所以液晶屏在文本方式下只能显示英文,不能显示汉字。液晶屏的操作主要包括:初始化、设置液晶屏的工作模式(文本或者图形)、更新显示、开启(或者关闭)背光等。

6.触摸屏程序设计

触摸屏是专门处理是否有笔或手指等物体按下触摸屏,平常相互绝缘的两层导电层就在触摸点位置有了一个接触,并在按下时分别给两组电极通电。因其中一面导电层(顶层)接通X轴方向的5V均匀电压场,使得检测层(底层)的电压由零变为非零,控制器侦测到这个接通后,其对应位置的模拟电压信号经过A/D转换送回处理器。经过坐标转换后,得到触摸点的x/y坐标。

触摸屏接口专用芯片ADS7843是Burr-Brown公司生产的,能够完成电极电压的切换及采集接触点处的电压值,并进行A/D转换。在完成一次x/y坐标采样的过程中需要一次模式转换即在点击触摸屏之前是等待中断模式,当有触摸动作产生触摸屏中断以后,在x/y的坐标采集驱动中设置成自动的x/y位置转换模式,在完成采集以后再转换回等待中断模式,准备下一次的触摸采样。

四、总结

嵌入式驱动程序设计渗透在掌上电脑、笔记本电脑和手机等各个领域,这些设备要想正确工作,必须借助相应硬件及其驱动程序。随着嵌入式系统在工业控制领域、智能机器人、移动通讯以及智能家电、网络家电的应用,驱动程序设计方面的开发人员需求量也会越来越多。

基金项目:北京信息科技大学《嵌入式系统安全》课程建设项目

[参考文献]

[1]王小妮、魏桂英、杨根兴. 嵌入式组件设计[M].北京航空航天大学出版社,2012

驱动程序设计篇3

在程序设计课程的教学中,教师采用任务驱动教学法大多是把任务布置给学生并作简单讲解后,由学生自己看书学习完成任务,学生的创新能力和独立分析问题、解决问题的能力明显提高,但这种教学法也有缺陷,主要是学生自学太多,总体学习效率较低,学生各自为证统一性差,而且没有改变不同层次学生学习的问题,鉴于这些原因,我们可把“任务驱动”和“分组”两种教学法结合起来应用,教学效果会更好。

一、分组

1、分组前的工作

分组前要对全班各个学生的学习能力和知识基础有全面深入的了解,要发现和培养学生中的学习带头人,这个过程往往要占去全部课程学习时间的1/3左右,在分组前的教学可用不分组的任务驱动教学法或讲解——上机——点评归纳的教学法,边教学边了解学生,同时教学的进行使学生打下一定的理论基础和制作技能。

2、怎样分组

一个班级有几十个学生,可分为若干个学习小组,但分组数不宜超过5组,组数太多使每组人数太少不便于对学生作统一要求,教师兼顾太多组亦会顾此失彼;每个小组要确立一至二名学习带头人作为学习小组长,同时兼顾学生间的友情和合作,方便互相学习,好中差三类学生适当搭配完成分组。

二、任务驱动下的分组学习

1、设置任务

教师精心设置任务是教学成功的第一步,如果要学习的新知识点多,我们可把教材中的每一章设计成一个大任务,再将大任务分为若干小任务,每一节又由一个或几个小任务组成;在教材和各种参考资料中会有许多练习题,任务驱动学习要求精选习题配合新知识点学习,而不是做大量习题的“题海战术”;如果已经把大多数的新知识点学完,我们就要设置综合程序设计任务,培养学生综合运用知识技能进行程序开发设计的能力。

对于同一章节的学习或同一部分内容所设置的任务,任务可准备多个,便于把任务分配到各个学习小组使用。

2、任务的分配

在分配任务到各个小组之前,教师应招集各个小组长进行研讨学习,小组长在教师的提点下提出自己学习并完成任务的思路,教师甚至可以让小组长先行去完成任务,使小组长能更好地带领全组同学完成任务。当这些准备工作做好后,就可以把任务分发到各个小组的学生中去,要让每个学生都明确完成任务要用到的新知识点和任务要求所要达到的目的,使他们有的放矢去学习并完成任务。各个小组间的任务可以相同,也可以不同。如果任务相同,在学生学习完成同一任务的过程中,教师把各个小组完成任务的优劣进行对比讲评,在各个小组之间形成竞争,提高学习效率,同时使对全班学生的统一要求达到更好的效果。如果各个小组的任务不同,可以使全班分小组学习应用不同的知识点,各个小组完成任务后进行小组之间的交叉对比学习,最终使各个小组都能完成多个任务,全班学生接触到更广阔的知识面,取得更高的学习效率。

3、任务的完成

完成任务的过程就是学生学习运用知识点进行程序设计的过程,在这个过程中学生是学习的主角,因为教师在之前已经培训了各个小组长,他们在各个小组学生学习完成任务的过程中要起到以点带面的作用,其实由已经学会了的学生去教那些正在学习的学生会有不错的教学效果。教师在这个过程中要做的就是督促和鼓励学生去完成任务,当然,对于学生的典型问题教师可以分小组或在全班进行讲解,保证不会因为“卡壳”造成学习效率的降低。

当各个小组的任务完成到一定程度时,教师要及时调用学生的程序,在全班进行演示点评,造成班级中各个小组之间一种竞争为了更好地完成任务的态势,同时也是小组之间相互借鉴学习的机会。通过这样的学习并完成任务的过程,各个学生按任务要求所做的作品既有个人的创造性,又能达到任务要求的统一标准,学生作品的水平普遍比其它教学方法要高得多。

驱动程序设计篇4

Abstract:This paper introduces the design of Device Drivers of PCI synchronous clock card based on WDF model. Briefly introduces the system architecture and works on our own PCI synchronous clock card, and Analysis the framework of the WDF model and the design process. Focused on the research and development of the WDF Device Drivers based on the PCI synchronous clock card, including hardware access, Interrupt notification. The driver has passed the test for stability and reliability.

Key words: WDF; PCI; interrupt; driver; synchronous clock card.

时间是科学实验、科学研究和工程技术等领域中的一个基本物理参量。为了保证系统各部分时间的一致性和正确性,系统内各设备的同步时钟从卡从时钟源获取高精度的标准时间,提供给相应设备。这样系统内各设备的时间与时间源相同而保持一致。同步时钟卡一般采用PCI总线方式。PCI总线能够实现设备间的快速访问,它以突出的性能受到计算机和通信界工程师们的青睐。

因此如何开发出稳定、可靠、高效的PCI设备驱动程序成为驱动工程师们面临的一个棘手的问题[5]。过去对于PCI设备驱动程序的开发大多采用WDM(Windows Driver Model)框架,但是它编程比较复杂,快速掌握其开发要领对于初学者来说比较困难[5]。本文所述的PCI同步时钟卡的驱动程序的开发采用微软最新推出的WDF(Windows Driver Foundation)驱动模型。WDF驱动模型提供事件驱动和面向对象的驱动程序开发框架,大大降低了设备驱动程序的开发难度[5]。

1 同步时钟卡系统架构

本文所述的驱动程序是基于自行研发的PCI同步时钟卡,其原理框图如图1所示。本同步时钟卡选择PCI9052芯片做为PCI总线的接口芯片。该电路除了用到PCI9052外,还用到了单片机、EEPROM、双口RAM、CPLD。单片机是系统的控制单元;串行EEPROM存储了PCI9052芯片所需要的配置信息;双口RAM用于PC机与时钟卡之间交换数据;CPLD用于200us时标的产生和中断的控制。

同步时钟卡的工作流程如下:同步时钟从卡接收时钟源输出的时间信号,单片机将其解析成高精度的同步时间信息,控制逻辑(CPLD)通过1PPS脉冲信号产生200us的高精度时间刻度,于是产生高精度的同步绝对时标,连续存储于双口RAM中,最后计算机通过PCI总线接口获取高精度的绝对时间。本系统中计算机获取双口RAM中的时间数据的方式有两种:(1)PC机主动读取双口RAM中的数据。(2)外部事件通过中断通知PC机事件发生,PC机收到通知后读取双口RAM中的时间信息,可获得外部事件发生的精确时刻。两种方式分别涉及驱动程序的硬件访问和中断通知。于是涉及到本文介绍的重点:基于WDF模型的PCI总线驱动程序的开发。

2 WDF驱动程序设计

微软对过去的WDM(Windows Driver Model)驱动程序的架构做了改进,形成了全新的WDF(Windows Driver Foundation)框架结构。它将原来普通软件开发中面向对象的技术应用到了驱动程序的开发中。WDF改变了驱动程序与操作系统内核之间的关系,在传统的WDM驱动程序中,不仅要处理硬件,还要处理驱动程序与操作系统内核之间的交互[4]。现在WDF则使驱动程序与操作系统内核独立开来,驱动程序与操作系统交互工作将由框架内封装的方法(函数)去完成,这样驱动开发工程师只需专注处理目标硬件的行为即可,避免了两面不周顾此失彼的弊端。不仅大大降低了驱动程序的代码量,还使整个系统更加稳定、可靠。

WDF驱动程序包括两个类型,一个是内核级的,称为KMDF(Kernel-Mode Driver Framework);另一个是用户级的,称为UMDF(User-Mode Driver Framework)。本文所述的驱动程序采用KMDF模式。

2.1 WDF驱动程序开发流程

本文所用开发环境为Microsoft Windows Driver Kit(WDK) 8.1和Microsoft Visual Studio 2013,操作系统为Windows7。先安装VS2013,再安装WDK8.1,便可在VS2013中直接创建KMDF工程。根据同步时钟卡所需功能编写好驱动程序即可进行编译。

WDF驱动程序框图如图2所示。

2.2 基于WDF模型的PCI设备驱动程序的实现

WDF模型的设备驱动程序从功能上可分为三个部分:初始化设备、控制设置与交换数据[3]。初始化设备主要实现设备的识别、驱动对象与设备对象的建立与硬件资源的分配;控制设置负责应用程序与驱动程序的连接和设备的打开;交换数据处理的是设备功能的具体应用,即PCI总线与同步时钟卡之间的数据传输。

从本质上来说,WDF模型的设备驱动程序是由入口函数DriverEntry和事件例程及其子函数组成的[3]。操作系统在第一次加载驱动程序时会通过调用DriverEntry例程来完成设备驱动程序和框架的初始化[3]。所有的驱动程序都必须包含一个DriverEntry例程。对于不同类型的驱动程序其入口函数DriverEntry也不同,可分为:设备驱动、纯软件驱动与过滤驱动。本文所述的PCI总线驱动程序属于设备驱动,在入口函数DriverEntry中,主要完成两件事:注册EvtDriverDeviceAdd回调例程、创建和初始化WDFDRIVER对象。

WDF_DRIVER_CONFIG_INIT(&config,PCIdriverEvtDeviceAdd);

//注册EvtDriverDeviceAdd回调例程

status = WdfDriverCreate(DriverObject, RegistryPath,...);

//创建驱动对象

2.2.1初始化设备

在驱动程序被成功初始化完成之后,操作系统会顺序调用EvtDriverDeviceAdd、EvtDevicePrepareHardware等回调例程以实现所控制的设备的初始化。

当首次枚举设备时,EvtDriverDeviceAdd例程在系统初始化时被PnP管理器调用。在系统运行过程中,任何时候一个新的相同设备被枚举,系统都将调用此例程。EvtDriverDeviceAdd例程是设备初始化过程中最新被调用的回调例程,它需要完成:设备对象的创建,创建符号链接或设备对象GUID接口,创建一个或多个I/O队列,各种事件的回调函数的注册,如即插即用、电源管理、I/O处理例程等[1]。

EvtDriverDeviceAdd例程的主要代码如下所示:

注册即插即用基本例程:

WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

pnpPowerCallbacks.EvtDevicePrepareHardware = PCIDriverEvtDevicePrepareHardware;

pnpPowerCallbacks.EvtDeviceReleaseHardware = PCIDriverEvtDeviceReleaseHardware;

..........

WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

创建设备对象:

WDF_FILEOBJECT_CONFIG_INIT(&f_config,...);

WdfDeviceInitSetFileObjectConfig(DeviceInit, &f_config,WDF_NO_OBJECT_ATTRIBUTES);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, ..);

status = WdfDeviceCreate(&DeviceInit, &attributes, &control_device);

创建队列对象并注册回调例程:

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,....);

ioQueueConfig.EvtIoDeviceControl = PCIdriverEvtIoDeviceControl;

ioQueueConfig.EvtIoStop = PCIdriverEvtIoStop;

status = WdfIoQueueCreate(control_device,&ioQueueConfig,...);

创建符号链接:

status = WdfDeviceCreateSymbolicLink(control_device, &ustring);

创建中断对象:

deviceContext = GetDeviceContext(control_device);

WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,PCIDriverEvtInterruptIsr,

PCIDriverEvtInterruptDpc);//设置中断服务例程和延迟过程调用WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&interruptAttributes,..);

status = WdfInterruptCreate(control_device,&interruptConfig,

&interruptAttributes,&deviceContext->Interrupt);

EvtDriverDeviceAdd例程调用完成之后,系统将调用EvtDevicePrepareHardware例程初始化地址指针,将设备所占用的I/O地址和内存地址映射为虚拟地址,驱动程序将通过这些虚拟地址完成与设备的数据传输。由于串行EEPROM存储了PCI9052芯片所需要的配置信息,系统将自动为本文所述的PCI同步时钟卡分配资源,它们包括双口RAM的内存地址、PCI9052的I/O地址空间,所以EvtDevicePrepareHardware例程必须将这些资源映射为虚拟地址。对于I/O端口,只需将首地址与地址数目值保存在设备上下文;对于存储器芯片,调用MmMapIoSpace函数将物理地址映射为系统内核虚拟地址,然后保存于设备上下文。相对应的,当设备被卸载时,系统会自动调用EvtDeviceReleaseHardware回调例程释放之前申请的硬件资源。

for (i = 0; i < WdfCmResourceListGetCount(ResourceListTranslated); i++) {//WdfCmResourceListGetDescriptor函数获取该资源的描述符

descri = WdfCmResourceListGetDescriptor(ResourceListTranslated, i);

switch (descri->Type)

{case CmResourceTypeMemory:

Mem_Count++;

if (Mem_Count == 2)//将双口RAM地址映射为虚拟地址

{pDevice_context->MemBaseAddress = MmMapIoSpace(

descri->u.Memory.Start,

descri->u.Memory.Length,

MmNonCached);

pDevice_context->MemLength = descri->u.Memory.Length;}

break;

case CmResourceTypePort://将PCI9052的I/O地址映射为虚拟地址

pDevice_context->Io_baseAddress = descri->u.Port.Start.LowPart;

pDevice_context->Io_length = descri->u.Port.Length;

default:

break;}}

2.2.2控制设置与数据交换

应用程序实现和驱动程序通信的过程是:应用程序首先调用CreateFile函数打开设备,然后可以使用DeviceIoControl和驱动程序通信,包括写数据给驱动程序和从驱动程序读数据两种情况,也可以用WriteFile写数据给驱动程序或用ReadFile从驱动程序读数据,当应用程序退出时,调用用CloseHandle关闭设备。本文所述的系统是用DeviceIoControl和驱动程序通信。CreateFile打开设备的方式有两种:符号链接名与GUID接口,本文所述驱动程序采用的是符号链接名的方式。

m_hDevice=CreateFile(sLinkName,...);//以符号链接名的方式打开设备

上述代码中sLinkName为符号链接名,它与驱动程序中设置的符号链接名相同。m_hDevice为返回的设备的有效句柄,应用程序就可以应用它调用DeviceIoControl函数与驱动程序交换数据。应用程序的请求会被放入请求队列中,并在EvtIoDeviceControl函数之中被处理。

本文中应用程序获取时钟卡上的时间信息的方式有两种:(1)直接读取。(2)中断方式。

对于第一种方式,应用程序直接调用DeviceIoControl函数与驱动程序交换数据。由于系统的双口RAM被映射到虚拟内存,驱动程序可以使用下面两条指令对双口RAM进行读写: READ_REGISTER_XXX;//读双口RAM,WRITE_REGISTER_XXX;//写双口RAM。

对于中断方式,当被捕获的外部事件发生时,驱动程序会进入中断服务例程EvtInterruptIsr,然后进入延时过程调用EvtInterruptDpc,首先清中断源,然后将双口RAM中的时间数据读取到设备上下文中缓存,该数据即为外部事件发生的时间,最后通知应用程序读取该数据。应用程序将调用DeviceIoControl函数获取设备上下文中的时间信息。驱动程序与应用程序通信的方法有两种:DeviceIoControl异步完成和WIN32事件通知。本文所述系统采用WIN32事件通知的方法。对于此种方法,应用程序初始化时首先生成一个通知事件,并通过DeviceIoControl函数的输入缓冲区发送给驱动程序,驱动程序创建相应的内核事件,同时使能PCI9052的LINT1中断,当该事件发生时,驱动程序会通知应用程序,应用程序的一个子线程不停的循环等待驱动程序发来的事件发生通知。当设备被卸载时需要撤销该内核事件。具体主要代码如下:

应用程序生成通知事件:

mhEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

应用程序子线程中等待事件发生:

while (WaitForSingleObject(mhEvent, 0) != WAIT_OBJECT_0)

{...}

驱动程序创建相应的内核事件:

ObReferenceObjectByHandle(....);

允许PCI中断,使能PCI9052的本地LINT1中断,pREG为PCI9052映射的I/O空间的基 地址:

inter = READ_PORT_USHORT(pREG + 0x4c);

inter |=0x43;

WRITE_PORT_USHORT(pREG + 0x4c, inter);

清中断源,设置PCI9052的CS3引脚有效,通知CPLD清掉LINT1信号:

inter = READ_PORT_USHORT(pREG + 0x50);

inter |= 0x800;

WRITE_PORT_USHORT(pREG + 0x50, inter);

驱动程序给应用程序发送事件,通知应用程序读取数据:

KeSetEvent(pDevice_context->Event, 0, FALSE);

驱动程序内撤销内核事件:

ObDereferenceObject(...);

3 结语

驱动程序是硬件与应用程序通信的桥梁,它对系统性能提升的作用举足轻重。高效、稳定、可靠的驱动程序可以使系统性能得到很好的提升。

本文简要介绍了PCI同步时钟从卡的工作原理,并重点讨论了基于WDF模型的PCI设备驱动程序设计方法。本文所述的PCI同步时钟卡驱动程序,在WDK8.1中成功编译,自动生成SYS文件(驱动程序代码)和INF文件(设备安装信息),成功安装并且能够稳定可靠地运行。经测试,捕获的时间精度达到误差小于200us,满足系统设计要求。涉及本驱动程序的系统已应用于三峡大坝左岸发电厂发变机组的故障录波系统中,运行稳定可靠。总而言之,WDF驱动模型优化并简化了设备驱动程序的开发,比传统的WDM驱动模型更加稳定。

参考文献

[1]武安河.Windows设备驱动程序WDF开发[M].北京:电子工业出版社,2009.

[2][美]Ronald D. Reeves 著,张猛等 译.Windows设备驱动程序开发[M].北京:人民邮电出版社,2012.

驱动程序设计篇5

USB 协议是1994年底由康柏、IBM、英特尔等几家公司联合提出来的外部总线接口协议。USB就是英文中Universal Serial Bus(通用串行总线)的缩写。USB总线具有其他总线所不具备的如:热插拔、数据传输可靠、扩展方便、成本低等一系列特点,因此在嵌入式系统中被广泛使用。

一个USB系统一般是由一个USB主机控制器、一个或多个USB集线器和一个或多个USB设备节点组成。USB系统的物理连接具有层次性。USB总线连接USB设备和USB主机,是一种星型拓扑结构。USB的拓扑结构如图1所示。

在一个USB系统传输数据的过程中有两个非常重要的概念,就是USB传输模式和USB描述符。USB传输模式是指USB设备传输数据的形式。USB设备支持四种传输模式:控制传输模式、同步传输模式、中断传输模式和批量传输模式。控制传输模式是用来处理USB主端口到USB从端口的数据传输,主要是设备控制指令、设备查询状态指令和确认指令。同步传输模式是指传输和时间关系密切的信息所使用的一种传输方式,是一种周期的、连续的单向传输方式。中断传输模式这类传输模式主要用于传输非周期性的、自然发生的、数据量很小的信息,这类数据传输的方向是从设备到主机,适用于键盘、鼠标、操纵杆等设备上。最后一种是批量传输模式,该模式适用于大量的、对时间没有要求的数据传输,如U盘或者移动硬盘等设备。

USB设备在逻辑上分为几个层次,分别是设备层(Device)、配置层(Config)、接口层(Interface)、端点层(Endpoint)。各个层次都有与之相对的描述符,分别是设备描述符、配置描述符、接口描述符和端点描述符。

2 Linux下的USB驱动框架

USB设备的设备描述符在Linux系统中用usb_device_descriptor结构体表示,它描述了USB设备的一般信息。配置描述符用usb_config_descriptor结构体表示,它给出了USB设备的配置信息。接口驱动程序是在一个配置内给出一个接口信息,它在Linux中由usb_interface_descriptor结构体表示。端口描述符被主机用来决定每个端口的带宽需求,它在Linux系统中由usb_endpoint_descriptor结构体表示。

编写一个USB驱动程序,是从usb_driver结构体开始的。Linux中模块加载函数调用usb_register()和usb_unregister()从而对usb_driver结构体进行加载与卸载。如果某个设备信息与该驱动中usb_device_id usb_mouse_id_table 结构体的信息相一致,则会调用usb_driver中探测成员函数probe(),将初始化USB断点信息,并对设备做一些初始化工作,分配urb结构体,准备数据传输。其urb处理大致框架结构如图2所示。

当鼠标设备在用户空间打开时,将提交 probe 函数构建的 urb 请求块,urb 将开始为传送数据而忙碌了。urb 请求块就像一个装东西的“袋子”,USB 驱动程序把“空袋子”提交给 USB core,然后再交给主控制器,主控制器把数据放入这个“袋子”后再将装满数据的“袋子”通过 USB core 交还给 USB 驱动程序,这样一次数据传输就完成了。

3 结束语

由于USB简单方便快捷等优点,许多外接设备会越来越青睐USB接口,这是一种发展的趋势。Linux系统具有开源、安全等特性,用户也在急剧增加。届时,会有越来越多的USB驱动加入Linux内核之中。

参考文献

[1]Jonathan Corbet,Alessandro Rubini,Greg Kroah-Hartman等.LINUX设备驱动程序[M].北京:中国电力出版社,2006.

[2]Universal Serial Bus Specification Compaq,Intel,Mi―crosoft,NEC Revision 1.1.September 23,1998.

[3]温卡特斯瓦兰.精通Linux驱动程序开发[M].北京:人民邮电出版,2009.

[4]胡晓军,张爱成.USB接口卡发技术[M].西安:西安电子科技大学出社,2005:15-17.

作者简介

驱动程序设计篇6

1系统硬件结构介绍

本系统的硬件平台主要由OK2440开发板、基于MCP2515的CAN总线通信模块和以STC89C52为控制器的CAN节点模块组成。CAN通信模块用来完成OK2440开发板和STC89C52控制的节点模块之间的数据传输。

1.1 MCP2515功能简介

MCP2515是一款独立的CAN总线控制器,完全支持CAN V2.0B 技术规范。MCP2515 拥有六个验收滤波寄存器和两个验收屏蔽寄存器,通过它们可以过滤掉总线上不需要的报文,从而减少MCU关于处理CAN总线上无用数据的开销。MCP2515与MCU 的连接是通过业界标准串行外设接口来实现的。

1.2 TJA1050功能简介

TJA1050 是介于CAN控制器和物理总线之间的一种符合ISO 11898标准的高速CAN收发器。其最高速率可达1Mbit/s,而且它的电磁抗干扰EMI性极高,至少可以连接110个节点。在实际电路中,可为物理总线提供差动发送和为CAN控制器提供差动接收。

2 MCP2515相关驱动程序设计

2.1 Linux设备驱动简介

在Linux系统中,由于对硬件的操作必须处在特权模式下,在用户工作模式下,程序一般不能直接和硬件进行通信。因此,设备驱动程序则承担了用户模式下硬件和用户应用程序之间的通信工作,同时它还为应用程序和内核中其他的部分访问这些设备提供了程序接口。大多数设备驱动程序可以在系统工作时,以动态方式进行加载,在不需要的时候又可以将其卸载掉。

2.2 MCP2515驱动程序设计

2.2.1 MCP2515驱动初始化函数

在MCP2515的驱动初始化函数中首先通过s3c2440_spi_ioremap()函数将S3C2440上的SPI寄存器的物理地址映射到内核空间,这样才可以在驱动程序中访问和配置S3C2440的SPI寄存器。在正确的配置S3C2410的SPI寄存器后,通过s3c2440_spi_init()来完成对S3C2440相关寄存器的赋值。然后通过s3c2440_irq_init()函数来完成中断方面相关的设置。MCP2515_init()和MCP2515_dev_init()两个函数主要是针对于MCP2515控制器进行相关的配置和为MCP2515设备驱动程序申请和初始化内存空间。最后通过MCP2515 _cdev_register(Device0)函数完成MCP2515在内核中的注册。

2.2.2 MCP2515相关中断函数的注册

在CAN总线驱动程序中,CAN通信模块接收和发送数据必须以中断的方式与系统内核之间进行数据的交换,所以在MCP2515的驱动程序中必须用到内核中的相关中断函数。对于MCP2515的中断注册函数request_irq(),如果此中断注册函数返回值为0则表示中断注册成功,返回负数则表示注册失败。

2.2.3 MCP2515的文件操作函数

MCP2515_fops中定义了很多与设备有关的操作函数,内核可以通来它来访问与MCP2515操作有关的函数。在MCP2515的文件操作函数中,read()和write()两个函数是用来完成读写CAN总线上数据的功能的,通过传递不同的参数给驱动程序中的read()和write(),我们可以读取和写入相应的数据。驱动中的CAN总线读函数read()是整个驱动程序设计的难点,其中在函数的设计中采用了Linux内核阻塞机制。read()读取完CAN总线上的数据后,通过验收滤波寄存器和屏蔽滤波寄存器来决定总线上的数据帧是否存入到总线控制器相应的接收缓冲寄存器里。

2.2.4 MCP2515的卸载函数

当我们不需要继续使用某个设备时,我们可以将这个设备从内核中卸载掉。在设备的卸载过程中,必须将其内核中所对应的设备号释放掉。在模块的卸载函数中,我们通过调用int unregister_chrdev_region(unsigned int major,const char *name)函数来完成设备驱动的卸载。此函数的两个参数分别对应设备文件的主设备号和设备名。在卸载模块时,Linux内核会把设备名与内核中已注册的设备名称进行对比,如果两者相等,则完成设备的卸载,反之则卸载失败。MCP2515的驱动卸载函数主要是完成MCP2515驱动在内核中所占用的中断的释放和MCP2515在内核中的注销。

3 结语

本文重点讨论了S3C2440中MCP2515的驱动程序设计方法,并详细介绍了Linux系统下如何开发MCP2515的驱动程序的方法。实验结果表明,本文所设计的Linux下MCP2515驱动程序可以在OK2440开发板上正常运行,基本可以完成CAN总线上数据的正常发送与接收,测试结果符合论文的要求。本文提到的基于Linux下MCP2515驱动程序的开发,对其他Linux驱动程序的开发具有一定的启示作用。

参考文献

[1]宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.

[2]杨庆华,张景元.单片机和MCP2515的CAN总线通信模块设计[J].单片机与嵌入式系统应用,2007.

驱动程序设计篇7

文献标识码:B

文章编号:1004―373X(2008)04―063―03

开发驱动程序的软件主要有:MicroSoft公司的DDK,Jungo公司的Windriver和Compuware NuMega公司的Driver Studio三种。DDK是最基本的驱动程序开发工具,比较复杂,适于专业的驱动程序开发人员,不适于硬件开发人员开发驱动程序。Windriver开发驱动程序不需要熟悉操作系统内核知识,针对硬件PCI/ISA/PCM―CIA/USB开发驱动程序比较方便,但驱动程序的效率不高、缺乏灵活性。Driver Studio把DDK用类的形式进行封装,简化设备驱动程序的开发,方便又不失灵活性。所以这里选择Driver Studio作为驱动程序的开发工具。

在结合PCM高速遥测数据发送卡的基础上,本文介绍WDM驱动程序的结构特点和PCM高速遥测数据发送卡的硬件结构,并阐述针对数据发送卡的特点,详细地讨论驱动程序关键部分的设计。

1 PCM遥测数据发送卡的硬件结构

图1为遥测数据发送卡的原理框图。码型变换器的功能是根据原始PCM数据产生3种输出码型:NRZ―L,NRZ―M及NRZ―S之一,以适应更加广泛的测试目的。多电平驱动器将来自FPGA的LV TTL电平的PCM数据和时钟信号转换为3种电平接口输出,分别是TTL,EIA422及MLVDS。同步FIFO作为硬件数据帧缓存存储由PCI总线写入的数据帧,然后由序列生成器读出。序列生成器根据PCM时钟速率产生串行移出的PCM原始数据将来自FIFO的32位并行数据转换为串行输出,同时根据移位寄存器的状态产生发向FIFO的读数请求:

2 WDM驱动程序的结构及特点

WDM(Windows Driver Model)是在原有的NT内核模式驱动程序的基础上发展来的,他增加了PnP(Plugand Play)、电源管理、WMI(Windows Management Instru―mentation)等功能。WDM模型的层次结构如图2所示。

层次结构可以使I/O请求过程更加清晰。影响设备的每一个操作都使用I/O请求包(IRP),通常IRP被送到设备堆栈的最上层,然后逐渐过滤到下层驱动程序。每处理1个IRP,I/O管理器就调用1次StartIO例程,从而着手IRP处理工作;如何处理完全取决于具体的设备,调用驱动程序中相应的例程。驱动程序处理完IRP后,会将结果返回给I/O管理器,再由I/O管理器返回给用户应用程序。

3 PCM遥测数据发送卡WDM驱动程序的设计

在设备的驱动程序设计中,需要处理PCI设备的硬件读写、中断处理、DMA等功能。可以把驱动程序视为一个框架和若干例程的结合体,各个例程处理不同的IRP,而框架负责在IRP到来时调用相应的例程。利用Driver―Works的驱动程序向导(Driver Wizard)新建一个PCI设备驱动程序框架,然后在这个框架基础上添加必要的实现功能的处理代码,就可以完成整个驱动程序的设计。下面以PCM遥测数据发送卡为例讨论其主要的功能驱动程序例程的实现。

3.1硬件初始化例程

OnStartDevice(KIrp I)参数例程中包含2种系统分配的资源配置信息:原始的资源配置信息(AllocatedRe―sources);转换后的资源配置信息(AllocatedResourcesTranslated)。因为I/O总线和CPU在寻址物理硬件的方式不同,所以存在2种资源列表。从注册表、PCI配置空间和其他地方获取原始的资源值和转换这些值的操作全部由PnP管理器完成,WDM驱动程序需要做的仅是从设备启动IRP中获取这些资源。

3.2 中断服务例程

中断服务例程运行在DIRQL级别上,需要尽可能快地运行。本设计在中断服务例程中,首先判断中断是否自己设备产生的,如果是,则调用一个在DISPATCH_LEV―EL级别上运行的延迟过程调用(DPC)。当中断服务例程完成后,一旦处理器获得DISPATH_LEVEI。运行权,就会运行DPC。中断服务例程流程图如3所示。

3.3 中断延迟调用例程

在延迟调用例程中,判断中断原因如果是DMA中断就启动DMA继续发送。如果是发送通道中断,则判断通道号,并把相应软件FIFO里面的待发送数据传送到硬件FIFO里。在此过程中需要检查在将软件FIFO中的数据写入硬件FIFO中后,如果软件FIFO已被读空,则应禁止通道中断,否则通道中断因为优先级高,会一直于有效状态,导致系统死锁。而在用户程序写软件FIFO的处理函数中,检查通道中断,如果被禁止,则应将新写入软件FIFO的数据读取一部分写入硬件FIFO中,然后开启通道中断。

3.4应用程序与驱动程序的通信例程

DeviceControl(KIrp I)主要用于应用程序与驱动程序之间的通信,如向硬件读写数据以及软件FIFO的操作等。DevcieControl响应用户应用程序DeviceloControl()发送的IRP,根据IOCTL代码来判断调用子处理函数PCI_9054_IOCTL_READ_Handler(I),PCI_9054_IOCTL_WRITE_Handler(I).DEV_IOCTL_TXI_FIFO_WRITE_Handler(I)分别完成对硬件的读写和软件FIFO的写操作。

3.5 DMA传输操作

硬件FIFO半满时产生通道中断,在DPC里,判断是通道中断,则初始化KDmaTransfer,然后调用OnD-maReady();在OnDmaReady()中启动首次DMA传输,传输时发生中断,在DPC中判断是否DMA中断,如果是,则调用Continue()再次启动下次传输,至此全总数据传输完成。其流程图如图4所示。

4 驱动程序编译、调试和安装

当驱动程序编写完成后,必须在DDK环境下进行编译,执行Rebuild aIl命令,编译完成后生成*.sys文件和*.inf文件。调试工具使用Softlce,基本过程如下:

(1)使用Symbol Loader加载驱动程序*.nms文件,然后激活Softlee,设置断点跟踪调试;

(2)用Genint命令产生虚拟中断测试,中断服务例程;

驱动程序设计篇8

1.1 WDM模式(Windows Driver Model)

Windows2000对驱动程序的编写不再基于以往的Win3.x和Win9x下的VxD(虚拟设备驱动程序)结构,而是基于一种新的驱动模型——WDM(Windows Driver Model)。

WDM为Windows98/2000/XP操作系统的设备驱动程序的设计提供了统一的框架。WDM来源于Windows NT的分层32位设备驱动程序模型(layered 32-bit device driver model)。它支持更多的特性,如即插即用(PnP)、电源管理、WMI和NT事件。

1.2 设备驱动程序

设备驱动程序是操作系统的一个组成部分,它由I/O管理器(I/O Manager)管理和调动。Windows2000操作系统下的I/O管理器功能描述如图1所示。

I/O管理器每收到一个来自用户应用程序的请求就创建一个I/O请求包(IRP)的数据结构,并将其作为参数传递给驱动程序。驱动程序通过识别IRP中的物理设备对象(PDO)来区别是发送给哪一个设备。IRP结构中存放请求的类型、用户缓冲区的首地址、用户请求数据的长度等信息。驱动程序处理完这个请求后,在该结构中填入处理结果的有关信息,调用IoCompleteRequest将其返回给 I/O管理器,用户应用程序的请求随即返回。访问硬件时,驱动程序通过调用硬件抽象层的函数实现。

    1.3 DriverStudio工具简介

NuMega Lab公司开发的DriverStudio是一整套开发、调试和检测Windows平台下设备驱动程序的工具软件包。它把DDK(Device Development Kit)封装成完整的C++函数库,根据具体硬件通过向导生成框架代码,并且提供了一套完整的调试和性能测试工具SoftICE、DriverMonitor等。

2 应用实例

本文利用PCI专用接口芯片PCI9052设计了一个数据传输控制卡。卡上主要的芯片有PCI9052、FIFO(CY7C4221)、CPLD(MAX7064S)和A/D转换器(MAX1197)。传输卡硬件框图如图2所示。面阵CCD得到的视频信号经过调理电路,生成的视频调理信号通过A/D转换器进行数字化处理,送入FIFO中。在CPLD的控制下,数据经过PCI9052送入PCI总线,再传送到计算机内存中,并显示在监视器上。驱动程序必须实现如下几个基本功能:(1)硬件中断;(2)能支持应用程序获取数据;(3)能根据外部FIFO(CY7C4221)的状态启动或停止突发传输。

在数据输入过程中,最重要的是对数据进行实时控制,因此需要硬件中断。在中断程序中,根据外部FIFO状态完成数据的读入。

2.1 用DriverWizard生成驱动程序框架

DriverStudio中的DriverWorks软件为开发WDM程序提供了一个完整的框架。它包含一个可快速生成WDM驱动程序框架的代码生成向导工具DriverWizard,而且还带有许多类库。在用DriverWizard生成的程序框架中写入相对于设备的特定代码,编译后即可得到所需的驱动程序。

在利用DriverWorks V2.7的向导Driver Wizard完成驱动程序的框架时共有11个步骤,其中关键步骤有:

(1)在第四步中选中PCI,并在VendorID和DeviceID中分别输入厂商号和设备号,还需填入PCI Subsystem ID和PCI Revision ID。这四项可以用网上的免费软件PCITree或PCIView浏览PCI设备,用这两个软件也可以得到BAR0~BAR5的资源分配情况和中断号。

    (2)第七步IRP队列排队方法,它决定了驱动程序检查设备的方式。本设计选SystemManaged,则所有的IRP排队都由系统(即I/O管理器)完成。

(3)第九步是最关键的一步。首先在Resources中添加资源,在name中输入变量名,在PCI Base Address中输入0~5的序列号。0~5和BAR0~BAR5一一对应。在设置中断对话框中,在name栏写入中断服务程序的名称,选中创建中断服务程序ISR?穴Create ISR?雪,不选创建延迟程序调用DPC(Create DPC),选中Make ISR/DPC class functions,使ISR/DPC成为设备类的成员函数。

其次选中Buffer以选取读写方式,用于描述与I/O操作相关的数据缓冲区。本设计需要快速传送大量数据,因此采用Direct I/O方式。

(4)在第十步中,需要加入与应用程序或者其他驱动程序通信的I/O控制代码参量。

2.2 驱动程序模块框图和代码分布

PCI设备驱动程序模块包括配置空间的访问模块、IO端口模块、内存读写模块和终端模块等。各模块之间是对等的。驱动程序模块框图如图3所示。

驱动程序初始化模块代码段放在#pragma code_seg(″INT″)和#pragma code_seg()之间。在系统初始化完成后,这部分代码从内存中释放,防止占用系统宝贵的内存资源。#pragma code_seg()之后是驱动程序和系统的许多模块的实现部分。这部分在驱动程序运行后不会从内存中释放。

2.3 驱动程序主要模块的实现

(1)配置空间的访问模块

DriverWorks的KPciConfiguration类封装了访问PCI设备配置空间的所有操作。首先初始化这个类的实例:

KpciConfiguration PciConfig()m_Lower.TopOfStack());

/?觹m_Lower是 KpnpLowerDevice类的对象。m_LowerTopOfStack()返回当前设备堆栈顶部的设备对象。*/

初始化完后可以直接利用成员函数 ReadHeader/ WriteHeader函数访问所有的配置寄存器。

为了确定映射空间的类型和大小,先向目标基地址寄存器写入0Xffffffffh,然后回读该寄存器的值。如果最低位为1,表示映射于I/O空间,反之为存储空间;如果映射于存储空间,从第四位开始计算0的个数可以确定内存空间的大小;如果是I/O方式,从第二位开始计算0的个数可确定I/O空间的大小,最大为256字节。如果设备的存储空间超过256字节,要实现设备的整个存储部分的访问,就必须采用内存映射。

(2)I/O操作模块

Driverworks的KIoRange类封装了I/O端口访问的操作。部分代码如下:

{……

KIORange DevIoPort () ;//创建实例

NTSTATUS status= DevIoPort ().Initialize ( pResListTranslated,pResListRaW,PciConfig.BaseAddressIndexToOrdinal(0));

/* 第一个参数为转换后的资源列表指针;第二个参数为原始资源列表指针;第三个参数中的0为 I/O口对应的基地址,用来转换成特定端口资源的序数?*/

If(NT _SUCCESS(status))

{……

DevIoPort.inb(0,LineBuf1,10);

/*成功初始化后可分别用KIoRange类的成员函数inb(/outb)从端口中读/写字节 */

}

else{Invalidate();return status;

/*未能初始化成功,错误信息在status中*/

{

……}

(3)内存读写模块

DriverWorks的 KMemoryRange类封装了端口访问的操作。

status=m_MemoryRange().Initialize(pResListTranslated,pResListRaw, PciConfig.BaseAddressIndexToOrdinal(0));

此函数的参数、意义及具体用法与I/O端口的操作基本相同。

内存对象也用来发送控制字,以控制CPLD的开始和停止等。实际上控制字是通过PCI9052发送的。该控制字地址已被映射成PCI的内存空间。所以定义一个指向内存空间的内存对象,通过该对象即可发送控制字。

(4)中断模块

在中断模块,首先要激活PCI9052中断使能位,然后判断硬件中断响应是否产生,如果有,则进行突发传输,读入FIFO中的数据。

BOOLEAN TranCard::Isr_MyIrq(void)

{ if (// 中断未产生)

{……

return FALSE;}

else

{/* 如果产生硬件中断,设置命令寄存器,进行突发数据传输 */

return TRUE;}

}

为了将硬件中断与编写的中断服务程序连接在一起,采用InitializeAndConnect方法,部分代码如下:

NTSTATUS TranCardDevice?押?押OnStartDevice(KIrp I )

{……

status=m_MyIrq. InitializeAndConnect(

pResListTranlated,

LinkTo(Isr_MyIrq),

This;)

……}

2.4 驱动程序的调用

编写驱动程序本身不是最终目的,最终目的是调用驱动程序管理资源,并为用户应用程序使用。驱动程序加载以后,它的许多进程处于Idle状态,实际上需要用户应用程序去调用激活。应用程序利用Win32 API直接调用驱动程序,实现驱动程序和应用程序的信息交互。

    首先用CreateFile()打开设备,获得一个指向设备对象的句柄。使用CreateFile函数时应注意:由于驱动程序是*.sys,所以第一个参数应该是这个设备对象的标志连接(symbolic link)。该标志连接名有一个设置数据文件搜索路径的数字号,而这个数字号通常是零。如果这个连接名是″TranCard″,则传递给CreateFile的宇符串就是:″\\\\.\\ TranCard0″。例如:

HANDLE hDevice=CreateFile(″\\\\.\\TranCard0″)GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ, NULL?, OPEN_EXISTING,0,NULL);

然后用 DeviceIoControl()进行数据的传送。最后用CloseHandle( )关闭设备句柄。

下面是应用DeviceIoControl()程序片段。

{……

m_b=DeviceIoControl(hDevice,TRANCARD_IOCTL_

RECEIVE(buffer, sizeof,buffer, NULL,0,&buffersize,NULL);

……}

2.5 驱动程序的调试

驱动程序设计篇9

基于TCP/IP体系结构采用Ad hoc技术的无中心节点的自组无线网络结构,具有自组能力、良好的抗毁性、机动性、鲁棒性和易于构建,能很好满足在军事、抢险、应急通信等复杂环境中对无线通信系统的需求[1]。

国外针对采用Ad hoc技术的无线传感网络通常使用IEEE 802.15.4(Zigbee)技术、IEEE 802.15.1(蓝牙)技术、IEEE802.11a/b/g/n(WiFi)技术、IEEE 802.16(WiMax)技术等[2]。而针对采用Ad hoc技术的应急无线通信网络通常使用Zigbee技术、WiFi技术和非公开的无线技术。基于Zigbee技术和WiFi技术的自组网络的终端传输距离受限,无法实现长距离、在高速运动中的数据传输。基于PowerPC+FPGA的无线系统实现长距离、在高速运动中的数据传输,能很好的满足军事和应急通信对无线通信系统的要求。

本文基于PowerPC+FPGA平台设计一种FPGA驱动程序来实现一路无线信号的发射和一路无线信号的接收,使用设备树文件来配置FPGA网络MAC地址、FPGA访问地址、中断信息等硬件配置信息,MAC地址保存在U-Boot环境变量中,U-Boot在引导Linux内核启动之前把MAC地址添加到设备树文件中。

1 FPGA驱动设计与实现

1.1 PowerPC平台硬件架构

基于PowerPC+FPGA的无线系统由网络基带板、射频板和背板组成,网络基带板和射频板通过背板连接。网络基带板实现操作系统的支持,FPGA实现无线通信的链路层和物理层以及无线信号的收发控制。射频板实现一路无线信号的发射和接收。网络基带板使用Freescale公司的MPC8536E处理器,提供256MB的Nor Flash存储空间,512MB的DDR2 SDRAM内存空间,两个RS232接口,两个千兆以太网接口,一个PCI总线接口,一个miniPCIe接口,三个USB host接口。FPGA使用Xilinx公司的XC5VLX110T,提供32Mb配置文件存储空间,使用LVDS信号接口和RS232接口与射频板进行通信。MPC8536E通过eLBC局部总线与FPGA通信,预留PCIe总线和eSPI接口。见图1系统硬件架构图。

1.2 PowerPC平台的统软件架构

操作系统选择开源的嵌入式操作系统Linux,引导程序选用开源的引导程序U-Boot。根文件系统选择Ramdisk文件系统。U-Boot选择u-boot-200908的版本,Linux选用2.6.32-rc5的版本。

随着Linux/PowerPC内核的发展,把32位和64位PowerPC内核代码合并,使用一个OpenFirmware式的固件接口设备树来支持所有的PowerPC平台,在这之前大多数PowerPC的嵌入式系统使用板卡特定数据结构在引导程序和Linux内核之间进行数据传递,引入设备树简化了Linux/PowerPC内核启动顺序[1]。U-Boot使用设备树文件把硬件配置信息传递给Linux内核。Linux/PowerPC内核对每个硬件平台都定义一个machdep_calls数据结构,内核在启动时调用probe_machine()遍历“.machine.desc”代码段,并调用machdep_calls数据结构相应的.probe()函数,每个.probe()检查设备树并返回真,确定设备树支持该硬件平台[1]。使用设备树的大多数嵌入式PowerPC平台使用of_platform平台总线,of_platform平台总线是一个软件注册的虚拟总线。Linux内核平台代码使用of_platform_bus_probe()遍历设备树的一部分,为其中的每个设备分配和注册一个数据结构of_device。反过来设备驱动程序使用数据结构of_platform_driver来注册,of_platform平台总线负责匹配设备和驱动程序。

1.3 FPGA网络驱动设计与实现

1.3.1 FPGA网络驱动的设计

Linux系统将设备分为三种类型:字符设备、块设备和网络设备,字符设备和块设备都是面向数据流的,通过/dev目录下的设备文件来访问,Linux系统中字符设备和块设备的区别在于驱动程序和内核之间的接口,字符设备使用数据结构file_operations的成员函数与Linux内核通信,而块设备使用数据结构block_device_operations的成员函数。网络接口是由内核中的网络子系统驱动,负责数据包的发送和接收,因此网络驱动程序是围绕数据包的传输和接收而设计的[2]。内核主要调用数据结构net_device_ops的成员函数来实现内核和网络驱动之间的数据传输。而在数据结构net_device_ops中的成员函数中调用内核提供:netif_start_queue、netif_stop_queue、netif_wake_queue、netif_rx等函数。网络接口必须使用数据结构net_device来注册,在与外界进行数据包的交换时调用,网络设备既响应来自内核的发送数据的请求,也要异步地接收来外部的数据包,并向内核请求把从外部接收到的数据包传送给内核,网络驱动程序还支持管理任务比如设置MAC地址、修改传输参数以及维护流量和错误统计等[2]。

FPGA驱动程序需要实现一路无线信号的收发控制,为了实现有线网络和无线网络之间的路由转发,因此按照网络驱动来设计。FPGA网络驱动程序主要包括定义网络设备私有数据结构,网络设备访问方法和FPGA寄存器访问方法,驱动模块注册和注销函数,中断处理函数。其中网络设备访问方法的实现主要通过数据结构net_device的成员数据结构指针netdev_ops的成员函数来实现。

(1)定义网络设备私有数据结构。FPGA通过eLBC局部总线与MPC8536E通信,FPGA既是一个网络设备,也是一个局部总线上的设备。FPGA网络设备私有数据结构既包含网络设备数据结构net_device指针,也包含设备数据结构of_device指针,同时也要包含mii_if_info数据结构、自旋锁、信号量、sk_buff_head数据结构、work_struct数据结构等变量,定义如下:

2 实验测试

2.1 点对点测试

两台无线系统平台通过网络和串口分别连接两台Linux系统的计算机,两个无线系统平台之间通过空口连接,使用iperf命令进行数据接收和发送测试:测试结果显示:流量运行平稳,都在10Mbps以上,满足设计要求。

2.2 自组网测试

四台无线系统平台实现Ad hoc自组网,其中2台无线系统经过2跳进行流量测试:测试结果显示:流量运行平稳,都在1Mbps以上,满足设计要求。

3 结束语

本文设计的FPGA驱动程序合理高效,支持一路无线信号的发射和一路无线信号的接收,实现了无线系统之间点对点进行通信,四台无线系统实现了Ad hoc自组网络。在后续的研究中,优化FPGA网络驱动程序,支持四路无线信号的发射与接收。

参考文献:

[1]Grant Likely,Josh Boyer.A Symphony of Flavours:Using the device tree to describe embedded hardware[R].Ottawa,Canada:Linux Symposium,2008.

[2]Corbet J,Rubini A.魏永明,耿岳,译.Linux设备驱动程序[M].第3版.北京:中国电力出版社,2006.

[3]常关羽,许晴.Ad Hoc环境下基于稳定链路的语音通信系统设计与实现[J].小型微型计算机系统,2011(01):107-111.

[4]JeroenHoebeke,IngridMoerman,BartDhoedt and Piet Demeester,An Overview of Mobile Ad Hoc Networks:Applications and Challenges[J].Journal of the Communications Network,2004(07):60-66.

[5]Bernard Sklar.徐平平,宋铁生,叶芝慧,译.数字通信――基础与应用[M].北京:电子工业出版社,2010.

[6]MPC8536E PowerQUICC III Integrated Processor Hardware Specifications[M].Rev.5 05/2011 Freescale.

[7]MPC8536E PowerQUICC III? Integrated Processor Reference Manual[M].Rev.1 05/2009 Freescale.

[8] PowerPC? e500 Core Family Reference Manual[M].Rev.1,2005,Freescale.

[9]EREF 2.0:A Programmer’s Reference Manual for Freescale Power Architecture? Processors[M].Rev.0,2011,Freescale.

[10]SreekrishnanVenkateswaran.宋宝华,何韶然,史海滨,吴国成,译.精通Linux设备驱动程序开发[M].北京:人民邮电出版社,2010.

[11]王齐,Linux PowerPC详解[M].北京:机械工业出版社,2007.

[12]CHRISTIAAN BENVENUTI.夏宏,阎江毓,黄景昌,译.深入理解Linux网络技术内幕[M].北京:中国电力出版社,2009.

驱动程序设计篇10

建构主义理论[2]认为知识不是通过教师传授得到的,而是学习者在一定的情境,即社会背景下借助他人的帮助(如教师或学习伙伴),利用必要的学习资料,通过意义建构的方式获得的。在知识获取的过程中,强调学生是信息加工的主体,是意义的主动建构者,而不是外部刺激的被动接受者,驱使学生不断学习的动力应该是逐步解决问题而获得的成就感,而不是教师不断地灌输和填鸭,教师在学习过程中起着引导学生如何发现问题、分析问题以及解决问题的作用。因此,问题驱动的教学方法受到日益重视,在高等数学[3]、线形代数[4]、管理学原理[5]以及计算机原理[6]、计算机应用基础[7]等课程的教学中得到广泛的应用。

C++程序设计语言是贝尔实验室的Bjarne stroutsup在吸收C程序设计语言优点的基础上开发的支持面向对象程序设计的计算机编程语言[8]。它既能支持结

构化程序设计已保持对C语言的兼容,又通过类(class)机制实现面向对象编程。当前,C++程序设计语言成为国内外众多高校计算机专业学生学习计算机编程的第一门程序设计课程,该门课程学习的好坏对于学习其他计算机专业核心课程(如数据结构、操作系统、编译原理)至关重要;另外,程序设计类课程实践性强,非常适合采用问题驱动式的教学方法。因此,本文探讨问题驱动的教学方法在C++程序设计课程教学中的应用,对于提高计算机专业学生的C++程序设计能力具有重要的实际意义,对于其他计算机专业课程的建设和改革具有一定的借鉴意义。

1问题驱动的教学方法在C++程序设计教学中的应用

1.1问题驱动的教学方法简介

所谓问题驱动的教学方法,就是借助现代化的教学环境和教学手段,设计合适的问题或选择典型的实际问题,通过引导学生如何分析问题和解决问题,从而启发学生思维、培养学生兴趣的教学方法,培养学生探究学习、协作学习、终身学习的习惯,为进一步学习和深造奠定坚实的基础。

问题驱动的教学过程的实施对教师提出了更高的要求。教师在课程教学中遵循如下原则:(1)教师

基金项目:天津理工大学教改基金(2008016)资助,天津市高等学校科技发展基金(20071306)资助。

作者简介:夏承遗,男,副教授,博士,研究方向为计算机应用技术、复杂系统建模分析等;孙世温,女,讲师,博士,研究方向为计算机应用技术、复杂系统建模分析等。

需要根据教材的内容、学生的认知规律和实际情况,以提出问题的方式引导学生主动学习和思考;(2)所设计的问题要涵盖课程的主要的知识点,同时又要循序渐进,有一定的梯度;(3)鼓励学生大胆尝试,勇于在课堂上提出问题,教师在分析答疑过程中帮助学生提高他们解决问题的能力。

1.2问题驱动的C++程序设计教学案例

基于上述原则,结合C++程序设计语言的特点选取一些实际问题和经典问题,讲解C++编程求解问题的过程,有利于学生对C++程序设计的学习和掌握,进而提高C++程序设计能力。这里介绍几个教学案例。

1.2.1从“Hello World”程序入门

C++程序设计课程是学生学习编程的开始,如何引导学生快速入门,并激发学生进一步学习的欲望至关重要。传统的教学方法首先介绍C++语言的语法特点,然后介绍C++程序的基本结构,再举一些程序实例。我们正好相反,首先提出问题要求编程在屏幕上打印“Hello World”字样;然后,以特定的编译器(如Visual C++6.0)为基础,课堂上当场编写程序代码(如图1所示),同时演示C++程序的编辑、编译和连接等调试过程;还可以引导学生,如何修改程序在屏幕上输出其他字样,如“The Great Wall”,等等。这样的做法,一方面使学生很快了解真实编译环境下C++程序的基本框架;另一方面也可以鼓励学生自己动手编程,从一开始就充分调动学生的学习积极性。

图1C++结构化程序框架

与此同时,C++语言还支持面向对象程序设计,以类为基础重新编程实现在屏幕上输出“Hello World”(如图2),进一步使学生了解C++程序的完整结构。

最后,基于上述实例程序,总结C++程序的基本结构如下:(1)程序主要由类和函数组成,图1所示程序是图2程序的退化形式(即结构化形式,保持对C语言的兼容);(2)每一个程序有且只有一个主函数(main函数),并且是程序的入口点;(3)程序可能会用到一些系统库函数或对象,此时使用文件包含预处理,如#include 。

图2C++面向对象程序框架

1.2.2类对象的初始化问题

C++类对象的初始化是C++教学中的一个难点,很多学生不理解为什么要引入构造函数进行初始化。为此,我们通过梳理C++中各种数据类型的初始化过程,循序渐进、逐步深入到对象初始化的问题,并在教学中适当设置问题,要求学生思考。

对于C++基本类型数据,初始化是一个相对容易的过程,在变量定义时直接赋初值即可。例如,int a=3;float f[3]={1, 2, 3}。前者给普通变量赋初值,后者给数组赋初值。

对于结构(struct),由于成员默认具有公有(public)的存取权限,我们也可直接进行初始化。

struct Date {

int year, month, day;

};

可以直接给结构变量赋初值,如struct Date d1= {2007, 10, 4};

但是,对于类(class),由于成员默认具有私有(private)的存取权限,试图直接进行初始化,必然是徒劳的。

class CDate {

int year, month, day;

};

给类对象直接赋初值,如CDate d1={2007, 10, 4};编译出错。实际上,这相当于直接访问类对象的私有(private)数据成员,如D1.year=2007;d1.month=10;d1.day=4;当然被禁止。

所以,类对象的初始化依靠直接赋初值的办法是行不通的,必须另劈蹊径。另外,对于C++基本数据类型的变量,如果没有初始化,我们还可以有补救的措施,例如,

int a;//定义一个变量,但未初始化

…//其它一些操作

a=3;//赋值

++a;//自增量操作

同样,这些补救措施对类对象来说也是无济于事,受到成员的私有(private)的存取权限所禁止。并且,类对象是对现实世界对象的直接模拟,要求一旦创建就应该具有一个有意义的初值,并且是立即和自动完成的。所有这一切,都说明初始化的任务,必然落到成员函数的身上;但普通的成员函数需要用户程序显式调用,无法自动完成,必然要一个特殊的成员函数完成初始化的过程,C++中称为构造函数,类的唯一性和对象的多样性决定了构造函数名称与类名相同。然后,通过一些实例程序来演示对象的初始化过程,学生将更容易理解为什么要用构造函数进行对象的初始化。

1.2.3虚函数与多态性问题

虚函数是C++支持面向对象程序设计运行时多态性的基本技术,但程序中有了虚函数未必就能够实现运行时的多态性,初学者经常在这里感到费解。在教学中,我们首先要求同学分析图6和图7所示的两个程序实例,程序执行结果分别是什么?前者在控制台屏幕上显示“===BaseClass===”;而后者在屏幕上显示“===DerivedClass===”。

为什么会出现这样不同的结果呢?其实,在图3所示的程序中,尽管在基类c_Base和派生类c_ Derived中都定义了虚函数virtual void print(),但将派生类对象赋值给基类对象之后,此时将派生类对象剪切为基类对象,然后再调用print()只能使用基类中定义的函数了;而在图4的程序中,在使基类的对象指针指向派生类对象之后,基类指针代表着一个派生类对象,故能够调用派生类中定义的虚函数。再进一步,需要从编译器底层探讨C++中虚函数的实现机制,现代的编译器为每一个包含虚函数的类增加一个虚指针成员(vptr)和一个虚表(vtable),具体细节不再详述,可引导学生查阅相关的文献[9, 10],以培养学生主动学习的能力。

基于上述分析可以得出如下结论,C++通过虚函数实现运行时的多态性必须满足如下三个条件:(1)公有继承,即继承方式为public;(2)在基类和派生类中定义虚函数;(3)通过基类指针或引用调用虚函数。

总之,通过上述几个案例的介绍,为开展问题驱动的程序设计课程的教学起一个抛砖引玉的作用。结合不同的程序设计语言特色与相关知识,设计合适的问题,并引导学生对问题进行分析和讨论,同时在教学中留给学生充分的思考空间,发挥学生的主观能动性,进而提升课堂教学的效果。

图3通过基类对象调用虚函数

图4通过基类指针调用虚函数

1.3实验、实践与考试环节

对于像第二批以及第三批本科的学生,学生学习主动性相对较差,我们在努力提高课程教学效果的同时,还必须加强实验、实践以及考试环节的改进和设计,以提高学生动手编程的能力。我们采取的主要措施包括:

(1) 高度重

视实验环节。实验是培养和锻炼学生程序设计能力的一个重要手段。实验前,必须严格要求学生做好实验准备,对实验题进行认真分析、画好程序流程图并在纸介质上写好源代码;实验中,要求学生熟练掌握程序的编辑、编译、链接等过程,尤其要认真对待程序调试过程遇到的各种错误,排除各种错误的过程是提高编程能力的重要环节,并对程序调试中的一些共性问题进行统一的讲评,及时帮助学生解决实验中遇到的各种问题;实验后,要求学生认真撰写实验报告,特别要求学生写清实验中遇到哪些问题,又是如何解决这些问题的。

(2) 改进考试环节。结合这种问题驱动的教学方法,我们也对考试环节进行了必要的改进,改变传统只进行期末笔试的方式。我们将考试分成期中考试和期末考试两个阶段,并且每次考试包括笔试和上机编程考核两个方面,其中笔试主要涉及C++的一些重要的语法知识,以程序阅读和分析为主;上机主要考核学生编程和调试程序的能力。

(3) 增加课程设计环节。平时练习和实验主要训练学生的基本能力以及对重要语法知识的掌握,问题相对简单,程序规模也较小。所以,在课程结束后,结合数据结构中线形表的知识,布置学生完成一个小型的管理信息系统(MIS),如人事管理系统、工资管理系统以及学生学籍管理系统等。一方面,对学生编制较大规模的程序有一个综合的训练;另一方面,学生在认真完成后,实现一个功能相对完善的程序,会有较大的成就感,有利于激发学生进一步学习计算机专业知识的兴趣。

1.4教学效果的评价

如何科学合理地评价教学效果是一件非常困难的事情。但是,我们发现在我院计算机专业2007级采用问题驱动的教学方法后,学生的精神面貌、学习的热情和主动性有明显的改进,表1给出了2006和2007两届学生期中和期末考试及格率情况,从一个

侧面反映了教学效果的提升,坚定了我们继续改进和完善问题驱动教学法的信心。

表1采用问题驱动教学法前后学生及格率情况

及格率期中考试期末考试

笔试上机笔试上机

200675.1%50.2%80.2%48.7%

200789.3%65.6%91.8%70.5%

从表1可以看出,采用问题驱动教学法之后,学生在笔试和上机考核方面都有明显提高,同时,我们也看到学生上机考试的成绩仍不够理想。因此,如何进一步提高学生动手编程能力有待进一步的探索和尝试。

总之,我们在课堂教学中要注意吸引学生,努力提高学生自主学习的兴趣,在课后布置一定的编程任务,并认真检查,同时对课程的考试环节进行必要的设计,增加上机考核,给学生一定的压力,从而保持在教学全过程中对学生进行督促和指导,切实提高教学效果。

2结束语

努力改进教学模式和提高课程教学效果是提升高等教育质量的一个重要方面,搞好每门课程尤其是一些专业基础课程的教学,激发学生学习专业课程的兴趣,进而激励学生进一步开展研究性学习,甚至开展创新性的研究工作,为培养高素质、适应社会需求的计算软软件人才奠定基础。本文以C++程序设计课程为例讨论了在计算机专业的程序设计类课程开展问题驱动模式的教学方法的尝试,取得了初步的效果,一定程度上促进了学生编程能力的提高。但是,仅靠程序设计课程的改革是远远不够的,这一新的教学方法值得进一步完善和改进以及在其他计算机专业课程中的教学实践中加以推广和应用。

参考文献:

[1] 教育部,财政部. 教育部财政部关于实施高等学校本科教学质量与教学改革工程的意见[Z]. 2007.

[2] 张建伟,陈琦. 简论建构性学习和教学[J]. 教育研究,1999,(5)56-60.

[3] 张奠宙,张萌南. 新概念:用问题驱动的数学教学[J]. 高等数学研究,2004,7(3):8-10.

[4] 赵慧斌. 问题驱动是线性代数有效的教学方法之一[J]. 高等数学研究,2008,11(4):91-94.

[5] 吴晓匀. 问题驱动型教学模式在《管理学基础》课程教学中的运用[J]. 华南热带农业大学学报,2005,11(2):88-93.

[6] 李英杰. 问题驱动教学法及其在计算机原理教学中的应用[J]. 电脑编程技巧与维护,2008,(12):99-101.

[7] 徐秀珍,徐学. 浅谈问题驱动式教学方法在《计算机应用基础》课程中的应用[J]. 内蒙古民族大学学报:自然科学版,2008,23(4):462-464.

驱动程序设计篇11

对于高速网络fddi(fiber distributed data interface)网卡驱动程序还需要smt(station management)站管理功能的实现,否则将不能作为一个fddi站连入环结构中,只能实现点到点间的数据通信。故有必要将smt软件移植到网卡驱动程序中,这将又导致对miniport nic驱动程序编程框架的破坏,于是有必要形成fddi网卡驱动程序(包含smt)与windows nt操作系统的良好接口──由逻辑网卡的注册和mac层驱动程序的初始化来完成。

所以,本课题旨在深入研究应用microsoft公司的ddk(device driver kit)将smt移植于windows nt的fddi网卡驱动程序过程中如何注册miniport nic驱动程序。即怎样正确注册逻辑网卡和mac驱动程序的初始化。着重讨论与初始化相关的上边缘函数的使用和调用关系以及初始化过程中遇到的各种问题的具体解决。

第一章windows nt环境下fddi网卡驱动程序

总体结构介绍

第一节windows nt网络结构

§1.1.1 windows nt网络体系结构

windows nt的网络体系结构是基于国际标准化(iso)制定的标准模型──开放式系统互连(open system interconnection:osi)参考模型分层建立的,这种方式有利于随时扩展其它功能和服务。

windows nt网络模型开始于mac子层,网卡驱动程序就驻留在其中。它通过相关的网卡把windows nt与网络连接起来,图中的多个网卡表明在一台运行windows nt的计算机上能使用多种网卡。

这一网络体系结构包括两个重要接口──ndis接口与传输驱动

程序接口(tdi)。这两个接口把两个层隔离开来,办法是相邻的部件只允许按单一的标准来写,不允许多重标准。例如一个网卡驱动程序(在ndis接口的下面)就不需要特地按每个传输协议来写它的代码块,恰恰相反,该驱动程序是写给ndis接口的,它通过符合ndis的相应传输协议来请求服务。这些接口包含在windows nt的网络体系结构中,以容纳可移植、可互换的模块。

在两个接口之间,是传输协议。它在网络中起着组织者的作用。一个传输协议规定了数据以何种方式呈递给下一个接收层,以及如何对数据相应地进行打包。它通过ndis把数据传给网卡驱动程序,并通过tdi把数据传给转发程序(redirector)

tdi之上是转发程序,它把本地的网络资源申请转送给网络。

为了能和其他厂商的网络互连,windows nt允许有多个转发程序。对于每一个转发程序windows nt计算机必须也有一个相应的供应者(provider)(由网络厂商提供)。多供应者路由选择程序决定适当的供应者,然后借助于供应者,对应用请求到相应的转发程序做出选择。

§1.1.2 windows nt网络驱动程序

windows nt支持两种类型的网络驱动程序

传输驱动程序

实现数据链路层中的逻辑链路控制子层协议和传输层协议。向 下与ndis接口,向上与tdi接口。

网卡驱动程序

实现对物理层的管理和数据链路层中介质访问控制子层协议,通过ndis向下管理物理网卡,向上与传输驱动程序通信。

§1.1.3 windows nt网卡驱动程序

windows nt环境下的网卡驱动程序也分为两种:

miniport网卡驱动程序:miniport驱动程序只须实现与网络硬件相关的操作(包括发送和接收)。而所有底层网卡驱动程序的通用操作(如同步),一般由ndis接口程序来实现。

full网卡驱动程序:full网卡驱动程序必须实现所有硬件相关和同步、排队等操作。例如full网卡驱动程序为了响应数据接收,需要保持本身的捆绑信息,而miniport就可以由ndis接口库来实现。

在windows nt的早期版本中,full网卡驱动程序要求开发者实现许多底层操作,来处理多处理器的核心问题以及处理器、线程的同步,这样不同的开发者在大量重复着许多相同的工作。

而miniport网卡驱动程序允许开发者仅仅写一些与网络硬件相关的代码即可,而那些通用的函数由ndis接口库来实现,这样开发出来的驱动程序减少了不必要的工作。

第二节miniport驱动程序的结构

ndis接口规范了网卡驱动程序的实现,同时也对tdi驱动程序的实现提出了一定的要求,在nt中,ndis约束下的网卡驱动程序、tdi驱动程序和系统的关系如下图所示:

图2.0 ndis约束下的网卡驱动程序、tdi驱动程序和系统的关系

miniport驱动程序包括驱动程序对象、驱动程序源代码和ndis接口库代码。windows nt ddk提供ndis.h作为miniport驱动程序的主要头文件,定义了miniport驱动程序的入口点、ndis接口库函数和通用数据结构。

上边缘函数的作用是网卡驱动与ndis接口库进行通信,而下边缘函数是tdi协议驱动程序与ndis通信的手段。

§1.2.1 miniport网卡对象

ndis用一个叫做逻辑网卡的软件对象来描述系统中的每块网卡,而逻辑网卡与windows nt设备对象的通信由i/o子系统来管理,描述网卡的设备对象包括相关的网络信息如名字、网络地址和网卡内存基地址等,它还包含与硬件相关的驱动程序状态数据(捆绑数目,捆绑句柄,包过滤数据库等)。ndis分配一个句柄到miniportinitialize这个上边缘函数的一个结构中,然后miniport网卡驱动程序将在以后提供这个句柄来给ndis调用,这个结构一直被ndis保持,并且对miniport驱动程序不透明。

当miniport网卡驱动程序初始化一块网卡时,它创立自己的内部数据结构来描述网卡,记录需要它管理的与设备相关的状态信息。当miniport网卡驱动程序调用ndismsetatttibutes或ndismsetattributesex两ndis库函数时,它传递一个句柄给这数据结构。这样,当调用miniport驱动程序入口点时,它就传递这个句柄来验证驱动程序所对应的网卡的正确性。这个数据结构为miniport网卡驱动程序所拥有并维护。

§1.2.2网络对象标识符

miniport nic驱动程序还需要维护一组对象,这些对象是系统定义的对象标识符(object idetifier:oid)来标识,以描述驱动程序的性能和当前状态信息。为查询这些信息,上层驱动程序调用ndisrequest向ndis接口库指示oid。oid表示了调用所需的信息类型,如miniport驱动程序所支持的lookahead缓冲区大小等。ndis接到上层驱动程序的查询请求,将oid传递给上边缘函数miniportqueryinformation实现对oid的查询,如果上层驱动程序请求改变状态信息则调用miniportsetinformation实现对oid的设置。

§1.2.3 miniport网卡驱动程序代码

典型的miniport nic驱动程序必须有一些函数来通过ndis接口实现上层驱动程序与硬件的通信。这些函数称为上边缘服务函数。

这些上边缘服务函数由驱动程序的开发者根据驱动程序面向的特定低层网络类型和硬件以及相应环境,可以有选择地实现,但必须保证驱动程序最基本的功能,这些基本功能包括初始化、发送、中断处理、重置、参数查询与设置和报文接收。

miniportinitialize:操作系统根据系统配置信息,检测出网卡已安装时,由ndis接口在初始化时调用,主要完成低层网络类型确定,对应于物理网卡的逻辑网卡初始化,中断信息注册,网卡与主机通讯方式的确认。i/o端口的申请与注册,内存映像,mib的初始化,物理网卡的验证与初始化等。

miniportreconfigure:支持网卡参数动态变化,和miniportinitilize一样由ndis接口以初始化级别调度执行(不能屏蔽中断,必须由驱动程序承认并清除在此期间产生的中断),支持即插即用和软配置的网卡在动态改变参数时,必须提供此函数。

miniportqueryinformation:查询网卡的状态以及网卡驱动程序的操作或统计参数,如是否支持组通讯、网卡的物理速率是否支持回环、是否支持直接拷贝等,这些参数以oid方式统一管理。

miniportsetinformation:ndis接口或协议驱动程序通过调用此接口改变驱动程序维护的oid库,一些操作参数的改变也将同时改变驱动程序状态,例如组地址的设置。

miniportreset:包括网卡硬件重置和驱动程序软件重置,软件重置包括驱动程序状态重置,以及一些相关的参数重置,还需考虑有些参数的恢复,重置时不必完成所有正在活跃的外部请求,但必须释放已占用的外部资源。

miniporthalt:挂起网卡并释放该网卡驱动程序占用的所有资源,在此期间不屏蔽中断。

miniportisr:高优先级的中断处理程序,进行的工作包括初始中断处理类型,决定是否进行中断转交,对卡上中断进行处理 等,该服务类型只在以下情况被调用:

ndis接口调用miniportinitialize和miniporthalt两函数时。

.中断处理类型设为每此中断处理过程都调用时。

为使系统能及时响应所有硬件中断,高优先级的硬件中断处理程序应尽可能的减少运行时间,防止长时间的屏蔽低优先级中断,避免造程中断丢失。

miniporthandleinterrupt:由中断延时处理程序在中断延时处理时进行调用。ndis排队所有的延时处理,该服务主要处理发送完成、报文接收、描述符用尽、溢出、网卡异常等中断。

miniportsend:ndis收到上层发送请求时经过若干协议处理再向下调用此服务过程,发送的packet已含有llc和mac头,该服务过程进行边界对齐、packet约束重整、描述符映射和报文发送、以及发送资源和packet缓冲队列管理。

miniporttransferdata:多个已和网卡捆绑的协议驱动程序在接收到报文到达指示后,向网卡驱动程序发出传送请求以拷贝各自所需的报文数据部分,网卡驱动程序根据各协议驱动程序对单个packet是否进行多次拷贝,以决定是否暂存只允许单次拷贝的packet等。

miniportcheckhandle:ndis每秒调用此服务函数一次,驱动程序发现网卡异常时报告给ndis由ndis调用miniportreset进行硬件重恢复。

miniportenableintrrupt:中断使能。

miniportdisableinterrupt:中断屏蔽。

另外,每个网卡驱动程序必须有一个初始化入口点,由driver entry函数实现,它和系统相关,由操作系统在装入驱动程序时调用,主要完成初始化ndis wrapper,再由wrapper初始生成驱动程序管理块并完成相应各种初始化工作,登录网卡驱动程序所有上边缘服务入口点,同时写入ndis版本信息。

§1.2.4 ndis接口库

ndis接口库包括在ndis.sys中,它是一个核态函数库,有一套抽象的函数,无论协议驱动程序还是nic驱动程序都连接到这个库中,以实现上下层之间的操作。

第二章fddi网卡驱动程序的加载和运行

第一节 网卡驱动程序的安装

windows nt网卡驱动程序安装的目的是实现网卡相应硬件信息和驱动程序在windows nt注册库中的注册,使windows nt能够正确识别网卡,了解所必需的软硬件信息并能在windows nt启动时加载相应驱动程序。

网卡驱动程序安装时,首先在主群组的控制面板中选择“网络”,然后添加网卡,指定相应信息文件──oemsetup.inf的路径,以完成以下两个必要的操作:

复制驱动程序到相应的系统目录(windows nt根目录\system32\drivers\)中;

在windows nt注册库中存入相应软硬件信息。

下面主要以fddi网卡为例介绍安装驱动程序所必需的工作:

§2.1.1网卡一般硬件参数

对于fddi网卡,必须在编写其oemsetup.inf文件时确定以下硬件参数:

总线类型:pci(5)……括号中的数字5表示pci总线在ndis中的总线类型代码;

厂商代号:0x5588……系统加载时确定网卡的标记,也是编程时确定pci槽号的标识;

cfid: 0x01;

介质类型:光纤(3) ……括号中的数字表示光纤在ndis中的介质类型代码;

是否支持全双工:支持。

对于其它的硬件信息在此inf配置信息文件中可有可无,如若配置,则可在驱动程序的编写时利用这些信息,方便编程,同时有利于其它应用对其参数的确定和使用。

§2.1.2 fddi网卡加载时需在注册库登录表里做的网络配置

网卡驱动程序的安装通常将创建登录表中的四个不同子键:

software registrion键,对应于驱动程序,存在于hkey_local_machine\software\company\ productname\version中。我们的fddi网卡驱动程序所对应的是hkey_local_machine\software\net612\yhfddi\yhfddi1.0;

网卡的软件登录键,存在于hkey_local_machine\software\microsoft\ windows nt\nt3.51\networkcards\yhfddi1;

驱动程序的服务登录键,存在于hkey_local_machine\system\currentcontrolset\services

网卡的服务登录键,存在于hkey_local_machine\system\currentcontrolset\services

对于每一个网络部件,一个名为netrules的特殊子键在邻近的驱动程序或网卡登录子键里创建,netrules标识网络部件为网络整体的一部分。

fddi网卡驱动程序对应的标准软件登录表项将出现在以下路径:

hkey_local_machine\software\net612\yhfddi\yhfddi1.0;

驱动程序对应的标准项的值为:

description =yhfddi/pci adapter controller

install date =……

……

refcount =0x01

servicename =yhfddi

softwaretype =driver

title =yhfddi/pci adapter controller

而且在yhfddi驱动程序相关的netrules子键下,这些值项为:

bindable =yhfddi driver yhfddi adapter non exclusiver

bindform =“yhfddisys”yes no container

class = reg_multi_sz “yhfddi driver basic”

infname =oemnad1.inf

type =yhfddisys ndisdriver yhfddidriver

use =driver

yhfddi网卡在如下路径的networkcards子键里介绍:

hkey_local_machine\software\microsoft\

windows nt\nt3.51\networkcards\yhfddi1;

网卡的标准项包括以下这些值:

description =yhfddi/pci adapter controller

install date =……

manufacturer =net612

productname =yhfddi

servicename =yhfddi01

title =[01]yhfddi/pci adapter controller

§2.1.3编写inf信息配置文件

gui inf描述语言被windows nt用以书写系统所有部件的配置文件,当然也可以用以书写网络系统各部件的配置文件,该配置文件描述了网络部件安装、配置、删除的执行过程。当网络部件进行初始安装或二次安装(通常通过ncpa进行)时,安装程序读取部件对应的配置文件,进行解释执行。gui inf描述语言由节、命令、逻辑操作、变量规范、流程控制以及一套调用dll或外部程序的机制组成,其中,节是配置文件的主体,节可分为install节(类似于函数),shell节(也类似于函数,但可调用insall和shell节),detect节(不包含命令),一个配置文件一般由若干不同类型的节组成。驱动程序的开发者根据需要可以在配置文件中编写相应代码,使得用户和系统之间能进行交互,并且由用户决定一些配置参数。

nt网卡配置文件有其一套规范,驱动程序开发者必须按规范编写配置文件,一般来说,一个配置文件至少应该提供下面三个节:

安装入口点:[identify]shell节。该节主要功能是给出安装部件的类型名,系统通过它识别该部件属于哪一大类(display,mouse,scsi,network等)中的哪一类(网络adapter,driver,transport,service,network和netprovidor),同时,还需要给出映像文件和配置文件所在的源介质及标识。

[returnoption]shell节。系统执行安装identify节后,执行该节。它主要功能是检查所需安装的部件是否支持的硬件平台和语言,并给出网卡名(有些配置文件支持多类网卡,此时必须让用户进行选择,并获得选择结果)。

[installoption]shell节。该节是配置文件得主体,也是上次安装完后再次进行配置、删除、更新的入口点。主要功能是拷贝映像文件和配置文件,生成配置的各种选项,创建该部件在注册库中对应的各种登录子树并更新重写。

第二节 驱动程序的加载过程

驱动程序设计篇12

对于高速网络fddi(fiber distributed data interface)网卡驱动程序还需要smt(station management)站管理功能的实现,否则将不能作为一个fddi站连入环结构中,只能实现点到点间的数据通信。故有必要将smt软件移植到网卡驱动程序中,这将又导致对miniport nic驱动程序编程框架的破坏,于是有必要形成fddi网卡驱动程序(包含smt)与windows nt操作系统的良好接口──由逻辑网卡的注册和mac层驱动程序的初始化来完成。

所以,本课题旨在深入研究应用microsoft公司的ddk(device driver kit)将smt移植于windows nt的fddi网卡驱动程序过程中如何注册miniport nic驱动程序。即怎样正确注册逻辑网卡和mac驱动程序的初始化。着重讨论与初始化相关的上边缘函数的使用和调用关系以及初始化过程中遇到的各种问题的具体解决。

第一章windows nt环境下fddi网卡驱动程序

总体结构介绍

第一节windows nt网络结构

§1.1.1 windows nt网络体系结构

windows nt的网络体系结构是基于国际标准化(iso)制定的标准模型──开放式系统互连(open system interconnection:osi)参考模型分层建立的,这种方式有利于随时扩展其它功能和服务。

windows nt网络模型开始于mac子层,网卡驱动程序就驻留在其中。它通过相关的网卡把windows nt与网络连接起来,图中的多个网卡表明在一台运行windows nt的计算机上能使用多种网卡。

这一网络体系结构包括两个重要接口──ndis接口与传输驱动

程序接口(tdi)。这两个接口把两个层隔离开来,办法是相邻的部件只允许按单一的标准来写,不允许多重标准。例如一个网卡驱动程序(在ndis接口的下面)就不需要特地按每个传输协议来写它的代码块,恰恰相反,该驱动程序是写给ndis接口的,它通过符合ndis的相应传输协议来请求服务。这些接口包含在windows nt的网络体系结构中,以容纳可移植、可互换的模块。

在两个接口之间,是传输协议。它在网络中起着组织者的作用。一个传输协议规定了数据以何种方式呈递给下一个接收层,以及如何对数据相应地进行打包。它通过ndis把数据传给网卡驱动程序,并通过tdi把数据传给转发程序(redirector)

tdi之上是转发程序,它把本地的网络资源申请转送给网络。

为了能和其他厂商的网络互连,windows nt允许有多个转发程序。对于每一个转发程序windows nt计算机必须也有一个相应的供应者(provider)(由网络厂商提供)。多供应者路由选择程序决定适当的供应者,然后借助于供应者,对应用请求到相应的转发程序做出选择。

§1.1.2 windows nt网络驱动程序

windows nt支持两种类型的网络驱动程序

传输驱动程序

实现数据链路层中的逻辑链路控制子层协议和传输层协议。向 下与ndis接口,向上与tdi接口。

网卡驱动程序

实现对物理层的管理和数据链路层中介质访问控制子层协议,通过ndis向下管理物理网卡,向上与传输驱动程序通信。

§1.1.3 windows nt网卡驱动程序

windows nt环境下的网卡驱动程序也分为两种:

miniport网卡驱动程序:miniport驱动程序只须实现与网络硬件相关的操作(包括发送和接收)。而所有底层网卡驱动程序的通用操作(如同步),一般由ndis接口程序来实现。

full网卡驱动程序:full网卡驱动程序必须实现所有硬件相关和同步、排队等操作。例如full网卡驱动程序为了响应数据接收,需要保持本身的捆绑信息,而miniport就可以由ndis接口库来实现。

在windows nt的早期版本中,full网卡驱动程序要求开发者实现许多底层操作,来处理多处理器的核心问题以及处理器、线程的同步,这样不同的开发者在大量重复着许多相同的工作。

而miniport网卡驱动程序允许开发者仅仅写一些与网络硬件相关的代码即可,而那些通用的函数由ndis接口库来实现,这样开发出来的驱动程序减少了不必要的工作。

第二节miniport驱动程序的结构

ndis接口规范了网卡驱动程序的实现,同时也对tdi驱动程序的实现提出了一定的要求,在nt中,ndis约束下的网卡驱动程序、tdi驱动程序和系统的关系如下图所示:

图2.0 ndis约束下的网卡驱动程序、tdi驱动程序和系统的关系

miniport驱动程序包括驱动程序对象、驱动程序源代码和ndis接口库代码。windows nt ddk提供ndis.h作为miniport驱动程序的主要头文件,定义了miniport驱动程序的入口点、ndis接口库函数和通用数据结构。

上边缘函数的作用是网卡驱动与ndis接口库进行通信,而下边缘函数是tdi协议驱动程序与ndis通信的手段。

§1.2.1 miniport网卡对象

ndis用一个叫做逻辑网卡的软件对象来描述系统中的每块网卡,而逻辑网卡与windows nt设备对象的通信由i/o子系统来管理,描述网卡的设备对象包括相关的网络信息如名字、网络地址和网卡内存基地址等,它还包含与硬件相关的驱动程序状态数据(捆绑数目,捆绑句柄,包过滤数据库等)。ndis分配一个句柄到miniportinitialize这个上边缘函数的一个结构中,然后miniport网卡驱动程序将在以后提供这个句柄来给ndis调用,这个结构一直被ndis保持,并且对miniport驱动程序不透明。

当miniport网卡驱动程序初始化一块网卡时,它创立自己的内部数据结构来描述网卡,记录需要它管理的与设备相关的状态信息。当miniport网卡驱动程序调用ndismsetatttibutes或ndismsetattributesex两ndis库函数时,它传递一个句柄给这数据结构。这样,当调用miniport驱动程序入口点时,它就传递这个句柄来验证驱动程序所对应的网卡的正确性。这个数据结构为miniport网卡驱动程序所拥有并维护。

§1.2.2网络对象标识符

miniport nic驱动程序还需要维护一组对象,这些对象是系统定义的对象标识符(object idetifier:oid)来标识,以描述驱动程序的性能和当前状态信息。为查询这些信息,上层驱动程序调用ndisrequest向ndis接口库指示oid。oid表示了调用所需的信息类型,如miniport驱动程序所支持的lookahead缓冲区大小等。ndis接到上层驱动程序的查询请求,将oid传递给上边缘函数miniportqueryinformation实现对oid的查询,如果上层驱动程序请求改变状态信息则调用miniportsetinformation实现对oid的设置。

§1.2.3 miniport网卡驱动程序代码

典型的miniport nic驱动程序必须有一些函数来通过ndis接口实现上层驱动程序与硬件的通信。这些函数称为上边缘服务函数。

这些上边缘服务函数由驱动程序的开发者根据驱动程序面向的特定低层网络类型和硬件以及相应环境,可以有选择地实现,但必须保证驱动程序最基本的功能,这些基本功能包括初始化、发送、中断处理、重置、参数查询与设置和报文接收。

miniportinitialize:操作系统根据系统配置信息,检测出网卡已安装时,由ndis接口在初始化时调用,主要完成低层网络类型确定,对应于物理网卡的逻辑网卡初始化,中断信息注册,网卡与主机通讯方式的确认。i/o端口的申请与注册,内存映像,mib的初始化,物理网卡的验证与初始化等。

miniportreconfigure:支持网卡参数动态变化,和miniportinitilize一样由ndis接口以初始化级别调度执行(不能屏蔽中断,必须由驱动程序承认并清除在此期间产生的中断),支持即插即用和软配置的网卡在动态改变参数时,必须提供此函数。

miniportqueryinformation:查询网卡的状态以及网卡驱动程序的操作或统计参数,如是否支持组通讯、网卡的物理速率是否支持回环、是否支持直接拷贝等,这些参数以oid方式统一管理。

miniportsetinformation:ndis接口或协议驱动程序通过调用此接口改变驱动程序维护的oid库,一些操作参数的改变也将同时改变驱动程序状态,例如组地址的设置。

miniportreset:包括网卡硬件重置和驱动程序软件重置,软件重置包括驱动程序状态重置,以及一些相关的参数重置,还需考虑有些参数的恢复,重置时不必完成所有正在活跃的外部请求,但必须释放已占用的外部资源。

miniporthalt:挂起网卡并释放该网卡驱动程序占用的所有资源,在此期间不屏蔽中断。

miniportisr:高优先级的中断处理程序,进行的工作包括初始中断处理类型,决定是否进行中断转交,对卡上中断进行处理 等,该服务类型只在以下情况被调用:

ndis接口调用miniportinitialize和miniporthalt两函数时。

.中断处理类型设为每此中断处理过程都调用时。

为使系统能及时响应所有硬件中断,高优先级的硬件中断处理程序应尽可能的减少运行时间,防止长时间的屏蔽低优先级中断,避免造程中断丢失。

miniporthandleinterrupt:由中断延时处理程序在中断延时处理时进行调用。ndis排队所有的延时处理,该服务主要处理发送完成、报文接收、描述符用尽、溢出、网卡异常等中断。

miniportsend:ndis收到上层发送请求时经过若干协议处理再向下调用此服务过程,发送的packet已含有llc和mac头,该服务过程进行边界对齐、packet约束重整、描述符映射和报文发送、以及发送资源和packet缓冲队列管理。

miniporttransferdata:多个已和网卡捆绑的协议驱动程序在接收到报文到达指示后,向网卡驱动程序发出传送请求以拷贝各自所需的报文数据部分,网卡驱动程序根据各协议驱动程序对单个packet是否进行多次拷贝,以决定是否暂存只允许单次拷贝的packet等。

miniportcheckhandle:ndis每秒调用此服务函数一次,驱动程序发现网卡异常时报告给ndis由ndis调用miniportreset进行硬件重恢复。

miniportenableintrrupt:中断使能。

miniportdisableinterrupt:中断屏蔽。

另外,每个网卡驱动程序必须有一个初始化入口点,由driver entry函数实现,它和系统相关,由操作系统在装入驱动程序时调用,主要完成初始化ndis wrapper,再由wrapper初始生成驱动程序管理块并完成相应各种初始化工作,登录网卡驱动程序所有上边缘服务入口点,同时写入ndis版本信息。

§1.2.4 ndis接口库

ndis接口库包括在ndis.sys中,它是一个核态函数库,有一套抽象的函数,无论协议驱动程序还是nic驱动程序都连接到这个库中,以实现上下层之间的操作。

第二章fddi网卡驱动程序的加载和运行

第一节 网卡驱动程序的安装

windows nt网卡驱动程序安装的目的是实现网卡相应硬件信息和驱动程序在windows nt注册库中的注册,使windows nt能够正确识别网卡,了解所必需的软硬件信息并能在windows nt启动时加载相应驱动程序。

网卡驱动程序安装时,首先在主群组的控制面板中选择“网络”,然后添加网卡,指定相应信息文件──oemsetup.inf的路径,以完成以下两个必要的操作:

复制驱动程序到相应的系统目录(windows nt根目录\system32\drivers\)中;

在windows nt注册库中存入相应软硬件信息。

下面主要以fddi网卡为例介绍安装驱动程序所必需的工作:

§2.1.1网卡一般硬件参数

对于fddi网卡,必须在编写其oemsetup.inf文件时确定以下硬件参数:

总线类型:pci(5)……括号中的数字5表示pci总线在ndis中的总线类型代码;

厂商代号:0x5588……系统加载时确定网卡的标记,也是编程时确定pci槽号的标识;

cfid: 0x01;

介质类型:光纤(3) ……括号中的数字表示光纤在ndis中的介质类型代码;

是否支持全双工:支持。

对于其它的硬件信息在此inf配置信息文件中可有可无,如若配置,则可在驱动程序的编写时利用这些信息,方便编程,同时有利于其它应用对其参数的确定和使用。

§2.1.2 fddi网卡加载时需在注册库登录表里做的网络配置

网卡驱动程序的安装通常将创建登录表中的四个不同子键:

software registrion键,对应于驱动程序,存在于hkey_local_machine\software\company\ productname\version中。我们的fddi网卡驱动程序所对应的是hkey_local_machine\software\net612\yhfddi\yhfddi1.0;

网卡的软件登录键,存在于hkey_local_machine\software\microsoft\ windows nt\nt3.51\networkcards\yhfddi1;

驱动程序的服务登录键,存在于hkey_local_machine\system\currentcontrolset\services

网卡的服务登录键,存在于hkey_local_machine\system\currentcontrolset\services

对于每一个网络部件,一个名为netrules的特殊子键在邻近的驱动程序或网卡登录子键里创建,netrules标识网络部件为网络整体的一部分。

fddi网卡驱动程序对应的标准软件登录表项将出现在以下路径:

hkey_local_machine\software\net612\yhfddi\yhfddi1.0;

驱动程序对应的标准项的值为:

description =yhfddi/pci adapter controller

install date =……

……

refcount =0x01

servicename =yhfddi

softwaretype =driver

title =yhfddi/pci adapter controller

而且在yhfddi驱动程序相关的netrules子键下,这些值项为:

bindable =yhfddi driver yhfddi adapter non exclusiver

bindform =“yhfddisys”yes no container

class = reg_multi_sz “yhfddi driver basic”

infname =oemnad1.inf

type =yhfddisys ndisdriver yhfddidriver

use =driver

yhfddi网卡在如下路径的networkcards子键里介绍:

hkey_local_machine\software\microsoft\

windows nt\nt3.51\networkcards\yhfddi1;

网卡的标准项包括以下这些值:

description =yhfddi/pci adapter controller

install date =……

manufacturer =net612

productname =yhfddi

servicename =yhfddi01

title =[01]yhfddi/pci adapter controller

§2.1.3编写inf信息配置文件

gui inf描述语言被windows nt用以书写系统所有部件的配置文件,当然也可以用以书写网络系统各部件的配置文件,该配置文件描述了网络部件安装、配置、删除的执行过程。当网络部件进行初始安装或二次安装(通常通过ncpa进行)时,安装程序读取部件对应的配置文件,进行解释执行。gui inf描述语言由节、命令、逻辑操作、变量规范、流程控制以及一套调用dll或外部程序的机制组成,其中,节是配置文件的主体,节可分为install节(类似于函数),shell节(也类似于函数,但可调用insall和shell节),detect节(不包含命令),一个配置文件一般由若干不同类型的节组成。驱动程序的开发者根据需要可以在配置文件中编写相应代码,使得用户和系统之间能进行交互,并且由用户决定一些配置参数。

nt网卡配置文件有其一套规范,驱动程序开发者必须按规范编写配置文件,一般来说,一个配置文件至少应该提供下面三个节:

安装入口点:[identify]shell节。该节主要功能是给出安装部件的类型名,系统通过它识别该部件属于哪一大类(display,mouse,scsi,network等)中的哪一类(网络adapter,driver,transport,service,network和netprovidor),同时,还需要给出映像文件和配置文件所在的源介质及标识。

[returnoption]shell节。系统执行安装identify节后,执行该节。它主要功能是检查所需安装的部件是否支持的硬件平台和语言,并给出网卡名(有些配置文件支持多类网卡,此时必须让用户进行选择,并获得选择结果)。

[installoption]shell节。该节是配置文件得主体,也是上次安装完后再次进行配置、删除、更新的入口点。主要功能是拷贝映像文件和配置文件,生成配置的各种选项,创建该部件在注册库中对应的各种登录子树并更新重写。

第二节 驱动程序的加载过程

§2.2.1 windows nt的启动过程

第一阶段:调入装入程序。和硬件平台相关,x86机器首先由rom装入根扇区,再由根扇区装入ntldr;

第二阶段:硬件检测。x86机器调ntdetect程序最大限度地获取各种硬件设备信息,引导hal及基本卷设备驱动程序,以便引导nt内核;

第三阶段:获取注册库中各种控制信息,如用户定义的非页内存大小;第四阶段:初始化注册库 \registry\machine下system和hardware并创建currentcontrolset,为装入相关硬件设备驱动程序作准备;

第五阶段:装入基本核心驱动程序;

第六阶段:释放一些已经完成使命的装入初始数据块;

第七阶段:进一步初始化注册库,以便有些依赖于基本核心驱动程序的上层驱动程序能顺利装入;

第八阶段:服务控制器装入应该由该服务控制器装入的各种驱动程序。

§2.2.2 fddi网卡驱动程序的加载过程

在windows nt启动的第五个阶段,将加载核心驱动程序。而对于ndis网卡驱动程序是在ndis接口(ndis.sys)加载后调入运行,向ndis wrapper注册、初始化、查询设置参数等。

windows nt启动时,相应的实体如nt的服务控制器根据注册库中yhfddi驱动程序的配置注册信息,初始化ndis wrapper,并装入相应的驱动程序,生成驱动程序管理块结构,申请内存以保存各种信息,向ndis wrapper注册驱动程序。初始化和注册完毕后,再由服务控制器读取注册库中相应的链接信息。

在ndis wrapper和yhfddi驱动程序初始化和注册成功后,ndis wrapper根据系统相应的注册信息,加入和yhfddi驱动程序所对应的fddi网卡,同时读入网卡的注册信息,并进行网卡注册和网卡初始化。

在以上过程成功后,wrapper将查询和设置驱动程序的各种参数,了解驱动程序对哪些操作支持,决定对上层驱动程序的支持范围。

第三节fddi网卡驱动程序的注册

driverentry函数是windows nt ddk规定的核心驱动程序的入口点,wrapper识别到入口点后,调入驱动程序,在driverentry函数内完成两个基本注册任务:

调用ndisminitializewapper函数向ndis接口报告驱动程序将以miniport类网卡驱动程序注册。ndis建立它需要记录的驱动程序状态信息,同时返回ndiswrapperhandle,驱动程序保存这个句柄,以利后来调用ndisxxxconfiguration和initialization等函数。

填写ndisxx_miniport_characteristics属性结构,主要记录ndis版本号和驱动程序支持的miniportxxx函数的入口点,然后调用ndismregisterminiport函数实现驱动程序的整体注册。

以yhfddi为例所要注册的属性结构的内容大致如下:

ndis_miniport_characteristics yhfddichar;

(ndis_miniport_characteristics这个结构将在第三章介绍)

yhfddichar.majorndisversion=yhfddi_ndis_major_version;

yhfddichar.minorndisversion=yhfddi_ndis_minor_version;

这两个属性决定驱动程序是ndis的哪个版本所支持,我们所用的是ndis3.0

yhfddichar.disableinterrupthandler=yhfddidisableinterrupt;

yhfddichar.enableinterrupthandler=yhfddienableinterrupt;

yhfddichar.isrhandle=yhfddiinterruptservice;

yhfddichar.handleinterrupthandler=yhfddihandleinterrupt;

以上四项属性是中断处理所需的上边缘服务函数的入口点(句柄)。fddi网卡驱动程序需要有smt站管理功能,而smt是以中断处理方式进行的,故这四项属性在fddi网卡驱动程序中是很重要的。

yhfddichar.initializehandler=yhfddiinitialize;

此项注册的是驱动程序的初始化函数句柄。

yhfddichar.queryinformationhandler= yhfddiqueryinformation;

yhfddichar.setinformationhandler=yhfddisetinformation;

这两项注册的是参数查询和设置函数的句柄。

yhfddichar.sendhanler= yhfddisend;

yhfddichar.transferdatahandler= yhfdditransferdata;

主要提供数据发送和接收函数句柄。

yhfddichar.resethandler=yhfddireset;

此项注册网卡软硬件重置函数句柄。

yhfddichar.halthandler= yhfddihalt;

此项注册网卡驱动程序挂起函数句柄。

yhfddichar.checkforhandler=null;

yhfddichar.reconfigurehandler=null;

这两个上边缘服务函数是fddi网卡驱动程序所不提供的,故置为null。

填好这些结构以后,调用以下函数实现驱动程序的注册:

ndismregisterminiport(

yhfddiwrapperhandle,

&yhfddichar,

sizeof(yhfddichar));

其中yhfddiwrapperhandle是在此之前初始化wrapper调用ndisminitializewrapper所得的句柄。

如果调用ndismregisterminiport不能返回ndis_status_success,必须在退出driverentry之前释放已经分配的资源(如yhfddiwrapperhandle等),故调用

ndisterminatewrapper(yhfddiwrapperhandle,null)。

这样驱动程序没能正确注册,亦不能正常运行。

第四节 网卡驱动程序对象查询与设置

如果ndis的管理实体要查询或设置一个特定的网络对象,它必须提供一个32位的oid。oid的结构如下: 图2.3.0 oid结构图

由上可以看到,oid可分为三大类:

所有ndis驱动程序都有的一般对象;

特定介质的对象;

特殊的与具体实现相关的对象(如多目地址表的长度)。

一般的和特定介质的oid被记录在windows nt ddk中,对于这些oid ddk文本指明了相关的对象能否通过miniportqueryinformation查询参数和通过miniportsetinformation设置参数。

oid也可被分为操作特性(如多目地址表长度参数)和统计参数(如广播包接收)。最后oid可分为必须的和可选的两种。

oid的前三个字节表明oid的不同类别,而最后一个字节确定这一类别内特定的信息管理对象。

针对于fddi网卡,被查询的oid的第一个字节为0x03。而ndis所查询的介质相关参数为:

0x03010104 oid_fddi_long_max_list_size

0x03010108 oid_fddi_short_max_list_size

0x03010102 oid_fddi_long_current_addr

0x03010106 oid_fddi_short_current_addr

tcp/ip传输驱动程序所要查询的fddi oid为:

0x03010102 oid_fddi_long_current_addr

0x03010103 oid_fddi_long_multicast_list

0x03010107 oid_fddi_short_multicast_list

通过以上两阶段的查询,ndis和tcp/ip驱动程序就分别了解了网卡驱动程序对其的支持,从而进行相应的捆绑,以便数据传输时正确选择网卡驱动程序。

第五节 开发环境与调试方法

开发环境:

fddi网卡驱动程序的开发环境为nt server 3.51,sdk,ddk for workstation 3.51, vc++4.1,硬件平台为586。

调试平台:

主机为nt server 3.51,windbg32

目标机为nt workstation3.51 (check 944)

调试方法:

利用dbgprint把目标机上关键信息通过串口传到主机进行分析,以得出ndis驱动程序的调度机制和运转状况;

利用assert产生异常断点,由主机对异常进行控制

自定义宏,进行分级控制,以根据不同情况产生不同调试信息

第四章 与smt移植相关的问题讨论

在本yhfddi网卡驱动程序中,smt的移植是极其关键的一部分,主要承担了驱动程序中硬件初始化和中断延迟处理。但由于smt是相对独立的软件,这样就有一个ndis wrapper与smt间参数传递的问题。所以本章主要讨论miniport驱动程序与smt的关系和移植smt过程中初始化的要求、中断处理的要求,ndis wrapper与smt如何传递参数。

(一)miniport fddi网卡驱动程序与smt的关系。

在第一章已经谈及网卡驱动程序主要实现osi参考模型中的物理层和mac层。而对于fddi网络的物理层又可分为介质相关子层和介质无关子层。

对于我们的fddi/pci是基于x.3.19、x3.148、x3.166和x3.229而实现的。

smt在整个iso七层模型中属低两层范畴。下图是iso模型与fddi层次的对应关系,从而可知fddi miniport驱动程序在nt网络结构中的位置。

即在windows nt fddi网卡驱动程序应包含smt,实现fddi拓扑环上的站管理。

而在驱动程序内部smt主要是在miniport驱动程序中的中断延迟处理上边缘服务中实现的,也可以说是将smt嵌入中断延迟处理程序中,实现ndis接口对smt的正确调度。

yh-fddi驱动程序的实现可分为硬件无关部分和硬件相关部分。

移植smt过程中初始化的要求.

这里的初始化主要是指硬件初始化,包括寄存器的初始化和数据结构的初始化,由smt共用的硬件相关例程库中硬件初始化部分来完成. 我们在开发过程序是调用fddi_main(bdd_t*bdd)这个函数来调用smt共用的硬件相关例程库的.可见使用fddi_main(bdd_t*bdd)时,需要传递bdd这个参量,而bdd_t这个数据结构的定义如下:

它包含了各类硬件寄存器的基址,所以要对其进行正确赋值就必须首先在nt的内存中映射一块虚存与网卡内存相对应,也就实现了bdd_t结构的赋值,对fddi_main(bdd_t *bdd)的正确调用.

因此,我们在调用fddi_main前首先将网卡上寄存器内存空间映射到nt的虚存空间上,并将bdd结构正确赋值.以映射bsi_phy_base为例,具体过程如下:

pchar destination;

bdd_t *bdd;

ndis_physical_address physicaladdress;

ulong baseaddress;

ndis_status status;

baseadress =0x0d0000+bsi_phy_base;

ndissetphysicaladdresshigh(physicaladdress,0);

ndissetphysicaladdresslow(physicaladdress,baseaddress);

status=ndismmapiospace(

(pvoid *)&destination,

miniportadapterhandle,

physicaladdress,

bsi_phy_len

);

bdd->bsi_vir_base=(pchar) destination;

adapter-> bdd->bsi_vir_base= bsi_vir_base;

/*对adapter结构中的bdd结构赋值,以便在其它上边缘函数中使用这些虚存基地址*/

中断处理要求.

对于中断处理,在smt中主要调用cspintrhandandler()来实现.我们的fddi网卡驱动程序是miniport方式的,若在isr中做此处理将占用大量系统资源,使系统崩溃,所以我们采用只在isr中进行中断的排队,而在dpc中调用cspintrhandler()来完成中断处理.

在中断处理方面还有一个中断屏蔽和中断使能的问题,这两方面smt并不提供,故我们要正确处理.

具体处理方法见第三章.

ndis wrapper与smt间参数如何传递.

miniport方式的网卡驱动程序中,网卡上有中断时,系统反映给ndiswrapper,再由wrapper调度中断处理上边缘服务实现中断处理,在我们的yhfddi网卡驱动程序的中断具体处理是smt完成的所以在调用cspintrhandler时应将adapter结构传进smt以便在以后应用.

如在处理接收中断时,处理的最后应调用ndisindicatefddireceive,向ndiswrapper指示以接收到一个数据包,而ndisindicaterfddireceive的调用需要adapterminiporthandle作为参数,这就必须一级级从中断延迟处理函数(yhfddi handleinterrupt)中将adapter结构传递下来. 当然,其它方面如发送,也会有类似的问题需要考虑.

总之,对于smt的移植,需要详尽的在程序中做好接口,才能实现与

smt的数据交换.

结束语

ndis规范在网络两层间提供了一个统一界面,ndis对网络本身而言,是一个带有协议功能的标准接口,对实现者而言,它应该是一个环境,这种环境不仅带有协议功能,更重要的是带有和软、硬平台无关的核心功能支持,它不会受软、硬平台的变化严重影响,无疑,它是软件的移植和兼容的可靠保证,ndis把网络的一部分共性抽象出来,并根据具体的操作系统实现系统和平台相关的基础库以保证ndis的标准性和对开发者提供最大的功能支持,这也将加速和规范开发过程,但是,在操作系统之上提供ndis基础库获得标准同时也失去直接作用于操作系统带来的灵活性以及更强的功能支持,同时,ndis处于网络中层和低层之间,低层网络的快速发展和ndis对网络部分共性的抽象必然导致ndis对实现者的滞后,例如ddk3.51提供的ndis开发环境只支持10m以太网、fddi、令牌网(802.5)、localtalk、arcnet等,而对新出现的快速以太网及atm不提供支持,这对我们如何在ndis环境下实现诸如atm的lan emulation,ip over atm、快速以太网带来很大问题。

smt是实现fddi网卡驱动程序的关键,然而由于应用ddk开发miniport驱动程序时要遵循其结构框架,所以要想完整地按其结构移植smt,就必须分解smt适应之,即要求对smt有一个很好的理解。但smt是庞大的给开发带来了一定的困难。

参考文献

【1】《device driver kit用户手册》

【2】《device driver kit核心驱动程序设计》

驱动程序设计篇13

第七阶段:进一步初始化注册库,以便有些依赖于基本核心驱动程序的上层驱动程序能顺利装入;

第八阶段:服务控制器装入应该由该服务控制器装入的各种驱动程序。

§2.2.2 fddi网卡驱动程序的加载过程

在windows nt启动的第五个阶段,将加载核心驱动程序。而对于ndis网卡驱动程序是在ndis接口(ndis.sys)加载后调入运行,向ndis wrapper注册、初始化、查询设置参数等。

windows nt启动时,相应的实体如nt的服务控制器根据注册库中yhfddi驱动程序的配置注册信息,初始化ndis wrapper,并装入相应的驱动程序,生成驱动程序管理块结构,申请内存以保存各种信息,向ndis wrapper注册驱动程序。初始化和注册完毕后,再由服务控制器读取注册库中相应的链接信息。

在ndis wrapper和yhfddi驱动程序初始化和注册成功后,ndis wrapper根据系统相应的注册信息,加入和yhfddi驱动程序所对应的fddi网卡,同时读入网卡的注册信息,并进行网卡注册和网卡初始化。

在以上过程成功后,wrapper将查询和设置驱动程序的各种参数,了解驱动程序对哪些操作支持,决定对上层驱动程序的支持范围。

第三节fddi网卡驱动程序的注册

driverentry函数是windows nt ddk规定的核心驱动程序的入口点,wrapper识别到入口点后,调入驱动程序,在driverentry函数内完成两个基本注册任务:

调用ndisminitializewapper函数向ndis接口报告驱动程序将以miniport类网卡驱动程序注册。ndis建立它需要记录的驱动程序状态信息,同时返回ndiswrapperhandle,驱动程序保存这个句柄,以利后来调用ndisxxxconfiguration和initialization等函数。

填写ndisxx_miniport_characteristics属性结构,主要记录ndis版本号和驱动程序支持的miniportxxx函数的入口点,然后调用ndismregisterminiport函数实现驱动程序的整体注册。

以yhfddi为例所要注册的属性结构的内容大致如下:

ndis_miniport_characteristics yhfddichar;

(ndis_miniport_characteristics这个结构将在第三章介绍)

yhfddichar.majorndisversion=yhfddi_ndis_major_version;

yhfddichar.minorndisversion=yhfddi_ndis_minor_version;

这两个属性决定驱动程序是ndis的哪个版本所支持,我们所用的是ndis3.0

yhfddichar.disableinterrupthandler=yhfddidisableinterrupt;

yhfddichar.enableinterrupthandler=yhfddienableinterrupt;

yhfddichar.isrhandle=yhfddiinterruptservice;

yhfddichar.handleinterrupthandler=yhfddihandleinterrupt;

以上四项属性是中断处理所需的上边缘服务函数的入口点(句柄)。fddi网卡驱动程序需要有smt站管理功能,而smt是以中断处理方式进行的,故这四项属性在fddi网卡驱动程序中是很重要的。

yhfddichar.initializehandler=yhfddiinitialize;

此项注册的是驱动程序的初始化函数句柄。

yhfddichar.queryinformationhandler= yhfddiqueryinformation;

yhfddichar.setinformationhandler=yhfddisetinformation;

这两项注册的是参数查询和设置函数的句柄。

yhfddichar.sendhanler= yhfddisend;

yhfddichar.transferdatahandler= yhfdditransferdata;

主要提供数据发送和接收函数句柄。

yhfddichar.resethandler=yhfddireset;

此项注册网卡软硬件重置函数句柄。

yhfddichar.halthandler= yhfddihalt;

此项注册网卡驱动程序挂起函数句柄。

yhfddichar.checkforhandler=null;

yhfddichar.reconfigurehandler=null;

这两个上边缘服务函数是fddi网卡驱动程序所不提供的,故置为null。

填好这些结构以后,调用以下函数实现驱动程序的注册:

ndismregisterminiport(

yhfddiwrapperhandle,

&yhfddichar,

sizeof(yhfddichar));

其中yhfddiwrapperhandle是在此之前初始化wrapper调用ndisminitializewrapper所得的句柄。

如果调用ndismregisterminiport不能返回ndis_status_success,必须在退出driverentry之前释放已经分配的资源(如yhfddiwrapperhandle等),故调用

ndisterminatewrapper(yhfddiwrapperhandle,null)。

这样驱动程序没能正确注册,亦不能正常运行。

第四节 网卡驱动程序对象查询与设置

如果ndis的管理实体要查询或设置一个特定的网络对象,它必须提供一个32位的oid。oid的结构如下: 图2.3.0 oid结构图

由上可以看到,oid可分为三大类:

所有ndis驱动程序都有的一般对象;

特定介质的对象;

特殊的与具体实现相关的对象(如多目地址表的长度)。

一般的和特定介质的oid被记录在windows nt ddk中,对于这些oid ddk文本指明了相关的对象能否通过miniportqueryinformation查询参数和通过miniportsetinformation设置参数。

oid也可被分为操作特性(如多目地址表长度参数)和统计参数(如广播包接收)。最后oid可分为必须的和可选的两种。

oid的前三个字节表明oid的不同类别,而最后一个字节确定这一类别内特定的信息管理对象。

针对于fddi网卡,被查询的oid的第一个字节为0x03。而ndis所查询的介质相关参数为:

0x03010104 oid_fddi_long_max_list_size

0x03010108 oid_fddi_short_max_list_size

0x03010102 oid_fddi_long_current_addr

0x03010106 oid_fddi_short_current_addr

tcp/ip传输驱动程序所要查询的fddi oid为:

0x03010102 oid_fddi_long_current_addr

0x03010103 oid_fddi_long_multicast_list

0x03010107 oid_fddi_short_multicast_list

通过以上两阶段的查询,ndis和tcp/ip驱动程序就分别了解了网卡驱动程序对其的支持,从而进行相应的捆绑,以便数据传输时正确选择网卡驱动程序。

第五节 开发环境与调试方法

开发环境:

fddi网卡驱动程序的开发环境为nt server 3.51,sdk,ddk for workstation 3.51, vc++4.1,硬件平台为586。

调试平台:

主机为nt server 3.51,windbg32

目标机为nt workstation3.51 (check 944)

调试方法:

利用dbgprint把目标机上关键信息通过串口传到主机进行分析,以得出ndis驱动程序的调度机制和运转状况;

利用assert产生异常断点,由主机对异常进行控制

自定义宏,进行分级控制,以根据不同情况产生不同调试信息

第四章 与smt移植相关的问题讨论

在本yhfddi网卡驱动程序中,smt的移植是极其关键的一部分,主要承担了驱动程序中硬件初始化和中断延迟处理。但由于smt是相对独立的软件,这样就有一个ndis wrapper与smt间参数传递的问题。所以本章主要讨论miniport驱动程序与smt的关系和移植smt过程中初始化的要求、中断处理的要求,ndis wrapper与smt如何传递参数。

(一)miniport fddi网卡驱动程序与smt的关系。

在第一章已经谈及网卡驱动程序主要实现osi参考模型中的物理层和mac层。而对于fddi网络的物理层又可分为介质相关子层和介质无关子层。

对于我们的fddi/pci是基于x.3.19、x3.148、x3.166和x3.229而实现的。

smt在整个iso七层模型中属低两层范畴。下图是iso模型与fddi层次的对应关系,从而可知fddi miniport驱动程序在nt网络结构中的位置。

即在windows nt fddi网卡驱动程序应包含smt,实现fddi拓扑环上的站管理。

而在驱动程序内部smt主要是在miniport驱动程序中的中断延迟处理上边缘服务中实现的,也可以说是将smt嵌入中断延迟处理程序中,实现ndis接口对smt的正确调度。

yh-fddi驱动程序的实现可分为硬件无关部分和硬件相关部分。

移植smt过程中初始化的要求.

这里的初始化主要是指硬件初始化,包括寄存器的初始化和数据结构的初始化,由smt共用的硬件相关例程库中硬件初始化部分来完成. 我们在开发过程序是调用fddi_main(bdd_t*bdd)这个函数来调用smt共用的硬件相关例程库的.可见使用fddi_main(bdd_t*bdd)时,需要传递bdd这个参量,而bdd_t这个数据结构的定义如下:

它包含了各类硬件寄存器的基址,所以要对其进行正确赋值就必须首先在nt的内存中映射一块虚存与网卡内存相对应,也就实现了bdd_t结构的赋值,对fddi_main(bdd_t *bdd)的正确调用.

因此,我们在调用fddi_main前首先将网卡上寄存器内存空间映射到nt的虚存空间上,并将bdd结构正确赋值.以映射bsi_phy_base为例,具体过程如下:

pchar destination;

bdd_t *bdd;

ndis_physical_address physicaladdress;

ulong baseaddress;

ndis_status status;

baseadress =0x0d0000+bsi_phy_base;

ndissetphysicaladdresshigh(physicaladdress,0);

ndissetphysicaladdresslow(physicaladdress,baseaddress);

status=ndismmapiospace(

(pvoid *)&destination,

miniportadapterhandle,

physicaladdress,

bsi_phy_len

);

bdd->bsi_vir_base=(pchar) destination;

adapter-> bdd->bsi_vir_base= bsi_vir_base;

/*对adapter结构中的bdd结构赋值,以便在其它上边缘函数中使用这些虚存基地址*/

中断处理要求.

对于中断处理,在smt中主要调用cspintrhandandler()来实现.我们的fddi网卡驱动程序是miniport方式的,若在isr中做此处理将占用大量系统资源,使系统崩溃,所以我们采用只在isr中进行中断的排队,而在dpc中调用cspintrhandler()来完成中断处理.

在中断处理方面还有一个中断屏蔽和中断使能的问题,这两方面smt并不提供,故我们要正确处理.

具体处理方法见第三章.

ndis wrapper与smt间参数如何传递.

miniport方式的网卡驱动程序中,网卡上有中断时,系统反映给ndiswrapper,再由wrapper调度中断处理上边缘服务实现中断处理,在我们的yhfddi网卡驱动程序的中断具体处理是smt完成的所以在调用cspintrhandler时应将adapter结构传进smt以便在以后应用.

如在处理接收中断时,处理的最后应调用ndisindicatefddireceive,向ndiswrapper指示以接收到一个数据包,而ndisindicaterfddireceive的调用需要adapterminiporthandle作为参数,这就必须一级级从中断延迟处理函数(yhfddi handleinterrupt)中将adapter结构传递下来. 当然,其它方面如发送,也会有类似的问题需要考虑.

总之,对于smt的移植,需要详尽的在程序中做好接口,才能实现与

smt的数据交换.

结束语

ndis规范在网络两层间提供了一个统一界面,ndis对网络本身而言,是一个带有协议功能的标准接口,对实现者而言,它应该是一个环境,这种环境不仅带有协议功能,更重要的是带有和软、硬平台无关的核心功能支持,它不会受软、硬平台的变化严重影响,无疑,它是软件的移植和兼容的可靠保证,ndis把网络的一部分共性抽象出来,并根据具体的操作系统实现系统和平台相关的基础库以保证ndis的标准性和对开发者提供最大的功能支持,这也将加速和规范开发过程,但是,在操作系统之上提供ndis基础库获得标准同时也失去直接作用于操作系统带来的灵活性以及更强的功能支持,同时,ndis处于网络中层和低层之间,低层网络的快速发展和ndis对网络部分共性的抽象必然导致ndis对实现者的滞后,例如ddk3.51提供的ndis开发环境只支持10m以太网、fddi、令牌网(802.5)、localtalk、arcnet等,而对新出现的快速以太网及atm不提供支持,这对我们如何在ndis环境下实现诸如atm的lan emulation,ip over atm、快速以太网带来很大问题。

smt是实现fddi网卡驱动程序的关键,然而由于应用ddk开发miniport驱动程序时要遵循其结构框架,所以要想完整地按其结构移植smt,就必须分解smt适应之,即要求对smt有一个很好的理解。但smt是庞大的给开发带来了一定的困难。

参考文献

【1】《device driver kit用户手册》

【2】《device driver kit核心驱动程序设计》

【3】《device driver kit网络驱动程序设计》

在线咨询