http://qsyang.yeah.net
现代微机原理与接口技术
1
Windows98/2000驱动程序编写方法
(下)
杨全胜
http://qsyang.yeah.net
现代微机原理与接口技术
2
4.Driver Works的使用
1)生成简单框架
http://qsyang.yeah.net
现代微机原理与接口技术
3
工程文件名工程文件目录
http://qsyang.yeah.net
现代微机原理与接口技术
4
选择驱动类型
http://qsyang.yeah.net
现代微机原理与接口技术
5
创建功能驱动程序 创建过滤器驱动程序
http://qsyang.yeah.net
现代微机原理与接口技术
6
选择相应总线本例不驱动硬件
http://qsyang.yeah.net
现代微机原理与接口技术
7
驱动类名称驱动类文件名
http://qsyang.yeah.net
现代微机原理与接口技术
8
选择需要处理的消息句柄
http://qsyang.yeah.net
现代微机原理与接口技术
9
http://qsyang.yeah.net
现代微机原理与接口技术
10
http://qsyang.yeah.net
现代微机原理与接口技术
11
http://qsyang.yeah.net
现代微机原理与接口技术
12
添加和应用程序之间通信的控制代码
http://qsyang.yeah.net
现代微机原理与接口技术
13
http://qsyang.yeah.net
现代微机原理与接口技术
14
http://qsyang.yeah.net
现代微机原理与接口技术
15
测试用应用程序名称
http://qsyang.yeah.net
现代微机原理与接口技术
16
http://qsyang.yeah.net
现代微机原理与接口技术
17
http://qsyang.yeah.net
现代微机原理与接口技术
18
驱动类设备类
http://qsyang.yeah.net
现代微机原理与接口技术
19
驱动类文件设备类文件测试用的控制台程序文件驱动安装指导文件
http://qsyang.yeah.net
现代微机原理与接口技术
20
此时已经具备了一个驱动程序以及做测试用的应用程序的基本框架,我们可以在 VC集成环境下修改有关程序,增加相关的具体操作代码,然后就可以编译和调试了。
http://qsyang.yeah.net
现代微机原理与接口技术
21
该驱动程序框架包含了几个最基本的类,这些类是:
class Sample,public KDriver // 驱动程序类,用于初始化驱动程序
{
SAFE_DESTRUCTORS
public:
// 以下成员函数注意和 WDM中有关例程联系起来看
virtual NTSTATUS DriverEntry(PUNICODE_STRING RegistryPath);
virtual NTSTATUS AddDevice(PDEVICE_OBJECT Pdo);
void LoadRegistryParameters(KRegistryKey &Params);
int m_Unit;
// The following data members are loaded from the registry during DriverEntry
ULONG m_bBreakOnEntry;
};
http://qsyang.yeah.net
现代微机原理与接口技术
22
class SampleDevice,public KPnpDevice // 是设备类 KDvice的派生类,用于在
WDM环境下支持即插即用设备
{
// Constructors
public:
SAFE_DESTRUCTORS;
SampleDevice(PDEVICE_OBJECT Pdo,ULONG Unit);
~SampleDevice();
// Member Functions 注意和 PNP的次功能代码联系起来看
public:
DEVMEMBER_DISPATCHERS
virtual NTSTATUS OnStartDevice(KIrp I);
virtual NTSTATUS OnStopDevice(KIrp I);
virtual NTSTATUS OnRemoveDevice(KIrp I);
virtual NTSTATUS DefaultPnp(KIrp I);
virtual NTSTATUS DefaultPower(KIrp I);
virtual NTSTATUS OnDevicePowerUp(KIrp I);
virtual NTSTATUS OnDeviceSleep(KIrp I);
void SerialRead(KIrp I);
void SerialWrite(KIrp I);
http://qsyang.yeah.net
现代微机原理与接口技术
23
NTSTATUS SAMPLE_IOCTL_Read_Handler(KIrp I);
NTSTATUS SAMPLE_IOCTL_Write_Handler(KIrp I);
NTSTATUS SAMPLE_IOCTL_ReadWrite_Handler(KIrp I);
#ifdef _COMMENT_ONLY
virtual NTSTATUS Create(KIrp I);
virtual NTSTATUS Close(KIrp I);
virtual NTSTATUS DeviceControl(KIrp I);
virtual NTSTATUS SystemControl(KIrp I);
virtual NTSTATUS Read(KIrp I);
virtual NTSTATUS Write(KIrp I);
#endif
// Member Data
protected:
// Unit number for this device (0-9)
ULONG m_Unit;
KPnpLowerDevice m_Lower;
SampleDevice_DriverManagedQueue m_DriverManagedQueue;
// TODO,Create additional driver managed queues,These might be
// of the same class (SampleDevice_DriverManagedQueue),
// or you might choose to derive another class.
};
http://qsyang.yeah.net
现代微机原理与接口技术
24
先编译驱动程序工程在 VC的集成环境中下面我们讲解编译、执行和调试这个驱动程序。
http://qsyang.yeah.net
现代微机原理与接口技术
25
http://qsyang.yeah.net
现代微机原理与接口技术
26
再编译测试应用程序工程
http://qsyang.yeah.net
现代微机原理与接口技术
27
http://qsyang.yeah.net
现代微机原理与接口技术
28
下面使用 DriverStudio带的工具加载驱动程序和查看调试信息。
驱动程序监视,可实时看到驱动程序发出的调试输出语句驱动程序装载器,可动态调用驱动程序
http://qsyang.yeah.net
现代微机原理与接口技术
29
驱动程序监视器界面
http://qsyang.yeah.net
现代微机原理与接口技术
30
驱动程序装载器界面
http://qsyang.yeah.net
现代微机原理与接口技术
31
http://qsyang.yeah.net
现代微机原理与接口技术
32
http://qsyang.yeah.net
现代微机原理与接口技术
33
http://qsyang.yeah.net
现代微机原理与接口技术
34
http://qsyang.yeah.net
现代微机原理与接口技术
35
http://qsyang.yeah.net
现代微机原理与接口技术
36
http://qsyang.yeah.net
现代微机原理与接口技术
37
下面我们来修改有关代码,以便增加驱动程序和应用程序之间相互通信的内容。需要增加的内容包括:
a,使用 Read和 Write方式分别从驱动程序读入字符和向驱动程序写字符。
b,使用 IO控制代码方式分别从驱动程序读入字符和向驱动程序写字符。
c,使用 IO控制代码方式向驱动程序写字符串再从驱动程序中读出该字符串,并返回反馈串信息。
注意,程序中 暗红色显示的部分 是我们添加或修改过的语句,其他是 DriverWorks自动生成的。语句中
,t<< xxxxx”这样的语句是向调试软件输出信息,该信息可以再 DriverMonitor或其他调试监视器中看到。
2)完成应用程序和驱动程序之间的信息交换
http://qsyang.yeah.net
现代微机原理与接口技术
38
a,使用 Read和 Write方式分别读写
SampleDevice.cpp
void SampleDevice::SerialRead(KIrp I)
{
t << "Entering SampleDevice::SerialRead," << I << EOL;
NTSTATUS status = STATUS_SUCCESS;
PUCHAR pBuffer = (PUCHAR) I.BufferedReadDest();//取得返回数据
BUFF的指针
ULONG dwTotalSize = I.ReadSize(CURRENT); // Requested read size
char buff[512];
int n =512,j = (n % 26);
for (int i=0; i<n; i++,j=(j + 1)%26)
{ buff[i] = 'a' + j; }
buff[dwTotalSize]=?\0?; //指定串尾
strcpy((char *)pBuffer,buff);
// 把给应用程序的数据拷贝给返回 BUFF
t <<,The string you will read is \”,<< buff <<,\“” << EOL; // 输出调试信息
ULONG dwBytesRead = strlen(buff); // Count of bytes read
I.Information() = dwBytesRead; // 返回给应用程序的信息的字节个数
I.Status() = status;
m_DriverManagedQueue.PnpNextIrp(I);
}
http://qsyang.yeah.net
现代微机原理与接口技术
39
void SampleDevice::SerialWrite(KIrp I)
{
t << "Entering SampleDevice::SerialWrite," << I << EOL;
NTSTATUS status = STATUS_SUCCESS;
PUCHAR pBuffer = (PUCHAR)I.BufferedWriteSource();//取得存放应用程序写给驱动程序的数据的 BUFF的指针
ULONG dwTotalSize = I.WriteSize(CURRENT);// 获得应用程序写给驱动程序的信息的字节数。
ULONG dwBytesSent = dwTotalSize;
char buff[512];
strcpy(buff,(char *)pBuffer);// 应用程序写给驱动程序的数据在
I.BufferedWriteSource()返回的指针中。
buff[dwBytesSent] = '\0';
t << "Write to driver is \"" << buff << "\"" << EOL;
I.Information() = dwBytesSent; // 返回用户实际写的字节数
I.Status() = status;
m_DriverManagedQueue.PnpNextIrp(I);
}
http://qsyang.yeah.net
现代微机原理与接口技术
40
Test_Sample.cpp
void doRead(int n) // 从驱动程序中读数据
{
char *buf;
ULONG nRead;
int i,j;
buf = (char *) malloc(n);
if (buf == NULL)
{
printf("Failed to allocate buffer for read");
Exit(1);
}
// Read data from driver
printf("Reading from device - ");
ReadFile(hDevice,buf,n,&nRead,NULL);
// 参数分别是设备句柄、输入缓冲地址、缓冲大小(字节数)、实际读的数据字节数、覆盖结构指针。
http://qsyang.yeah.net
现代微机原理与接口技术
41
printf("%d bytes read from device (%d requested).\n",
nRead,nRead);
// Print what was read
while(i < nRead)
{
// j = min((i+26),n);
// for(; i < j; i++)
// {
// printf("%c,",buf[i]);
// }
// printf("\n");
printf("%c,",buf[i++]);
}
printf("\n");
free(buf);
}
这几句删除
http://qsyang.yeah.net
现代微机原理与接口技术
42
void doWrite(int n) // 向驱动程序中写数据
{
char *buf;
ULONG nWritten;
int i,j;
buf = (char *) malloc(n);
if (buf == NULL)
{
printf("Failed to allocate buffer for write");
Exit(1);
}
// start with the mod26 letter of the number of bytes to write
j = (n % 26);
// load buffer with dummy data (abcdefg...)
for (i=0; i<n; i++,j=(j + 1)%26)
{
buf[i] = 'a' + j;
}
http://qsyang.yeah.net
现代微机原理与接口技术
43
// Write data to driver
printf("Writing to device - ");
WriteFile(hDevice,buf,n,&nWritten,NULL);
// 写数据,参数的含义是驱动程序句柄、写缓冲、写缓冲大小
、实际驱动程序得到的信息的字节数、覆盖结构指针。
printf("%d bytes written to device (%d attempted).\n",
nWritten,n);
i = 0; // Print what was written
while(i < n)
{
j = min((i+26),n);
for(; i < j; i++) {
printf("%c,",buf[i]);
}
printf("\n");
}
free(buf);
}
http://qsyang.yeah.net
现代微机原理与接口技术
44
b,使用 IO控制代码方式分别读写
SampleDevice.cpp
NTSTATUS SampleDevice::SAMPLE_IOCTL_Read_Handler(KIrp I)
{ // 对应用程序读驱动程序的请求作响应
NTSTATUS status = STATUS_SUCCESS;
t << "Entering SampleDevice::SAMPLE_IOCTL_Read_Handler," << I <<
EOL;
char buff1[512];
ULONG fwLength=0;
strcpy(buff1,"Welcome to driver!");
fwLength = strlen(buff1)+1;
if (I.IoctlOutputBufferSize() >= fwLength) {// 如果读入缓冲够长
strcpy((PCHAR)I.IoctlBuffer(),buff1); // 将信息拷给应用程序读入缓冲
I.Information() = fwLength; // 返回信息长度
}
else {
I.Information() = 0; // 否则信息长度为 0
t << "buff size too small" << EOL;
}
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
45
NTSTATUS
SampleDevice::SAMPLE_IOCTL_Write_Handler(KIrp I)
{ // 接受从应用程序中来的信息
NTSTATUS status = STATUS_SUCCESS;
t << "Entering SampleDevice,,
SAMPLE_IOCTL_Write_Handler," << I << EOL;
char buff[512];
ULONG fwLength=0;
strcpy(buff,(PCHAR)I.IoctlBuffer()); // 拷贝从应用程序得到的命令串到驱动程序局部数据区
t <<,InputPut Data is \”,<< buff <<,\“” <<EOL; // 显示从应用程序得到的命令串。
I.Information() = 0;
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
46
Test_Sample.cpp
void Test_SAMPLE_IOCTL_Read(void)
{
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHAR bufOutput[IOCTL_OUTBUF_SIZE];// Output from device
ULONG nOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_Read) in driver
printf("Issuing Ioctl to device - ");
strcpy(bufInput,"This is a sample.");
if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_Read,NULL,0,
bufOutput,IOCTL_OUTBUF_SIZE,&nOutput,NULL))
{
printf("ERROR,DeviceIoControl returns %0x.",GetLastError());
Exit(1);
}
else
printf("Return from driver is \"%s\"(%d)",bufOutput,nOutput);
}
http://qsyang.yeah.net
现代微机原理与接口技术
47
void Test_SAMPLE_IOCTL_Write(void)
{
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHARbufOutput[IOCTL_OUTBUF_SIZE];// Output from device
ULONG nOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_Write) in driver
printf("Issuing Ioctl to device - ");
strcpy(bufInput,"Now let us write this string.");
if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_Write,bufInput,
strlen(bufInput),NULL,0,&nOutput,NULL)) // 该函数参数分别是设备句柄,IO控制命令、写缓冲、写缓冲大小、读缓冲、读缓冲大小、实际读的字节数、覆盖结构指针(注意,这里的 bufInput是指 Input到设备,所以对应用软件这是写缓冲,bufOutput是从设备 output到应用程序,是读缓冲。
{
printf("ERROR,DeviceIoControl returns %0x.",
GetLastError());
Exit(1);
}
}
http://qsyang.yeah.net
现代微机原理与接口技术
48
c,使用 IO控制代码方式写并且读SampleDevice.cpp
NTSTATUS
SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
t << "Entering
SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler," << I <<
EOL;
char buff[512],buff1[512];
ULONG fwLength=0;
strcpy(buff,(PCHAR)I.IoctlBuffer());// 拷贝应用程序来的信息
t << "InputPut Data is \"" << buff << "\"" <<EOL;
strcpy(buff1,"this is feedback from driver! Application give me
this string \"");
strcat(buff1,buff);
strcat(buff1,“\”“); // 以上是组织反馈的信息
http://qsyang.yeah.net
现代微机原理与接口技术
49
fwLength = strlen(buff1)+1;
if (I.IoctlOutputBufferSize() >= fwLength)
{
strcpy((PCHAR)I.IoctlBuffer(),buff1);// 拷贝反馈信息
I.Information() = fwLength; // 设置反馈信息字节数
}
else
{
I.Information() = 0;
t << "buff size too small" << EOL;
}
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
50
Test_Sample.cpp
void Test_SAMPLE_IOCTL_ReadWrite(void)
{
bufOutput is written by the device to return data to this application
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from device
ULONGnOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_ReadWrite) in driver
printf("Issuing Ioctl to device - ");
strcpy(bufInput,"This is a sample.");
if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_ReadWrite,bufInput,
strlen(bufInput),bufOutput,IOCTL_OUTBUF_SIZE,&nOutput,NULL) )
{
printf("ERROR,DeviceIoControl returns %0x.",GetLastError());
Exit(1);
}
else
printf("Feedback is \"%s\"(%d)",bufOutput,nOutput);
}
http://qsyang.yeah.net
现代微机原理与接口技术
51
http://qsyang.yeah.net
现代微机原理与接口技术
52
http://qsyang.yeah.net
现代微机原理与接口技术
53
3)直接对端口寄存器读写
DriverStudio提供了 KIoRange类来将外部总线的 I/O地址空间范围映射到处理器总线的地址空间范围。
该类的成员函数主要有
KIoRange 构造函数 (4 种格式 )
Initialize 初始化和重新初始化一个实例 (3种格式 )
~KIoRange 析构函数
Invalidate 从已初始化状态删除该对象
IsValid 测试该对象是否已经初始化
inb 读一个或多个字节 (2 种形式 )
Outb 写一个或多个字节 (2 种形式 )
Inw 读一个或多个字 (2 种形式 )
Outw 写一个或多个字 (2 种形式 )
ind 读一个或多个双字 (2 种形式 )
outd 写一个或多个双字 (2 种形式 )
http://qsyang.yeah.net
现代微机原理与接口技术
54
KIoRange::KIoRange(只介绍 WDM形式)
FORM 3 (WDM):
KIoRange(
ULONGLONG CpuPhysicalAddress,//转换成外围设备地址的 CPU总线上的物理地址
BOOLEAN InCpuIoSpace,//如果 IO范围是在 CPU总线的 IO空间中为 TRUE,否则为 FALSE
ULONG Count,//以字节计的区域的大小
BOOLEAN MapToSystemVirtual =TRUE//指定是否需要构造函数创建一个非页系统空间的地址空间映射,如果驱动程序读写设备中的数据,就需要这种映射
);
FORM 4 (WDM),(注意,这种形式不被 DriverStudio 2.0支持。 )
KIoRange(
PCM_RESOURCE_LIST pTranslatedResourceList,//指向转换资源表的指针
ULONG Ordinal=0,//指定 pTranslatedResourceList指向的资源列表中的一个特殊端口资源
BOOLEAN MapToSystemVirtual =TRUE
);
FORM 5 (WDM):
KIoRange(
PCM_RESOURCE_LIST pTranslatedResourceList,//可通过 KIrp::TranslatedResources获得
PCM_RESOURCE_LIST pRawResourceList,//指向原始资源表的指针
ULONG Ordinal=0,
BOOLEAN MapToSystemVirtual =TRUE
);构造 KIoRange类。
http://qsyang.yeah.net
现代微机原理与接口技术
55
KIoRange::Initialize(只介绍 WDM形式)
FORM 2 (WDM):
NTSTATUS Initialize(
ULONGLONG CpuPhysicalAddress,
BOOLEAN InCpuIoSpace,
ULONG Count,
BOOLEAN MapToSystemVirtual=TRUE
);
FORM 3 (WDM),(注意,这种形式不被 DriverStudio 2.0支持。 )
NTSTATUS Initialize(
PCM_RESOURCE_LIST pTranslatedResourceList,
ULONG Ordinal=0,
BOOLEAN MapToSystemVirtual =TRUE
);
FORM 4 (WDM):
Initialize(
PCM_RESOURCE_LIST pTranslatedResourceList,
PCM_RESOURCE_LIST pRawResourceList,
ULONG Ordinal=0,
BOOLEAN MapToSystemVirtual =TRUE
);
初始化或重新初始化 KIoRange的实例。
http://qsyang.yeah.net
现代微机原理与接口技术
56
KIoRange::inb
FORM 1:
UCHAR inb( ULONG ByteOffset );
FORM 2:
VOID inb(
ULONG ByteOffset,
PUCHAR Buffer,
ULONG Count
);
从映射空间读一个或多个字节。
http://qsyang.yeah.net
现代微机原理与接口技术
57
KIoRange::outb
FORM 1:
VOID outb(
ULONG ByteOffset,//以字节为单位的目标位置到 IO空间开始位置的偏移值
UCHAR Data //要写的一个字节数据
);
FORM 2:
VOID outb(
ULONG ByteOffset,
PUCHAR Buffer,//指向包含要写数据的缓冲的指针
ULONG Count //缓冲中要写数据的字节数
);
写一个或多个字节到映射的 IO空间。
http://qsyang.yeah.net
现代微机原理与接口技术
58
写端口( 索引信息,地址 70H)
m_ParPortIos.outb(0,0x02); // 准备读分钟信息
读端口(读分钟信息,地址 71H)
UCHAR data = m_ParPortIos.inb(1);
下面我们来访问 CMOS的数据。
首先定义类 KIoRange的一个实例,以定义相关地址空间。
KIoRange m_ParPortIos;
初始化实例(指定 CMOS的端口首地址,并映射)
status = m_ParPortIos.Initialize(
0x70,// CMOS端口首地址是 70H
TRUE,//在 CPU I/O空间内
8,// 设备读写数据的字节宽度
TRUE // 映射到系统空间
);
http://qsyang.yeah.net
现代微机原理与接口技术
59
4) 截获中断和挂接中断服务例程
DriverStudio提供了 KInterrupt类来截获和挂接中断。
该类的成员函数主要有
KInterrupt 构造函数 (3种格式 )
Initialize 在无效状态下初始化一个对象 (3种格式 )
Connect 绑定 ISR(中断服务例程)到中断
InitializeAndConnect 一步完成初始化与绑定工作,要用资源列表作为输入。
~KInterrupt 析构函数
Invalidate 在初始化状态下删除对象
IsValid 检查对象是否初始化
Disconnect 使中断和 ISR与中断分离
Synchronize 当得到一个中断自旋锁时请求同步功能
http://qsyang.yeah.net
现代微机原理与接口技术
60
KInterrupt::KInterrupt(只介绍 WDM形式)
FORM 3,(WDM)
KInterrupt(
KIRQL irql,//即插即用设备提供的 IRQL值
ULONG vector,//即插即用设备提供的向量值
KINTERRUPT_MODE Mode,//LevelSensitive或 Latched中选一,
BOOLEAN bShareVector=FALSE,//该向量是否被几个设备共享
KAFFINITY affinity=1,//this is the processor affinity mask.
BOOLEAN bSaveFloat =FALSE //是否需要在中断到来使保存浮点处理器上下文,X86平台下必须使 FALSE
);
构造类 Kinterrupt的实例。
http://qsyang.yeah.net
现代微机原理与接口技术
61
KInterrupt::Initialize(只介绍 WDM形式)
FORM 2,(WDM)
VOID
Initialize(
KIRQL irql,
ULONG vector,
KINTERRUPT_MODE Mode,
BOOLEAN bShareVector=FALSE,
KAFFINITY affinity=1,
BOOLEAN bSaveFloat=FALSE
);
初始化对象。只在对象没有初始化的时候使用。
http://qsyang.yeah.net
现代微机原理与接口技术
62
KInterrupt::Connect
FORM 1:
NTSTATUS Connect(
PKSERVICE_ROUTINE Isr,//作为 ISR服务的函数的地址
PVOID Context //当系统调用 ISR的时候传递给他的无类型的参数
);
FORM 2:
NTSTATUS Connect(
PKSERVICE_ROUTINE Isr,
PVOID Context,
PKSPIN_LOCK pSpin,
KIRQL SynchIrql
);
绑定一个中断到 ISR(中断处理程序)。
http://qsyang.yeah.net
现代微机原理与接口技术
63
KInterrupt::InitializeAndConnect
NTSTATUS InitializeAndConnect(
PCM_RESOURCE_LIST pResourceList,//指向资源列表的指针
PKSERVICE_ROUTINE Isr,
PVOID IsrContext,
ULONG Ordinal=0,
BOOLEAN bSaveFloat=FALSE
);
初始化一个中断并绑定到一个 ISR上。
对于 WDM 驱动程序,pResourceList 必须是一个转换资源表,例如是 KIrp::TranslatedResources的返回值。
http://qsyang.yeah.net
现代微机原理与接口技术
64
下面我们来举例说明。
首先 定义类 KInterrupt的一个实例
KInterrupt m_TheInterrupt;
在设备类中声明一个成员函数 TheIsr作为中断服务例程
ISR。
class SampleDevice,public KPnpDevice
{ ……
public:
MEMBER_ISR (SampleDevice,TheIsr);
……
#ifdef _COMMENT_ONLY
BOOLEAN TheIsr( void) { return TRUE ; };
#endif
……
}
http://qsyang.yeah.net
现代微机原理与接口技术
65
在 OnStartDevice例程中获取包括中断的设备资源并初始化中断和挂接 ISR
SampleDevice,:OnStartDevice(KIrp I)
{
……
PCM_RESOURCE_LIST pResList =
I.TranslatedResources(); //获取设备资源
//初始化中断并挂接中断服务例程 TheIsr
status = m_TheInterrupt.InitializeAndConnect(
pResList,
LinkTo(TheIsr),
this
);
……
}
http://qsyang.yeah.net
现代微机原理与接口技术
66
5) 如何写 Win32类型的驱动程序的测试 程序
DriverStudio自动生成的驱动程序的测试程序是一个控制台程序,下面我们将利用该控制台程序来写一个 Win32
的程序。
第一步,在由 DriverStudio自动生成一个驱动程序工作区 (Workspace)中添加一个新的子工程,该子工程指定为一个 MFC的 EXE程序。 右键点击
http://qsyang.yeah.net
现代微机原理与接口技术
67
http://qsyang.yeah.net
现代微机原理与接口技术
68
第二步,手工在新的工程中添加几个文件这几个程序需要手工添加进去,实际上这几个程序都在 DriverStudio自动生成的原来的两个工程文件中 (
这个例子是 MyIOPort和
Test_MyIOPort工程 )。将他们添加到新工程中,方法是右键点击新工程中的相关文件夹,在弹出菜单中选择 Add Files to
Folder…,然后找到要添加的文件并添加。
http://qsyang.yeah.net
现代微机原理与接口技术
69
第三步,打开 OpenByIntf.cpp文件,在开始第一行添加
#include "stdafx.h"
第四步,1
2
3 4
5
C:\PROGRAM FILES\COMPUWARE\SOFTICE
DRIVER SUITE\DRIVERWORKS\INCLUDE
http://qsyang.yeah.net
现代微机原理与接口技术
70
第五步,1
2
3
4
setupapi.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
可以直接从自动生成的控制台工程的设置中拷贝这些库的名称
http://qsyang.yeah.net
现代微机原理与接口技术
71
最后,在控制台程序的 Test_XXXX.CPP程序基础上进行必要的修改。
注意要保留的是打开设备、关闭设备、读写设备有关的函数。界面部分应该全部换成 Windows界面的代码
,而不是保留控制台代码。
现代微机原理与接口技术
1
Windows98/2000驱动程序编写方法
(下)
杨全胜
http://qsyang.yeah.net
现代微机原理与接口技术
2
4.Driver Works的使用
1)生成简单框架
http://qsyang.yeah.net
现代微机原理与接口技术
3
工程文件名工程文件目录
http://qsyang.yeah.net
现代微机原理与接口技术
4
选择驱动类型
http://qsyang.yeah.net
现代微机原理与接口技术
5
创建功能驱动程序 创建过滤器驱动程序
http://qsyang.yeah.net
现代微机原理与接口技术
6
选择相应总线本例不驱动硬件
http://qsyang.yeah.net
现代微机原理与接口技术
7
驱动类名称驱动类文件名
http://qsyang.yeah.net
现代微机原理与接口技术
8
选择需要处理的消息句柄
http://qsyang.yeah.net
现代微机原理与接口技术
9
http://qsyang.yeah.net
现代微机原理与接口技术
10
http://qsyang.yeah.net
现代微机原理与接口技术
11
http://qsyang.yeah.net
现代微机原理与接口技术
12
添加和应用程序之间通信的控制代码
http://qsyang.yeah.net
现代微机原理与接口技术
13
http://qsyang.yeah.net
现代微机原理与接口技术
14
http://qsyang.yeah.net
现代微机原理与接口技术
15
测试用应用程序名称
http://qsyang.yeah.net
现代微机原理与接口技术
16
http://qsyang.yeah.net
现代微机原理与接口技术
17
http://qsyang.yeah.net
现代微机原理与接口技术
18
驱动类设备类
http://qsyang.yeah.net
现代微机原理与接口技术
19
驱动类文件设备类文件测试用的控制台程序文件驱动安装指导文件
http://qsyang.yeah.net
现代微机原理与接口技术
20
此时已经具备了一个驱动程序以及做测试用的应用程序的基本框架,我们可以在 VC集成环境下修改有关程序,增加相关的具体操作代码,然后就可以编译和调试了。
http://qsyang.yeah.net
现代微机原理与接口技术
21
该驱动程序框架包含了几个最基本的类,这些类是:
class Sample,public KDriver // 驱动程序类,用于初始化驱动程序
{
SAFE_DESTRUCTORS
public:
// 以下成员函数注意和 WDM中有关例程联系起来看
virtual NTSTATUS DriverEntry(PUNICODE_STRING RegistryPath);
virtual NTSTATUS AddDevice(PDEVICE_OBJECT Pdo);
void LoadRegistryParameters(KRegistryKey &Params);
int m_Unit;
// The following data members are loaded from the registry during DriverEntry
ULONG m_bBreakOnEntry;
};
http://qsyang.yeah.net
现代微机原理与接口技术
22
class SampleDevice,public KPnpDevice // 是设备类 KDvice的派生类,用于在
WDM环境下支持即插即用设备
{
// Constructors
public:
SAFE_DESTRUCTORS;
SampleDevice(PDEVICE_OBJECT Pdo,ULONG Unit);
~SampleDevice();
// Member Functions 注意和 PNP的次功能代码联系起来看
public:
DEVMEMBER_DISPATCHERS
virtual NTSTATUS OnStartDevice(KIrp I);
virtual NTSTATUS OnStopDevice(KIrp I);
virtual NTSTATUS OnRemoveDevice(KIrp I);
virtual NTSTATUS DefaultPnp(KIrp I);
virtual NTSTATUS DefaultPower(KIrp I);
virtual NTSTATUS OnDevicePowerUp(KIrp I);
virtual NTSTATUS OnDeviceSleep(KIrp I);
void SerialRead(KIrp I);
void SerialWrite(KIrp I);
http://qsyang.yeah.net
现代微机原理与接口技术
23
NTSTATUS SAMPLE_IOCTL_Read_Handler(KIrp I);
NTSTATUS SAMPLE_IOCTL_Write_Handler(KIrp I);
NTSTATUS SAMPLE_IOCTL_ReadWrite_Handler(KIrp I);
#ifdef _COMMENT_ONLY
virtual NTSTATUS Create(KIrp I);
virtual NTSTATUS Close(KIrp I);
virtual NTSTATUS DeviceControl(KIrp I);
virtual NTSTATUS SystemControl(KIrp I);
virtual NTSTATUS Read(KIrp I);
virtual NTSTATUS Write(KIrp I);
#endif
// Member Data
protected:
// Unit number for this device (0-9)
ULONG m_Unit;
KPnpLowerDevice m_Lower;
SampleDevice_DriverManagedQueue m_DriverManagedQueue;
// TODO,Create additional driver managed queues,These might be
// of the same class (SampleDevice_DriverManagedQueue),
// or you might choose to derive another class.
};
http://qsyang.yeah.net
现代微机原理与接口技术
24
先编译驱动程序工程在 VC的集成环境中下面我们讲解编译、执行和调试这个驱动程序。
http://qsyang.yeah.net
现代微机原理与接口技术
25
http://qsyang.yeah.net
现代微机原理与接口技术
26
再编译测试应用程序工程
http://qsyang.yeah.net
现代微机原理与接口技术
27
http://qsyang.yeah.net
现代微机原理与接口技术
28
下面使用 DriverStudio带的工具加载驱动程序和查看调试信息。
驱动程序监视,可实时看到驱动程序发出的调试输出语句驱动程序装载器,可动态调用驱动程序
http://qsyang.yeah.net
现代微机原理与接口技术
29
驱动程序监视器界面
http://qsyang.yeah.net
现代微机原理与接口技术
30
驱动程序装载器界面
http://qsyang.yeah.net
现代微机原理与接口技术
31
http://qsyang.yeah.net
现代微机原理与接口技术
32
http://qsyang.yeah.net
现代微机原理与接口技术
33
http://qsyang.yeah.net
现代微机原理与接口技术
34
http://qsyang.yeah.net
现代微机原理与接口技术
35
http://qsyang.yeah.net
现代微机原理与接口技术
36
http://qsyang.yeah.net
现代微机原理与接口技术
37
下面我们来修改有关代码,以便增加驱动程序和应用程序之间相互通信的内容。需要增加的内容包括:
a,使用 Read和 Write方式分别从驱动程序读入字符和向驱动程序写字符。
b,使用 IO控制代码方式分别从驱动程序读入字符和向驱动程序写字符。
c,使用 IO控制代码方式向驱动程序写字符串再从驱动程序中读出该字符串,并返回反馈串信息。
注意,程序中 暗红色显示的部分 是我们添加或修改过的语句,其他是 DriverWorks自动生成的。语句中
,t<< xxxxx”这样的语句是向调试软件输出信息,该信息可以再 DriverMonitor或其他调试监视器中看到。
2)完成应用程序和驱动程序之间的信息交换
http://qsyang.yeah.net
现代微机原理与接口技术
38
a,使用 Read和 Write方式分别读写
SampleDevice.cpp
void SampleDevice::SerialRead(KIrp I)
{
t << "Entering SampleDevice::SerialRead," << I << EOL;
NTSTATUS status = STATUS_SUCCESS;
PUCHAR pBuffer = (PUCHAR) I.BufferedReadDest();//取得返回数据
BUFF的指针
ULONG dwTotalSize = I.ReadSize(CURRENT); // Requested read size
char buff[512];
int n =512,j = (n % 26);
for (int i=0; i<n; i++,j=(j + 1)%26)
{ buff[i] = 'a' + j; }
buff[dwTotalSize]=?\0?; //指定串尾
strcpy((char *)pBuffer,buff);
// 把给应用程序的数据拷贝给返回 BUFF
t <<,The string you will read is \”,<< buff <<,\“” << EOL; // 输出调试信息
ULONG dwBytesRead = strlen(buff); // Count of bytes read
I.Information() = dwBytesRead; // 返回给应用程序的信息的字节个数
I.Status() = status;
m_DriverManagedQueue.PnpNextIrp(I);
}
http://qsyang.yeah.net
现代微机原理与接口技术
39
void SampleDevice::SerialWrite(KIrp I)
{
t << "Entering SampleDevice::SerialWrite," << I << EOL;
NTSTATUS status = STATUS_SUCCESS;
PUCHAR pBuffer = (PUCHAR)I.BufferedWriteSource();//取得存放应用程序写给驱动程序的数据的 BUFF的指针
ULONG dwTotalSize = I.WriteSize(CURRENT);// 获得应用程序写给驱动程序的信息的字节数。
ULONG dwBytesSent = dwTotalSize;
char buff[512];
strcpy(buff,(char *)pBuffer);// 应用程序写给驱动程序的数据在
I.BufferedWriteSource()返回的指针中。
buff[dwBytesSent] = '\0';
t << "Write to driver is \"" << buff << "\"" << EOL;
I.Information() = dwBytesSent; // 返回用户实际写的字节数
I.Status() = status;
m_DriverManagedQueue.PnpNextIrp(I);
}
http://qsyang.yeah.net
现代微机原理与接口技术
40
Test_Sample.cpp
void doRead(int n) // 从驱动程序中读数据
{
char *buf;
ULONG nRead;
int i,j;
buf = (char *) malloc(n);
if (buf == NULL)
{
printf("Failed to allocate buffer for read");
Exit(1);
}
// Read data from driver
printf("Reading from device - ");
ReadFile(hDevice,buf,n,&nRead,NULL);
// 参数分别是设备句柄、输入缓冲地址、缓冲大小(字节数)、实际读的数据字节数、覆盖结构指针。
http://qsyang.yeah.net
现代微机原理与接口技术
41
printf("%d bytes read from device (%d requested).\n",
nRead,nRead);
// Print what was read
while(i < nRead)
{
// j = min((i+26),n);
// for(; i < j; i++)
// {
// printf("%c,",buf[i]);
// }
// printf("\n");
printf("%c,",buf[i++]);
}
printf("\n");
free(buf);
}
这几句删除
http://qsyang.yeah.net
现代微机原理与接口技术
42
void doWrite(int n) // 向驱动程序中写数据
{
char *buf;
ULONG nWritten;
int i,j;
buf = (char *) malloc(n);
if (buf == NULL)
{
printf("Failed to allocate buffer for write");
Exit(1);
}
// start with the mod26 letter of the number of bytes to write
j = (n % 26);
// load buffer with dummy data (abcdefg...)
for (i=0; i<n; i++,j=(j + 1)%26)
{
buf[i] = 'a' + j;
}
http://qsyang.yeah.net
现代微机原理与接口技术
43
// Write data to driver
printf("Writing to device - ");
WriteFile(hDevice,buf,n,&nWritten,NULL);
// 写数据,参数的含义是驱动程序句柄、写缓冲、写缓冲大小
、实际驱动程序得到的信息的字节数、覆盖结构指针。
printf("%d bytes written to device (%d attempted).\n",
nWritten,n);
i = 0; // Print what was written
while(i < n)
{
j = min((i+26),n);
for(; i < j; i++) {
printf("%c,",buf[i]);
}
printf("\n");
}
free(buf);
}
http://qsyang.yeah.net
现代微机原理与接口技术
44
b,使用 IO控制代码方式分别读写
SampleDevice.cpp
NTSTATUS SampleDevice::SAMPLE_IOCTL_Read_Handler(KIrp I)
{ // 对应用程序读驱动程序的请求作响应
NTSTATUS status = STATUS_SUCCESS;
t << "Entering SampleDevice::SAMPLE_IOCTL_Read_Handler," << I <<
EOL;
char buff1[512];
ULONG fwLength=0;
strcpy(buff1,"Welcome to driver!");
fwLength = strlen(buff1)+1;
if (I.IoctlOutputBufferSize() >= fwLength) {// 如果读入缓冲够长
strcpy((PCHAR)I.IoctlBuffer(),buff1); // 将信息拷给应用程序读入缓冲
I.Information() = fwLength; // 返回信息长度
}
else {
I.Information() = 0; // 否则信息长度为 0
t << "buff size too small" << EOL;
}
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
45
NTSTATUS
SampleDevice::SAMPLE_IOCTL_Write_Handler(KIrp I)
{ // 接受从应用程序中来的信息
NTSTATUS status = STATUS_SUCCESS;
t << "Entering SampleDevice,,
SAMPLE_IOCTL_Write_Handler," << I << EOL;
char buff[512];
ULONG fwLength=0;
strcpy(buff,(PCHAR)I.IoctlBuffer()); // 拷贝从应用程序得到的命令串到驱动程序局部数据区
t <<,InputPut Data is \”,<< buff <<,\“” <<EOL; // 显示从应用程序得到的命令串。
I.Information() = 0;
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
46
Test_Sample.cpp
void Test_SAMPLE_IOCTL_Read(void)
{
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHAR bufOutput[IOCTL_OUTBUF_SIZE];// Output from device
ULONG nOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_Read) in driver
printf("Issuing Ioctl to device - ");
strcpy(bufInput,"This is a sample.");
if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_Read,NULL,0,
bufOutput,IOCTL_OUTBUF_SIZE,&nOutput,NULL))
{
printf("ERROR,DeviceIoControl returns %0x.",GetLastError());
Exit(1);
}
else
printf("Return from driver is \"%s\"(%d)",bufOutput,nOutput);
}
http://qsyang.yeah.net
现代微机原理与接口技术
47
void Test_SAMPLE_IOCTL_Write(void)
{
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHARbufOutput[IOCTL_OUTBUF_SIZE];// Output from device
ULONG nOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_Write) in driver
printf("Issuing Ioctl to device - ");
strcpy(bufInput,"Now let us write this string.");
if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_Write,bufInput,
strlen(bufInput),NULL,0,&nOutput,NULL)) // 该函数参数分别是设备句柄,IO控制命令、写缓冲、写缓冲大小、读缓冲、读缓冲大小、实际读的字节数、覆盖结构指针(注意,这里的 bufInput是指 Input到设备,所以对应用软件这是写缓冲,bufOutput是从设备 output到应用程序,是读缓冲。
{
printf("ERROR,DeviceIoControl returns %0x.",
GetLastError());
Exit(1);
}
}
http://qsyang.yeah.net
现代微机原理与接口技术
48
c,使用 IO控制代码方式写并且读SampleDevice.cpp
NTSTATUS
SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
t << "Entering
SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler," << I <<
EOL;
char buff[512],buff1[512];
ULONG fwLength=0;
strcpy(buff,(PCHAR)I.IoctlBuffer());// 拷贝应用程序来的信息
t << "InputPut Data is \"" << buff << "\"" <<EOL;
strcpy(buff1,"this is feedback from driver! Application give me
this string \"");
strcat(buff1,buff);
strcat(buff1,“\”“); // 以上是组织反馈的信息
http://qsyang.yeah.net
现代微机原理与接口技术
49
fwLength = strlen(buff1)+1;
if (I.IoctlOutputBufferSize() >= fwLength)
{
strcpy((PCHAR)I.IoctlBuffer(),buff1);// 拷贝反馈信息
I.Information() = fwLength; // 设置反馈信息字节数
}
else
{
I.Information() = 0;
t << "buff size too small" << EOL;
}
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
50
Test_Sample.cpp
void Test_SAMPLE_IOCTL_ReadWrite(void)
{
bufOutput is written by the device to return data to this application
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from device
ULONGnOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_ReadWrite) in driver
printf("Issuing Ioctl to device - ");
strcpy(bufInput,"This is a sample.");
if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_ReadWrite,bufInput,
strlen(bufInput),bufOutput,IOCTL_OUTBUF_SIZE,&nOutput,NULL) )
{
printf("ERROR,DeviceIoControl returns %0x.",GetLastError());
Exit(1);
}
else
printf("Feedback is \"%s\"(%d)",bufOutput,nOutput);
}
http://qsyang.yeah.net
现代微机原理与接口技术
51
http://qsyang.yeah.net
现代微机原理与接口技术
52
http://qsyang.yeah.net
现代微机原理与接口技术
53
3)直接对端口寄存器读写
DriverStudio提供了 KIoRange类来将外部总线的 I/O地址空间范围映射到处理器总线的地址空间范围。
该类的成员函数主要有
KIoRange 构造函数 (4 种格式 )
Initialize 初始化和重新初始化一个实例 (3种格式 )
~KIoRange 析构函数
Invalidate 从已初始化状态删除该对象
IsValid 测试该对象是否已经初始化
inb 读一个或多个字节 (2 种形式 )
Outb 写一个或多个字节 (2 种形式 )
Inw 读一个或多个字 (2 种形式 )
Outw 写一个或多个字 (2 种形式 )
ind 读一个或多个双字 (2 种形式 )
outd 写一个或多个双字 (2 种形式 )
http://qsyang.yeah.net
现代微机原理与接口技术
54
KIoRange::KIoRange(只介绍 WDM形式)
FORM 3 (WDM):
KIoRange(
ULONGLONG CpuPhysicalAddress,//转换成外围设备地址的 CPU总线上的物理地址
BOOLEAN InCpuIoSpace,//如果 IO范围是在 CPU总线的 IO空间中为 TRUE,否则为 FALSE
ULONG Count,//以字节计的区域的大小
BOOLEAN MapToSystemVirtual =TRUE//指定是否需要构造函数创建一个非页系统空间的地址空间映射,如果驱动程序读写设备中的数据,就需要这种映射
);
FORM 4 (WDM),(注意,这种形式不被 DriverStudio 2.0支持。 )
KIoRange(
PCM_RESOURCE_LIST pTranslatedResourceList,//指向转换资源表的指针
ULONG Ordinal=0,//指定 pTranslatedResourceList指向的资源列表中的一个特殊端口资源
BOOLEAN MapToSystemVirtual =TRUE
);
FORM 5 (WDM):
KIoRange(
PCM_RESOURCE_LIST pTranslatedResourceList,//可通过 KIrp::TranslatedResources获得
PCM_RESOURCE_LIST pRawResourceList,//指向原始资源表的指针
ULONG Ordinal=0,
BOOLEAN MapToSystemVirtual =TRUE
);构造 KIoRange类。
http://qsyang.yeah.net
现代微机原理与接口技术
55
KIoRange::Initialize(只介绍 WDM形式)
FORM 2 (WDM):
NTSTATUS Initialize(
ULONGLONG CpuPhysicalAddress,
BOOLEAN InCpuIoSpace,
ULONG Count,
BOOLEAN MapToSystemVirtual=TRUE
);
FORM 3 (WDM),(注意,这种形式不被 DriverStudio 2.0支持。 )
NTSTATUS Initialize(
PCM_RESOURCE_LIST pTranslatedResourceList,
ULONG Ordinal=0,
BOOLEAN MapToSystemVirtual =TRUE
);
FORM 4 (WDM):
Initialize(
PCM_RESOURCE_LIST pTranslatedResourceList,
PCM_RESOURCE_LIST pRawResourceList,
ULONG Ordinal=0,
BOOLEAN MapToSystemVirtual =TRUE
);
初始化或重新初始化 KIoRange的实例。
http://qsyang.yeah.net
现代微机原理与接口技术
56
KIoRange::inb
FORM 1:
UCHAR inb( ULONG ByteOffset );
FORM 2:
VOID inb(
ULONG ByteOffset,
PUCHAR Buffer,
ULONG Count
);
从映射空间读一个或多个字节。
http://qsyang.yeah.net
现代微机原理与接口技术
57
KIoRange::outb
FORM 1:
VOID outb(
ULONG ByteOffset,//以字节为单位的目标位置到 IO空间开始位置的偏移值
UCHAR Data //要写的一个字节数据
);
FORM 2:
VOID outb(
ULONG ByteOffset,
PUCHAR Buffer,//指向包含要写数据的缓冲的指针
ULONG Count //缓冲中要写数据的字节数
);
写一个或多个字节到映射的 IO空间。
http://qsyang.yeah.net
现代微机原理与接口技术
58
写端口( 索引信息,地址 70H)
m_ParPortIos.outb(0,0x02); // 准备读分钟信息
读端口(读分钟信息,地址 71H)
UCHAR data = m_ParPortIos.inb(1);
下面我们来访问 CMOS的数据。
首先定义类 KIoRange的一个实例,以定义相关地址空间。
KIoRange m_ParPortIos;
初始化实例(指定 CMOS的端口首地址,并映射)
status = m_ParPortIos.Initialize(
0x70,// CMOS端口首地址是 70H
TRUE,//在 CPU I/O空间内
8,// 设备读写数据的字节宽度
TRUE // 映射到系统空间
);
http://qsyang.yeah.net
现代微机原理与接口技术
59
4) 截获中断和挂接中断服务例程
DriverStudio提供了 KInterrupt类来截获和挂接中断。
该类的成员函数主要有
KInterrupt 构造函数 (3种格式 )
Initialize 在无效状态下初始化一个对象 (3种格式 )
Connect 绑定 ISR(中断服务例程)到中断
InitializeAndConnect 一步完成初始化与绑定工作,要用资源列表作为输入。
~KInterrupt 析构函数
Invalidate 在初始化状态下删除对象
IsValid 检查对象是否初始化
Disconnect 使中断和 ISR与中断分离
Synchronize 当得到一个中断自旋锁时请求同步功能
http://qsyang.yeah.net
现代微机原理与接口技术
60
KInterrupt::KInterrupt(只介绍 WDM形式)
FORM 3,(WDM)
KInterrupt(
KIRQL irql,//即插即用设备提供的 IRQL值
ULONG vector,//即插即用设备提供的向量值
KINTERRUPT_MODE Mode,//LevelSensitive或 Latched中选一,
BOOLEAN bShareVector=FALSE,//该向量是否被几个设备共享
KAFFINITY affinity=1,//this is the processor affinity mask.
BOOLEAN bSaveFloat =FALSE //是否需要在中断到来使保存浮点处理器上下文,X86平台下必须使 FALSE
);
构造类 Kinterrupt的实例。
http://qsyang.yeah.net
现代微机原理与接口技术
61
KInterrupt::Initialize(只介绍 WDM形式)
FORM 2,(WDM)
VOID
Initialize(
KIRQL irql,
ULONG vector,
KINTERRUPT_MODE Mode,
BOOLEAN bShareVector=FALSE,
KAFFINITY affinity=1,
BOOLEAN bSaveFloat=FALSE
);
初始化对象。只在对象没有初始化的时候使用。
http://qsyang.yeah.net
现代微机原理与接口技术
62
KInterrupt::Connect
FORM 1:
NTSTATUS Connect(
PKSERVICE_ROUTINE Isr,//作为 ISR服务的函数的地址
PVOID Context //当系统调用 ISR的时候传递给他的无类型的参数
);
FORM 2:
NTSTATUS Connect(
PKSERVICE_ROUTINE Isr,
PVOID Context,
PKSPIN_LOCK pSpin,
KIRQL SynchIrql
);
绑定一个中断到 ISR(中断处理程序)。
http://qsyang.yeah.net
现代微机原理与接口技术
63
KInterrupt::InitializeAndConnect
NTSTATUS InitializeAndConnect(
PCM_RESOURCE_LIST pResourceList,//指向资源列表的指针
PKSERVICE_ROUTINE Isr,
PVOID IsrContext,
ULONG Ordinal=0,
BOOLEAN bSaveFloat=FALSE
);
初始化一个中断并绑定到一个 ISR上。
对于 WDM 驱动程序,pResourceList 必须是一个转换资源表,例如是 KIrp::TranslatedResources的返回值。
http://qsyang.yeah.net
现代微机原理与接口技术
64
下面我们来举例说明。
首先 定义类 KInterrupt的一个实例
KInterrupt m_TheInterrupt;
在设备类中声明一个成员函数 TheIsr作为中断服务例程
ISR。
class SampleDevice,public KPnpDevice
{ ……
public:
MEMBER_ISR (SampleDevice,TheIsr);
……
#ifdef _COMMENT_ONLY
BOOLEAN TheIsr( void) { return TRUE ; };
#endif
……
}
http://qsyang.yeah.net
现代微机原理与接口技术
65
在 OnStartDevice例程中获取包括中断的设备资源并初始化中断和挂接 ISR
SampleDevice,:OnStartDevice(KIrp I)
{
……
PCM_RESOURCE_LIST pResList =
I.TranslatedResources(); //获取设备资源
//初始化中断并挂接中断服务例程 TheIsr
status = m_TheInterrupt.InitializeAndConnect(
pResList,
LinkTo(TheIsr),
this
);
……
}
http://qsyang.yeah.net
现代微机原理与接口技术
66
5) 如何写 Win32类型的驱动程序的测试 程序
DriverStudio自动生成的驱动程序的测试程序是一个控制台程序,下面我们将利用该控制台程序来写一个 Win32
的程序。
第一步,在由 DriverStudio自动生成一个驱动程序工作区 (Workspace)中添加一个新的子工程,该子工程指定为一个 MFC的 EXE程序。 右键点击
http://qsyang.yeah.net
现代微机原理与接口技术
67
http://qsyang.yeah.net
现代微机原理与接口技术
68
第二步,手工在新的工程中添加几个文件这几个程序需要手工添加进去,实际上这几个程序都在 DriverStudio自动生成的原来的两个工程文件中 (
这个例子是 MyIOPort和
Test_MyIOPort工程 )。将他们添加到新工程中,方法是右键点击新工程中的相关文件夹,在弹出菜单中选择 Add Files to
Folder…,然后找到要添加的文件并添加。
http://qsyang.yeah.net
现代微机原理与接口技术
69
第三步,打开 OpenByIntf.cpp文件,在开始第一行添加
#include "stdafx.h"
第四步,1
2
3 4
5
C:\PROGRAM FILES\COMPUWARE\SOFTICE
DRIVER SUITE\DRIVERWORKS\INCLUDE
http://qsyang.yeah.net
现代微机原理与接口技术
70
第五步,1
2
3
4
setupapi.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
可以直接从自动生成的控制台工程的设置中拷贝这些库的名称
http://qsyang.yeah.net
现代微机原理与接口技术
71
最后,在控制台程序的 Test_XXXX.CPP程序基础上进行必要的修改。
注意要保留的是打开设备、关闭设备、读写设备有关的函数。界面部分应该全部换成 Windows界面的代码
,而不是保留控制台代码。