阅读:3738回复:12
关于Irp->MdlAddress以及direct io的讨论
我在应用程序里开辟了一个32MB的缓冲区,然后用deviceiocontrol把缓冲区的地址传到驱动里,ioctl方式是direct_io如下:
UCHAR *pDataBuffer; ULONG ulLength = 32*1024*1024; BOOLEAN bResult = FALSE; ULONG nBytes = 0; pDataBuffer= (unsigned char *)malloc (ulLength); bResult = DeviceIoControl(hDevice, IOCTL_ISP1581_BULK_READ, NULL, 0, pDataBuffer, ulLength, &nBytes, NULL); 因为usb一次不可能申请这么多的数据,因此我需要在驱动里进行多次传输。在驱动程序中,首先通过Irp->MdlAddress得到ulLenth,如下: ULONG bufferLength = MmGetMdlByteCount(Irp->MdlAddress); ULONG singleTransferLength = 64*1024; 然后循环向usbd申请数据,比如我每次申请64k的数据。例程如下: for(int i = 0; i< 512; i++) { UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb urbSize, //size of urb pipeHandle, //usbd pipe handle NULL, //TransferBuffer Irp->MdlAddress, //mdl singleTransferLength, //bufferlength transferFlags, //flags NULL); //link ntStatus = D12_CallUSBD(DeviceObject, urb);// 向usbd申请数据。 } 现在问题是:我第一次申请了64k数据,那么第二次申请的时候地址指针该怎么变化,Irp->MdlAddress是自动后移的吗,还是需要我手动来移动,如果是手动的话我该怎么做?多谢了! |
|
最新喜欢:![]() |
沙发#
发布于:2003-06-27 17:37
1、
UsbBuildInterruptOrBulkTransferRequest ( ... IN PVOID TransferBuffer OPTIONAL, IN PMDL TransferBufferMDL OPTIONAL, ... )只需要一个。 2、我觉得你这样做, TransferBuffer 需要,TransferBufferMDL 参数为NULL。你可以申请一块 64*1024 大小的 TransferBuffer ,然后把 TransferBuffer 拷贝到你的 Irp->MdlAddress 对应的用户缓冲区的对应位置。 这个 TransferBuffer 是重复使用的,而拷贝的目的地址即Irp->MdlAddress 对应的用户缓冲区中的偏移你需要自己算,这简单是64*1024 的整数倍。 --------------------------------- 回答的对请支持 |
|
|
板凳#
发布于:2003-06-27 19:14
你的意思是说,我从usbd得到数据后,再在驱动里把这些数据拷贝到app提供的缓冲区中,也就是Irp->MdlAddress中,这样我觉得效率不是太好,我之所以想用前面的方法,就是因为我的设备数据率比较高,如果在拷贝一次,会不会占用比较多的时间呢,毕竟是比较大的一批数据呀。
要不我还用buffered io方式,我通过公共的头文件把开好的缓冲区地址传到驱动里,这样可以吗? |
|
地板#
发布于:2003-06-30 09:07
用你的方式 Irp->MdlAddress 不能自动后移。
你用buffered io方式,其实也需要拷贝一次,因为I/0 管理器会用IRP->AssociatedIrp.SystemBuffer作为交换缓冲的,也就是说你也必须从它里面拷贝到用户缓冲区的。 |
|
|
地下室#
发布于:2003-06-30 14:24
你说的意思我明白了,现在假如我先把数据读到TransferBuffer里,然后再手动拷贝到Irp->MdlAddress中,这个偏移地址该怎么计算呢,是在Irp->MdlAddress.ByteOffset吗,下面是mdl结构的定义,你还是送佛送到西,帮我帮到底吧:
typedef struct _MDL { struct _MDL *Next; CSHORT Size; CSHORT MdlFlags; struct _EPROCESS *Process; PVOID MappedSystemVa; PVOID StartVa; ULONG ByteCount; ULONG ByteOffset; } MDL, *PMDL; 比如我读回了64k的数据,历程如下, PVOID ioBuffer = Irp->AssociatedIrp.SystemBuffer; ……//发送urb给usbd读取数据, 然后将读回来的数据从ioBuffer复制到Irp->MdlAddress: RtlCopyMemory(Irp->MdlAddress, ioBuffer, singleTransferLength); 那么下面偏移地址怎么计算???也就是说我下一次拷贝数据是怎样才能拷贝到Irp->MdlAddress的下一个64k内存中呢。 我初学驱动,所以对这些基本的东西一点都不懂,实在是麻烦你了swf2003,多谢了!!! |
|
5楼#
发布于:2003-06-30 15:00
MmGetMdlByteCount 获得MDL描述的缓冲长度。
pAddr = MmGetSystemAddressForMdlSafe 获得MDL对应的系统空间的虚地址。 按如下拷贝 RtlCopyMemory(pAddr + i*singleTransferLength, ioBuffer, singleTransferLength); |
|
|
6楼#
发布于:2003-06-30 15:14
十分感谢swf2003
感激之情不是这100分所能表达的了的 可是我除了这样表示之外没有别的办法了 谢谢!谢谢了! |
|
7楼#
发布于:2003-07-29 11:00
swf2003,还得麻烦你,这是不好意思,我在实现你上面提到的方法时,拷贝数据那一行出现错误error C2036: \'void *\' : unknown size,我的方法如下:
方法1: PVOID ioBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG SingleTransferLength; ULONG bufferLength = MmGetMdlByteCount(Irp->MdlAddress); PVOID pMdlAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 然后用UsbBuildInterruptOrBulkTransferRequest()循环读取数据放到ioBuffer中,每次成功返回后都拷贝数据如下: RtlCopyMemory((pMdlAddress + i*SingleTransferLength), ioBuffer, SingleTransferLength); 方法2: 唯一与上面不同的是我用ExAllocatePool()给ioBuffer分配了SingleTransferLength大小的内存,但编译的时候都出现开始提到的错误,在拷贝那一行出现错误:\'void *\' : unknown size, 难道不能如上所用的方法使用吗? |
|
8楼#
发布于:2003-07-29 13:15
pAddr + i*singleTransferLength 的地址没法定位,因为 pAddr 是 void * 类型,你把 pAddr 转换成 BYTE *型。
|
|
|
9楼#
发布于:2007-02-26 15:29
jinghuiren大虾上面的问题解决了吗? 我想请教一下
|
|
|
10楼#
发布于:2007-02-26 17:24
引用第8楼swf2003于2003-07-29 13:15发表的“”: 答案 |
|
11楼#
发布于:2007-02-26 18:44
谢谢jinghuiren大虾,我觉得你对驱动的理解挺深的,
很多问题都是看你的帖子搞清楚的,再次感谢! |
|
|
12楼#
发布于:2007-02-27 10:55
那说明我以前是大菜
东西都是问出来的。。 不过,现在是小菜了而已 |
|