欢迎来到易发表网,发表咨询:400-808-1701 订阅咨询:400-808-1721

关于我们 期刊咨询 科普杂志

驱动程序设计优选九篇

时间:2023-03-02 15:08:39

驱动程序设计

驱动程序设计第1篇

关键词:wince 驱动程序;开发;设计

1 引言

WINCE和Windows 98或Windows 2000不同,它可以工作在12种不同的处理器体系结构、180余种CPU上;同时,WINCE是一个实时操作系统(实时系统的意义就是输入的指令不必进入队列就可以马上处理,过去我们使用的DDS就是实时系统),可以满足应用程序所需要的实时性要求。

Windows CE的模块化设计使得它能够在大量的平台上定制使用,从客户电子设备到专用的工业控制器。由于它是模块化的,因而我们可以使用满足平台系统需求的最小软件模块和组件集合来设计嵌入式系统平台,从而使内存用量最小,但最大可能地提高操作系统的性能。因此外围扩展设备就必须要有硬件驱动才能正常工作。

和其它的操作系统一样,Windows CE也提供设备驱动软件,这些软件的目的是驱动内部和外围的硬件设备,或为它们提供接口。设备驱动程序将操作系统和设备链接起来,使得操作系统能够识别设备或者为应用程序提供设备服务。

Windows CE支持广泛的基于各种CE平台的设备驱动程序。也提供一些用于驱动程序开发的模型(model) ,其中包括来自其它操作系统的驱动程序模型(model),因为这些丰富多变的驱动程序模型, Windows CE适应大部分的内部和外围设备口Microsoft Windows CE设备驱动程序工具包配备了文档资料,这些文档资料使得你能够为Windows CE创建设备驱动程序。目前,Windows CE提供了四种设备模型,其中两种是专用于Windows CE的模型,另外两种外部模型来自其它操作系统。

2 驱动程序开发简介

2.1 开发工具

Windows CE驱动可以使用Platform Builder或者Visual Studio开发,但是开发人员一般都使用Platform Builder开发设备驱动程序,对于部分驱动也会使用Visual Studio开发,应用程序开发人员更多的使用Visual Studio开发驱驱动程序。作为BSP(Board Support Package)的一部分进行整体编译开发。

2.2 驱动分类

2.2.1 按加载方式和接口类型分类

1) 本机驱动程序(Built-In Drivers)

通常由GWES加载,驱动接口一般都是定制的(Custom Purpose)。

2) 流驱动程序(Stream Drivers)

通常由Device Manager加载,驱动接口是标准的流式接口。

3) 混和型驱动程序

同时有定制式和流驱动两套驱动接口,但是和系统交互只使用流式驱动接口,比如PC卡槽驱动。

2.2.2 按驱动层次分类

1) 层次型驱动程序(Layered Driver)

> MDD(Model Device Driver),与硬件无关,面向上层应用程序,一般由微软建立统一框架;

> PDD(Platform Dependent Driver),针对具体硬件平台的操作代码,一般由驱动开发商实现MDD和PDD之间通过标准的设备驱动服务供应商接口DDSI连接。

2) 独立型驱动程序(Monolithic Driver)

> 独立驱动程序包含了MDD面向上层应用和PDD面向硬件平台两方面的代码;

> 适用于操作不复杂的驱动;

> 减少了MDD和PDD传递之间传递信息的开销,实时性更强;

3 流驱动程序的实现

    流驱动程序必须实现一套标准接口,流驱动程序适用于IO操作,这也是嵌入式系统中最常见的设备驱动,操作接口和文件系统操作相似,通过CreateFile,ReadFile,WriteFile,IOControl函数等来操作应用程序和流驱动交互,可以把设备当作文件操作。

3.1 文件前缀名确定

    根据文件前缀名在系统中必须唯一这一特点,在定义文件前缀名必须是三个字母,若有多个同类设备,由后缀一个阿拉伯数字区分,例如COM1,LPT3等等。文件前缀名将会在驱动的标准接口函数中体现,比如XXX_Init,XXX_Close等。

3.2 通用函数

    根据设备的不同,所需函数不同,通用函数如下所示:

1) XXX_Init:通知设备管理器为设备初始化分配资源;

2) XXX_Deinit:通知设备管理器回收设备初始化时分配的资源;

3) XXX_Open:打开设备。应用程序调用CreateFile时,通过文件系统映射为XXX_Open;

4) XXX_Close:关闭设备。应用程序调用CloseFile时,通过文件系统映射为XXX_Close;

5) XXX_PowerUp:设备上电时,操作系统调用该函数完成必要的上电操作;

6) XXX_PowerDown:设备掉电时,操作系统调用该函数完成必要的关机操作

7) XXX_Read:从打开的设备文件中读取数据,可以通过ReadFile映射;

8) XXX_Write:向打开的设备文件写数据,可以通过WriteFile映射;

9) XXX_Seek:文件定位,根据设备情况决定是否支持;

10) XXX_IOControl:IO操作扩展,可以根据设备情况来决定支持何种特殊的操作模式。

3.3 DEF文件建立

    流驱动一般以DLL形式存在,DEF文件定义了DLL需要导出的接口集,因此DEF文件的名称与设备驱动名称相同。

3.4 写注册表

    在wince中任何设备的识别都是通过注册表来实现的,因此必须在注册表中添加具体的设备驱动项,以便系统识别。具体方法如下:

在注册表中增加驱动程序入口点,找到注册表项,注册项位于注册表的Root Key下,一般为[HKEY_LOCAL_MACHINEDriversBuiltInSampleDrv],建立必要的子键和键值,“Prefix”和“DLL”是两个重要,而且是必须的键,分别描述了设备前缀名和驱动程序的动态连接库名,然后根据具体设备的需要建立驱动程序需要的其子他键。

4 调试驱动程序

驱动程序编写完毕后,就应该进行硬件的调试。具体方法如下:

4.1 调试区信息(Debug Zone)

调试区一般和WinCE的控制台调试工具Cesh.exe配合调试,在不打断OS运行情况下,进行驱动的实时调试,利用宏开关,可以选择需要输出的调试区信息,可以得到进程,线程和调试状态信息。并且可以利用IDE环境,动态选择开关调试区信息,但是打印驱动程序输出调试信。必须借助于至少一种外设显示调试信息,比如串口或者网卡或者其他通过调用RETAILMSG或者DEBUGMSG完成,不影响OS的运行,保证驱动程序运行的真实性,动态输出设备的状态信息,调试相对简单,也是最广泛使用的一种调试方法。

4.2 核心调试工具(Kernel Debugger)

核心调试工具将会禁止所有硬件中断,挂起操作系统,因此可以单步调试OS或者核心代码,可以访问堆栈信息,但是必须在Platform的环境下,利用至少一种外设进行通信。

4.3 硬件辅助调试方法

利用硬件调试工具可以观察物理设备的真实状态,一般常用的方法可以利用JTAG工具实时查看CPU内部寄存器,利用逻辑分析仪或者示波器实时查看物理外设的输入输出状态。利用指示LED来显示驱动程序实时状态信息。

4.4 Visual Studio调试

可以利用VS内置的调试工具进行单步跟踪,状态调试等。

5 测试驱动程序

驱动程序经过调试以后就需要对驱动的功能进行测试。其常用的方法如下:

1) 写一个应用程序来测试驱动程序的正确性

2) 模拟各种可能发生的硬件输入状态来测试驱动程序的正确性

3) 利用Windows CE自带的测试工具CETK来测试驱动程序的性能和完备性

6 驱动程序的集合和发布

6.1 驱动程序集成

驱动程序经过调试和测试确定其正确性后,就可以对驱动程序进行集成了。具体过程如下:

1) 在BSP的Driver目录下建立新的驱动文件夹MyDrv

2) 实现MyDrv驱动以及相关的DEF文件

3) 如果需要用到硬件中断资源,修改原BSP中的相关中断处理函数OEMInterruptEnable,OEMInterruptDisable,OEMInterruptDone,OEMInterruptHandler

4) 在Platform.reg中,增加驱动程序相关项

5) 在Platform.bib中,增加驱动程序的相关注册表项MyDrv.Dll$(_FLATRELEASEDIR)MyDrv.dll NK SH

6.2 驱动程序发布

驱动程序进过集成以后就可以发布使用了,具体的发布过程如下所示:

1) 利用CAB Wizard生成.cab驱动包

2) 直接提供驱动程序文件夹以及相关注册表项和修改说明

7 总结

本为详细的介绍了,wince下驱动开发的流程,介绍了驱动程序开发到发布的详细过程,并详细说明了各个部分的实现和操作方法,使是初学者对wince下驱动程序的开发流程和一般的开发工具有了初步的了解。

驱动程序设计第2篇

随着新技术的不断涌现和DSP实时系统的日趋复杂,不同类型的外部设备越来越多。为这些外部设备编写驱动程序已经成为依赖操作系统管理硬件的内在要求。但是,由于内存管脚、响应时间和电源管理等条件的限制,为一个给定的DSP系统编写设备驱动程序有时候会很困难。针对设备驱动程序开发者遇到的上述难题,TI公司为C64x系列[1]DSP的开发者提供了一种类/微型驱动模型(class/mini-driver model)[2]。该模型在功能上将设备驱动程序分为依赖硬件层和不依赖硬件层两层,两层之间使用通用接口。实践结果表明,采用类/微型驱动模型进行设计后,应用软件可以复用绝大部分相似设备的驱动程序,从而提高驱动程序的开发效率。

1 类/微型驱动模型简介

在类/微型驱动模型中,类驱动通常用于完成多线程I/O请求的序列化功能和同步功能,同时对设备实例进行管理。在包括视频系统I/O和异步I/O的典型实时系统中,只有少数的类驱动需要表示出外部设备的类型。

类驱动通过每个外部设备独有的微型驱动对设备进行操作。微型驱动通过控制外设的寄存器、内存和中断资源对外部设备实现控制。微型驱动程序必须将特定的外部设备有效地表示给类驱动。例如:视频显示设备存在一些不同的帧存,应用软件会根据不同的I/O操作进行帧存的分配,此时微型驱动必须映射视频显存,使得类驱动可以对不连续的内存(分别存放RGB或YUV分量)设计特定的I/O请求。

    类/微型驱动模型允许发送由开发者定义数据结构的I/O请求包给微型驱动来控制外部设备,此分层结构使设备驱动的复用能力得到加强,并且丰富了发送给微型驱动的I/0请求包的结构。

类/微型驱动模型结构如图1所示。上层的应用程序不直接控制微型驱动,而是使用一个或一个以上的类驱动对其进行控制。每一个类驱动在应用程序代码中表现为一个API[3]函数并且通过微型驱动的接口IOM与微型驱动进行通信。类驱动使用DSP/BIOS中的API函数实现诸如同步等的系统服务。

类驱动通过标准的微型驱动接口调用微型驱动控制硬件设备。到目前为止DSP/BIOS共定义了三种类驱动:流输入输出管理模块(SIO)、管道管理模块(PIP)和通用输入输出模块(GIO)。在PIP和SIO类驱动中,调用的API函数已经存在于DSP/BIOS的PIP和SIO模块中。这些API函数需将参数传给相应的适配模块(adapter),才能与微型驱动交换数据。而在GIO类驱动中,调用的API函数则直接与微型驱动通信(需在CCS2.2以上)。

每一个微型驱动都为类驱动和DSP/BIOS设备驱动管理提供了标准接口。微型驱动采用芯片支持库(Chip Sup-port Library)[4]管理外围设备的寄存器、内存和中断资源。

2 类驱动的编写

SIO和PIP两个接口模块用于支持DSP和外设之间的数据交换。这两种模块都可以通过类驱动中的适配模块和微型驱动的IOM连接进行数据传输。SIO的适配模块称为DIO,PIP的适配模块称为PIO。

    GIO模块[5]的传输模式是基于流输入输出模式的同步I/O模式,更适合文件系统I/O。在编写类驱动时,可以直接调用GIO的读写API函数,这些函数的接口已经内置于微型驱动的IOM中。

2.1 SIO模块和DIO模块

DSP/BIOS中的SIO模块为每个DSP/BIOS线程提供一个独立的I/O机制,它支持动态创建。SIO模块有自己的驱动模型,称为DEV。DEV程序和微型驱动的编写方法相似,都要实现函数表中的打开、关闭和缓存管理等函数,然而结构比较复杂。相比之下,DIO模块可以简化SIO模块和IOM之间的连接,使得通信和同步变得更简单。

DIO模块必须实现下列基本功能函数:

(1)回调函数 在外设的通道实例创建结束时,如果微型驱动已经完成内存分配,那么适配模块将通过回调函数通知微型驱动待调用函数的地址,同时回调函数也将通知适配模块缓存已经建立,并最终通知上层应用程序。

(2)传输函数 传输函数将调用微型驱动中的md-SubmitChan函数。微型驱动中的mdSubmitChan函数将从适配模块获得一块缓存,并将缓存中的新信息通过通道实例通知给中断服务程序(ISR)。DIO模块通过传输函数实现应用程序与微型驱动之间的通信。

2.2 PlP模块和PlO模块

DSP/BIOS中PIP模块提供管理异步I/O的数据管道。每个管道对象都拥有一块同样大小的缓存,这些缓存分别为同样数量的等长小块。小块的数量和长度在DSP/BIOS中设置。虽然小块的长度是固定的,但应用程序可以把小于这个长度的数据放入缓存小块中。一个管道有两个结束状态:写完缓存和读完缓存。通常,无论哪个结束状态都会激活I/O设备。数据通知函数用来执行读写同步任务和通知PIP缓存填满或清空。写数据时,PIP_alloc函数用来获得缓存,PIP_put函数用于将数据写入缓存。写完后,读数据通知函数notifyReader将被调用。读数据时,PIP_get函数用来接收缓存中的数据,刃PIP_free函数在数据不再被使用时将缓存清空。清空完后,写数据通知函数notifyWriter将被调用。

    PIO模块通过PIP模块从应用程序中获得缓存,并将获得的缓存提供给微型驱动使用。当微型驱动使用完缓存时,PIO模块还可以将缓存交还给应用程序。

PIO模块必须实现下列基本功能函数:

(1)主函数 当应用程序给设备分配缓存时,PIP的缓存管理调用rxPrime和txPrime函数。这两个函数调用DSP/BIOS的API函数获得缓存并提供给微型驱动使用。主函数负责给适配模块和应用程序的缓存分配发送起始信号。

(2)回调函数 当微型驱动已完成内存分配时,适配模块通过回调函数rxCallback或txCallback通知微型驱动待调用函数的地址,同时回调函数也通知适配模块缓存已经建立,并最终通知给上层应用程序。

(3)传输函数:传输函数将调用微型驱动中的md—SubmitChan函数。mdSubmitChan函数将从适配模块中获得一块缓存,并将缓存的新信息通过通道实例通知给中断服务程序(ISR)。PIO模块通过传输函数实现应用程序与微型驱动之间的通信。

2.3 GIO模块

GIO模块在提供必要的同步读/写API函数及其扩展函数的同时,将代码和使用数据缓存的大小尽量简化。如图2所示,应用程序可以调用GIO的API函数直接与微型驱动的IOM交换数据,这些API函数使得GIO成为了第三种类驱动。

当调用GIO_create创建一个外部设备的通道实例时,GIO在通道实例中增加了状态和I/O请求状态结构、IOM数据包(IOM_Packets)及一个GIO数据对象。GIO创建的通道实例的数据结构如下:

typedef stmct GIO_Obj{

IOM_Fxns *fxns; /* 函数表指针*/

Uns mode; /* 创建模式 */

Uns timeout; /* 超时时间 */

IOM_Packet syncPacket;/* 同步时使用的IOM_Packet */

QUE_Obj freeList; /* 异步I/O队列 */

Ptr syncObj; /* 同步对象地址 */

Ptr mdChan; /* 通道实例地址 */

}GIO_Obj,*GIO_Handle;

函数表指针是应用程序和微型驱动函数表(fxns)的接口;创建模式包括:输入(IOM_INPUT)、输出(IOM_OUTPUT)和双向(IOM_NOUT);IOM Packet在类驱动和微型驱动间的异步操作时使用;同步对象地址指向特定通道的同步信号;通道实例地址指向微型驱动创建的通道实例。

3 微型驱动的设计和实现

类/微型驱动模型中的微型驱动直接控制外部设备。只要微型驱动创建了规定的函数,应用程序就可以方便地通过DIO适配模块、PIO适配模块或(和)GIO类驱动调用。这些规定的函数包括:通道绑定函数(md—BindDev)、通道创建/删除函数(mdCreateChan/md—DeleteChan)、I/O请求发送函数(mdSubmitChan)、中断服务函数(ISRs)和设备控制函数(mdControlChan)。这些规定的函数将放入微型驱动的函数接口表(IOM_Fxns)中的相应位置,供应用程序通过适配模块或GIO类驱动调用。函数接口表的结构如下:

typedef struct IOM_Fxns

{

IOM_TmdBindDev mdBindDev;

IOM—TmdUnBindDev mdUnBindDev;

IOM—TmdControlChan mdControlChan;

IOM_TmdCreateChan mdCreateChan;

IOM_TmdDeleteChan mdDeleteChan;

IOM_TmdSubmitChan mdSubmitChan;

}IOM_Fxns;

3.1 绑定通道函数

DSP/BIOS设备初始化时将调用每个已注册到微型驱动中的绑定函数(mdBindDev)。绑定函数一般要实现下列功能:根据配置的设备参数和可能存在的全局设备数据初始化外围设备;挂入中断服务函数(ISRs);获得缓存、McBSPs、McASPs和DMA等资源。

如果微型驱动使用多个外部设备,则DSP/BIOS为每个外设调用绑定函数。设备参数devid用来区分设备。如果支持一个设备,则绑定函数必须检查是否已经有设备绑定。

微型驱动如果使用静态数据来减少实时处理的动态数据分配,可以使用输入/输出数据指针(devp)。输入/输出数据指针将传给通道创建函数(mdCreateChan)。

3.2 通道创建/删除函数

从应用的观点出发,在应用程序和外部设备之间必须有一个逻辑交流通道用来交换数据。应用程序通过微型驱动创建一个或多个逻辑通道对象作为应用程序的逻辑通道。通道创建函数(mdCreateChan)根据需要创建通道对象并给通道对象设置初始值。通道删除函数(md—DeleteChan)则删除已创建好的通道对象。虽然每个微型驱动的通道对象数据结构都略有不同,但有些字段是必须的,如通道模式、等待I/O包序列和回调函数。以下是一个常见的通道对象数据结构:

typedef struct ChanObj {

Bool inuse; /* 如果为TRUE,则通道已打开 */

Int mode; /* 通道模式 */

IOM_Packet *dataPacket; /*I/O包 */

QUE_Obj pendList, /* 等待I/O包序列 */

Uns *bufptr; /* 当前缓存指针 */

Uns bufcnt; /* 未处理的缓存数目 */

IOM_TiomCallback cbFxn; /* 回调函数 */

Ptr cbArg; /* 回调函数参数地址 */

}ChanObj,*ChanHandle;

3.3 I/O请求发送函数

微型驱动中的I/O请求发送函数(mdSubmitChan)用来处理IOM_Packet包中的命令字段。根据不同命令字段,微型驱动将处理命令或返回错误信息(IOM_ENOTIMPL)。

微型驱动支持的命令字段有:IOM_READ、IOM_WRITE、IOM_ABORT和IOM_FLUSH。微型驱动创建的输入通道由IOM_READ命令来执行输入任务,创建的输出通道则由IOM_WRITE命令来执行输出任务。要放弃或者刷新已经发送的I/O请求,可以使用IOM_BORT或IOM FLUSH命令。当放弃时,I/O请求包队列中的所有输入输出请求都将被放弃。当刷新时,所有的I/O输出包顺序执行,而所有的输入I/O包都被放弃。

3.4 中断服务函数

微型驱动的中断功能就是去处理外部设备的触发事件,例如周期性的中断。中断通常是表示外设采样完数据或者处理完数据,也可以用于为DMA提供同步信号,微型驱动必须处理这些中断。通常微型驱动中的中断服务函数ISRs必须完成以下功能: 出列IOM_Packet请求;设置下一次传送或服务请求;调用类驱动的回调函数以保证和应用程序同步,并返回IOM_Packet。

    3.5 设备控制函数

微型驱动支持的控制操作因不同的外部设备而异。IOM定义了一些通用的控制代码供驱动程序调用。特定设备独有的控制代码必须自己编写,其特征值必须大于128(IOM_CNTL_USER)。目前IOM支持的通用的控制代码有:

IOM_CHAN_RESET:将创建的通道实例重新恢复到初始状态。

IOM_CHAN TIMEDOUT:当应用程序或类驱动超时时,此控制代码将进行超时操作。例如,一个超时的IOM_Packet,如果没执行回调函数,可能会被返回类驱动。

IOM_DEVICE_RESE:外部设备重新恢复到初始状态,它将影响为这个外部设备创建的所有通道实例。

微型驱动支持的控制代码和控制操作必须告诉使用微型驱动的应用程序开发者,特别要注明该代码的针对对象(是针对通道实例还是针对设备实例)。例如:改变外设波特率的控制代码,必须注明是针对某个通道或者所有通道的,否则容易给应用程序带来错误。

4 类/微型驱动模型驱动应用实例——C64x系列DSP/BIOS中PCI设备的驱动

4.1 微型驱动的设计与编写

(1) 设计mdBindDev的部分程序代码:

static Int mdBindDev(Ptr *devp,Int devid,Ptr devParams)

{

……

QUE_new(&device.hiShPrioQue)/*户建立IOM包队列*/

QUE_new(&device.lOwPrioQue);

……

hwiAttrs.ccMask=IRQASK_NONE;

/*初始化PCI中断*/

hwiAttrs.arg=NULL;

IRQ_map(1RQ_EVIDSPINT,intrld);

HWI_dispatchPlug(intrId,(Fxn)isr,—1,&hwiAttrs);

}

(2)设计mdCreateChah的部分程序代码

static Int mdCreateChan(Ptr *chanp,Ptr devp,String name,

Int mode,Ptr chanParams,IOM_Tiom

Callback cbFxn,Ptr cbArg)

{

……

驱动程序设计第3篇

关键词:WDM;PCI;DDK;设备驱动程序

中图分类号:TP333文献标识码:A 文章编号:1009-3044(2011)07-1534-03

Designed of PCI Device Driver Based on DDK

ZHAO bin1, TIAN Ze1, CHEN Jia2

(1.Xi'an Shiyou University, Xi'an 710065, China; 2. Xidian University, Xi'an 710072, China)

Abstract: This paper takes a PCI device as an example, describes WDM drivers and PCI bus protocols. And introducing a method of WDM driver design base on DDK(Driver Development Kit), realizing identification and testing function.

Key words: WDM; PCI; DDK; device driver

因为某项目的需求,需要在PC机上调试一PCI设备,在Windows系统下实现主机通过PLX9056桥芯片对PCI设备的访问,但前提条件是当操作系统装载驱动程序正确的情况下。如果驱动程序装载不正常,主机首先就不能够识别PCI设备;如果驱动程序运行不正常,用户就不能正确的访问PCI设备。因此,PCI驱动程序是实现主机识别板卡以及正确访问设备的关键。

目前常用的驱动开发工具有:微软提供的DDK(Device Driver Kits),以及第三方厂商提供的DriverStudio和WinDriver,现在大多数驱动开发人员都是使用DriverStudio和WinDriver,其中DriverStudio将DDK函数按照逻辑功能组织,把很多常用功能封装成类,建立了一个基于C++语言的面向对象的编程环境,大大降低了开发难度和开发周期;WinDriver将一些基本的操作如存储读写、I/O端口读写、中断服务、DMA操作等进行了封装,开发者只需编写一个外壳来调用这个驱动程序,就可以完成对硬件设备的访问。前两种开发工具使用简单,开发速度快,但开发的驱动程序执行效率受到限制。DDK虽然编程难度较大,对编程人员的要求也较高,但是功能强大,编程灵活,使用范围广,可应用于各类硬件驱动程序的编写,而且有助开发人员深刻理解驱动程序和WDM(Windows Driver Mode),所以DDK是更理想的开发工具。

1 WDM式设备驱动的概述

1.1 WDM概念

设备驱动程序需与操作系统最底层进行交互,不同的操作系统底层结构对应于不同的设备驱动程序模型,也影响设备驱动程序的兼容性。在Windows 2000以后,微软公司加入了新的驱动程序模型,这就是WDM。

1.2 WDM式驱动的基本结构

WDM模型中,两个驱动设备对象分别是物理设备对象(Physical Device Object,简称PDO)和功能设备对象(Function Device Object,简称FDO)。其关系是“附加”与“被附加”的关系。

当某个设备插入PC机时,PDO会自动创建。确切的说,PDO是由总线驱动创建的。PDO需要配合FDO一起使用,系统会提示检测到新设备,要求安装驱动程序。需要安装的驱动程序就是WDM程序,此驱动程序就是创建FDO并附加到PDO之上。当一个FDO附加在PDO上的时候,PDO设备对象的子域AttachedDevice会记录FDO的位置。PDO靠近物理设备,被称作底层驱动,而FDO接近发出I/O请求,被称作高层驱动。并且从WDM驱动的设计思路可以看出,WDM驱动是支持即插即用的。

在FDO和PDO之间还会存在过滤驱动,在FDO上面的过滤驱动被称作上层过滤驱动,在FDO下层的驱动,被称作下层过滤驱动。在WDM模型中,过滤驱动不是必须存在的,PDO和FDO是必须的。

2 PCI总线协议

PCI总线协议是PC上最基本的总线,一般显卡、网卡都设计成PCI总线设备。其他总线都是挂在PCI总线上的。例如,ISA总线是通过PCI-ISA桥设备挂在PCI总线上,而USB总线是通过USB HOST设备挂在PCI总线上的。

2.1 PCI总线简介

PCI(Pheripheral Component Interconnect)总线是当前最流行的总线之一,是由Intel公司首先推出的一种局部总线。它定义了32位数据地址总线,并且可以扩展为64位,其支持突发读写操作,也同时可以支持多组设备。

在当前的PC体系结构内,几乎所有外部设备采用的各种各样的接口总线,均是通过桥接电路挂接在PCI系统内的。在这种PCI系统中,Host/PCI桥称为北桥,连接主处理器总线到基础PCI局部总线。PCI-ISA桥称为南桥,连接基础PCI总线到ISA总线。其中南桥通常还含有中断控制器、IDE控制器、USB控制器和DMA控制器等设备。

2.2 PCI配置空间简介

PCI有三个相互独立的物理地址空间:设备存储器地址空间、I/O地址空间和配置空间。配置空间是PCI所特有的一个物理空间。由于PCI支持设备即插即用,所以PCI设备不占用固定的内存地址空间或I/O地址空间,而是可以由操作系统决定其映射的基址。

系统加电时,BIOS检测PCI总线,确定所有连接在PCI总线上的设备以及它们的配置要求,并进行系统配置,实现真正的即插即用。

3 开发实例

Windows从总体上分为内核模式(Kernel Mode)和用户模式(User Mode)。驱动程序运行在内核模式下,拥有操作系统的最高权限。编写驱动程序主要是为了操作硬件设备,这些硬件设备的操作主要包括访问物理映射内存、设备端口等。而应用程序是运行在用户模式下,应用程序无法直接与硬件设备通信,必须借助于驱动程序。

所开发的PCI设备应用软件和驱动软件驻留在PC机中,其中应用软件与特定的子系统有关,应用软件通过调用PCI驱动软件实现子系统功能要求。应用软件和驱动软件在Windows下的关系如图2所示。

3.1 PCI设备驱动程序

PCI模块驱动软件是实现PCI板卡与宿主机(PC机)应用软件间的接口控制与数据传递的专用软件,它可提供PCI板卡与PC机各类消息数据的读、写支持,以及对PCI板卡内部程序的调度。

PCI驱动程序开发软件是DDK,用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为IRP(I/O Request Package,即输入输出请求包)数据结构,不同IRP数据会被“派遣”到不同的派遣函数(Dispatch Function)。

驱动软件的入口程序是DriverEntry,在DriverEntry中包含了AddDevice函数的设置。PCI设备是属于被动加载的设备,操作系统必须加载PDO后调用AddDevice例程,而AddDevice例程就是负责创建FDO并附加到PDO之上。

其次,DriverEntry必须加入IRP_MJ_PNP的派遣回调函数。IRP_MJ_PNP就是即插即用IRP,是由即插即用管理器发送给PCI驱动程序的。

当启动PCI设备的时候,设备管理器将IRP_MN_START_DEVICE发送给PCI驱动。在处理完此IRP后,驱动程序会将处理结果存储在IRP的设备堆栈中。程序可从当前堆栈就可以获取PDO从PCI配置空间中的有用信息,如中断号、设备物理内存及IO端口信息等。因为实际应用中,不能提前知道这些描述符在数组中出现的位置,因此在实现中必须用循环先把资源值提取到一组局部变量中,然后在处理这些资源信息。

对于枚举PCI设备资源,主要分为四类,分别是设备端口、设备物理内存、DMA、中断等。在实现中,程序里枚举了I/O端口资源,物理内存资源和中断资源。其中,I/O端口资源包括I/O端口地址、I/O端口地址长度,物理内存资源包括基地址0和基地址2,中断资源包括中断请求级、中断向量、CPU亲缘关系、中断模式以及共享中断等。

在设备即将停止的时候,即插即用管理器将发送IRP_MN_REMOVE_DEVICE给PCI驱动,这个IRP标志着设备即将关闭,PCI驱动在此时会做一些资源回收工作。

因此开发PCI设备驱动最重要的一步就是将IRP_MN_START_DEVICE中获取的设备资源记录下来,以便以后使用。

3.2 PCI设备应用程序与驱动程序的通讯

PCI设备应用程序的开发软件是VC6.0,在应用程序中寻找设备是通过设备接口和设备号决定的,其实现过程主要是通过SetupDiXX系列函数得到设备接口。

在实际应用中,PLX9056的本地配置寄存器映射在PLX9056配置寄存器中基地址寄存器0,待测试设备的内存空间由硬件设计人员映射在PLX9056的基地址寄存器2。因此,在应用程序中需定义供用户使用的通过基地址0和基地址2的读写接口函数。例如:

基本的读函数有:

ULONG ReadFromBase0(HANDLE handle,ULONG Offset,

UCHAR *buff,ULONG length);

ULONG ReadFromBase2(HANDLE handle,ULONG Offset,

UCHAR *buff,ULONG length);

基本的写函数有:

ULONG WriteToBase0(HANDLE handle,ULONG Offset,

UCHAR *buff,ULONG length);

ULONG WriteToBase2(HANDLE handle,ULONG Offset,

UCHAR *buff,ULONG length);

应用程序可以通过Win32 API DeviceIoControl操作设备与驱动程序互相通信。DeviceIoControl内部会使操作系统创建一个IRP_MJ_DEVICE_CONTROL类型的IRP,然后操作系统会将这个IRP转发到派遣函数中。

而以上的读写接口函数的本质就是调用DeviceIoControl来实现的。例如从基地址0读函数ReadFromBase0函数原型,如图3。

其中,DDK定义的DeviceIoControl的函数原型为:

BOOL DeviceIoControl{

HANDLE hDevice,//设备句柄

DWORD dwIoControlCode, //控制码

LPVOID lpInBuffer,//输入数据缓冲区指针

DWORD nInBufferSize, //输入数据缓冲区长度

LPVOID lpOutBuffer, //输出数据缓冲区指针

DWORD nOutBufferSize,//输出数据缓冲区长度

LPDWORD lpByteReturned,//输出数据实际长度单元长度

LPOVERLAPPED lpOverlapped //重叠操作结构指针

};

DeviceIoControl的第二个参数是I/O控制码,控制码也称IOCTL值,是一个32位的无符号整型。DDK提供一个宏CTL_CODE,定义为:

CTL_CODE(DeviceType,Function,Method,Access)

其中,DeviceType为设备对象的类型;Function为驱动程序定义的IOCTL值,0x000到0x7ff为微软保留,0x800到0xfff由程序员自己定义;Method是操作模式,其中包括METHOD_BUFFERED为使用缓冲区方式操作,METHOD_IN_DIRECT为使用直接写方式操作,METHOD_OUT_DIRECT为使用直接读方式操作,METHOD_NEITHER为使用其他方式操作;Access为访问权限。

如上述例子ReadFromBase0函数,在驱动程序中用CLT_CODE宏定义定义的IOCTL码:

#define IOCTL_READ_BASE_BAR0 CTL_CODE(

FILE_DEVICE_UNKONWN,

0x800,

METHOD_BUFFERED,

FILE_ANY_ACCESS)

驱动程序中IOCTL派遣函数的实现是首先得到当前I/O堆栈,从I/O堆栈中再一次得到输入缓冲区大小,输出缓冲区大小,以及IOCTL。在实现过程中,运用C语言中的switch语句分别处理不同的IOCTL。在每个IOCTL情况下,就必须使用DDK提供的内核函数WRITE_REGISTER_XX系列函数和READ_REGISTER_XX系列函数操作物理设备内存。具体流程如图4所示。

当应用程序需要操作读写接口函数时,设备管理器就会发送相对应的IRP给设备驱动,驱动程序就会调用DispatchControl函数找到相应的IOCTL码,应用程序再调用DeviceIoControl操作设备。

4 结束语

本文以实际应用的一个PCI设备驱动开发为例着重介绍了驱动程序和应用程序的相互关系,并且还简单介绍了WDM式设备驱动和PCI总线协议。设备驱动程序是Windows操作系统重要的内核组建,在系统中起至关重要。如果驱动程序出错,很容易使Windows操作系统崩溃。开发利用DDK开发驱动程序能够使开发者加深对Windows内核和WDM规范的理解。

参考文献:

[1] 张帆,史彩成.Windows驱动开发技术详解[M].北京:电子工业出版社,2009.

[2] Walter Oney.Programming The Microsoft Windows Driver Model[M].1999.

[3] PCI Tech Company.PCI 9056BA Data Book[M].USA,2003.

驱动程序设计第4篇

关键词 VxWorks;多串口驱动程序设计

中图分类号:TP368 文献标识码:A 文章编号:1671-7597(2013)13-0156-01

嵌入式安全平台研制项目中,尤其应重视对多通路并发串行数据的传送和安全问题的处理。从当前市场发展状况看,传统的通用串口芯片在数据的接受和传送上已很难满足大数据传送的要求,所以,应考虑使用传送速度更高的串口芯片。同时针对标准的VxWorks驱动程序不能满足高速串口芯片的运行要求,本文重点对多通道高速串口驱动程序的设计进行简单的介绍。

1 VxWorks程序架构介绍

1.1 基本框架

VxWorks系统中I/O系统并不包含串行设备的驱动程序,其功能的实现主要凭借ttyDrv。串行设备的正常使用,一方面应保证其能够支持目标接口和I/O系统,另一方面其应在轮训两种方式或中断方式下正常工作。

对串行设备驱动程序而言,一般与设备无关的部分在虚拟设备ttyDrv实现,而主要程序需要程序员进行编写,然后利用系统提供的接口将其安装到ttyDrv中。虚拟设备ttyDrv重点负责I/O系统和驱动程序间的信息通讯。当系统中有对I/O操作的请求时,虚拟设备ttyDrv首先对请求进行处理,同时将请求涉及的命令交给设备驱动程序,在该驱动程序的操控下,实现对I/O系统的实际操作,同时在ttyDrv操作控制下将入口函数挂接在I/O系统中,然后对设备的相关描述进行初始化操作,处理完毕后系统会自动将其添加到设备列表中。一旦I/O系统发现有请求的命令时,就会触发挂接在I/O系统入口函数,从而响应有关请求。虚拟设备ttyDrv挂接函数时首先会利用ttyDrv()函数调用iosDrvinstall()函数,然后将ttyIoctl()、ttyOpen()、tyWtite()、tyRead()等一些函数挂接在驱动程序中供响应请求用。

1.2 创建专用串口设备

专用串口设备创建时系统会进行初始化处理。首先,初始化设备的描述符,并通过函数tyDevInit()初始化tyLib以及select的功能。其次,创建信号量以及用于输入、输出的缓冲区。最后,通过调用iosDevAdd()函数完成两项工作:1)将设备添加到设备的列表中;2)设置设备的工作模式为中断。

1.3 设备的读、写操作

应用程序为了响应读写操作会首先调用write()函数,接着I/O系统将数据请求传递ttyDrv执行函数tyWtite(),并通过复制的方式将存在于用户缓冲区的内容加载到环形缓冲区中,并初始化处理发送的循环,这里调用的函数是xxTxStartUp,将原来设置为中断的工作模式打开为发送工作做好准备,系统通过调用xxIntTx中断服务程序完成字符的发送工作,最后将中断清除。

当串口发现相关数据后,会立刻调用xxRcvInt中断服务程序在制定的缓冲区位置进行写操作,与此同时还需要将数据传送给高层协议,该传送过程需要使用tyIRd()进行操作。用户利用函数read()进行读操作的同时,I/O系统会使用函数tyRead(),将环形队列的内容读入到用户缓冲区中。

2 VxWorks下多通道串口驱动程序设计

2.1 基本设计要求

多通道串口驱动程序设计时应满足以下几点要求:首先,设计工作的开展应以OX16PCI958串口芯片为基础,同时还应保证每路串口通道满足多任务并发访问的要求,并且能够对中断是否有效进行准确的判断,以此进一步提高CPU的利用率。其次,在实现端口设置的同时,能够保证芯片和应用程序之间进行正确的通讯。

2.2 设计应注意的问题

2.2.1 多任务并发设计

为了满足驱动程序能够正确处理并发需求的要求,驱动程序内部采用中断所和任务锁界定对临界资源的修改权限,并保证了连续寄存器操作指令能够不断被打断。驱动程序实际的设计时每个通道会对应一个独立的ST16C_CHAN,从而当访问某个通道时不会对其他通道造成影响,以此实现并发访问。

2.2.2 中断共享设置

为了提高CPU的工作效率,外部设备与CPU之间的通讯机制为中断,以此防止频繁查看外部设备,增加CPU的运算时间。中断运行的原理是:系统会利用存在于sysSerial.c文件中的函数sysSerSerialHwInit()实现对pciConfigInByte()函数的调用,同时将参数设置为PCI_CFG_DEV_INT_LINE,并从寄存器中获得中断线,并使用pciIntConnect()函数将函数ST16C958Int()进行挂接,最后为了对中断进行共享还需要调用sysIntEnablePIC()函数。另外,在处理中断时还应注意其他共享同一信号设备的中断。

2.2.3 端口设置

用户访问虚拟设备ttyDrv时会首先调用ioctl()函数,与此同时I/O系统也会调用ttyIoctl()函数,该函数会访问ST16C958Ioctl()函数然后实现查询、设置工作模式、设置波特率等功能。另外,驱动程序设计时还应注重把握应用程序和串口访问数据之间的交互设计。

3 总结

在VxWorks下以OX16PCI958芯片为基础进行多串口驱动程序设计,综合数据结构等方面的知识,实现了多通道串口通信驱动的要求,同时对今后VxWorks下多串口卡驱动程序的设计具有较高的借鉴价值。

参考文献

驱动程序设计第5篇

关键词: WinDriver; Windows驱动程序; CPCI总线; VC++6.0

中图分类号: TN964?34 文献标识码: A 文章编号: 1004?373X(2013)18?0051?04

0 引 言

设备互联(PCI)总线是一种先进的高性能局部总线,可同时支持多组设备[1]。CPCI总线应用于工业和嵌入式领域,其规范改进自PCI规范,CPCI规范在电气方面兼容PCI规范,只是在封装结构上进行了加强,CPCI板的封装结构基于IEC 60297?3,IEC 60297?4以及IEEE 1101.10定义的欧式板卡外形[2]。既然电气特性上兼容PCI规范,因此CPCI驱动程序的设计本质就是PCI驱动程序设计。

当前Windows环境下用于PCI设备驱动开发的工具主要是DDK,DriverStudio以及WinDriver。前两者功能强大,但是开发者需要熟知操作系统的体系结构、汇编语言和设备驱动程序结构体系方法,还需要具备丰富的驱动程序开发经验,否则可能造成软件不稳定甚至系统崩溃,另外前两者开发周期长。而Jungo公司开发的WinDriver改变了传统的驱动程序开发方法,其整个驱动程序中的所有函数都是工作在用户态下,使开发者不需要掌握前两者所需的预备知识就可以开发出与之相媲美的程序[3]。

为了实现在主控计算机和信号处理板之间快速通信,采用了CPCI并行总线技术,信号处理板采用内嵌PCI模块的DSP6416芯片。软件开发基于Windows平台和VC++6.0编程环境,为了便于应用程序调用驱动程序,按照模块化的软件设计思想,驱动程序以DLL动态链接库的形式封装。为提高工作效率、缩短开发周期,开发工具选用WinDriver。

1 WinDriver简介

WinDriver是一套设备驱动程序开发组件,它的目的就是方便程序员快速开发出PCI,ISA,CPCI,PCIE等设备的Windows驱动程序[4]。

1.1 WinDriver原理

WinDriver的体系架构分为两种模式:用户模式和内核模式。对硬件进行操作时,开发者应用程序调用WinDriver用户模式的库函数,用户模式的库函数再调用WinDriver内核,WinDriver内核再调用操作系统底层函数实现对硬件的最终访问。其与硬件模板、用户驱动程序、用户应用程序之间的关系即体系架构见图1[5?6]。对于某些在用户模式下不能实现的高性能硬件驱动程序,可通过WinDriver的内核插件功能实现:在用户模式下完成编程和调试,不做任何修改,直接将该高性能要求的程序模块植入内核插件,WinDriver即从内核模式下调用该程序模块。

1.2 WinDriver特点

作为一款实用的驱动程序开发工具包,WinDriver的主要优点和特征如下:

(1)通过内核插件功能(Kernel PlugIn)能够实现用户模式的易用和内核模式的高性能;

(2)友好的驱动向导允许不写一行代码即可实现硬件诊断;

(3)支持所有PCI/PCMCIA/CardBus/ISA/EISA/CompactPCI/PCIExpress设备,与制造商无关;

(4)可以利用常见的软件开发平台包括MSDEV/VisualC/C++,Borland Delphi,Visual Basic6.0等;

(5)开发者不需要知道DDK,ETK,DDI及任何其他系统层面的编程知识;

(6)支持I/O、DMA中断处理和直接访问板卡映射的存储器;

(7)支持多CPU及多PCI总线平台。

1.3 用WinDriver开发驱动程序

利用WinDriver开发驱动程序有2种方式:通过驱动程序向导生成驱动程序框架,再对框架程序进行修改和调试;直接编写驱动程序。

通过驱动程序向导开发步骤:板卡检测、诊断;生成驱动程序框架;调试、编译驱动程序。

直接编写代码方式步骤:

(1)包含WinDriver相关的头文件;

(2)WinDriver库函数调用,WinDriver库函数典型调用流程见图2[7]。

2 CPCI信号处理板卡驱动程序设计

2.1 硬件环境

实现PCI总线协议一般有2种方法:一是用FPGA设计实现,由于PCI协议比较复杂,实现较困难;二是采用专业PCI总线控制芯片,如AMCC公司的S5933、PLX公司的PCI 9080等通用PCI接口芯片[8]。本信号处理板采用第二种方法,选用自带PCI接口模块的DSP6416,主控计算机上的应用程序通过驱动程序将控制命令字主动写入DSP内存,实现主控计算机对信号处理板的控制;信号处理板结果数据处理完毕后,向主控计算机发中断,驱动程序响应该中断,并主动读取指定DSP内存获取结果数据。

结果数据和模块状态信息存入L2缓存单元,主控计算机下发的命令字也写入L2缓存单元。结果数据缓存划分为大小各为28 KB的Block1和Block2两块区域;模块状态信息缓存大小为24字节;控制命令缓存大小为1 B。DSP中与PCI操作有关的缓存定义见表1。

表1 DSP中与PCI操作有关的缓存定义

当Block1缓存填满后,新的结果数据存入Block2缓存,同时DSP给主控计算机发PCI中断,主控计算机通过PCI接口读取Block1;同理当Block2填满后,新的结果数据存入Block1缓存,主控计算机通过PCI读取Block2。Block1和Block2缓存交替接收结果数据。

2.2 CPCI驱动程序DLL接口设计

为了便于应用程序访问驱动程序,按照模块化的软件设计思想,驱动程序以DLL动态链接库的形式进行封装,应用程序通过与驱动程序DLL之间的接口来访问信号处理模块的板上资源,下发控制命令、获取结果数据。主要接口及其功能描述如下:

(1)DSP6416DLL_Init(CWnd* pMainWnd):打开并注册WDC库、打开设备,初始化中断;

(2)DSP6416DLL_SendCmd(BYTE BCommand):主控计算机中的控制命令数据写入DSP中命令存储区;

(3)DSP6416DLL_ReadState(BYTE *StateData):从DSP的状态存储区读取信号处理板的状态数据;

(4)DSP6416DLL_ReadResult(BYTE *ResultData):从DSP的Block1或Block2数据缓存区读取结果数据;

(5)DSP6416DLL_Exit():关闭中断,关闭设备,关闭WDC库。

2.3 CPCI驱动程序实现

在硬件环境和接口、驱动程序封装形式及其软件接口确定后,剩下的工作就是CPCI驱动程序的实现。该工作主要内容为驱动程序DLL各接口函数的编码实现和WinDriver库函数调用。

2.3.1 文件包含

包含与WinDriver相关的头文件:windrvr.h,windrvr_int_thread.h,wdc_lib.h。

2.3.2 驱动程序初始化

驱动程序初始化主要工作和步骤包括:打开WinDriver,WinDriver授权、版本号检查、板卡检测、板卡信息获取、模块配置、板卡注册和PCI中断使能,驱动程序初始化流程见图3。

2.3.3 驱动程序向DSP内存写数据

DSP6416的PCI接口支持四种类型的数据交换[9?10]:从模式写,外部PCI主设备通过PCI接口写数据到DSP;从模式读,外部PCI主设备通过PCI接口读取DSP中的数据;主模式写,DSP主设备通过PCI接口向外部设备写数据;主模式读,DSP主设备通过PCI接口向外部设备读数据。

4 结 语

通过实际应用,发现用WinDriver开发的本驱动程序运行稳定可靠,达到了主控计算机对信号处理板实时控制,特别是信号处理板中大容量数据实时上传的目的。由于系统方案确定了CPCI并行总线作为通信手段,硬件设计时采用了自带主从式PCI接口模块的DSP6416芯片,驱动开发工具选择了快速高效的WinDriver工具包,以及对驱动程序形态进行DLL封装,本驱动程序从需求设计到完成编码和调试不到一个月的时间,在保证软件质量的同时,缩短了研制周期,提高了开发效率。

参考文献

[1] 李贵山,戚德虎.PCI局部总线开发者指南[M].西安:西安电子科技大学出版社,1997.

[2] PICMG. Compact PCI core specification PICMG 2.0 R3.0 [R]. [S.l.]: PICMG, 1999.

[3] 王磊,鲁新平,李吉成.WinDriver在开发基于PLX9056芯片的PCI设备驱动程序中的应用[J].现代电子技术,2006,29(18):77?79.

[4] 李静,赵保军.基于TMS320C6416内嵌PCI设备驱动程序开发[J].微机发展,2005,15(10):135?137.

[5] Jungo Ltd. WinDriver PCI/ISA/CardBus v8.02 user’s guide [R]. US: Jungo Ltd, 2005.

[6] 简育华.基于WinDriver的 PCI驱动程序开发[J].火控雷达技术,2011,40(1):68?70.

[7] Jungo Ltd. WinDriver PCI/PCMCIA/ISA v8.02 Low?Level API Reference[R]. US: Jungo Ltd, 2005.

[8] 宋新超,柴恒.基于WinDriver的数字信号处理器PCI驱动开发[J].舰船电子对抗,2012,35(4):82?84.

驱动程序设计第6篇

关键词:嵌入式操作系统;Win CE;SPI;驱动程序

中图分类号:TP311文献标识码:B

文章编号:1004-373X(2009)10-069-04

Design of EP9315-SPI Driver Based on Win CE

ZHANG Dong1,XU Dijian2

(1.Chongqing University of Arts and Sciences,Chongqing,402160,China;2.Chongqing University of Science and Technology,Chongqing,401331,China)

Abstract: It is very important to compile driver connecting operating system with corresponded hardware device.Based on stream interface driver model,the design of SPI driver in embedded operating system Win CE in development environment of platform builder 4.2 and design method are introduced and analysed,realizing virtual address map,key code and the relationship between driver and SPI application program in EVC program environment is discussed.Driver and corresponded application program can be operated on FS_EP9315 development platform of ucdragon rightly.Experience indicates the methord is right and feasible.

Keywords:embedded operating system;Win CE;SPI;driver program

0 引 言

嵌入式是“以应用为中心,以计算机技术为基础,软硬件可裁剪,适合应用系统对功能、可靠性、成本、体积、功耗严格要求的计算机系统”。Windows 是Microsoft推出的功能强大的紧凑、高效、可伸缩的32位嵌入式操作系统,主要面对各种各样嵌入式系统的产品[1,2]。

该系统具有多线程、多任务、完全抢占式的特点,是为各种具有严格资源限制的硬件系统所设计的。为了将操作系统和硬件设备连接起来,硬件和软件的驱动联系就显得很重要。SPI是一种高速、全双工、同步的通信总线,在芯片的管脚上只占用4根线,节约了芯片的管脚,同时为PCB的布局节省了空间,提供了方便,正是出于这种简单易用的特性,现在越来越多的芯片都集成了这种通信协议。SPI的工作模式有两种:主模式和从模式,SPI总线可以配置成单主单从、单主多从、互为主从。为了充分利用芯片的SPI接口进行相应的驱动程序设计以及应用程序设计,通用方法的研究就显得十分重要。

1 Win CE提供的驱动模型

Win CE操作系统支持两种类型的驱动程序,一种为本地驱动程序,是把设备驱动程序作为独立的任务实现的,直接在顶层任务中实现硬件操作,因此有明确和专一的目的。本地驱动程序适合于那些集成到Win CE平台的设备,诸如键盘、触摸屏等设备。另一种是具有定制接口的流接口驱动程序,它是一般类型的设备驱动程序,为用户一级的动态链接库(DLL)文件,用来实现一组固定的函数称为“流接口函数”,这些流接口函数使得应用程序可以通过文件系统访问这些驱动程序。这里论述的SPI驱动就属于流接口驱动。

2 SPI驱动程序的设计

2.1 EP9315芯片及SPI接口简介

EP9315是一款基于ARM920T,由Cirrus Logic公司生产的工业级芯片[3,4] ,内带MMU,16 KB的指令Cache,16 KB的数据Cache和数学协处理器,主频为200 MHz,系统总线为100 MHz。该芯片拥有一组SPI接口,利用它可方便实现与SPI器件进行通信,可大大简化工程应用的硬件设计软件。

SPI驱动程序采用Win CE流驱动的标准形式。下面从驱动程序具体设计步骤以及驱动代码的编写两个方面做较为详细的阐述。

2.2 SPI驱动程序设计步骤

在Platform Builder 4.2下设计Win CE流接口驱动程序可按照以下步骤进行[5-7]:

(1) 在C:\\Win CE420\\PLATFORM\\ep931x\\drivers目录下新建一个目录SPI;

(2) 从其他驱动目录下复制makefile文件到SPI目录下;

(3) 用文本编辑器建立4个文本文件,文件名分别为SPI.c,SPI.h,SPI.def和sources;

(4) 编辑目录C:\\Win CE420\\PLATFORM\\ep931x\\driver下的dirs文件。用文本编辑器打开该文件,找到“DIRS=”等式,在该等式最后添加一行, 如下面所示:

DIRS=…

SPI

(5) 在Platform Builder 4.2中打开Platform.bib文件,在该文件最后和FILES之前加入一行,指明在生成Windows CE内核映射时自动将SPI.dll加入到内核映像中,添加内容如下:

SPI.dll MYM(_FLATRELEASEDIR)\ SPI.dll NK SH

(6)具体的流接口驱动程序跟注册表密不可分,在Platform Builder 4.2中打开platform.reg文件,在该文件最后加入如下所示注册表信息,以使在生成操作系统映像时,Platform Builder将注册表信息加入到注册表中。在Platform.reg中添加内容如下:

[HKEY_LOCAL_MACHINE\\Drivers\\BuiltIn\\SPI]

"Prefix"=" SPI "

"Dll"=" SPI.dll"

"FriendlyName"=" SPI Driver"

"Index"=dword:1

"Order"=dword:0

驱动程序设计第7篇

关键词:VxWorks;USB设备驱动;管道;回调

中图分类号:TP316文献标识码:A文章编号:1009-3044(2008)24-1200-04

Design of USB Device Driver Based on Real Time Operation System VxWorks

WANG Hao

(College of Computer, Xidian University, Xi'an 710071, China)

Abstract:The architecture of USB dirver based on VxWorks is given, general method and key technology in developing USB device dirver are analyzed.Then the device driver of LM9833 is implemented, expectant performace of target system is achieved. The general process of developing USB device dirver used in this paper can be refered by others USB device driver developing based on VxWorks.

Key words: VxWorks; USB device driver; pipe; callback

1 VxWorks下USB驱动概述

VxWorks是WindRiver公司开发的具有工业领导地位的高性能实时操作系统(Real Time Operation System, RTOS)内核。VxWorks5.5实现了USB1.1协议栈。图1提供一个VxWorks下USB主驱动栈的简单结构。

在栈的最低层是USB主控制器(USB Host Controller, HC),这是主系统中控制每一个USB设备的硬件。在主控制器上层是一个与硬件独立的主控制器驱动(USB Host Controller Driver,HCD)。USBD是在HCD之上的与硬件独立的模块,USBD管理每一个与主机相连的设备,向高层提供可与USB设备通信的路径,USBD实现了USB总线枚举、总线带宽分配、传输控制等操作。在栈的顶层是USB Client 模块,一般是特定的USB Class Driver,负责管理与USB主机连接的不同类型的设备。用户自己的USB设备驱动程序通常是在USBD这一层上完成。

2 VxWorks下USB设备驱动详解

2.1 驱动程序提供的函数

2.1.1 向应用程序提供的接口函数

设备驱动程序的主要作用是向上层应用程序屏蔽硬件,向上层应用程序提供统一的接口函数,驱动程序一般需要实现的函数如表1所示。

图1 USB主驱动栈结构

表1 驱动程序提供的接口

usbMSCDevInit();这是一个通用的初始化例程,可以在BSP中调用,也可以由应用程序来调用,但只能被调用一次,该例程初始化必须的数据结构,并向USBD注册驱动程序。USB设备与USB主控制器之间的所有操作都通过USBD来完成,因此在调用usbMSCDevInit()之前必须确定USBD已经初始化,在使用USB设备之前也要确保USB主控制器已经挂接到USBD。

usbMSCDevCreate();这是一个创建设备例程,当有设备接入时,回调函数usbMSCDevAttachCallback()调用该例程创建一个逻辑设备,当这个例程被调用时必须在系统中存在一个实际的USB物理设备。

usbMSCDevDestroy();从系统中删除设备。首先释放设备占有的资源,从设备链表中移除该设备,同时调用usbdPipeDestroy()销毁该设备与主机之间的通信管道,最后释放设备结构体。

usbMSCDevShutDown();该例程卸载已注册的设备驱动程序,并回收所有已分配资源,包括删除设备、回收信号量等。

2.1.2 两个重要的回调函数

在编写USB设备驱动程序时,除了上述接口函数外,还需要编写另外两个重要的回调函数:usbMSCDevAttachCallback()和usbMSCIrpCallback()。usbMSCDevAttachCallback()用于跟踪设备的请求实现动态接入或删除;usbMSCIrpCallback()是一个IRP callback,当每一个IRP执行完成之后调用该回调函数,实现IRP之间同步。

2.2 设备标识

在VxWorks中USB设备用USBD_NODE_ID来唯一区别,它是USBD用来跟踪一个特定设备的句柄,它与USB设备的真正USB地址无关。这表明Client并不关心设备是物理上与哪一个USB主控制器连接,应用为每个设备抽象一个Node ID,使Client可以不用考虑物理设备的连接细节以及USB地址分配。当一个Client通知有一个设备连接或断开时,USBD经常通过Node Id来定位设备。同样,当USB设备与USBD通信时,它必须向USBD传递该设备的Node Id。Node ID通常作为设备结构体的一个重要成员。

2.3 回调(Callback)

USB操作是严格遵守时序的,WindRiver USBD采用回调机制来解决时序问题。例如在USBD识别一个动态连接事件之后会激活一个动态attach callback操作,这是一个注册到USBD的回调例程,回调函数会判断当前的操作,如果是接入(USBD_DYNA_ATTACH),就会调用usbMSCDevCreate()来在当前的USB句柄上创建一个逻辑设备结构体;如果是移出(USBD_DYNA_REMOVE)就会调用usbMSCDevDestroy()来删除设备。同样,当USBD处理完成一个USB IRP之后,Client的一个IRP callback被激活,该回调例程是由Irp.userCallback域来指定。在IRP callback中释放IRP同步信号量。

2.4 数据传输

USB设备与主机之间是通过USB管道进行通信的。一旦Client配置完一个设备,就可以利用USBD提供的管道(pipe)传输功能与设备进行数据交换。管道是建立在USBD Client与设备特定的endpoint之间的单向通道。调用usbdPipeCreate()函数创建一个管道后返回一个管道句柄USBD_PIPE_HANDLE,以后所有的读写操作都分别在各自的管道句柄上进行。管道在刚创建完后是处于终止的状态,为了能有效使用它们,还必须用usbdFeatureClear()来清除该终止状态。每一个管道有以下性质:USBD_NODE_ID、端点地址,管道类型、数据流方向、包的最大有效载荷量、带宽需求等。对于块传输没有带宽限制。VxWorks的USB驱动程序的各层驱动程序间通过IRP机制进行通信,当有数据传输请求发生时,上层向下传递IRP。USBD得到请求后,调用HCD接口,将IRP转化为usb的传输。这就需要提供一个特殊的回调函数usbMSCIrpCallback(),当块传输结束时调用该回调函数。以下是读设备的具体过程。

1) 创建设备时创建out和in管道:

usbdPipeCreate(usbdHandle, NodeId, outEpAddress, configuration, interface, USB_XFRTYPE_BULK, USB_DIR_OUT,maxPacketSize,0,0, outPipeHandle);

usbdPipeCreate(usbdHandle, NodeId, inEpAddress, configuration, interface, USB_XFRTYPE_BULK, USB_DIR_IN,maxPacketSize,0,0, inoutPipeHandle);

2) 定义IRP callback:usbMSCIrpCallback(pVOID p)。

3) 构造USB_IRP outIrp请求包。

4) 提交outIrp:usbdTransfer (usbdHandle, outPipeHandle, &outIrp)。读命令在outIrp.bfrList[0].pBfr域中。

5) 等待outIrp处理结束,结束调用usbMSCIrpCallback()释放IRP同步信号量。

6) 构造USB_IRP inIrp请求包。

7) 提交inIrp:usbdTransfer (usbdHandle, inPipeHandle, &inIrp)。

8) 等待inIrp处理结束,读取的数据在inIrp.bfrList[0].pBfr域中。

2.5 多个设备管理

驱动程序用LIST_HEAD 来存储多个设备,每个接入的USB设备利用其LINK节点加入到LIST_HEAD链表当中;一个LINK节点包含三部分:linkFwd指针、linkBack指针和pStruct指针;其中pStruct指向一个待连接的设备结构体。当有一个设备创建完成时调用usbListLink()将该设备加入链表,删除设备之前调用usbListUnlink()从链表中移出该设备。由于USB设备是用Node ID来唯一标识的,在查找设备的时需要利用usbListNext()来遍历设备链表,直到某个设备的Node ID与特定设备的Node ID相匹配为止。在多个设备管理时,采用USBD_NODE_ID usbd_scan_id[DEVICE_NUM]数组来存放多个设备的Node ID,在对设备进行读写时只需提供设备的索引序号就可以直接得到设备Node ID,提高了对设备的访问速度。

3 VxWorks下LM9833驱动程序实现

3.1 LM9833 USB接口简介

LM9833扫描仪控制器在一个单独的IC上可以提供一个完整的USB图像扫描控制系统。它的USB接口提供4个USB端点(Control Endpoint,Interrupt Endpoint,Bulk In Endpoint和Bulk Out Endpoint),内部有00~7F个寄存器,其中00寄存器是存放一个8bits的图象数据,其它分别为控制或状态寄存器。通过向bulk out端点发送四字节的读命令可以从bulk in端点读取这些寄存器的值,也可以向bulk out端点发送四字节的写命令加待写数据完成写寄存器。四字节命令依次表示:读写模式(1字节)、起始地址(1字节)、读写长度(2字节)。其中读写模式bit0为0表示写,1表示读;bit1为0表示非增模式,为1表示增模式,即读写寄存器完成之后寄存器地址加1。LM9833的工作过程就是通过读写这些寄存器来完成的。

3.2 设备描述符结构

typedef struct _usbScanDev

{

USBD_NODE_ID scanDevId; /* USBD node ID of the device */

UINT16 configuration; /* Configuration value */

UINT16 interface; /* Interface number */

UINT16 altSetting; /* Alternate setting of interface */

UINT16 outEpAddress; /* Bulk out EP address */

UINT16 inEpAddress; /* Bulk in EP address */

USBD_PIPE_HANDLE outPipe; /* Pipe handle for Bulk out EP */

USBD_PIPE_HANDLE inPipe; /* Pipe handle for Bulk in EP */

USB_IRP inIrp; /* IRP used for bulk-in data */

USB_IRP outIrp; /* IRP used for bulk-out data */

USB_IRP statusIrp; /* IRP used for reading status */

UINT8 * scanInData; /* Pointer for bulk-in data */

UINT8 * scanOutData; /* Pointer for bulk-out data */

BOOL connected; /* TRUE if USB_SCAN device connected*/

LINK scanDevLink; /* Link to other SCAN devices */

UINT8 CommandByte[4]; /* Which read/write command the device */

UINT16 actBytes; /* actual bytes will be transfered */

UINT8 direction; /* data transfer direction */

} USB_SCAN_DEV, *pUSB_SCAN_DEV;

设备描述符结构中包含了设备的一些重要信息和访问该设备时的必须资源,如Node ID、IN/OUT管道、IN/OUT IRP等等。

3.3 注册设备(LM9833)驱动程序

注册驱动程序一般包含两大步:与USBD建立连接和注册attach callback。以下是注册LM9833驱动程序的源代码。

#define USB_SCAN_CLASS 0xff

#define USB_SCAN_SUB_CLASS0x00

#define USB_SCAN_DRIVE_PROTOCOL0xff

STATUS usbScanDevInit()

{……

if(usbdClientRegister ("SCAN_CLASS", &usbdHandle)!=OK||

usbdDynamicAttachRegister (usbdHandle, USB_SCAN_CLASS, USB_SCAN_SUB_CLASS,

USB_SCAN_DRIVE_PROTOCOL, usbScanDevAttachCallback) != OK)

……

}

usbScanDevInit()调用usbdClientRegister()向USBD注册一个名为SCAN_CLASS的Client,同时调用usbdDynamicAttachRegister()向USBD注册一个回调例程usbScanDevAttachCallback (),跟踪该Client请求,当设备动态地接入或移出系统时会自动地调用该回调函数。一个Client在利用usbdDynamicAttachRegister()进行注册时只对特定的class、subclass、protocol感兴趣。在成功注册Client后,USBD返回一个Client句柄(USBD_CLIENT_HANDLE),以后对USBD的调用都会用到这个句柄。Attach callback 如下。

LOCAL VOID usbScanDevAttachCallback

(

USBD_NODE_ID nodeId,

UINT16 attachAction,

UINT16 configuration,

UINT16 interface,

UINT16 deviceClass,

UINT16 deviceSubClass,

UINT16 deviceProtocol

)

该回调函数主要响应外部设备的动作,实现USB设备的动态接入和移除。

3.4 创建设备

创建设备函数如下:

LOCAL STATUS usbScanPhysDevCreate(USBD_NODE_ID nodeId, UINT16 configuration, UINT16 interface)

当接入设备时激活usbScanDevAttachCallback()操作,回调函数会根据接入(USBD_DYNA_ATTACH)动作调用usbScanPhysDevCreate()创建一个逻辑设备,在创建设备的同时,创建设备与USB主机之间通信的管道(pipe)。管道是建立在USB设备端点(endpoint)之上,是主机与设备之间数据传输的单向通道。设备与主机之间数据传输管道是建立在批量端点(bulk endpoint)之上,有BULK_IN和BULK_OUT两个端点,从而建立双向的数据通路。最后将该设备加入设备链表,进行多个设备的管理。创建设备流程如图2所示。

图2 创建设备流程

3.5 读写设备

对设备进行读写时,首先需要将读写函数转换成设备能够识别的命令,对于LM9833来说,需将读写函数转换成LM9833所能识别的四字节读写命令,读写时将这四字节的命令置于IRP包数据域的最前端,这样到数据到达设备时首先接收到的是四个字节的命令,LM9833会根据这四个字节的命令完成相应的功能。读写函数原型为:

STATUS usbScanRead/usbScanWrite

(

UINT dev, /* sequence number of the device */

UINT Addr, /* start address in register */

UINT8 *pBuffer, /* pBuffer to receive/send data from/to device*/

UINT Len, /* lenth of pBuffer */

BOOL bIncrement /* incremece of address in register or not */

)

LM9833的一个读写控制流程如图3所示,查找设备流程如图4所示。

图3 LM9833读写控制流程

图4 查找设备流程

设备命令组帧:

const unsigned int MODE_INC_READ = 0x03;

const unsigned int MODE_NOINC_READ = 0x01;

const unsigned int MODE_INC_WRITE = 0x02;

const unsigned int MODE_NOINC_WRITE = 0x00;

switch (Cmd)

{

case USB_SCAN_WRITE:/* bulk out */

pScanDev->CommandByte[0] = (bIncrement>0)? MODE_INC_WRITE : MODE_NOINC_WRITE;

pScanDev->CommandByte[1] = Addr+((bIncrement>0)? i : 0);

pScanDev->CommandByte[2] = (Len >> 8); /* length of the data to be written */

pScanDev->CommandByte[3] = (Len & 0xff);

memcpy(pScanDev->scanOutData, pScanDev->CommandByte, 4); /* 4 bytes Lm9833 command followed by write data */

memcpy(pScanDev->scanOutData + 4, pBuffer + i, Len);

pScanDev->actBytes = Len+4; /* actual length to be transfered*/

pScanDev->direction = USB_SCAN_DIR_OUT;

break;

case USB_SCAN_READ: /* bulk in */

驱动程序设计第8篇

关键词:PCI总线设备驱动程序WDM模式DriverStudio

PCI总线规范是为提高微机总线的数据传输速度而制定的一种局部总线标准。在设计自行开发的基于PCI总线的数据传输设备时,需要开发相应的设备驱动程序。通常开发PCI设备驱动程序有多种模式,在Windows2000环境下,主要采用WDM模式。本文针对自行开发的基于PCI总线的CCD视频信号传输控制卡,编写了符合WDM模式的驱动程序。

1WDM模式驱动程序

1.1WDM模式(WindowsDriverModel)

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

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

1.2设备驱动程序

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

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

1.3DriverStudio工具简介

NuMegaLab公司开发的DriverStudio是一整套开发、调试和检测Windows平台下设备驱动程序的工具软件包。它把DDK(DeviceDevelopmentKit)封装成完整的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生成的程序框架中写入相对于设备的特定代码,编译后即可得到所需的驱动程序。

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

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

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

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

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

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

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

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

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

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

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

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

KpciConfigurationPciConfig()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端口访问的操作。部分代码如下:

{……

KIORangeDevIoPort();//创建实例

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

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

If(NT_SUCCESS(status))

{……

DevIoPort.inb(0,LineBuf1,10);

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

}

else{Invalidate();returnstatus;

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

{

……}

(3)内存读写模块

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

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

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

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

(4)中断模块

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

BOOLEANTranCard::Isr_MyIrq(void)

{if(//中断未产生)

{……

returnFALSE;}

else

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

returnTRUE;}

}

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

NTSTATUSTranCardDevice?押?押OnStartDevice(KIrpI)

{……

status=m_MyIrq.InitializeAndConnect(

pResListTranlated,

LinkTo(Isr_MyIrq),

This;)

……}

2.4驱动程序的调用

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

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

HANDLEhDevice=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驱动程序的调试

采用SoftICE、DriverMonitor作为调试工具,基本调试过程如下:(1)使用symbolloader加载驱动程序,然后使用SoftICE跟踪调试,确认驱动程序正常加载;(2)对核心的中断响应程序代码,用SoftICE中的Genint命令产生虚拟中断,单步跟踪中断;(3)硬件发送大量的数据,通过查看内存的数据,确认数据传输是否正确。

驱动程序设计第9篇

0、引言

“面向对象程序设计”是软件工程专业和计算机科学与技术专业的一门专业核心课程。该课程是软件工程等课程的先修课程,同时又是进行软件开发的直接工具,是把所学的专业知识转化为应用的桥梁,是学生就业专业知识的关键技术,所以该课程在整个教学体系中占据非常重要的地位。目前该课程在教学中仍普遍采用传统的以语法讲授为主线的课堂教学模式,从而导致学生学习该课程的主动性和积极性不高,缺乏知识运用和解决实际问题的能力,教学效果也不理想。针对目前“面向对象程序设计”课程教学中存在的问题,课程组将基于项目的教学方法应用于该课程的教学实践,并取得了初步成效。笔者从教学目标、教学内容、教学方法和手段、教学组织和教学评价等几个方面介绍项目驱动在“面向对象程序设计”课程教学改革中的应用,并希望可以与工作在教学改革第一线的教学同行进行交流和探讨。

1、项目驱动教学的理论基础与认知研究

1.1 目前课程教学中存在的问题

面向对象程序设计(OOP)是一种全新的程序设计思想。但目前该课程大都以演绎的方式来教授,教学中存在重语言介绍、轻对象思想和方法传授的情况,即在教学内容的组织上是以特定的面向对象程序设计语言结构组织的,从基本语言要素、语法和语句结构组织,然后再举一些例子说明这些语句的应用,而这些例子都是一些语言语法层面上的简单应用,很少涉及实际问题的解决。这种教学方式不仅不利于学生领会和理解面向对象的思想和方法,更不利于培养学生使用面向对象方法解决实际问题能力。

1.2 建构主义

工程与科学教学中主要采用的演绎式教学法将课程或知识点作为学科内一个自成系统的知识体系来处理。教师按照从一般原理到数学模型再到模型应用这样的方式进行教学,很少会提到为什么要这样做,以及这样的模型可以用来解决什么实际问题,学生为什么要学习这些东西等,而学生的任务就是被动地吸收这些知识。

在教育心理学中有一个公认的准则,就是只有当人们清楚地意识到有必要去了解某个事物时,他才会最为强烈地去主动学习。如果只是告诉学生某项知识或技能在日后会用得到,并不能起到有效的激励作用。

与传统教育模式不同的建构主义认为学生的学习是将新的信息纳入到自己已有的认知框架中。因此,教育应该从学生可能熟悉的内容与经历出发,与学生已有的知识结构联系起来。教学内容应该与实际应用有关,并与其他知识领域相关联,而不应是抽象的或独立的。教育者要创造条件引导学生自行建构知识,并从实践经历中获得证据来修正自己的知识建构。

建构主义支持归纳式的教学,即教学不是从一般原理到应用,而是首先从具体事物出发,提出一个有待解决的实际问题;然后教师在学生解决问题的过程中向学生提供所需的信息,帮助学生把握事实、了解规则、知道程序、明白原理。项目驱动的教学也是归纳式教学的一种。

1.3 认知研究

心理学与神经学方面的研究对归纳式的项目驱动教学提供了强有力的支持。

布兰斯福德(Bmnsf-ord)等人在文献中指出:“凡是新的学习都涉及先前学习所得信息的转移”,即学生对新知识的接受程度受已有知识的影响是很强的。如果新知识与学生已有知识或认知有联系或一致的话,学生学习起来较容易。项目驱动教学是在学生能联系起来的情景、问题或应用的背景下提出新的知识。因此,这样的教学内容能够与学生已有的认知结构结合起来,是有易于学生接受的。

学生的学习动机会影响到学生愿意投入学习的时间的多少。如果学生发现学习的东西有用,而且能够用来做一些对别人有影响的事情的话,学习就会更有积极性。项目驱动的教学通过与实际应用相关的项目来提供一门课程的教学内容与技能。学生在学习的过程中能够亲身体会到所学知识的实用性。因此,这样的教学方法能够大大增进学生学习的积极性。

此外,如果教学环境与实际工作环境相似,学生在日后就能够很容易地将课程所学得的知识与技能移用到实际工作场景中。项目驱动的教学围绕真实的项目来组织教学,因此有助于弥补学生的学习环境与实际工作环境两者之间的不一致,从而有利于学生将所学的东西应用到实际工作中去。

综上所述,把项目驱动教学应用于“面向对象程序设计”课程的教学中,能够激发学生的学习兴趣,有效地提高学生学习的积极性和主动性,改善教学效果,并有利于学生的职业素质和能力的培养。

2、项目驱动教学的应用

课程组将项目驱动的教学模式应用于“面向对象程序设计”课程的教学过程中,教学以项目为核心,学生为主体。教师在教学中起主导作用,将软件工程化思想融入到教学内容中,以软件产品的生产周期作为课程内容的主框架,教学内容包括若干个不同层次的软件项目,通过项目引出知识点。项目驱动教学模式在课程教学中的应用激发学生动手实践和分析思考,提高了学生的综合应用能力。

下面从教学内容、教学方法和手段、教学组织和教学评价等方面介绍将项目驱动教学应用于“面向对象程序设计”课程改革的具体做法。

2.1 基于项目驱动的教学内容改革

课程组通过选用国外原版经典教材,引进国外的先进教学理念,依据课程教学大纲,以职业活动为导向,以学生为教学主体,以项目为中心,对课程教学内容进行整合、序化,构建了模块化课程结构,如图1所示。该结构将课程内容划分为4个模块:语言基础、面向对象程序设计基础、面向对象程序设计的方法理论和开发应用,并细化每个模块的知识点和职业素质、技能和能力培养的要求,突出面向对象程序设计的方法理论和开发应用,着重培养学生的职业素养、主动学习和创新的能力。

在上述4个教学模块中,教学内容是按项目驱动的。在讲授课程内容时直接从面向对象程序设计入手,将语言基础的知识分散到其他模块中进行讲解。在2、3、4级模块中,通过项目来详细展示每个单元的重要理论和概念,所涉及的语法知识会随着解决问题的需要而引入。基于项目驱动教学的2、3、4级模块所包含的项目如图2所示。

项目驱动教学实施的关键在于项目的设计与选取。教学项目的设计与选取遵循有的放矢、与实际应用相关联的原则。同时项目的难易程度要以不将学生逼到其“最近发展区(Zone ofProximal development)”之外为原则,即选择的项目要比学生可以独立完成的项目难一些,但是在教师指导下或与其他学生合作能够完成。

2.2 基于项目驱动的教学方法改革

根据软件设计开发的工程性特点,“面向对象程序设计”课程的教学灵活地运用了“基于项目的教学方法”,突出了“理论教学构筑学生的知识结构,实践教学构筑学生的职业技能结构”的教学原则,并将面向对象程序设计的基本原理、软件编程的基本规范和软件设计建模的教学完全地融合在一起。

项目驱动教学法与传统的教学法相比,有很大的区别,主要表现在改变了传统的3个中心,将以“教师”为中心转变为以“学生”为中心,以“知识体系”为中心转变为以“项目”为中心,以“理论讲解”为中心转变为以“项目实践”为中心。在教学过程中,学生可以参与软件产品的构思、设计、实施和运行,这给学生创造了感知软件、动手实践、分析思考的机会。通过解决问题,学生的学习兴趣被激发,基本的工程素质和能力得到了培养。“基于项目的教学方法”目的在于创造条件引导学生通过亲自参与,自行构建知识,而不是简单地接受教师的诠释。

2.3 教学评价和考核方法改革

项目驱动教学重在知识的应用与集成,因此教学的考核与评价要强调对概念的理解,重视对知识、技能学习过程的评价,关注实践环节及工程应用能力,应对学生进行多视角、多方位的综合测评,力求知识与能力的协调统一和考核评价的客观与公正。课程组将考试形式由笔试改为机试,并增加课程设计考核环节。学生最终成绩的评定方法是:机试占20%,日常表现(出勤率、作业与实验成绩)占20%,自我评价与同学生评价占10%,项目设计和参与程度占20%,答辩情况占20%,撰写论文或报告占10%。考核形式的改革会引导学生在课程学习中注重编程能力和解决问题能力的培养。

3、项目驱动在教学中的应用效果与评价

从2009~2010学年的第一学期开始,课程组将项目驱动应用于“面向对象程序设计”的课程教学中。通过与传统教学进行对比,我们得出以下两方面的结论。

3.1 项目驱动对教学产生的正面效果

项目驱动教学增进了学生在概念理解方面的思维能力,增强了学生分析问题、解决问题的能力,能够有效地调动学生学习的积极性,提高学习的责任心,改善了学生与学生、教师与学生之间的互动关系,在学生的团队合作与沟通能力培养方面起到积极的作用,特别是对于那些学习风格不适于传统课堂授课的学生的教学效果特别好。

3.2 项目驱动教学在应用中存在的问题

项目驱动教学并不是一种很容易开展的教学。从教师方面而言,该方法要求教师对课程知识的把握程度要深,要有丰富的教学经验,能够根据教学情况随机应变。就学生方面而言,基于项目的教学方法要求学生对自身的学习负有更多的责任。在项目实施过程中,各种项目管理与人际冲突等问题还会出现,这些都是学生所不习惯的,同时也对教师的教学组织能力提出了更高的要求。因此,有些教师和学生在一开始会对它感到不适应,在学习过程中也会出现两极分化现象。此外,如文献中所描述的,基于项目的教学容易产生内容知识方面的空白,忽视和遗漏一些关键知识点,从而影响学生今后对一些重要内容的进一步学习。

相关文章
相关期刊
友情链接