一场游戏一场梦

在我的歌声里早已没有你

My Links

Blog Stats

留言簿(0)

随笔分类

随笔档案

文章档案

其他blog -.-


搜索

最新评论

阅读排行榜

评论排行榜

2009年10月14日 #

多队列问题的思考,还没有验证。。。



得到一个句柄hDevice后,用IOCTL把句柄bind到一个队列上

IoctlDispacher

Irp得到stack,得到FILE_OBJECT,根据参数(x)把FILE_OBJECT bind到IrpRead[x]

具体用一个LIST_ENTRY记录这个FILE_OBJECT和x

pdx->listBind 类型为LIST_ENTRY

struct _BIND
{
    LIST_ENTRY link;
   PFILE_OBJECT fop;
   ULONG id;
}


ReadFile(hDevice...)

ReadDispacher

Irp得到stack,得到FILE_OBJECT,查询pdx->listBind

发表于 2009-10-14 16:22 fdo 阅读(397) | 评论 (0)编辑 收藏

2009年9月21日 #

DSP/BIOS注意

  1. 协作式多任务
  2. 任务间无需要考虑资源共享的同步问题
  3. 硬件中断和软件中断可以打断任务,需要考虑同步问题,但软硬中断最好不要和任务共享资源
  4. 如果要在软硬中断和任务间共享资源,需要在任务里面关中断(ATM_xxx内部也是关中断的)
  5. 任务切换只发生在TSK_sleep, SEM_pend,等例程调用时。TSK_yeild是显式放弃CPU
  6. 不要while(PIN&0x1)这样查询一脚状态,如果脚出错,该任务就会死循环,其他任务也无法得到CPU时间
  7. 真要查询某个脚状态应该只查询有限次,或许100次。
  8. 尽量使用中断方式,使用mini-driver构架

发表于 2009-09-21 21:00 fdo 阅读(929) | 评论 (2)编辑 收藏

2009年8月12日 #

想办法把数学符号用网页编排一下。。。。

 

意义和符号

举例


+

1+2


-

3-1


*
×
·

2.5×4 实数乘法

2·n 乘法

2n 乘法

(1+i)(2+i) 复数

a×b 向量叉积

a·b 向量点积

AB 矩阵乘法


/
÷

2÷54 实数除法

2/n 除法

映射
f:

f:A→B f(x)=ax+b


xn

y=f(x)=xn +a

对数
log
e
ln
lg

y=logex
y=ln(x)

三角
sin
cos
tan
cot
sec
csc

y=sin2(θ)
sin2(θ)+cos2(θ)=1

导数

y(2)

y=x2+1 ,y´=2x

微分
dy

y=x2+1 ,dy=d(x2+1)=2x·dx

积分

∫sin(x)=-cos(x)+C
abcos(x)=sin(x)| ab

极限
lim

lim n (1+1/n)n =e

求和

i(1,n) ai

求积

i(1,n) ai

圆周率
π

π=3.14

存在

∃x∈N | 2x=5 命题:存在整数x,使得2x=5

存在唯一
∃!

∃!x∈N | 2x=5 命题:存在唯一整数x,使得2x=5

对任意的

∀x∈N | 2x=5 命题:对任意的整数x,使得2x=5

属于

∀x∈N | 2x=5 命题:对任意的整数x,使得2x=5

使得
|

∃x∈N | 2x=5 命题存在整数x,使得2x=5

发表于 2009-08-12 20:03 fdo 阅读(996) | 评论 (0)编辑 收藏

2009年7月22日 #

我要这样看源代码!!!!!!!!!!!!!!!

我很喜欢看源代码,可是众多源文件如何下手?都添加到VS,还是code::block??如果可以打包成CHM或者PDF就好了。。
1.准备一个c2html.exe 这个东西有开源代码http://c2html.sourceforge.net/ down下来
   定制自己喜欢的样式,convert.c里有个 const CODEPART codepart[NUM_DIFF_PARTS] 这是一个表,修改自己想要的样式,比如我喜欢预处理是蓝的就改这一行为:
{check_begin_preprocessor,check_end_preprocessor,{LIGHT_BLUE,         {FALSE, FALSE,  FALSE     }}},

2.编译 当然是> cl main.c convert.c ........ OK得到main.exe..改个名字叫c2html.exe吧。。其实是我不知道cl输出文件命的参数。。第一次编译会有错误,这个错误把所有.c文件的 <c2htm.h>改成“c2htm.h“就O了

3.效果不怎么样啊,主要是字体我不喜欢,于是我就在 convert.c CTRL+F font 结果也没找到和字体,大小相关的东西。。于是跑到c2html.h看看,哦 马上 #define FONT_FACE "Courier New"/*"Monospace"*/ 再一看#define TAB_SIZE 8 马上该成4 重新编译一下,字体变了。TAB也舒服了。字体太大了。怎么办啊,没找到定义,于是想到了<body>标签(嘿嘿,N年前我学过一点HTML)果然发现了 write_header_footer.c里面有,马上 <font size=\"2\" face。。。。这个2是我试出来的,我一开始用10太大了。用5也大,最后试了个2比较喜欢。。

4.c2html.exe 出来了,把刚才看的main.c拖到 c2html.exe。不错,能生成,达到我喜欢的效果了,喜欢的快去定制哦

5.事情告一段落,到底是写个bat做批量处理(bat可以做文件历遍么-.-)还是再弄个exe用API呢。过几天吧,反正最近也不想看源代码.

6.html->chm的东西一大把。不搞

7.为自己玩了一把开源代码。。第一次哦

发表于 2009-07-22 23:19 fdo 阅读(2088) | 评论 (8)编辑 收藏

2009年7月14日 #

关于DSP/BIOS和mini-driver的一些问题

其实ddk文档说的很清楚了。不过我还是要记录一下几个要点,暂时可能又用不到了,我的记忆力是越来越不行了
以前认为凡事只要掌握规律就行,现在发现这太极端。其实有些事不用关心那么多,记住就行,真是越来越懒了。。

1.包驱动
IOM_Packet是GIO,PIO,SIO class driver和mini-driver通讯用的数据结构,通过内部一些成员,class driver和mini-driver之间可以共享一些ram.
2.函数指针表
IOM_Fxn 是一个表,这个表是GIO,PIO,SIO 接口和mini-driver间的一个对应,如GIO_write 会调用mdSubmitChan
3.chan
其实chan到底是什么很难用一句话来描述,chan是自己设计的,根据不同的需要可以设计不同的chan. 在内部一般chan的object的handle通常就是class driver中的handle。这个handle可以是mini-driver MEM_alloc出的,也可以是static的。
4.完成IO
完成IO很简单,就是一个callback.这个calback是class driver提供的。如果不打算开发新的class driver,那么只需要在想要完成的时候callback就行了,一般这个callback可以放在chan的object里。不同的chan可以callback不同的。比如ISR里callback,于是class可以在callack里发出信号,而此时一个block中的class 接口函数会及时地resume.
5.排队
排队机制不是必须的,c64xx_pci.c很好地做出了一种通用的排队机制
6.相关的接口
6.1 CSL chip support library(i2c,cache,edma,irq,......)
6.2 BIOS(sem,mbx,que,tsk,hwi)

忽略了一个IOM。运行中IOM没有一个实体,它只是一个接口规范,定义IOM_Packet Fxn等。

设计中应当将实际的设备,on-chip 或者 off-chip 的抽象成device,而一个device其实只是一个IOM_Fxn 在和class driver通讯。对于同一个设备的不同用法,可以抽象出chan,再某个chan上对应一种操作,一切都取决于实际的用途。

isr的问题。1.event要map到cpu(c64xx是4-15)2.event类型要看对应寄存器,文档写interrupt flag,有的写 interrupt src.大伤脑筋,以后一定要用interrupt flag,有时后flag居然在status register里。src是只要访问就自动清,没什么用。可以在刚进isr的时候判断一下,0就return.

用bios时千万不要isr前加interrupt词,不用bios时一定要加。这个保留词和栈操作有关,具体不研究,反正不乱用。

头文件一个要加。这个鬼编译器没有头文件也可以引用一个函数,即使参数不一样,也不报个错,等待自己的就是崩溃。另外像刚进一个函数参数都对的,进去了就变了的情况也多半是没加头文件。

另外还有一些代码无法调试,无汇编的情况,一般是启用的优化导致。一些static过程,比如只用了一次的static过程,会直接优化到caller内部。在static 过程 源代码无法下断点。真是伤害脑筋啊,因为我以前也不知道,接到一个老的工程他自己也不知道就优化。搞的我很郁闷,其实release就是优化的,为什么debug还搞呢

mdBindDevice时内部可能不能用assert.这个我还不清楚原因。用了也没什么大的影响,就是无法go main。

发表于 2009-07-14 22:03 fdo 阅读(1233) | 评论 (3)编辑 收藏

2009年5月25日 #

arm-linux开发步骤

拿到一块YC2440(s3c2440)的开发板,经过几天的学习,我对arm-linux系统开发步骤有了一些认识。就以开发这个开发板为例,arm-linux开发工作大概分4个部分

1.       硬件(hardware)

2.       引导加载器(bootloader)

3.       内核(kernel)

4.       文件系统(file system)

 

硬件

我并不是硬件工程师,但我知道硬件的设计基本上是从性能,结构,可靠性等方面的需求方面来考虑。比如串口调试很常用,那么硬件就需要设计串口。在比如硬件需要接LCD,就必须提供LCD接口

bootloader

bootloader是什么?

bootloader是一个引导程序,它最主要的功能是加载内核,所谓加载内核就是让内核代码常驻内存,并且得到执行。

 

bootloader因为什么而存在?

每一种CPU都有自己的启动方式

a)       CPU上电后从某个地址开始取指令运行,这样的指令往往是已经固化的,因为RAM刚上电时,里面的内容是没有意义的,很多单片机是这样方式。可以说这根本不是boot

b)      CPU上电后从ROM读代码到RAM,然后跳到RAM里开始执行,这种方式的CPU一般会拷贝固定长度的二进制代码到RAM,因为它不知道有效代码有长,只有一个固定的长度拷贝完成后,CPU才知道拷贝工作完成,以便从RAM执行。这就是boot

c)       方式二只能拷贝固定长度的代码到RAM运行,为了拷贝更多的代码到RAM运行,方式二就做了改进,首先进入RAM的代码不是一个功能固件,而是另一个功能代码的加载器(loader),这就是bootloader

 

armbootloader

arm会拷贝4K长度的代码运行。显然arm不是为4K的固件设计的。拷贝代码到RAM并不需要很多指令,因为ARMRAM的管理需要一个MMU控制器(可以让CPU访问更多的RAM或许)而这个控制器需要配置相关寄存器,所以代码可能要多一点,另外可能还有许多别的功能,所以代码可能会更多。当然都不超过4K时都没问题,但往往还是要过4K的。所以真正arm-linuxbootloader一般有两步骤:

a)       拷贝4K代码到RAM,开始执行

b)      拷贝另一段代码到RAM并初始化一些必须的硬件设置,开始执行

 

u-boot

 

u-boot是一种很流行的bootloader,除了加载内核,它还提供了许多其他功能。基本上u-boot是一个精简的linux,它提供人机交换的,一般现在linux开发都采用串口方式使用u-boot

关于u-boot的说明有很多,我简单说明一下

a)       u-boot可以被打断,通过串口向u-boot输入命令后,u-boot中断,可以执行各种命令,这些命令有专门的手册可以查询。串口其实就是u-boot的一个远程终端。

b)      u-boot可以设置网络,通过tftp服务,u-boot可以下载代码到RAM然后执行,也可以烧写到flash

c)       u-boot之所以有这么多功能是因为里面集成了许多驱动,如果要让u-boot有更多的功能可以在u-boot源代码里添加,如果要用硬件就需要添加驱动。

d)      如果要修改u-boot需要。。编译。。。。。。。。。。。。

 

内核

Linux内核部分是工作量比较多的部分

1.         交叉编译

2.         BSP

3.         Kconfig以及内核裁减

4.         镜像制作和烧写

交叉编译

关于交叉编译,网络上有很多文章。以ubuntu 8.10说明一下:

a)         下载编译器,比如arm-linux-gcc 3.4.1

b)        sudo tar vxjf arm-linux-gcc 3.4.1.bz2 –C /

c)         命令行编译需要设置环境变量

sudo gedit /etc/bash.bashrc

在文件最后添加 export PATH=$PATH:/usr/local/arm/3.4.1/bin

重新登录

d)        arm-linux-gcc –v 查看版本便知道交叉编译器是否安装成功

 

BSP

LinuxBSP其实就是外设驱动集合。比如扩了一个串口,需要编写设备驱动。关于设备驱动编写是一个很大的话题,我想这是另外需要一本书的《Linux Device Driver.3rd Edition》。看不懂可以看看参考http://www.deansys.com/doc/ldd3/index.html

 

Kconfig以及内核裁减

Kconfig是用于定制内核的,有了交叉环境、BSP以及内核源码后,就可以做Kconfig.源码包的Makefile需要从.config得到信息以便把需要的东西编译到内核,不需要的东西不放进来,这样的内核是最精简有效的。问题是这些信息是庞大的,正如管理一个大的工程用Makefile一样,管理一个越来越复杂的内核用Kconfig

 

以下引用自互联网

Kconfig文档的作用

内核源码树的目录下都有两个文档Kconfig2.4版本是Config.in)和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文档相关的内核配置菜单。在内核配置make menuconfig(xconfig)时,从Kconfig中读出菜单,用户选择后保存到.config的内核配置文档中。在内核编译时,主Makefile调用这个.config,就知道了用户的选择。

*上面的内容说明了,Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,能够修改Kconfig,这样就能够选择这个驱动,假如想使这个驱动被编译,要修改Makefile

so添加新的驱动时需要修改的文档有两种(注意不只是两个)

*Kconfig

*Makefile

要想知道怎么修改这两种文档,就要知道两种文档的语法结构

Kconfig

每个菜单都有一个关键字标识,最常见的就是config

语法:

config

symbol是个新的标记的菜单项,options是在这个新的菜单项下的属性和选项

其中options部分有:

1、类型定义:

每个config菜单项都要有类型定义,bool布尔类型、 tristate三态:内建、模块、移除 string字符串、 hex十六进制、 integer整型

例如config HELLO_MODULE

bool "hello test module"

bool类型的只能选中或不选中,tristate类型的菜单项多了编译成内核模块的选项,假如选择编译成内核模块,则会在.config中生成一个CONFIG_HELLO_MODULE=m的配置,假如选择内建,就是直接编译成内核影响,就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置.

2、依赖型定义depends onrequires

指此菜单的出现和否依赖于另一个定义

config HELLO_MODULE

bool "hello test module"

depends on ARCH_PXA

这个例子表明HELLO_MODULE这个菜单项只对XScale处理器有效。

3、帮助性定义

只是增加帮助用关键字help---help---

内核的Makefile

 

linux2.6.x/Documentation/kbuild目录下有周详的介绍有关kernel makefile的知识。

内核的Makefile分为5个组成部分:

Makefile     最顶层的Makefile

.config        内核的当前配置文档,编译时成为定层Makefile的一部分

arch/$(ARCH)/Makefile    和体系结构相关的Makefile

s/ Makefile.*      一些Makefile的通用规则

kbuild Makefile           各级目录下的大概约500个文档,编译时根据上层Makefile传下来的宏定义和其他编译规则,将源代码编译成模块或编入内核

顶层的Makefile文档读取 .config文档的内容,并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。 s目录下的Makefile文档包含了任何用来根据kbuild Makefile 构建内核所需的定义和规则。

(其中.config的内容是在make menuconfig的时候,通过Kconfig文档配置的结果。

举个例子:

    假设想把自己写的一个flash的驱动程式加载到工程中,而且能够通过menuconfig配置内核时选择该驱动该怎么办呢?能够分三步:

  第一:将您写的flashtest.c 文档添加到/driver/mtd/maps/ 目录下。

  第二:修改/driver/mtd/maps目录下的kconfig文档:

        config MTD_flashtest

             tristate “ap71 flash"

         这样当make menuconfig ,将会出现 ap71 flash选项。

第三:修改该目录下makefile文档。

ü       添加如下内容:obj-$(CONFIG_MTD_flashtest)       += flashtest.o

这样,当您运行make menucofnig时,您将发现ap71 flash选项,假如您选择了此项。该选择就会保存在.config文档中。当您编译内核时,将会读取.config文档,当发现ap71 flash 选项为yes 时,系统在调用/driver/mtd/maps/下的makefile 时,将会把 flashtest.o 加入到内核中。即可达到您的目的

 

 

make menuconfig后这个蓝色的终端里,有许多复杂的配置,根据需要配置好后保存就可以了。

 

ubuntu 8.10出现make menuconfig失败,一堆错误,这个需要

sudo apt-get install libncurses5-dev

 

镜像制作和烧写

内核镜像是被bootloader加载的,比如u-boot可以把内核镜像加载到RAM并执行。制作u-boot可加载的镜像需要使用mkimage工具,所以

sudo cp ~/tools/mkimage /usr/bin

make uImage

需要注意的是如果mkimage权限不对make uImage是会出错的,可以设置一下权限

sudo chmod 777 /usr/bin/mkimage

如果一切成功那么在linux-xxxx/arch/arm/boot下就有uImage文件了。

如果要更清楚里面的细节,需要对mkimage做进一步了解。

烧写的工作还是交给u-boot吧,大概工作是这样的:

a)         中断u-boot

b)        需要一个tftp服务器,比如Windows XP下安装tftpwin就可以了

c)         调用u-boot命令启动下载烧写

 

文件系统

待续


09.5.25 最后一次更新

发表于 2009-05-25 00:55 fdo 阅读(1496) | 评论 (5)编辑 收藏

2009年4月2日 #

一系列问题。。。

0.这是我在论坛问的问题
DispacherSend(....)
{
.....

WRITE_PORT_UCHAR(TRANSMIT,0x1);//这里就启动发送,在dispacher没返回pending时,isr就以及发生,dpc已经完成irp,怎么办???同步isr?

return STATUS_PENDING;
}
BOOLEAN OnInterrupt(..)
{
   if(TRANSMITINT)
  {
   IoRequestDpc(...)
  }

}

DpcForIsr()
{
   IoCompleteRequeset(..)
}


////////////////////////////////////////////////////////////////////////////
1.关于dispacher的irql
 wdm书上irql说是dispach_level,但其他章节的叙述看来是passive_level...

2.关于dispacher的返回
返回值到底给了谁?
a)iomgr创建irp
b)iocalldriver本身是同步调用
c)如果iomgr直接iocalldriver,那么返回值给了iomgr,iomgr将做后期处理
d)DPC里iocompleterequest ,将排队dpc obj,最终可能是在apc_level做真正的返回处理

分析:假设dispacher在dispach_level调用
a)在dispacher里return pending前,可能被isr打断,
b)isr里iorequestdpc时,一个dpc入队
c)irql回到dispach_level,假设dpc rountie先于dispacher调用
d)dpc rountie 里面complete irp但所谓完成也是iocomplete obj入队。之后,dispacher应该被resume,即return pending
e)irql到apc_level,排在队列里的iocomplete被完成
f)irql回到passive_level,线程调度恢复,此时win32里的同步deviceiocontrol操作才会真正resume,而得到的值应该是iocomplete obj完成时的,具体应该在一个XXXblock的数据结构里。

这样的分析有两个条件,1)dispacher在dispach_level调用,2)从isr到dispach_level,dpcer可能先于dispacher调用。

如果条件2改为dispacher先调用,也一样,iomgr知道如何处理,我想dispacher里iomarkpending就是起这个作用的,isr来临前dispacher 其实已经放弃了irp,返回值pending到底有什么用不知。或许最终apc complete iocomplete obj时,做判断?

如果条件1改为dispacher在passive_level调用,那么win32 resume和dispacher resume应该也有抢占问题,但这个不重要,只要iomgr把markpending的irp的dispacher的返回值忽略就行。。。。。

没有符号——大陆行货(阉割版)
////////--------------------------------------------------------------------------2009.4.11
翻了翻wrk代码。实际上dispacher是回调函数,对readfile,writefile等win32 api ioctl,其真正调用者应该是iomgr-iocalldriver. 在iomgr的某段代码里面调用了iocalldriver,dispacher的返回值只关系iomgr如何处理。简单的说,iocalldriver返回pending可能会导致iomgr 阻塞。进而阻塞win32线程,实际上中间有一个细节,我想应该说是阻塞一个文件对象(驱动?)所在的上下文,最终才阻塞win32. 当然iomarkirppending可能会让iomgr选择不阻塞。

这样的话,事情就清楚了,对于一个设备——文件句柄。只能有一个IRP pending.,即使在不同的线程中,IRP的一个中间受体是文件,一旦pending就必须完成。即使是non-block IRP,我想也不行!这样的话,必须有一个完成机制,打开另个文件句柄,发个IRP停止是一种做法,walter 的例子也是这么做的,我不知道是不是标准做法,我想应该不是!

我翻阅了src/kernel/serial。它的做法是分时。我想双工driver可以仿照文件行为
1.read行为应该类似普通文件
   a) 如果下面有数据,立即返回,如果没有,启动一个timer,以便read返回,这和non-block block IOCTL关系不大。
   b) 下面是否有数据,完全决定于驱动设计。对于一个中断设备,可以选择在pending期间才处理接收中断。也可以选择缓冲数据。
  c) serial也是用的这种分时方式。
2.write
  a)普通文件write也是会超时的。所以write也要提供一个timer
3.显然一个文件不应该同时写和读,即使技术上能实现。

至于排队IRP,书上说,排队是提高吞吐量。我认为排队揭示了一个重要原则,必须提供取消例程。应该说实际上对于一个设备驱动,只能串行处理irp,所谓排队应该有一个隐含条件,另一个设备句柄被打开了,有一个新的irp要处理,但当前的还没处理完,显然直接返回失败不是最好的办法,至少我认为这时排队irp是更好的方法,第二个实体不需要知道错误,它只需要同步挂起,或者overlap.它会在需要时被唤醒。

到目前为止,双工driver可以利用分时方法。双句柄当然可以不用分时,但双句柄有取消IRP.的问题。

总结一下:只为一个实体提供输入输出服务的设备。1.排队不是必须的(只能一个pending,)。2.分时是比较理想的方式3.overlaped是不需要的,因为对于同一个设备句柄,即使两个线程也不能overlap.第二个调用的会返回失败 重叠io正在请求中。我认为没必要花精力处理这种错误

发表于 2009-04-02 10:46 fdo 阅读(1375) | 评论 (3)编辑 收藏

2009年3月27日 #

..............bugcheck

1.用了这个语句
UCHAR** pCurret=NULL;

*pCurrent=frame[0]&0x80?pdx->pRecvH[source]:pdx->pRecvL[source];

指针的指针应该是pCurrent=frame[0]&0x80?&pdx->pRecvH[source]:&pdx->pRecvL[source];

直接kebugcheckex ..0xd1

2.AddDevice忘记初始化DPC对象了

ISR里IoRequesetDpc

直接kebugcheckex ..0xd1

终于会用windbg了


发表于 2009-03-27 16:59 fdo 阅读(1217) | 评论 (0)编辑 收藏

2009年1月12日 #

char 和 unsigned char 原来不一样,惭愧到极点。。。

#include "stdafx.h"


const char* check()
{
    char c=0xff;
    unsigned char val=0xff;
    return c==val?"yes":"no";
}
int _tmain(int argc, _TCHAR* argv[])
{

    printf("%s\n",check());

    return 0;
}


区别在 一个是movsx一个是movzx...........
00411AB6  movsx       eax,byte ptr [c]
00411ABA  movzx       ecx,byte ptr [val]
00411ABE  cmp         eax,ecx

发表于 2009-01-12 14:08 fdo 阅读(1945) | 评论 (2)编辑 收藏

2008年12月10日 #

关于DDK例子

传统的ISA/EISA总线设备,虽然不支持PnP Power管理,但仍然可以用WDM结构来写,显然,中文翻译的《Programming the Microsoft Windows Driver Model》多少是有点误导了我,英文的没看不知道。

WDM或者说KMD本身是设备驱动程序编写的一个框架,或者说规矩,或者说抽象,或者说风格

如何为遗留设备编写驱动,可以参考C:\WINDDK\3790\src\general\portio,这个例子是用inf配置资源的。LogConfig段用法是关键

root是一个好东西,可以虚拟设备

另外,要对设备枚举有更好的理解,可以看C:\WINDDK\3790\src\general\toaster,这里虚拟了一个总线,好好理解总线驱动如何工作,有帮理解其他总线设备如何工作,驱动如何编写


C:\WINDDK\3790\src\general\event是driver通知app的一个例子,里面介绍了事件方式和IRP Pending方式。我写过VxD,事件方式差不多,IRP Pending是VxD没有的。应该好好理解理解!VxD的User Mode APC方式我感觉很糟糕,以后不会用了

C:\WINDDK\3790\src\general\ioctl是IRP的一个例子,IRP是个复杂的东西,我认为,我想过些日子完全弄懂了在说吧。

发表于 2008-12-10 13:53 fdo 阅读(1805) | 评论 (0)编辑 收藏