驱动程序设计范例6篇

驱动程序设计

驱动程序设计范文1

随着新技术的不断涌现和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)

{

……

驱动程序设计范文2

关键词:嵌入式;CF卡;低层驱动;存储设备

中图分类号:TB文献标识码:A 文章编号:1672-3198(2012)12-0162-01

0 引言

设备驱动程序是构成Linux内核的主要部分,不合理的驱动设计会导致系统内核出现紊乱,由于不稳定而导致系统崩溃,使行成重要数据丢失或严重后果。因此,设计合理的驱动程序,有助于保障系统的整体稳定性。在S3C2410开发板下设计合理的驱动程序是本文研究的重点。

S3C2410的硬件平台是基于ARM公司的ARM920T处理器核,采用32位微控制器,价格低,功耗低,性能高;软件平台通过u-boot移植和内核编译完成,所有这些特性使S3C2410为 linux操作系统内核驱动程序设计提供了较好的解决方案。

目前,嵌入式系统中应用最广泛的存储卡是CF卡。多数情况下,使用PCMCIA控制器实现CF卡的操作,为了减少设备使用和成本降低,本文在没有PCMCIA控制器情况下,探讨分析设备驱动程序设计步骤,CF卡的配置及底层驱动如何工作等问题,研究实现了利用CF卡作为存储设备的嵌入式Linux系统。

1 系统设计

嵌入式系统使用CF卡作为存储设备的设计目前有很多,而开发设备的选型不同,开发的方法不同,本系统使用Linux操作系统,以S3C2410为开发平台,以ARM920T处理器为模板来实现CF卡的嵌入式系统。

驱动程序开发首先需对Linux操作系统中原有的IDE程序进行改造,用后台程序管理CF卡的热插拔事务,同时CF卡以Memory寻址访问方式进行8位寻址。在对Linux设备进行驱动程序设计时,具体设计步骤如下:

(1)启动系统,将设备登记到相应的设备数组,并返回设备的主驱动号。利用设备号对此数组进行索引。调用设备注册函数module_register_chrdev()进行设备注册。

(2)为驱动函数定义功能函数,当系统调用这些功能函数时,系统将自动运行函数定的模块实现特有的功能。

(3)当一个模块使用完成时,启动动态的卸载模块函数,调用cleanup_module()函数,并调用设备注销函数即可卸载函数。

在进行设计时,需注意Linux设备驱动程序接口和几个重要的数据结构。具体有以下四层接口:应用进程与内核、内核与文件、文件系统与设备驱动程序、设备驱动程序与硬件设备。

每个驱动程序都有一个数据结构,包含的函数指针指向所开发的接口,内核用主设备号作为索引访问数据结构。

2 接口和重要的数据结构

设备驱动程序是操作系统硬件设备和内核的接口,Linux 操作系统中,Linux 操作系统采用统一的接口,在硬件设备、设备驱动程序、文件系统、内核、应用程序进程间有相连的接口。

驱动程序有一个file_operations的数据结构,该数据结构提供了很多接口,其中常用的接口有open、read、write、seek、release等,为驱动程序开发提供了保障。驱动程序中struct inode数据结构为设备和文件对应了唯一的inode号,驱动程序中同时也使用了struct file、struct device 数据结构。

3 CF卡基本配置

CF卡在存储操作前,对CF卡进行的相关配置主要有以下几个方面:配置GPIO并分配寻址端口,用于传输CF卡信号。配置CF卡的属性存储空间和寻址访问方式。在系统中CF卡使用Memory寻址访问方式,将属性寄存器配置为0x00,其他属性寄存器保持默认值。验证对属性寄存器的值,当驱动属性值与默认值不匹配时,则说明Memory寻址访问方式没有正确使用CF卡,此时需修改属性值为默认值即可。

4 CF卡驱动程序设计

4.1 底层驱动实现

CF卡存储备份需要通过CF卡的底层驱动实现,这就要求CF卡能准确的接收及响应系统对它的I/0请求。具体流程如下:

(1)在读写命令时,使用LBA寻址模式来访问CF卡。当驱动对CF卡的I/O请求进行正确接收后,此时把相关参数值和ATA命令值写入对应的寄存器,并向CF卡ATA命令,即完成了ATA命令。

(2)填写ATA命令控制块后,CF卡可以利用轮询的方法对发送的命令做出响应。

(3)受外部环境影响造成CF卡没有接收到命令或者接收命令出错时,可以使用软重置将其恢复到初始状态,并重新发送该ATA命令。

快捷的实现存储备份需使CF卡能及时响应热插拔,把CF卡设定为TureIDE工作模式,这样CF卡就可以随意移动。在系统层注册字符型设备CFMGR文件实现探测热插拔事件、与应用层通信,实现分配或释放系统资源,从而驱动CF卡;在应用层及时监听热插拔事件并采用Select阻塞机制,达到尽量少的占用CPU资源。

4.2 驱动程序实现

驱动程序的作用在于为应用程序提供机制,它是内核的一部分。该驱动程序实现了设备初始化,在内核和设备间相互传送数据,读取、回送数据,检测错误等功能,开发的难点在于高效请求处理、中断、1/O操作等方面功能设计。

5 结语

本文通过系统驱动程序的设计流程分析,研究程序开发的接口和数据结构,对CF卡进行配置,研究开发驱动程序,实现了CF卡存储备份和快速热插拔,使其便于在其他系统中应用。

参考文献

[1]嵌入式Linux 中CF卡的管理研究[EB/OL].140.112.99.135/ntu/showthread.php?threadid=67.

驱动程序设计范文3

关键词: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)硬件发送大量的数据,通过查看内存的数据,确认数据传输是否正确。

驱动程序设计范文4

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

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

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

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

§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网络驱动程序设计》

驱动程序设计范文5

关键词:ACCESS;案例驱动;教学改革

ACCESS是一种关系型桌面数据库管理系统,具备功能强大和操作简单的特点,适合非计算机专业学生理解数据库技术。在ACCESS程序设计课程的教学中,引进案例分析,有助于合理调整学生的知识结构,并可帮助学生对项目背景、业务需求分析、功能需求分析、数据需求分析、数据库管理软件开发等过程进行系统的学习。

1教学现状及面临的问题

目前,教育部考试中心在全国计算机等级考试大纲中,将ACCESS列为二级程序设计考试的可选语种之一,大多数学校将ACCESS程序设计作为非计算机专业必修的程序设计语言课程。然而课程的教学效果并不理想,原因是课程的教学内容设计、教学中施受(师、生)双方所持有的理念、教学方法的设计等都存在以下不足之处。

第一,在课程的内容设计上,目前大致有两种类型:一种是数据库理论为主,另一种是数据库的基本应用为主。前一种内容设计架构主要着眼于提升学生在数据库方面的理论素养,但这对非计算机专业的学生来说,有“舍本求末”之嫌;后一种情况虽然在内容设计上强调“学以致用”,但要么是以比较陈旧的案例作为训练的素材,例题设计陈旧,要么就把实验内容设计得过于复杂。

第二,受传统教学的影响,课程教学中虽然引进了多媒体教学方法,但课程上的教授、教师往往过于侧重理论,一味讲解各种控件的属性、事件、方法等,且往往缺乏新颖、有趣、精简的课堂案例设计。

第三,等级考试引进后带来的新问题。等级考试中ACCESS语言的引进,本意是为了加强ACCESS语言的应用推广。不料它引发了一个副产品,教学中教师为考而强调基本概念和语法,只讲解无忧软件中的例题等,根本讲不透,学生为考而死记硬背标准答案,很少涉及实际应用,操作能力、综合分析问题能力及创新能力几近荒废。通过对最近几年考试分析,我们可以发现学生在综合编程题30分题中,满分只占20%左右,即学生的逻辑思维与分析问题的能力并没有得到提高。

故此种种,再加之各个高校扩招以来,学生素质已呈逐步下降趋势,学生主动学习意识不强,教学中施受(师、生)双方所持有的理念――为“考”而教,为“考”而学,自然而然形成并流传,几乎难以纠正。

显然,ACCESS程序设计课程教学改革如箭在弦,势在必行。我们认为,课程的应用性特点要求我们必须以应用能力的提升为目标,以案例本身的更新和案例教学法的优化来驱动这一改革。

2案例教学实践

案例驱动教学模式是提高学生综合应用能力的一种有效途径[1]。案例驱动是将知识点分解到若干实际案例,使学生从知识的被灌输者变成意义的主动建构者,教师也从知识的传授者与灌输者变成意义建构的帮助者和促进者[2]。让学生先有一个感性的认识,激发学生的学习兴趣。然后教师再剖析理论知识,理解高层次的理论知识,让学生参与思考、讨论、分析,逐步培养学生创新能力。

传统讲授面向对象的程序设计时,大多数教师都从基本概念和专业术语开始讲解,如关系数据库、对象、类、属性、事件、方法等,然后再讲窗体、报表。对于大一新生来说,理解难度太大,容易产生厌学情绪[3]。如果采用案例驱动教学,给学生先介绍一个学生成绩管理系统,从实际的例子入手,让学生掌握设计用户界面,激发学习兴趣之后,再引出界面所需的数据。而输入数据时要注意各数据的类型匹配,再讲解基本概念,这样学生很容易理解专业术语。

2.1案例设计

教师设计案例时,必须把握教学内容,从本校学生实际情况出发,尽可能设计一些学生容易理解、符合实际教学要求,难度适中。同时应用多媒体技术表现,实现各章节内容的嵌入,促进学生的自修能力让学生成为主体[4]。案例设计要有连贯性,讲解时要注意引导学生分析、思考、发现问题,从而实现知识扩展[5]。

将学生成果纳入案例教学,对历年学生创造程序进行评优,挑选最优秀的程序设计项目。在教学中演示给新生,分析案例的设计思路和实现方法,进而引出该案例中用到的知识点;举一反三,启发学生对案例进行讨论、分析、总结,对案例完善和扩展;最后达到知识融会贯通和创新能力的培养。

2.2案例组织

案例的设计非常重要,如何对案例进行合理编排与组织使学生能够接受与理解也是我们要认真考虑的问题。Access中程序设计是用VBA来实现,所以我们必须由浅入深、循序渐进地介绍VBA程序设计的基础知识及编程思想。用最贴近学生实际情况的案例,如循环语句可以设计学生成绩评定等级的案例。

案例组织应本着由简单到复杂,知识点由浅入深,有效扩充的原则。案例必须紧扣教学内容和教学目的,符合学生的认知规律。根据学生的层次不同,可以有选择性的要求学生掌握不同的案例,基础差的学生可以由老师参与一起分析案例,有目的地训练他们如何分析问题,提高他们的学习兴趣和实践能力[6-9]。

案例组织最重要一环还是教师课前准备,教师必须对案例进行全面的分析。掌握各个案例之间联系、把握各章知识点重点、难点。帮助学生掌握正确分析问题的方法,启发和诱导学生对案例进行归纳与总结。教师在课后认真总结学生提出的问题和容易出错环节,整理容易出错的案例并在教学中有针对性地进行讲解,从而实现整个案例教学进程的有效调控,确保教学的质量。

2.3案例实施

案例实施最重要的主体是学生,教师提前将下次课案例分发给学生,使学生在课前对内容进行阅读、思考、分析。教师在课堂组织学生讨论,总结与评定案例中出现的问题,引导学生对存在的疑问进一步思考和分析。

3经典项目案例分析

3.1教学大纲的要求

1) 掌握数据库表的基本操作步骤;

2) 表结构的设计与字段属性的设置;

3) 表之间的关系设置。

3.2提出问题

根据以上教学大纲要求,教师提前设置一个案例场景,描述如下:

“一所高等院校进行扩招以来,教师批改试卷的工作量越来越大。为了减轻教师批改的工作量,让教师把工作重点放到教学案例设计当中。因此,学校教务处委托你开发一个‘试卷管理系统’”。

该系统主要实现学生无纸化考试。包括考生管理、教师管理、试卷管理、成绩查询管理等。现在,作为一名程序设计人员,要求完成试题表与答题表的设计。

3.3分析问题

1) 试题表与答题表的信息,方便以后的查询、增加、删除、修改等操作,通过建立数据库来存取试题和答题信息;

2) 如何设计试题表的结构,如何设计答题表的结构。首先要求学生自己设计单选题、多选题、判断题结构。

3) 在建立表的结构时,如何合理的设计各字段的属性,包括类型、大小、主键等?操作步骤是怎样的?

3.4解决问题

1) 根据案例要求,引导学生进行讨论完成数据表的设计。具体参考操作步骤如下:

Step1:根据案例要求,教师规划出试题E-R图,如图1所示。

在此参考步骤中,根据图1教师和学生一起分析为什么要设计属性1、2、3和4;教师引导学生自己设计“答题E-R图”,并引申出关系数据库中的实体、属性、联系、域等基本概念。

Step2:根据E-R图,规划出试题数据表的数据字典,如表1所示。

Step3:根据数据字典,在ACCESS数据库中创建testque表,并输入测试题目记录;

教师提出问题供学生思考和实践:①题目字段类型为什么要设置为文本型?它的大小为可以设置为10吗?从而引出ACCESS中的中英文字符长度相同的概念。②将题号的数据类型 “数字类型”更改为“自动编号”类型,输入数据时是否更快捷?(请学生自行体会)。③题号字段为什么要设置主键?它的值能不能重复?(教师可在此引导学生进入答题表的建立,并强调试题表与答题表之间的联系)。

3.5课堂总结、学生独立设计

通过建立数据库和表的步骤,学生就更容易理解设计表结构的重要性。通过这个案例,学生掌握建立表的操作步骤,明白了表的设计过程以及表之间的联系,易于理解实体、属性、域等概念,为后续的程序设计奠定基础。

在整个教学过程完成后,教师对各知识点进行归纳,对未纳入案例的内容进行补充,引导学生独立设计案例,巩固所学知识。完成表记录输入后,教师提出根据试题表中记录如何实现批量修改、批量删除,从而引出操作查询设计。

4教学效果

通过教学实践验证案例驱动教学法,能更加激励学生学习的兴趣。在验证过程中,选取不同专业的新生,分为4个班,文科、理科各有两个班。甲班采用传统教学方法,乙班采用案例驱动教学法。教学后4个班级都参加全国计算机二级ACCESS等级考试,考试内容分为笔试和机试两部分,统计成绩如表2所示。

以上统计显示,文科笔试乙班比甲班及格率高12%,机试乙班在基本操作题和简单应用题正确率平均80%,特别是综合应用能力强于甲班3倍以上。理科笔试乙班比甲班及格率高20%,机试乙班在基本操作题和简单应用题正确率平均96%,综合应用能力强于甲班2倍以上。

5结语

在Access程序设计课程教学采用案例驱动方法,可以增强非计算机专业学生应用数据库的综合能力,有助于提高其所在专业应用计算机的水平和解决实际问题的能力。实践调查证明,采用范例引导型教学、师生互动教学,以综合实际案例为教学模式的案例驱动式教学是适合社会发展和需求的新型教学模式,它值得计算机基础教育工作者去进一步完善和推广。

参考文献:

[1] 黄冬梅,王爱继. 大学计算机基础课程的案例教学[J]. 计算机教育,2009(16):126-129.

[2] 袁维新. 影响知识建构的环境因素探析[J]. 教育科学,2003,19(1):41-44.

[3] 庞晓琼. 案例驱动的数据结构课程设计教学改革实践[J]. 计算机教育,2009(1):62-64.

[4] 龚沛曾,杨志强,顾春华,等. 大学生计算机实践能力培养的改革和实践[J]. 中国大学教学,2008(6):16-18.

[5] 黄永灿,徐甜. 案例驱动教学法在VFP程序设计课教学中的研究与实践[J]. 广西轻工业,2009,25(4):169-170.

[6] 李宏图. 案例驱动教学方法的探析与实践[J]. 昆明理工大学学报:社会科学版,2010,10(2):90-93

[7] 常梅,李迎秋,李永. 案例驱动在C语言程序设计教学中的探索实践[J]. 计算机教育,2009(22):82-84.

[8] 龚沛曾,杨志强,顾春华,等.构建综合教育环境,提高大学生计算机综合能力[J]. 计算机教育,2009(12):110-112.

[9] 黄陈英,曾俊,黎明. 教育技术在“Access数据库应用”实验教学中的应用初探[J]. 成都教育学院学报,2006, 20(10):73-75.

Cases-driving Reform and Practice of ACCESS Programming

LIANG Hua, CHEN Zhen, ZHANG Bo

(Hunan International Economics College, Changsha 410205, China)

驱动程序设计范文6

关键词:数字电视;嵌入式系统;NAND Flash;驱动开发;Linux

中图分类号:TP316文献标识码:A文章编号:1009-3044(2012)01-0070-04

Design and Implementation of NAND Flash Driver in Digital TV

LI Yang,Michael Collier

(College of Information and Electrical Engineering, Shandong University of Science and Technology, Qingdao 266590, China)

Abstract: With the global development of digital broadcasting, digital television has become the mainstream of market, SOC processor chips integrated analog and digital TV source decoder and high capabilities of post-processing has broad market prospects. As a kind of large-capacity storage devices, NAND Flash meets the harsh requirements of power, size, cost and resistance to shock by embedded system, which has been widely used. This paper probes into the principles of the NAND Flash devices in DTV and the design and implementation of NAND Flash driver based on the framework of Linux.

Key words: digital TV; embedded system; NAND Flash; driver development; Linux

在嵌入式系统开发过程中,大容量存储器模块的设计已经成了不可或缺的重要方面。数字电视SOC芯片的NAND Flash支持由两部分组成[1]:NAND Flash控制器和NAND Flash存储芯片(H27U1G8F2B)。当要访问NAND Flash中的数据时,必须通过NAND Flash控制器发送命令才能完成,因此开发一个高效的NAND Flash控制器的驱动程序显得尤其重要。

1 NAND Flash工作原理

1.1 NAND Flash组织结构

该数字电视系统采用的NAND Flash型号为K9F1G08U0B,整个芯片分为1024个块(block),块是擦除的基本单位。每个块又分为64页(page),每个页包含2112字节的容量,其中2K字节用于存放数据,64个字节用来存放ECC校验信息及其他额外数据。用户数据存储区总容量为128MB,额外数据区总容量为4MB。NAND Flash以页为单位读写数据,而以块为单位擦除数据[2]。NAND Flash的存储结构如图1所示。

图1 Nand Flash存储结构图

1.2 NAND Flash寻址方式

按照上述的组织方式可以形成三类地址:

Column Address:列地址

Page Address:页地址

Block Address:块地址

表1 NAND Flash寻址方式表

A0 ~A11是列地址,共12位以保证能寻址到2112的页容量;A12~A17是页地址,共6位,保证能寻址到每个块中的64个页;A18~A27是块地址,共10位,用来寻址1024个块。由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。整个地址传递过程需要如下4步才能完成,称为4-step addressing。

第1步是传递列地址的前8位,也就是A[0:7],不需移位即可传递到I/O[0:7]上;第2步是将NAND_ADDR右移8位,将列地址的后4位A[8:11]传到I/O[0:7]上;第3步将NAND_ADDR再右移8位,将页地址跟块地址的前两位放到I/O[0:7]上;

第4步将NAND_ADDR继续右移8位,将块地址的最后8位放到I/O[0:7]上。

1.3 NAND Flash操作方式

1)擦除操作:

擦除操作时以块为单位进行的,擦除的启动指令为60h,随后的2个时钟周期是块地址。其中只有A17到A27是有效的,而A12到A17是可以忽略的。块地址之后是擦除确认指令D0h,用来开始内部的擦除操作。器件检测到擦除确认命令后,在/WE的上升沿启动内部写控制器,开始执行擦除和擦除校验。内部擦除操作完成后,应该检测写状态位(I/O 0),从而了解擦除操作是否成功完成。

2)写操作:

写入操作以页为单位。写入之前必须在擦除之后,否则写入时将会出现错误。页写入周期中包括以下步骤:

写入串行数据输入指令80h。然后写入4个字节的地址,最后串行写入数据。串行写入的数据最多为2112B。串行数据写入完成后,需要写入“页写入确认”指令10h,这条指令将初始化器件内部写入操作。10h写入之后,NAND Flash的内部写控制器将自动执行内部写入和校验中必要的算法和时序,系统可以通过检测R/B的输出,或读状态寄存器的状态位I/O 0来判断内部写入是否结束。

2 NAND Flash控制器

该NAND Flash控制器的读写擦除都是来自AMBA APB总线的请求。NAND Flash控制器的主要功能是把来自于AMBA APB总线的请求转化为标准的NAND Flash的命令序列。

因为NAND Flash的普通的数字读写都是以页为基础的,所以在NAND Flash控制器中使用了一个2K的数据缓存buffer。

对于数据路径的设计,因为NAND Flash的输入输出总线是一个命令形式的串行总线,地址和数据复用一条总线,所以设计中有必要引入一个多路器。另外,为了提高系统的可靠性,数据通路中引入了可选的ECC功能。

3 NAND Flash驱动程序设计

3.1 LINUX MTD驱动框架

NAND Flash作为boot loader、内核与文件系统的最佳载体,是嵌入式系统中必不可少的一个外设。Linux内核引入了MTD内存技术设备子系统来为NAND Flash、NOR Flash等存储设备提供统一的接口,从而使Flash驱动的设计大大简化。引入MTD框架后,NAND Flash设备驱动可以分为如图3几层。

图3 NAND Flash驱动程序分层结构

1)硬件驱动层

NAND Flash硬件驱动层负责FLASH硬件设备的读、写、擦除,Linux MTD设备的NAND Flash驱动则位于/driver/mtd/nand子目录下。

2) MTD原始设备层:

MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码(mtdcore.c、mtdpart.c),另一部分是各个特定的FLASH的数据,例如分区等。

3) MTD设备层:

基于MTD原始设备,Linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90),构成设备层。MTD字符设备在mtdchar.c实现,MTD块设备在mtdblock.c实现。

4)设备节点:

通过mknod命令在dev子目录下建立MTD字符设备节点(主设备号为90)和块设备节点(主设备号为31),用户通过访问该设备节点即可访问MTD字符设备和块设备。

3.2 NAND Flash平台驱动结构体

NAND Flash平台驱动结构体定义如下:

static struct platform_driver hiview_nand_driver = {.probe= hiview_nand_probe,

.remove= hiview_nand_remove,

.suspend = hiview_nand_suspend,.resume= hiview_nand_resume,.driver= {

.name = "hiview-nand",.owner = THIS_MODULE,},}; 1) hiview_nand_probe函数是驱动真正开始工作的部分,主要作用是初始化硬件、扫描设备、分配相应的资源等[3]。这部分代码根据具体的NAND Flash器件有关,必须自己去实现。

2) hiview_nand_remove函数与函数hiview_nand_probe相对应,主要完成NAND Flash的反初始化工作,包括释放系统资源及关闭硬件时钟等。

3) suspend和resume主要用于电源管理的相关操作,在没有电源管理的系统中放个空函数即可。

3.3 NAND Flash底层操作函数实现

通过平台驱动中的hiview_nand_probe函数注册之后,相应的函数都挂载完毕,初始化工作也已经做完,此时NAND Flash便可以工作了[4]。上层在访问NAND Flash的时候,通过MTD,一层一层向下调用,最终调用到底层的操作函数。

1) hiview_nand_write_buf和hiview_nand_read_buf:

这是两个最基本的操作函数,其功能就是往NAND Flash控制器的FIFO中读写数据。比如要读取一页的数据,那么在发送完相关的读命令和等待时间之后,就会调用到你底层的read_buf,去NAND Flash的FIFO中,一点点把所需要的数据读取出来,放到内存的缓存中去。写操作也是类似,将我们内存中的数据,写到NAND Flash的FIFO中去。

2) hiview_nand_devready:

NAND Flash的一些操作,比如读1页数据,写入1页数据,擦除1个块,都需要一定的时间,在命令发送完成后,就是硬件开始忙着工作的时候了,而硬件什么时候完成。这些操作,就是通过这个函数去检查状态的。具体实现都是去读硬件的一个状态寄存器,其中某一位是否是1,对应着是处于“就绪”还是“忙”状态。

3) hiview_nand_enable_hwecc:

在硬件支持的前提下,前面设置了硬件ECC的话,要实现这个函数,用于每次在读写操作前,通过设置对应的硬件寄存器的某 些位,使得启用硬件ECC,这样在读写操作完成后,就可以去读取硬件校验产生出来的ECC数值了。

4) hiview_nand_correct_data:

当实际操作过程中,读取出来的数据所对应的硬件或软件计算出来的ECC和从OOB中读出来的ECC不一样的时候,就是说明数据有误了,就需要调用此函数去纠正错误[5]。对于常见的ECC算法来说,可以发现2位,纠正1位。更复杂的情况和更加注重数据安全的情况下,一般是需要另外实现更高效和检错和纠错能力更强的ECC算法。

4结束语

在驱动开发结束之后,将此驱动程序编译成模块,并整合到要移植的Linux系统中。经过系统的整机调试,此NAND Flash驱动功能完整,性能稳定,能够很好的支持YAFFS2文件系统,很好地满足了设计需求。参考文献:

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

[2]汉泽西,吕飞.大容量NAND Flash在嵌入式系统中的应用[J].石油仪器,2006 (2):62-66

[3] Love R. Linux内核设计与实现[M].陈莉君,译.北京:机械工业出版社,2006.