为什么要有StartIO例程?
如果你开发了一个串口设备,并为其开发了一个驱动程序, 还有一个应用程序。用户使用这个应用程序来操作这个串口设备,进行读取或者写信数据。 现在你可以会面临这样一个问题,即如果你的应用程序使用多线程来同时对这个设备进行读取数据和写入数据时怎么办? 这样很可能就会乱成混乱。为了解决这个问题, windows提供了排队的机制, 因为每一次对设备的读操作或者写操作都是向驱动程序发送一个IRP包, 所以如果我们按照先后顺序对这些包进行排队, 一个一个的处理,这样就可以避免这种混乱了。 这就是startIO的目的。
操作系统为我们提供了一个队列用来存放IRP包, 这个队列是这样定义的:
typedef _KDEVICE_QUEUE
{
CSHORT type;
CSHORT size;
LIST_ENTRY DeviceListHead;
KSPIN_LOCK Lock;
BOOLEAN Busy;
}KDEVICE_QUEUE
其中的确DeviceListHead保存在设备对象的 DeviceObject->DeviceQueue中。 每一个设备对象用这个来管理自己收到的IRP包。
如果我们想要对某个IRP实现队列管理的话,我们需要在该IRP对就的派遣函数中调用内核函数IoStartPacket(), 这个函数内部会进行
一系列的操作,如果驱动现在正在忙着处理某个IRP的话(队列中的Busy标志为true),那么就将这个IRP放到队列里面。如果没有在
忙的话,那么就直接调用StartIO例程对它进行处理。这个处理过程和程序的目的有关,OS不可能为我们写出来,要我们根据自己的需求来写。
我们写好这个函数(helloWdmIO)后在driveEntry()中调用DriverObject->StartIO = helloWdmIO; 注册后,系统的IoStartPacket()就会自动调用
它了。在编写helloWdmIO()时,在处理完数据后一定要调用系统的IoStartNextPacket()函数,用来来开始处理队列中的下一个IRP包。
这样就实现了对设备的串行操作,不会引起混乱了。
在上述的解决方案中,所有的IRP都存放在一个队列中,不管是读的还是写的,这样显得有些混乱。如果你想把读操作和写操作分开来的话,你可以自己创建并维护一个队列,只不过这种情况下你需要自己来维护这个队列,自己的写出IOstartPacket等一些函数,不过没关系,系统提供了这睦函数供你调用。是个比较容易的工作。