brucezh
驱动老牛
驱动老牛
  • 注册日期2002-01-30
  • 最后登录2007-02-01
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1912回复:11

驱动层和应用层缓冲区共享,尤其mengzi来看看

楼主#
更多 发布于:2002-07-18 16:13
用ds进行应用层和驱动层的缓冲区应用(用来做dma)。
要把在驱动层创建的缓冲区地址映射到应用层线程,要让缓冲区既可以被应用程序写入数据和读出数据,又可以在驱动层用其物理地址作DMA。
有哪些函数是必须调用的?所用参数如何设置?
LockPages()
MapToUserSpace()/MapToSystemSpace()
UnMap()
Unlockpages()


[编辑 -  7/18/02 by  brucezh]

[编辑 -  7/22/02 by  brucezh]

最新喜欢:

mapoflmapofl
打一枪……换个地方……再打一枪……
mengzi
驱动牛犊
驱动牛犊
  • 注册日期2001-08-02
  • 最后登录2004-05-25
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-07-26 21:14
brucezh兄:
    你说得很对,对于直接IO方式,总是使用OutBuffer,但我没有说清楚的是,对于缓冲IO,如使用InBuffer,则总是在内核态复制用户缓冲区,因而在使用时,就只能通过复制后的内核态的缓冲区地址进行访问,而对于直接IO方式,就是现在您用的这种方式,在用KMemory mem(I.Mdl())时,操作系统就会锁定用户缓冲区,并用MDL来描述改用户缓冲区(如用户态虚拟地址、cpu核心虚拟地址、缓冲区长度等等),我说的不对的地方在于,并没有进行数据传递,只是获取用户缓冲区的cpu核心虚拟地址(PULONG pBuffer = (PULONG) mem.MapToSystemSpace()),就可以在内核态对用户态缓冲区进行访问(在内核态可以访问任何资源),对于DMA就更复杂一些,同样是采用直接IO方式,但由于DMA传输需要物理地址连续的缓冲区,故在内核态必须分配一块物理地址连续的逻辑空间(称为映射寄存器),来作为中介(对于NT系统通常是16页),当用户缓冲区的长度大于这个逻辑空间时,就只能进行分割传输。
brucezh
驱动老牛
驱动老牛
  • 注册日期2002-01-30
  • 最后登录2007-02-01
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-07-25 17:02
多谢,也就是说,对于直接方式,从应用态向核心态和从核心态向应用态传输数据都应该通过OutputBuffer。
这里不进行内存锁定也不会出问题。
打一枪……换个地方……再打一枪……
mengzi
驱动牛犊
驱动牛犊
  • 注册日期2001-08-02
  • 最后登录2004-05-25
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-07-25 13:01
brucezh兄:
  上面的用户态程序的void Test_ASSERT_DMA_READ_IOCTL(void)
中有误,IOCTL_OUTBUF_SIZE应为10*4。
mengzi
驱动牛犊
驱动牛犊
  • 注册日期2001-08-02
  • 最后登录2004-05-25
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-07-25 12:59
brucezh兄:
关于DMA传输,请参看DriverWorks的pdf文件和help文件,敲入关键词查询即可,DMA的DS实现流程见pdf文件的第32页,该页展示的函数(Initiate、Continue、Terminate)封装的DDK调用见DS\\DriverWorks\\Source\\的Kdmaadapter.cpp、Kdmaxfer.cpp。编写者只需在StartIO例程的函数中调用Initiate例程(初始化并进行第一次分割传输),在DPC中调用Continue例程,编写者自己的回调函数中调用Terminate例程,关键是回调函数的编写,该回调函数的声明在Kdevice.h中,如果在开发过程中遇到具体问题,再继续交流。
   开发肯定是一步一步地来,首先是实现基本的IO访问(对于DS的DMA,用户缓冲区地址的获取和首次分割封装在Initiate例程中,以后的分割传输均在Continue中实现)。
   IO访问由两种方式,同步和异步,就是说需不需要进行IRP排队,对于DMA是要求异步的即排队的,因而DMA的实现必须是在StartIO例程的某个函数中启动DMA。所以这里只讲异步IO,又由于DMA只能采用直接IO方式,所以就只讲异步的直接IO方式的实现。
   譬如,测试你的数据是否传送进内核级并完成本次IRP,可以如下安排:
在用户态(应用程序)(从我的DMA写――写内存,改动成CPU写设备)
void Test_ASSERT_DMA_READ_IOCTL(void)
{
ULONG bufOutput[10]; // 32位传输
ULONG nOutput;

for(int i = 0; i< 10; i++)
bufOutput = i;        

if (!DeviceIoControl(hDevice,
   ASSERT_DMA_READ_IOCTL, //你可以有自己的CODE定义
   NULL,
   0,
   bufOutput,
   IOCTL_OUTBUF_SIZE,
   &nOutput,
  NULL)
   )
{
printf(\"ERROR: DeviceIoControl returns %0x.\", GetLastError());
Exit(1);
}
else
{
for(i =0; i<10; i++)
printf(\"return data is:%x\\n\", bufOutput;
}
}

检查一下DS的Wizard生成的XXioctrl.h的CODE定义,是否类似于下面,你可以直接修改
#define ASSERT_DMA_INCEPT_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_OUT_DIRECT, FILE_READ_DATA)
由于是测试数据是否传输到驱程,所以可以将METHOD_OUT_DIRECT改成METHOD_IN_DIRECT,其实不该也不影响,因为只是有关操作系统检查缓冲区的时机问题,在驱程中,譬如StartIO例程中的
NTSTATUS xxDevice::Serial_ASSERT_DMA_INCEPT_IOCTL_Handler(KIrp I)
{
     KMemory Mem(I.Mdl());
    PULONG pBuffer = (PULONG) Mem.MapToSystemSpace();//获取用户缓冲区的CPU核心虚拟地址,注意这里是32位传输
ULONG   dwTotalSize = I.IoctlOutputBufferSize();
for(int i=0; i<dwTotalSize ;i++)//显示从用户态传递进来的数据
    DbgPrint(\"Inputdata is %x\", pBuffer);
I.Information() = dwBytesRead;
//m_RangeMemory.outd(0x0, pBuffer,dwBytesRead/4);肯定有猝发传输
//或者for(i =0; i<10; i++)
//m_RangeIo.outd((i*4), pBuffer);
I.Status() = status;
m_DriverManagedQueue.NextIrp(I);//完成本次IRP返回到用户态,对于DMA,完成IRP返

回是在用户的回调函数中进行的,而且只需调用Initate例程即可
}
上述,谨供参考。

brucezh
驱动老牛
驱动老牛
  • 注册日期2002-01-30
  • 最后登录2007-02-01
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-07-22 14:10
我看到mengzi为别人做的这方面的解答,就自己试了一下。
用METHOD_IN_DIRECT。
应用程序把数据拷贝到OutputBuffer[],驱动中以以下方式得到地址:

KMemory mem(I.Mdl());
PUCHAR p=mem.MapToSystemSpace();
然后从p向驱动缓冲区拷贝数据。
最后向p写入处理结果,可是运行后兰屏,mengzi能不能细说一下正确的操作?多谢
打一枪……换个地方……再打一枪……
arthurtu
驱动巨牛
驱动巨牛
  • 注册日期2001-11-08
  • 最后登录2020-12-19
  • 粉丝0
  • 关注0
  • 积分26分
  • 威望161点
  • 贡献值0点
  • 好评度35点
  • 原创分0分
  • 专家分0分
  • 社区居民
6楼#
发布于:2002-07-22 13:29
可以看看其他的帖子呀。
共享内存的好多的。
brucezh
驱动老牛
驱动老牛
  • 注册日期2002-01-30
  • 最后登录2007-02-01
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-07-22 13:15
顶一下
打一枪……换个地方……再打一枪……
brucezh
驱动老牛
驱动老牛
  • 注册日期2002-01-30
  • 最后登录2007-02-01
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-07-19 13:22
我把驱动层的缓冲区地址映射到应用层,好像可以写。

那如果要把应用层的数据复制到驱动层缓冲区,要怎么操作?
DeviceIoctl应该用METHOD_IN_DIRECT还是METHOD_OUT_DIRECT?
帮助文件中说二者的输入缓冲区都是访问I.IoctlBuffer(),输出缓冲区都是访问I.Mdl(),究竟如何做呢?我想用METHOD_BUFFERED可以吗?
打一枪……换个地方……再打一枪……
mengzi
驱动牛犊
驱动牛犊
  • 注册日期2001-08-02
  • 最后登录2004-05-25
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-07-18 16:40
这不是快与快的问题,如果说速度,实际上我在S5933上,至少平均能达到80MBS/s。一般来说,在内核级创建或分配或享有的资源,对于用户态都是没办法直接访问的,尽管是在一个进程中。这是NT式系统之所以健壮的原因之一,也是保护模式操作系统的一个特性。
brucezh
驱动老牛
驱动老牛
  • 注册日期2002-01-30
  • 最后登录2007-02-01
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-07-18 16:31
翻过来好像没有这样快吧?
打一枪……换个地方……再打一枪……
mengzi
驱动牛犊
驱动牛犊
  • 注册日期2001-08-02
  • 最后登录2004-05-25
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-07-18 16:27
大哥,你为什么不反过来做呢?
游客

返回顶部