jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
阅读:3738回复:12

关于Irp->MdlAddress以及direct io的讨论

楼主#
更多 发布于:2003-06-27 17:00
我在应用程序里开辟了一个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是自动后移的吗,还是需要我手动来移动,如果是手动的话我该怎么做?多谢了!





最新喜欢:

a_1984a_1984
swf2003
驱动中牛
驱动中牛
  • 注册日期2003-02-13
  • 最后登录2011-10-28
  • 粉丝1
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
沙发#
发布于: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 的整数倍。

---------------------------------
回答的对请支持
你的认可是对我最大的鼓励!
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-06-27 19:14
你的意思是说,我从usbd得到数据后,再在驱动里把这些数据拷贝到app提供的缓冲区中,也就是Irp->MdlAddress中,这样我觉得效率不是太好,我之所以想用前面的方法,就是因为我的设备数据率比较高,如果在拷贝一次,会不会占用比较多的时间呢,毕竟是比较大的一批数据呀。

要不我还用buffered io方式,我通过公共的头文件把开好的缓冲区地址传到驱动里,这样可以吗?
swf2003
驱动中牛
驱动中牛
  • 注册日期2003-02-13
  • 最后登录2011-10-28
  • 粉丝1
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
地板#
发布于:2003-06-30 09:07
用你的方式 Irp->MdlAddress 不能自动后移。
你用buffered io方式,其实也需要拷贝一次,因为I/0 管理器会用IRP->AssociatedIrp.SystemBuffer作为交换缓冲的,也就是说你也必须从它里面拷贝到用户缓冲区的。
你的认可是对我最大的鼓励!
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
地下室#
发布于: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,多谢了!!!
swf2003
驱动中牛
驱动中牛
  • 注册日期2003-02-13
  • 最后登录2011-10-28
  • 粉丝1
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2003-06-30 15:00
MmGetMdlByteCount 获得MDL描述的缓冲长度。
pAddr = MmGetSystemAddressForMdlSafe 获得MDL对应的系统空间的虚地址。

按如下拷贝
RtlCopyMemory(pAddr + i*singleTransferLength, ioBuffer, singleTransferLength);
你的认可是对我最大的鼓励!
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2003-06-30 15:14
十分感谢swf2003
感激之情不是这100分所能表达的了的
可是我除了这样表示之外没有别的办法了
谢谢!谢谢了!
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
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,
难道不能如上所用的方法使用吗?
swf2003
驱动中牛
驱动中牛
  • 注册日期2003-02-13
  • 最后登录2011-10-28
  • 粉丝1
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2003-07-29 13:15
pAddr + i*singleTransferLength 的地址没法定位,因为  pAddr 是 void * 类型,你把 pAddr 转换成 BYTE *型。
你的认可是对我最大的鼓励!
wjt810907
驱动中牛
驱动中牛
  • 注册日期2004-08-18
  • 最后登录2011-04-16
  • 粉丝0
  • 关注0
  • 积分86分
  • 威望409点
  • 贡献值1点
  • 好评度402点
  • 原创分2分
  • 专家分0分
9楼#
发布于:2007-02-26 15:29
jinghuiren大虾上面的问题解决了吗? 我想请教一下
mcu_boy
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2007-02-26 17:24
引用第8楼swf20032003-07-29 13:15发表的“”:
pAddr + i*singleTransferLength 的地址没法定位,因为  pAddr 是 void * 类型,你把 pAddr 转换成 BYTE *型。


答案
wjt810907
驱动中牛
驱动中牛
  • 注册日期2004-08-18
  • 最后登录2011-04-16
  • 粉丝0
  • 关注0
  • 积分86分
  • 威望409点
  • 贡献值1点
  • 好评度402点
  • 原创分2分
  • 专家分0分
11楼#
发布于:2007-02-26 18:44
谢谢jinghuiren大虾,我觉得你对驱动的理解挺深的,
很多问题都是看你的帖子搞清楚的,再次感谢!
mcu_boy
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2007-02-27 10:55
那说明我以前是大菜
东西都是问出来的。。
不过,现在是小菜了而已
游客

返回顶部