阅读:1912回复:11
驱动层和应用层缓冲区共享,尤其mengzi来看看
用ds进行应用层和驱动层的缓冲区应用(用来做dma)。
要把在驱动层创建的缓冲区地址映射到应用层线程,要让缓冲区既可以被应用程序写入数据和读出数据,又可以在驱动层用其物理地址作DMA。 有哪些函数是必须调用的?所用参数如何设置? LockPages() MapToUserSpace()/MapToSystemSpace() UnMap() Unlockpages() [编辑 - 7/18/02 by brucezh] [编辑 - 7/22/02 by brucezh] |
|
最新喜欢:![]()
|
沙发#
发布于: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页),当用户缓冲区的长度大于这个逻辑空间时,就只能进行分割传输。 |
|
板凳#
发布于:2002-07-25 17:02
多谢,也就是说,对于直接方式,从应用态向核心态和从核心态向应用态传输数据都应该通过OutputBuffer。
这里不进行内存锁定也不会出问题。 |
|
|
地板#
发布于:2002-07-25 13:01
brucezh兄:
上面的用户态程序的void Test_ASSERT_DMA_READ_IOCTL(void) 中有误,IOCTL_OUTBUF_SIZE应为10*4。 |
|
地下室#
发布于: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例程即可 } 上述,谨供参考。 |
|
5楼#
发布于:2002-07-22 14:10
我看到mengzi为别人做的这方面的解答,就自己试了一下。
用METHOD_IN_DIRECT。 应用程序把数据拷贝到OutputBuffer[],驱动中以以下方式得到地址: KMemory mem(I.Mdl()); PUCHAR p=mem.MapToSystemSpace(); 然后从p向驱动缓冲区拷贝数据。 最后向p写入处理结果,可是运行后兰屏,mengzi能不能细说一下正确的操作?多谢 |
|
|
6楼#
发布于:2002-07-22 13:29
可以看看其他的帖子呀。
共享内存的好多的。 |
|
7楼#
发布于:2002-07-22 13:15
顶一下
|
|
|
8楼#
发布于:2002-07-19 13:22
我把驱动层的缓冲区地址映射到应用层,好像可以写。
那如果要把应用层的数据复制到驱动层缓冲区,要怎么操作? DeviceIoctl应该用METHOD_IN_DIRECT还是METHOD_OUT_DIRECT? 帮助文件中说二者的输入缓冲区都是访问I.IoctlBuffer(),输出缓冲区都是访问I.Mdl(),究竟如何做呢?我想用METHOD_BUFFERED可以吗? |
|
|
9楼#
发布于:2002-07-18 16:40
这不是快与快的问题,如果说速度,实际上我在S5933上,至少平均能达到80MBS/s。一般来说,在内核级创建或分配或享有的资源,对于用户态都是没办法直接访问的,尽管是在一个进程中。这是NT式系统之所以健壮的原因之一,也是保护模式操作系统的一个特性。
|
|
10楼#
发布于:2002-07-18 16:31
翻过来好像没有这样快吧?
|
|
|
11楼#
发布于:2002-07-18 16:27
大哥,你为什么不反过来做呢?
|
|