驱动程序范文

时间:2023-04-09 11:54:56

导语:如何才能写好一篇驱动程序,这就需要搜集整理更多的资料和文献,欢迎阅读由公务员之家整理的十篇范文,供你借鉴。

驱动程序

篇1

2、下拉菜单中选“属性”,

3、属性中选“硬件”,

4、硬件里选“设备管理器”,

5、设备管理器中点开“端口”,

6、端口里右键点“打印机端口”

7、选“属性”

8、属性里选“驱动程序

9、驱动程序里选“驱动程序详细信息”

10、此时在驱动文件窗口里显示的就是驱动文件所在位置及名称。

篇2

这归结于优化的功效,很多玩家都可以有针对性地对游戏进行优化设置,调整系统、优化资源,同时对游戏进行设置上的更改,寻找最佳的平衡点。

现在,我们来尝试针对NVIDIA及ATI两种主流显卡品牌的驱动程序进行优化说明,来看看它们有什么秘密吧!

ATI 提高《Doom》运行速度有技巧

如果你想玩《Doom》一类采用OpenGL的游戏,尤其是当你的电脑使用ATI显卡时,你必定会感到很烦恼。OpenGl性能不强使得ATI的显卡在以《Doom》为首的OpenGL游戏中一向表现不佳。因此,针对OpenGL部分的调节非常必要,尽可能提高这方面的性能是优化ATI显卡驱动程序的重要方向之一。

切换到ATI催化剂驱动程序的OpenGL选项卡上,选中“主要设置”的“自定义设置”,然后进行细节调整。将“纹理选项”和“Mipmap”的拉杆向左拉到“性能”上,这样可以保证在不明显降低画面质量的情况下使OpenGL游戏速度得到保证,同时将“等待垂直同步信号”调整成“始终为关”。

要想将ATI显卡的潜力进行最大化的挖掘,还要进行自定义设置。勾选“使用自定义设置”项后,再点击“自定义”按钮就可切换到自定义设置页面。在其中“消除混叠”其实就是指全屏抗锯齿,在这里,如果你的显卡是低于X1000系列的,那么最好选择2×或者干脆关闭。但是,最高级的显卡也不要妄想开启6×,这时根本无法体验游戏乐趣了。

NVIDIA 让秘密大白于天下

相比之下,NVIDIA的优化设置更为科学,不仅有预置的优化方案,也有适合高级玩家的细节调整。

先说简单的方法,在NVIDIA的ForceWare驱动程序中提供了很多游戏、应用程序的优化设置方案,当你想运行某个游戏前,只要在驱动控制面板中选中相应的优化方案就可以了。驱动中的方案会不定期进行调整、添加,即便很多新的游戏,也会在短期内拥有相应的预置优化方案。

当然,还是有很多玩家不会满足于预置方案,自主优化是另外一种选择。其中最能影响性能及兼容性的选项莫过于“Anisotropic filtering”,即各向异性过滤了。这个选项在开启时会让画面更加精细,但是,它还带来了性能大幅度下降、兼容性不佳的“副作用”,所以,如果你的显卡并不是非常新,但又想玩新游戏,不如把这个选项关闭,以获得更好的运行速度。

篇3

关键词:USB协议;Linux驱动;USB Device驱动

中图分类号:TP316文献标识码:A文章编号:1009-3044(2011)22-5418-02

Design of USB Device Drver Program on linux

SUN Yong-gang, JIAO Li-fei

(College of Science, GuiZhou University, Guiyang 550025, China)

Abstract:USB interface, with its efficient, reliable and widely is used in various embedded products. However, existing data on linux operating system, more studies USB Host, USB Device driver rarely is done. Therefore this paperthrough a simpleintroduction of USB protocol, as well as analysis of USB driver architecture about linux, is about an design of USB Device driver of linux systemfor embedded microprocessor S3C2440 .

Key words: USB agreement; linux driver;USB device driver

嵌入式产品通过的USB接口品可以很方便与PC的USB进行通信以完成数据的传输与交互。ARM嵌入式处理器性以其性能高、功耗低而被广泛地应用于消费电子、工业控制等众多领域。以ARM内核为核心集成了USB功能的处理器使得产品更简洁、更灵活、更方便。S3C2440集成了ARM920T内核,带MMU功能,可运行linux操作系统,同时带有两个USB Host一个USB Device控制器,因此在此基础上完成Linux 下的USB Device驱动程序有着重要的意义。本文是以此处理器为核心的嵌入式智能终端的Linux下的USB Device驱动程序设计。

1 USB体系结构及协议

1.1 USB硬件系统结构

USB接口是由+5V电源线、电源地线、信号线D+、信号线D-四根电缆线组成接口。其中+5V电源是向设备提供电源,信号线作用是传输数据, 为了提高信号传输的抗干扰能力这两根数据线采用差分传输。主机可以通过D+和D-线的电平高低来确设备是高速设备还是全速设备。

1.2 USB数据传输通道

USB主机与USB设备由很多端点构成,它们之间通过端点进行通讯。通过设置与些端点相对应的寄存器,可以为这些端点分配唯一的地址(由端点号和传输方向组成)。USB总线支持四种传输类型,他们分别是控制传输、同步传输、中断传输、批量传输。端点O只支持控制传输。

1.3 USB总线枚举

USB总线枚举就是当USB设备连接到USB主机时,主机通过缺省管道以控制传输方式来获取USB设备发来的设备描述符、配置描述符、接口描述符、端点描述符信息,并根据这些描述相关内容对USB设备进行相应的配置。

2 Linux USB 驱动程序

在Linux系统中,USB驱动程序可以分为USB Host驱动程序和USB Device驱动程序。Linux USB Host驱动程序和USB Device驱动程序总体架构如图1所示。

从图1可以知,在Linux USB Host中,USB控制器驱动是运行在USB 控制器硬件上面的的驱动动程序。该驱动实现了对USB 控制器硬件进行控制,一般称为USB固件驱动程序。USB设备驱动处于USB驱动的最顶层,它主要实现USB设备如何与主机进行通信。处在USB主机控制器驱动与USB设备驱动之间的是USB核心层,起到驱动程序桥梁的作用,该核心层为USB主机USB主机控制器驱动提供编程接口。

Linux系统中, USB Device驱动分为UDC驱动、Gadget API、Gadget驱动三个层次结构。UDC驱动处USB Device控制器硬件之上,该驱动程序控制USB控制器硬件工作,同时向上层提供操作USB控制器硬件的回调函数。处在中间层的是Gadget API层,该API向下层和上层提供统一的编程接函数的封装。Gadget驱动程序完成设备功能的实现。通过编写不同Gadget驱动程序可以使设备具有不同的功能。

3 S3C2440 USB Device驱动

3.1 S3C2440 USB接口特性

S3C2440嵌入式微处理器集成了一个设备控制器。该设备控制器具有以下特征:

1) 完全兼容USB1.1的协议。设备全速运行时可达到了12Mb/s。

2) 支持控制、中断和批量传输,批量传输支持DMA接口。

3) 自带5个的端点。端点EP0带有16byte的FIFO,该端点为双向的控制端点,其余4个端点都带有128字节输入/输出的FIFO(异步双端口RAM)的,支持中断或DMA批量传输。

3.2 S3C2440 USB Device驱动程序设计

一个完整的S3C2440 USB Device驱动程序由S3C2440_UDA驱动和gadget驱动两部分构成。S3C2440_UDA驱动是用来控制S3C2440的USB Device硬件控制器器,并把对硬件控制操作抽象为函数接口供上层调用。USB gedget驱动程序运行在S3C2440_UDA驱动程序之上的,不同的gedget驱动程序使该设备具有不同的功能。

Linux gadget驱动程序主要涉及到2个重要的结构体usb_gadget_driver和struct file_operations结构。其中usb_gadget_driver结构体包括bind、setup、disconnect等一些函数。Linux Gadget提供usb_gadget_register_driver函数对Gaget驱动进行注册。当Gadget驱动被注册后,Linux内核就会调用结构体usb_gadget_driver中的bind函数把Gadget驱动与UDA驱动进行绑定,这样就可以在Gadget驱动中使用UDA提供的统一接口函数。

bind函数中需要完成以下工作:

1) 使用usb_ep_autoconfig函数申请以后用到的传输端点。

2) 通过usb_ep_alloc_request函数为Gadget驱动分配一个请求。

3) 通过调用register_chrdev_region注册设备驱动程序。

Bind函数完成这后当有USB Host 向USB设备发出请求时,Linux系统将调用setup函数来响应请求。Setup函数把设备的设备描述符、配置描述符、接口描述符以及以后需要使用的几个端点描述符发送给USB Host,这些配置信息的发送都是通过usb_ep_queue函数来完的。

struct file_operations结构包含有open、read、write等函数。通过该结构体定义的变量被register_chrdev_region函数注册后该设备就可以像字符设备那样使有了。该结构中的一些函数完成的功能如下:

1) open函数通过init_waitqueue_head完成等待队列初始化。

2) read函数通过alloc_ep_req函数分配一个读请求变量,并为该变量中的complete设置一个请求完成函数,调用usb_ep_queue函数向端点提交I/O读请求。当内核从USB Device读到数据时就会调有刚才的完成函数。在完成读数据之前可以通过add_wait_queue和schedule()函数让进程挂起,在完成函数中唤醒挂起的进程。

3) write函数通过alloc_ep_req函数分配一个写请求变量,并为该变量中的complete设置一个请求,调用usb_ep_queue函数向端点提交I/O写请求。当内核向USB Device写完数据时就会调有刚才的完成函数。在完成写数据之前可以通过add_wait_queue和chedule()函数让进程挂起,在完成函数中唤醒挂起的进程。

至此整个驱动程序就设计完成了,图2为USB Host 与 USB Device 通信测试效果。

4 结束语

USB Device 为众多电子产品提供了一个与PC信息交互的更好的方案。本文通过对USB协议介绍,以及对Linux下USB驱动程序进行分析,在此基础上实现了USB Device驱动程序进行设计。实践表明该设计是可行的。

参考文献:

[1] 冯国进.嵌入式Linux驱动程序设计从入门到精通[M]北京:清华大学出版社,2008.

[2] 薛园园.USB应用开发技术大全[M].北京:人民邮电出版社,2007.

[3] 刘少峰,韦克平.USB软件系统的开发[J].计算机应用研究,2002,19(30).

[4] 于明,范书瑞,曾祥烨.ARM9嵌人式系统设计与开发教程[M].北京:电子工业出版社,2006.

篇4

首先找到我们电脑上的此电脑或者计算机,鼠标右击弹出菜单选择管理。

进入管理的页面之后我们找到设备管理器。

在设备管理器下我们找到一个手机驱动的标识,如果这里安装过了我们只需要自动更新一下即可,

如果没有安装的话我们使用数据线连接电脑查看我们的磁盘有没有手机磁盘。

都没有的话我们需要找到手机品牌官网,输入自己的手机型号。

篇5

关键词: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 */

篇6

引言

近年来电力行业为了快速部署变电站,采用了建造整体变电所的方法:在生产基地将变电站的内部设备安装、调试完成,只留下与外界的接口,整体运到变电站所在地后进行安装和简单调试即可投入运行。其内部设备通过CAN总线进行通信,系统原有的监控软件基于DOS系统,维护调试比较困难,因此想要寻求更方便、友好的系统支持。经过比较,嵌入式操作系统市场上风头正劲的Windows CE .NET成为最终选择。微软的最新产品Windows CE.NET提供了端对端的开发、调试手段,可以不拆卸设备的情况下通过Telnet登录到WindowsCE上进行调试和维护,其系统本身为嵌入式市场进行重新设计,包括创建一个基于WindowsCE的定制设备所需的一切。这样就需要将原来DOS下的程序移植到WindowsCE.NET下,但是各个硬件厂商目前还没有提供CAN通信卡在Windows CE.NET下的驱动,所以开发Windows CE.NET下的CAN卡驱动成为项目推行中的关键一环。

本文主要针对研华的双口CAN卡PCM3680进行分析,介绍在WindowsCE.ENT系统下进行底层设备驱动开发的方法并提供CAN通信的实例。

1 CAN总线通信协议及CAN通信卡介绍

CAN总线是德国Bosch公司20世纪80年代初为解决现代汽车中众多的控制与测试仪器之间的数据交换而开的一种串行数据通信协议。它是一种多主总线,废除了传统的站地址编码,而代之以对通信数据块进行编码。这种方法使网络内节点个数在理论上不受限制,扩展格式中的29位的标识码便可以定义2 29个不同的数据块。

在本项目中使用的是研华的PCM3680,这是一块嵌入式PC104的双口CAN总线通信卡;CAN控制器采用Philips的独立CAN控制器SJA1000芯片;CAN收发器采用Philips的P82C250,可以同时操作两个CAN网络,提供高达1Mb/s的传输速度。PCM3680支持很宽的中断范围:中断3、4、5、6、7、9、10、11、12、15,同时1000V的光电隔离提供系统高可靠性。在CAN卡通信中,要用到CAN控制器中的很多寄存器,各个寄存器的含义和作用可以参考控制芯片的说明书。图1列出驱动程序设计中用到最主要的寄存器结构。

2 CAN卡驱动底层函数设计

本方案设计CAN驱动是放在Windows CE操作系统的内核下层,位于OEM adaptation layer(OAL)层的一个真正的驱动,而不是在主程序中的串口操作。在Windows CE的设备管理器可以看到CAN1和CAN2两个端口,并且可以查看其工作的正常与否和对其进行配置。如:中断号和I/O地址。

2.1 CAN卡寄存器读写函数

CAN卡的通信是通过操作CAN卡上的CAN控制器进行的。在CAN控制器中有很多寄存器,如控制寄存器、命令寄存器、状态寄存器、中断寄存器等,通过读写这些寄存器中的命令状态字可以检测和控制CAN卡的行为。在Windows CE.NET下,通过调用DOK中的API函数HalTranslateBusAddress,将CAN卡分配的物理地址映射为逻辑地址。这样各个寄存器对应的就是CAN卡基地址的偏移地址,因此,对寄存器的读写就转化为对内存地址的读写。下面是CAN卡寄存器的读写函数:

*在偏移量为off的地址读取一个字节的数据inline BYTE CANR(LPCAN_HW_OPEN_INFO hCan,DWORD off)

{

return hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr[off];

*将一个字节数据写到偏移量为off的地址中inline VOID CANW(LPCAN_HW_OPEN_INFO hCan,DWORD off,BYTE val)

{

hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr[off]=val;

}

参数LPCAN_HW_OPEN_INFO定义的是CAN卡的数据结构,其中成员lpMappeBaseAddr[0]表示的是映射后基地址,lpMappedBaseAddr[1]就是基地址+1的地址,对应CAN卡的寄存器是命令寄存器。通过上述两个函数可操作CAN卡上的所有寄存器。

2.2 CAN卡初始化

CAN卡的控制器比较复杂,在通信前必须确认硬件信息正确性、初始化各寄存器。初始化函数的基本流程如图3所示。

第一步,检查端口号和硬件信息的正确性,主要是CAN卡中断号是否有效。

第二卡,设置CAN卡默认参数:

CanCardConfigInfo CAN_DEFAULT_SETTING=

{0X00,0XFF,0X03,0X1C};/*设置默认波特率为125Kbps*/

DWORD dwThreadID =0;

PHYSICAL_ADDRESS phyAddr={hwInfo->dwIOBaseAddr *16,0 };

第三卡,用WinCE API函数LocalAlloc为CAN卡驱动中用到的数据结构分配缓冲区;通过HalTranslateBusAddress和MmMapIoSpace函数映射I/O地址,提供直接访问设备的虚拟地址:

if(!HalTranslateBusAddress(Isa,0,phyAddr,0,&phyAddr))

goto _ExitInit;

hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr=

(LPBYTE)MmMapIoSpace(phyAddr,CANCARDADDRLEN,FALSE);

if(!hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr)

goto _ExitInit;

如果分配内存或映射逻辑地址失败,则退出初始化程序,CAN卡初始化失败。

第四步,初始化读写属性、共享模式、读超时时间和第二个CAN口的基地址。

第五步,创建CAN卡事件和数据接收事件:hCan->lpCanHWInfo->hCanEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

hCan->lpCanHWInfo->hRecvMsgEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

第六步,初始化中断,如果CAN卡有复位请求就退出初始化程序。设置好中断后启动数据接收线程,设置线程优先级继续线程处理;最后配置CAN卡参数,进入正常运行状态。

2.3 CAN卡信息发送

CAN卡的信息发送分为两个步骤。在对CAN卡基本信息进行检查后,首先设置发送缓冲的ID号。CAN标准模式的ID号为11位,偏移地址10中存放的是ID号的高8位,偏移地址11的高3位存放的是ID号的低3位,剩下5位分别是RTR位(远程传送请求位)和数据长度。通过CANW函数将处理后的数据写入到相应的偏移地址,设置完相应的地址数据后,通过循环将偏移地址12~19的数据采集回来存到数组中。然后,设置CAN卡的传输请求为允许并不断侦测状态寄存器的变化,当传输缓冲满标志或传输结束标志为1时通出程序,完成一次数据采集。传输缓冲区的寄存器如表1所列。

表1

ID号10ID.10ID.9ID.8ID.7ID.6ID.5ID.4ID.3RTR,数据长度码11ID.2ID.1ID.0RTRDLC.3DLC.2DLC.1DLC.0数据1~812~19数据数据数据数据数据数据数据数据表2

ID号20ID.10ID.9ID.8ID.7ID.6ID.5ID.4ID.3RTR,数据长度码21ID.2ID.1ID.0RTRDLC.3DLC.2DLC.1DLC.0数据1~822~29数据数据数据数据数据数据数据数据CAN消息发送函数的实现如下:

BOOL CAN_SendMessage(LPCAN_HW_OPEN_INFO hCan,LPCanCardMessageBuflpMsg)

{

BOOL bSuc=FALSE;

ASSERT(hCan && lpMsg && lpMsg->dwMessageLen <=8); /*防错处理*/

if(0= =(hCan->dwAccessCode & GENERIC_WRITE))

return FALSE;

:: EnterCriticalSection(&hCan->lpCanHWInfo->

TransmitCritSec); /*进入临界区*/

BYTE byV=static_cast<BYTE>(1pMsg->dwMsgID>>3);

CANW(hCan,10,byV); /*设置ID值高8位*/

byV=static_cast<BYTE>=((lpMsg->dwMsgID & 7)<<5);

if(lpMsg->bRTR) byV|=0x10;

byV+=static_cast<BYTE>(lpMsg->dwMessageLen);

CANW(hCan,11,byV);/*设置ID值低3位、RTR及数据长度*/

for(UINT i=0;<lpMsg->dwMessageLen;++i)

{

CANW(hCan,12+i,lpMsg->byMsg[i]);

} /*采集数据*/

CANW(hCan,1,1);/*重置传输请求*/

while(TRUE)

{byV=CANR(hCan,2);

if(byV & 0X40) /*传输缓冲区满,退出*/

{break;}

if(byV & 0X8){ /*传输结束,正确返回退出*/

bSuc = TRUE;

break;}

}

::LeaveCriticalSection(&hCan->lpCanHWInfo->TransmitCritSec); /*离开临界区*/

return bSuc;

}

2.4 CAN卡信息接收

CAN卡的信息接收是发送的逆过程,当接收缓冲区标志为1时,表示缓冲区已满可以接收数据,将数据接收到数组后释放接收缓冲区,然后对接收到的数据进行分解并存储到CAN卡信息缓冲区的结构体。接收缓冲区的寄存器结构如表2所列。

CAN消息接收函数的实现如下:

BOOL CAN_RecvRecvMessage(LPCAN_HW_OPEN_INFO

HCan,OUT LPCanCardMessageBuflpMsg)

{……

if(CANR(hCan,2)&1){ /*判断接收缓冲区是否已满*/

for(UINT i=0;i<10;++i)

recvBuf[i]=CANR(hCan,20+i);/*将数据暂存到临时缓冲区*/

CANW(hCan,1,4); /*释放接收缓冲区*/

LpMsg->dwMsgID=recvBuf[0]<<3; /*取出ID的高8位*/

BYTE byV =recvBuf[1];

LpMsg->dwMsgID+=byV >>5;/*取出ID低3位,然后和高8位合并*/

LpMsg->bRTR =byV &0x10?TRUE:/*返回RTR状态*/

LpMsg->dwMessageLen = byV &0XF; /*返回数据长度*/

……

}

else

{++hCan->lpCanHWInfo->dwErrorMsgCount;}/*没有收到数据,错误计数加1*/

::LeaveCriticalSection(&hCan->lpCanHWInfo->

ReceiveCritSec); /*离开临界区*/

Return bSuc;

}

2.5 CAN卡事件处理

CAN卡事件处理函数是CAN卡驱动程序中很重要的部分。驱动设计要求具有消息通知的功能,当事件发生时及时捕获事件并进行消息处理。

下面是事件处理函数的实现:

staric DWORD WINAPI CAN_EventHanle(LPVOID lpParam)

{

ASSERT(lpParam);

LPCAN_HW_OPEN_INFO hCan=(LPCAN_HW_OPEN_INFO)lpParam;

CanCardMessageBuf bufMsg;

while(TEUE)

{ /*循环等待CAN卡消息产生,然后进行处理*/

::WaitForSingleObject(hCan->lpCanHWInfo->hCanEvent,0XFFFFFFFF);

if(hCan->lpCanHWInfo->bKillCanThread) break; /*若CAN线程已关闭则中断*/

if(CAN_RecvMessage(hCan,&hufMsg)){ /*正确接收数据后*/

CAN_RecvBufPush(hCan,&bufMsg);} /*将数据压入缓冲*/

BYTE byV=CANR(hCan,3); /*将3号寄存器读出然后立即写入*/

CANW(hCan,3,byV);/*能够获取每次中断*/

InterruptDone(hCan->lpCanHWInfo->lpCanObj->dwSysIrqt);

} /*本次中断结束,等待下次中断*/

return 0;

}

2.6 其它函数

为了提供更多的功能和更方便地使用CAN卡进行通信,在CAN卡驱动程序中还设计了一些函数如CAN_Config用CAN卡信息配置、CAN_RecvBufPop用于处理接收缓冲区、CAN_Reset用于复位CAN卡、CheckHWInfo用于硬件信息检查等。这些函数提供了对CAN通信卡的设置、检查等功能,在这里不再详述了。

3 CAN卡驱动封装设计

CAN卡底层驱动函数虽然功能完整,但是对于用户使用比较复杂并且一般用户不需要了解底层实现的机制。为了便于使用,最后对CAN卡的驱动进行了封装,提供CanOpenFile、CanSendMsg等五个函数用于CAN总线的通信,以动态连接库(DLL)的形式提供给用户调用。封装函数及功能如下:

*CanOpenFile;初始化并打开CAN卡的一个端口。

*CanCloseFile;关闭由CanOpenFile打开的CAN卡端口。

*CanRecvMsg;接收CAN卡数据,打开CAN卡时必须具有GENERIC_READ权限。

*CanSendMsg;通过CAN卡发送数据。打开CAN卡时必须具有GENERIC_WRITE权限。

*CanIOControl;设置或获取CAN卡I/O参数支持的I/O控制包括:IOCTL_CAN_CONFIG,IOCTL_CAN_RESET,IOCTL_CAN_TIMEOUT,IOCTL_CAN_SENDREADY,IOCTL_CAN_RECVREADY。

下面是CanSendMsg函数实现的代码:

BOOL CanSendMSg(

HANDLE hCan,

LPCanCardMessageBuflpMsg)

{

if(!hCan||INVALID_HANDLE_VALUE= =hCan||

!lpMsg||lpMsg->dwMessageLen>8)return FALSE;

return CAN_SendMessage(LPCAN_HW_OPEN_INFO)

hCan,lpMsg);

该函数就是通过封装CAN卡的底层驱动函数SendMessage来实现的,这样将功能集中的五个函数更方便了用户使用。

结语

篇7

通信卡的硬件设计

1 通信卡的主要特点

通信卡的硬件设计目的是智能化通信:在卡上具有4个DMA通道及相应的数据缓冲存储区。在数据的接收过程中,通信卡会自动接收帧数据,判别帧长度,在帧尾将接收到的帧数据提交系统。在发送数据过程中,系统只须把发送的数据提交给本卡,具体的发送过程由该卡自行完成,不因多路通信而使主机增加开销。该卡有内/外时钟两种工作方式,近距离可省去调制解调器,波特率为600b/s-64Kb/s,提供2路符合RS-232/CCITT V.24和RS-422A标准的接口信号。

2 通信卡的电路设计

通信卡组成框图如图1所示。其主要由DMA控制器、总线竞争仲裁器、串行通信控制器、数据缓冲存储器SRAM、存储器I/O映像和物理地址产生器、总线接口及防护、波特率产生器、接口电路等单元电路组成。

DMA控制器作为通信卡的主设备,控制卡上的数据接收和发送(来自通信控制器和CPU),并负责仲裁优先权。由于在进行数据通信时,允许主机CPU访问本卡SRAM,且主机对其中某一路发控制命令时,不影响其余三路通信,这样将会使主机CPU与本卡DMA竞争本卡总线控制权。而总线上没有给出主机CPU指令排队状态序列,故不能直接设计多主竞争,因而在本卡总线上用门阵列设计了一个状态机,不断地监视总线争用情况,完成本卡总线竞争、仲裁功能。完成HDLC规程的串行通信的器件是INTEL 8274多规程串行控制器,它能完成2个独立的串行接收/发送全双工通信。为了使4个信道在一帧数据的发送或接收过程中,主机不干预,故将发送的一帧数据在发送开始前由CPU用批命令放入卡上的SRAM中,同样,在接收过程中,卡上DMA将接收到的数据放入SRAM中,等一帧接收完成后,再用批命令取出,放入系统存储器中。卡上SRAM不占用主机内存地址,采用I/O映像,该适配器插入主机之后,主机通过系统I/O地址对其访问,这由地址产生器完成。总线接口包括数据收发器,数据开关电路,读、写及中断等控制电路,地址译码等。波特率产生器提供了一个可编程的时钟信号发生器,用户可自行设置通信速率,供工作于内时钟方式时使用。接口电路提供符合RS-232/C CITT V.24和RS-422A标准的接口信号。

3 通信流程设计

如果要发送一帧数据,CPU用批命令将数据放到本卡SRAM中,然后设置相应的发送DMA通道。DMA通道是非自动重装方式,启动8274控制器发送,然后CPU就不需要管理,由卡上硬件自动发送。

如果需要接收数据,启动接收通道。接收通路自动搜索输入信号,搜索到数据帧时,由卡上DMA控制器来管理,将接收的数据放人本卡SRAM中,并向CPU请求中断,读出数据。

4 总线竞争设计

由于同时可进行四路通信,且CPU可随时对某一路发控制命令或访问卡上SRAM存储器,就将出现CPU与本卡主设备DMA争用本卡总线的状况。由于ISA总线没能给出CPU指令排队状态序列,这给总线仲裁带来了困难,而本卡的总线竞争、仲裁是由可编程逻辑器件设计的状态机来完成的。状态机使用一个4MHz信号作为时钟,共设3种状态:

①CPU控制状态。

②DMA控制状态。

③空闲状态,CPU及DMA均未能得到控制权。

当状态机检测到无CPU及DMA申请总线使用权时,就进入空闲状态,而一旦CPU或DMA请求总线,状态机立即将总线使用权交给CPU或DMA。如果正在CPU控制状态期间,DMA申请总线使用权,状态机仍然判定CPU控制总线,让DMA处于等待,直到检测CPU指令完成,状态机才转为DMA控制状态。如果在DMA控制状态时,CPU申请总线使用权,状态机仍然判定DMA控制总线,让CPU处于等待,直至DMA字节传送完,状态机转为CPU控制状态。CPU及DMA对总线的使用权是单个指令或字节传送,不设置总线封锁,因而CPU、DMA可频繁交换使用权,不会出现等待时间过长的现象。

通信卡的驱动程序设计

1 设备驱动程序的I/O模型

通信卡的驱动程序是利用Windows XP的DDK软件开发的标准的核心态设备驱动程序。它使用统一的“文件”形式,用户可以通过代表通信卡设备的文件名,在WIN32子系统中用文件操作函数来访问。该设备驱动和程序可以根据用户的需要,设置为自动加载,或手动加载,也可以动态的加载该驱动程序。通信卡的驱动程序设计成为支持同步I/O模型,也可以为异步I/O模型。

2 发送数据I/O例程设计

在用户态提交发送任务到核心态,由I/O管理程序负责调用驱动程序,驱动程序发送IRP交给硬件,假若当前发送器不忙,则具体的发送操作全部由发送器自行完成,而驱动程序则返回已经一个本帧可以发送的标志。具体的发送完成结果则可以在发送任务完成后查询得到。可是,如果程序向当前设备发送器提交发送任务时,该发送器正在处理上一帧,那么则有两种方法处理。

①立即方式:立即返回一个错误,当前设备忙,不能发送。

②阻塞方式:I/O管理器程序会调度相应的异步处理例程,将当前的发送任务放进任务队列中,返回一个标志:I/O挂起,当前设备忙,发送任务提交任务队列。驱动程序会在发送器空闲时,提交任务队列中的发送任务给发送器。完成发送任务后,将相关文件句柄设为有信号状态,通知本次发送任务完成。

3 接收数据I/O例程

接收数据例程采用客户/服务器的模式设计。由于用户的接收请求和硬件的接收并不是同步的,所以在设计中,为避免丢失数据,考虑创造一个专门的接收线程。这样,同步用户请求、接收线程、硬件层之间的通信就必须仔细地设计。图2示意了用户态接收请求、接收线程以及硬件层之间的通信同步。

①硬件层与接收线程之间通信

硬件层与接收线程之间通信的同步是通过同步事件对象来实现的。同步事件对象通常处于无信号状态,只有当成功地接收到一帧时,才将该事件置为有信号状态。接收线长久等待同步事件对象,在没有收到数据时,因同步事件对象处于无信号状态而阻塞。当硬件检测到数据时,实时中断服务程序负责将同步事件对象置为有信号状态,接收线程就会释放阻塞。将通信卡SRAM上的接收数据读进接收线程缓冲区队列,然后将同步事件对象置为无信号状态,接收线程再次阻塞,等待接收下一帧数据。

②用户层和接收线程之间的通信

当用户提交接收任务时,由驱动程序的调度程序读取接收线程的缓冲区队列,并将标志置为“空”,同时将缓冲队列事件置为无信号状态,并返回,如果缓冲区是空,则

・立即方式:立即返回无数据。

・阻塞方式:阻塞直到有数据队列进入。接收队列的每个缓冲区都对应一个通知事件,如果接收线程将SRAM中的数据读进队列,就将相应的通知事件置为有信号状态,用户请求就等待该通知事件,只要有数据在队列中,就读取返回,否则被阻塞。

4 硬中断服务程序设计

通信卡在全双工的通信中具有实时性,而且在较高的波特率,硬中断非常多。为了防止高优先级中断过多地抢占CPU时间,设计中采用了实时中断服务程序和延迟过程调用的方法。

在Windows XP系统中,每个内核函数和过程都运行于特定的优先级。较高优先级的函数或事件可以抢占较低优先级,反之则不然。实时中断服务程序ISR运行于DIRQL级,具有较高的优先级,它只能被更高级的硬中断所抢占,不会对同级或较低优先级的硬中断的响应。所以,在实时中断服务程序中,只做尽量少的必须工作,即读出中断向量,而将大量的数据传送及处理等工作交给延迟过程DPC去完成。因为DPC过程运行于DISPATCH_LEVEL级,是相对较低的优先级,它可以被任何级的硬中断所抢占。这样,既保证了硬中断的及时响应,又提高了程序的性能。

5 驱动程序人口例程

Windows XP为每个核心态的驱动程序提供了一个默认的标准入口点DriverEntry()。设计中,考虑到该例程运行于PASSIVE_LEVE级,系统只运行该例程一次就抛弃了,所以在驱动程序中用到的重要数据、对象等都不能保存在DriverEntry()例程中,必须在初始化过程中分配一块NoPaged内存来保存。通信卡的驱动程序的DriverEntry()例程主要完成如下功能。

读取Registry的硬件配置信息,声明I/O地址、中断等资源;创建代表通信卡的设备名MPSC,该名字对WIN32子系统是可见的;设置调度例程入口点;分配一块NoPaged的内存,存储重要信息;连接硬中断,设置中断服务程序,初始化线程、事件、信号灯、DPC等内核对象,返回状态STATUS_SUCCESS。

如果在以上过程中遇到错误,则需要做以下工作:断开硬中断;释放硬件资源;将相关的错误信息打包,并记录;返回错误信息。

6 设计驱动程序中需要注意的问题

由于通信卡在应用中具有一定的实时性,为了克服中断的不确定性。提高系统的性能,开发了Windows XP系统所有驱动程序中最难的异步驱动程序。在系统的内核开发,异步模型I/O操作中,内核对象的同步十分复杂,细微的差错都会导致系统彻底崩溃。在设计驱动程序中需要注意以下问题。

・在程序中用到的内核对象:事件、信号灯、线程以及连锁等,都必须将其存储在Nopaged内存中,否则,会造成系统崩溃。

篇8

关键词:嵌入式系统;linux;驱动程序

引言

Linux是一个遵循POSIX标准的免费操作系统。具有BSD和SYSV的扩展特性。与其他操作系统相比,嵌入式Linux系统以其可应用于多种硬件平台、内核高效稳定、源码开放、软件丰富、网络通信和文件管理机制完善等优良特性而正被作为研究热点,越来越多的研究人员采用Linux平台来开发自己的产品。Linux设备驱动程序在Linux内核源代码中占有很大比例,从2.0、2.2到2.4版本的内核,源代码的长度日益增加,其实主要是设备驱动程序在增加。

设备驱动程序的编写

设备驱动程序是linux内核的一部分,是操作系统内核和机器硬件之间的接口,它由一组函数和一些私有数据组成,是连接应用程序与具体硬件的桥梁。Linux的一个基本特点是它对硬件设备的管理抽象化,系统中的每一个设备都用一个特殊的文件来表示。所有的硬件设备都像普通的文件一样看待,使用与操作系统相同的标准系统来进行打开、读写和关闭。

在Linux操作系统下有3类主要的设备文件类型:块设备、字符设备、网络设备。字符设备是指存取时没有缓存的设备。可像文件一样访问字符设备,字符设备驱动程序负责实现这些行为。系统的控制台和并口就是字符设备的例子,它们可以很好地用“流”来描述。块设备是文件系统的宿主,如磁盘。Linux允许像字符设备那样读取块设备――允许一次传输任意数目的字节。结果是,字符设备和块设备读取数方式一致。而网络设备不同于字符设备和块设备,它面向的上一层不是文件系统而是网络协议层,是通过BSD套接口访问数据。与设备相对应的是三类设备驱动程序,字符设备驱动程序、块设备驱动程序、网络设备驱动程序。

字符设备驱动程序、块设备驱动程序与网络设备驱动程序的结构体是不同的。

在linux源代码linux/include/linux/fs.h中定义了字符设备和块设备驱动程序中必须使用的file_operations结构,每个设备驱动都实现这个接口所定义的部分或全部函数。随着内核的不断升级,file_operations结构也越来越大,不同的版本的内核会稍有不同。

应用程序只有通过对设备文件的open、release、read、write、ioctl等才能访问字符设备和块设备。用户自己定义好file_operations结构后,编写出设备实际所需要的各操作函数,对于不需要的操作函数用NULL初始化,这些操作函数将被注册到内核,当应用程序对设备相应的设备文件进行文件操作时,内核会找到相应的操作函数,并进行调用。如果操作函数使用NULL,操作函数就进行默认处理。

对于字符设备而言,llseek(),read(),write(),ioctl(),open(),release()这些函数是不可缺的;对十块设备,open(),release(),ioctl(),check_media_change(),revalidate()是不可缺少的。

网络设备结构体net_device定义在include\linuxhletdevice.h里,如下所示:

定义好net_device结构体后,根据实际情况编写操作函数,其中hard_start_xmit()函数是用来发送数据的,set mac address()是进行网络参数设置的。

当linux初始化时将调用初始化函数intdevice_init(),该函数包括以下内容:

注册所用设备。linux用设备号来标识字符设备和块设备。设备号分为主设备号和从设备号,最终形成设备接点。设备节点在访问字符设备和块设备的设备驱动程序时将使用。通常主设备号标识设备对应的驱动程序,大多数设备是“一个主设备号对应一个驱动程序”,如:虚拟控制台和串口终端由驱动程序4管理。次设备号由内核使用,用于确定设备文件所指的设备。字符设备和块设备注册时必须先定义好设备号。

字符设备注册函数如下:

int register_chrdev(unsigned int major,constchar*name,struct file_oprations*fops);其中major是主设备号。

由于对网络设备驱动程序的访问不需要设备节点,它的注册函数如下:

int register_netdev(struct net_device*dev)

注册设备所用的中断。中断在现代计算机结构中有重要的地位,操作系统必须提供程序响应中断的能力。一般是把一个中断处理程序注册到系统中去。操作系统在硬件中断发生后调用驱动程序的处理程序。

注册中断所用的函数如下:其中,irq是中断向量;handler是中断处理函数;flags是中断处理中的掩码;devices是设备名;dev_id是在中断共享使用的id。

当linux不使用该设备时,就要调用清除函

编写服务子程序

服务于I/O请求的子程序,又称为驱动程序的上半部分。调用这部分是由于系统调用的结果。这部分程序在执行的时候,系统仍认为是和进行调用的进程属于同一个进程,只是用户态变成了核心态,具有进行此系统调用的用户程序的运行环境,因此可以在其中调用sleep等与进程运行环境有关的函数。

中断服务子程序,又称为驱动程序的下半部分。在Linux系统中,并不是直接从中断向量表中调用设备驱动程序的中断服务子程序,而是由Linux系统来接收硬件中断,再由系统调用中断服务子程序。中断可以产生在任何一个进程运行的时候,因此在中断服务程序被调用的时候,不能依赖于任何进程的状态,也就不能调用任何与进程运行环境相关的函数。因为设备驱动程序一般支持同一类型的若干设备,所以一般在系统调用中断服务程序的时候,都带有一个或多个参数,以唯一标识请求服务的设备。

设备驱动程序的使用

直接将驱动程序编译进linux内核

将设备驱动程序复制到linux/drivers相关的子目录下,比如字符设备驱动程序就放在linux/drivers/char下。

修改linux/drivers相关的子目录的Makefile,

如obj-$(config_dev_driver)+=dev_driver.o,这样在编译内核时将会编译dev_driver.c,生成dev_driver.o.

对内核进行重新编译时,进行相关的配置,比如要使用AT91RM9200的UART,就要如下配置:

Character devices->Serial drivers.>AT91RM9200 serial port suppot

将驱动程序编译成驱动模块

在设备驱动程序中要有两个重要函数:

module_init(dev-init),module_exit(dev_exit)

利用相应的交叉编译器以及编译命令将驱动程序dev_driver.c编译成dev_driver.o这样的动态驱动模块。利用insmod命令给系统安装驱动模块,如果在/dev目录下没有相应的设备文件,就可以使用mknod创建一个设备文件。利用rmmod命令卸载驱动模块,设备文件的删除可以用rm命令。

篇9

A/D转换是单片机数据采集系统的重要组成部分,实时内核下A/D驱动程序的实现过程主取决于A/D转换器的转换时间。本文首先比较和分析μC/OS-II下A/D采样数据的三种方法;其次介绍C8051F015单片机A/D模数转换器配置及特点;最后,在μC/OS-II内核移植到8位单片机C8051F015的基础上,介绍编写A/D驱动程序的一般思想和方法。

1 μC/OS-II实时内核下的A/D读方法

实时内核下,驱动程序采用什么方法读取A/D采样数据是首先考虑的问题。许多因素将影响读取A/D,如A/D的转换时间、模拟值的转换频率、输入通道数等,但最主要的取决于A/D的转换时间。典型的A/D转换典型的A/D转换电路由模拟多路复用器(MUX)、放大器和模数转换器(ADC)三部分组成。下面描述读取A/D的三种方法。

    图1所示的是第1种读取方法。假设A/D转换器的转换时间较慢(5ms以上)。应用程序调用图1所示的驱动程序,并传递要读取的通道。驱动程序通过MUX选择要读取的模拟通道(①)开始读。有,延时几μs以便使信号通过MUX传递,并之稳定下来。接着,ADC被触发开始转换(②)。然后驱动程序延时一段时间以完成转换(③_。延时时间必须比ADC转换时间长。最后驱动程序读取ADC转换结果(④)。并将转换结果返回到应用程序(⑤)。

图2所示的是第2种读取方法。当模拟转换完成后,ADC产生的个中断信号。若ADC转换完成,ISR给信号量发一个信号(⑤),通知驱动程序,ADC已经完成转换。如果ADC在规定的时限内没有完成转换。信号量超过(③),则驱动程序不再等待下去。驱动程序和中断服务子程序(ISR)的伪代码如下:

ADRd(ChannelNumber)

{

选择要读取的模拟输入通道;

等待AMUX输出稳定;

启动ADC转换;

等待来自ADC转换结束中断产生的信号量;

if(超时){

*eer=信号错误;

return;

}else{

读取ADC转换结果并将其返回到应用程序;

}

}

    ADCoversion Complete ISR {

保存全部CPU寄存器; /*将CPU的PSW、ACC、B、DPL、DPH及Rn入栈*/

通知内核进入ISR(调用OSIntEnter()或OSIntNesting直接加1);

发送ADC转换完成信号; /*利用μC/OS-II内核的OSSemPost()*/

通知内核退出ISR(调用OSIntExit());

恢复所有CPU寄存器;/*将CPU的PSW、ACC、B、DPL、DPH及Rn出栈*/

执行中断返回指令(即RETI);

}

在这种方法里,要求ISR执行时间与调用等待信号的时间之和为A/D转换时间。

如果A/D转换时间小于处理中断时间与等待信号所需的时间之和,则可以用第三种方法。如图3所示,前两步(①②同以上两种方法)结束后,驱动程序接着在一个软件循环中等待(③)ADC直到完成转换。在循环等待时,驱动程序检测ADC的状态(BUSY)信号。如果等待时间超过设定的定时值(软件定时),则结束等待循环(循环等超时)。如果在循环等待中,检测到ADC发出转换结束的信号(BUSY)时,驱动程序读取ADC转换结果(④)并将结果返回到应用程序(⑤)。驱动程序伪代码如下:

ADRd(ChannelNumber){

选择要读取的模拟输入通道;

等待AMUX输出稳定;

启动ADC转换;

启动超时定时器;

while(ADC Busy & Counter 0);/*循环检测*/

if(Counter==0){

*err=信号错误;

return;

}else{

读取ADC转换结果并将其返回到应用程序;

}

}

A、D转换速度快,这种驱动程序的实现是最好的。

2 C8051F015单片机的A/D转换器

2.1 C8051C015单片机

C8051C015的美国Cygnal公司新推出的高速SOC型C8051Fxxx系列单片机。它的内核CIP-51与MCS-51的指令集完全兼容,CIP-51的系统时钟频率在0~25MHz。C8051Fxxx系列单片机采用流水线结构,与标准的8051相比,指令执行速度有很大的提高。CIP-51内核的指令执行时间是以系统时钟为单位,70%的指令执行时间为1个或2个系统时钟周期。C8051F015具有32KB的内存、2304B的RAM(片内256B、片外2048B)。CIP-51内核具有标准8052的所有外设部件,片上还集成有9通道10位A/D转换接口电路、SMBus/I2C、SPI串行接口。

2.2 C8051F015的A/D转换电路

C8051F015的A/D转换电路包括1个9通道可配置模拟多路开关AMUX(8路用于外部模拟输入、1路用于芯片环境温度的测量)、1个可编程增益放大器PGA和1个100ksps 10位分辨率的逐次逼近型ADC。A/D中还集成了跟踪保持电路和可编程窗口检测器。

ADC有4种启动方式:软件命令、定时器2溢出、定时器3溢出及外部信号输入。寄存器ADC0CN是配置启动和跟踪方式的控制寄存器。每次转换结束时,ADC0CH的ADBUSY(忙标志)的下降沿触发中断,也可用软件查询这个状态位。

2.3 ADC转换速度

C8051Fxxx系列单片机中ADC的速率都是可编程设置的。表1给出了所需最小分频系数与SYSCLK(系统时钟)的关系(ADC0CF为ADC配置寄存器)。

表1 ADC时钟分频系数与SYSCLK频率的关系

SYSCLK频率/MHzADC时钟分频系数ADC0CF的ADCSC2~1时钟频率<2.510002.5~520015~10401010~208(复位值)011时钟频率>20161xx在C8051F015单片机中,ADC的转换时钟周期至少在400ns,转换时钟应不大于2MHz。一般在启动ADC之前都要处于跟踪方式,而ADC一次转换完成要用16个系统时钟。另外,在转换之前还要加上3个系统时钟的跟踪/保持捕获时间,所以完成一次转换需19个ADC转换时钟(9.5μs)。

图1中的方法简单,转换时间在ms级以上,一般用于变化慢的模拟输入信号,不适用于C8051F015。图2中的方法,为了减少μC/OS-II内核调用ISR所用时间,ISR一般都用于汇编语言编写。从程序1中ISR伪代码可以看出,尽管ISR用汇编语言编写。代码效率高,但μC/OS-II调用ISR的时间与调用等待信号时间之和大于A/D的转换时间,所以CPU用于ISR和循环检测的开销大。

图3所示的方法显然适合于C8051F015单片机,其优点是:可以获得快速的转换时间;不需要增加一个复杂的ISR;转换时信号改变时间更短;CPU的开销小;循环检测程序可被中断,为中断信号服务。

图4 A/D驱动程序模块流程图

3 A/D驱动程序的编写

外设驱动程序是实时内核和硬件之间的接口,是连接底层硬件和内核的纽带。编写驱动程序模块应满足以下主要功能:①对设备初始化;②把数据从内核传送到硬件从硬件读取数据;③读取应用程序传送给设备的数据和回送应用程序请求的数据;④监测和处理设备出现的异常。

A/D转换电路作为一个模拟输入模块,μC/OS-II内核应把它作为一个独立的任务(以下称为ADTask())来调用。A/D驱动程序模块流程如图4所示。ADInit()初始化所有的模拟输入通道、硬件ADC以及应用程序调用A/D模块的参量,并且ADInit()创建任务ADTask()。ADTb1[]是一个模拟输入通道信息、ADC硬件状态等参数配置以及转换结果存储表。ADUpdate()负责读取所有模拟输入通道,访问ADRd()并传递给它一个通道数。ADRd()负责通过多路复用器选择合适的模拟输入,启动并等待ADC转换,以及返回ADC转换结果到ADUpdate()。

在μC/OS-II这时内核下各原型函数、数据结构和常量的定义如下:

INT16S ADRd(INT8U ch);

/*定义如何读取A/D,A/D必须通过AIRd()来驱动*/

void ADUpdate(void);

/*一定时间内更新输入通道*/

void ADInit(void);

/*A/D模块初始化代码,包括初始化所有内部变量(通过ADInit()初始化ADTb[]),初始化硬件A/D(通过ADInitI())及创建任务ADTask()*/

void ADTask (void data);

/*由ADInit()创建,负责更新输入通道(调用ADUpdate ())*/

void ADInitI (void);

/*初始化硬件A/D*/

AD_TaskPrio:设置任务ADTask()的优先级。

AD_TaskStkSize:设置分配给任务ADTask()的堆栈大小。

AD_MaxNummber:AMUX的输入通道数。

AD_TaskDly:设定更新通道的间隔时间。

AD ADTbl[AD_MaxNummber]:AD类型的数组(AD是定义的数据结构)。

4 结论

对于A/D转换器接口电路驱动程序的编写归纳出以下几点:

①在决定采用具体的驱动方案之前,分析接口电路的特点,尤其是了解A/D的转换速度;

②对于转换速度快的A/D转换器,可能出现CPU的处理速度与A/D转换速度不匹配,一般的A/D中不带有FIFO缓冲区,须有内存中开辟缓冲区;

篇10

第一节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)(由网络厂商提供)。多供应者路由选择程序决定适当的供应者,然后借助于供应者,对应用请求到相应的转发程序做出选择。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通信的手段。ndis用一个叫做逻辑网卡的软件对象来描述系统中的每块网卡,而逻辑网卡与windows nt设备对象的通信由i/o子系统来管理,描述网卡的设备对象包括相关的网络信息如名字、网络地址和网卡内存基地址等,它还包含与硬件相关的驱动程序状态数据(捆绑数目,捆绑句柄,包过滤数据库等)。ndis分配一个句柄到miniportinitialize这个上边缘函数的一个结构中,然后miniport网卡驱动程序将在以后提供这个句柄来给ndis调用,这个结构一直被ndis保持,并且对miniport驱动程序不透明。 当miniport网卡驱动程序初始化一块网卡时,它创立自己的内部数据结构来描述网卡,记录需要它管理的与设备相关的状态信息。当miniport网卡驱动程序调用ndismsetatttibutes或ndismsetattributesex两ndis库函数时,它传递一个句柄给这数据结构。这样,当调用miniport驱动程序入口点时,它就传递这个句柄来验证驱动程序所对应的网卡的正确性。这个数据结构为miniport网卡驱动程序所拥有并维护。miniport nic驱动程序还需要维护一组对象,这些对象是系统定义的对象标识符(object idetifier:oid)来标识,以描述驱动程序的性能和当前状态信息。为查询这些信息,上层驱动程序调用ndisrequest向ndis接口库指示oid。oid表示了调用所需的信息类型,如miniport驱动程序所支持的lookahead缓冲区大小等。ndis接到上层驱动程序的查询请求,将oid传递给上边缘函数miniportqueryinformation实现对oid的查询,如果上层驱动程序请求改变状态信息则调用miniportsetinformation实现对oid的设置。典型的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版本信息。ndis接口库包括在ndis.sys中,它是一个核态函数库,有一套抽象的函数,无论协议驱动程序还是nic驱动程序都连接到这个库中,以实现上下层之间的操作。

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

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

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

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

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

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

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

§2.1.1网卡一般硬件参数

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

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

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

cfid: 0x01;

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

是否支持全双工:支持。

对于其它的硬件信息在此inf配置信息文件中可有可无,如若配置,则可在驱动程序的编写时利用这些信息,方便编程,同时有利于其它应用对其参数的确定和使用。网卡驱动程序的安装通常将创建登录表中的四个不同子键:

software registrion键,对应于驱动程序,存在于hkey_local_machinesoftwarecompany productnameversion中。我们的fddi网卡驱动程序所对应的是hkey_local_machinesoftwarenet612yhfddiyhfddi1.0;

网卡的软件登录键,存在于hkey_local_machinesoftwaremicrosoft windows ntnt3.51networkcardsyhfddi1;

驱动程序的服务登录键,存在于hkey_local_machinesystemcurrentcontrolsetservices

网卡的服务登录键,存在于hkey_local_machinesystemcurrentcontrolsetservices

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

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

hkey_local_machinesoftwarenet612yhfddiyhfddi1.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_machinesoftwaremicrosoft

windows ntnt3.51networkcardsyhfddi1;

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

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的启动过程