hummingbird
驱动牛犊
驱动牛犊
  • 注册日期2003-10-13
  • 最后登录2004-02-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1405回复:4

WDM与应用程序通信问题

楼主#
更多 发布于:2003-12-23 15:34
一般参考书上都告诉我,WDM与应用程序通信,都是只有事件和DEVICEIOCTRL,能不能用共享内存的方式来实现通信呢?

驱动往应用层发数据时,每次都先用事件告诉应用程序,然后应用程序再用DEVICEIOCTRL回过头来读数据。能不能让驱动程序划一个专门的内存区,存放数据,当然数据到时,发事件给应用程序,应用程序直接读共享内存就可以了,这样方便很多。

当然我个人认为有点困难,DEVICEIOCTRL是从3级由操作系统提到0级来取数据,中间不明白操作系统到底作了什么,但我想如果从驱动程序方向由0级把数据送到3级能不能不可能啊?

不知道这算不算过于入门的话题,敬请解惑,谢谢

最新喜欢:

minewdyminewd...
reayi
驱动牛犊
驱动牛犊
  • 注册日期2002-11-06
  • 最后登录2010-03-30
  • 粉丝0
  • 关注0
  • 积分83分
  • 威望9点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2003-12-24 00:20
可以参考一下文章:应用程序和驱动之间的共享
Sharing Memory Between Drivers and Applications
Ó 2000 OSR Open Systems Resources, Inc.
Updated: 2002
 
At one time or another, most driver writers will have the need to share memory between a driver and a user-mode program. And, as with most such things, there are a wide variety of ways to accomplish the goal of sharing a block of memory between a driver and a user-mode application.  Some of these approaches are decidedly right and some are wrong. Two of the easiest techniques are:
 
? The application sends an IOCTL to the driver, providing a pointer to a buffer that the driver and the application thereafter share.
 
? The driver allocates a block of memory (from nonpaged pool for example), maps that block of memory back in the address space of a specific user-mode process, and returns the address to the application.
 
For the sake of brevity, we’ll restrict our discussion to these two, straightforward, techniques.  Other perfectly acceptable techniques include sharing a named section that’s backed by either the paging file or a memory mapped file.  Perhaps we’ll discuss those in a future article.  Also, note that this article won’t specifically address sharing memory that’s resident on a device.  While many of the concepts are the same, sharing device memory with a user-mode program brings with it its own set of special challenges.
 
Sharing Buffers Using IOCTLs
Sharing memory between a driver and a user-mode app using a buffer described with an IOCTL is the simplest form of “memory sharing”.  After all, it’s identical to the way drivers support other, more typical, I/O requests.  The base address and length of the buffer to be shared are specified by the application in the OutBuffer of a call to the Win32 function DeviceIoControl().  
 
The only interesting decision for the driver writer who uses this method of buffer sharing is which buffer method (or, “transfer type” as it’s known) to specify for the IOCTL.  Either METHOD_DIRECT (that is, using an MDL) or METHOD_NEITHER (using user virtual addresses) will work.  If METHOD_DIRECT is used, the user buffer will be locked into memory.  The driver will also need to call MmGetSystemAddressForMdlSafe() to map the described data buffer into kernel virtual address space. An advantage of this method is that the driver can access the shared memory buffer from an arbitrary process context, and at any IRQL.
 
There are a number of restrictions and caveats inherent in using METHOD_NEITHER to describe a shared memory buffer.  Basically, these are the same ones that apply any time a driver uses this method.  Chief among these is the rule that the driver must only access the buffer in the context of the requesting process.  This is because access to the shared buffer is via the buffer’s user virtual address.  This will almost certainly mean that the driver must be at the top of the device stack, called directly by the user application via the I/O Manager.  There can be no intermediate or file system drivers layered above the driver. Again practically speaking, this probably also means that the driver is restricted to accessing the user buffer from within its dispatch routines, when called by the requesting process.
 
Another important restriction inherent in using METHOD_NEITHER is that access by the driver to the user buffer must always be done at IRQL PASSIVE_LEVEL.  This is because the I/O manager hasn’t locked the user buffer in memory, and it could be paged out when accessed by the driver.  If the driver can’t meet this requirement, it will need to build an MDL and then lock the buffer in memory.
 
Another, perhaps less immediately obvious, restriction to this method
reayi
驱动牛犊
驱动牛犊
  • 注册日期2002-11-06
  • 最后登录2010-03-30
  • 粉丝0
  • 关注0
  • 积分83分
  • 威望9点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-12-24 00:24
另外可以用APC 机制让驱动程序调用应用程序的函数,参考代码:

#include \"ntddk.h\"
#include \"apc.h\"


NTSTATUS
DriverDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    );

VOID
DriverUnload(
    IN PDRIVER_OBJECT DriverObject
    );
    
NTSTATUS init();
void MapBuf(PVOID p);
void MyRoutine(struct _KAPC *Apc,
PKNORMAL_ROUTINE norm_routine,
void *context,
void *SysArg1,
void *SysArg2);
void SendAPC(ULONG addr, ULONG arg1, ULONG arg2, ULONG arg3);
ULONG APC_Routine=0;
PKTHREAD APC_Thread=NULL;
PVOID Buf=NULL;

void KeInitializeApc(struct _KAPC *Apc, PKTHREAD pthread,
unsigned char state_index,
PKKERNEL_ROUTINE ker_routine,
PKRUNDOWN_ROUTINE rd_routine,
PKNORMAL_ROUTINE nor_routine,
unsigned char mode,
void *context);

void KeInsertQueueApc(struct _KAPC *APC,
void *SysArg1,
void *SysArg2,
unsigned char arg4);


NTSTATUS init()
{
DbgPrint(\"%S:init\\n\",DRIVER_DEVICE_NAME);
return STATUS_SUCCESS;
}

struct _KAPC *apc;

void MyRoutine(struct _KAPC *Apc,
PKNORMAL_ROUTINE norm_routine,
void *context,
void *SysArg1,
void *SysArg2)
{
DbgPrint(\"%S:Kernel Routine\\n\",DRIVER_DEVICE_NAME);
ExFreePool(Apc);
return;
}

void SendAPC(ULONG addr, ULONG arg1, ULONG arg2, ULONG arg3)
{
unsigned char *b=NULL;
DbgPrint(\"%S:Send APC\\n\",DRIVER_DEVICE_NAME);
apc=ExAllocatePool(NonPagedPool, sizeof(struct _KAPC));
if(apc==NULL)
{
DbgPrint(\"%S:ExAllocatePool for APC fail.\\n\",DRIVER_DEVICE_NAME);
return;
}

/*
arg1=(ULONG)APC_Routine;
arg2=(ULONG)APC_Thread;
arg3=(ULONG)apc;*/

b=(unsigned char *)Buf;
if(b)
{
b[0]=\'a\';

b[2]=\'b\';

b[4]=\'c\';

}
KeInitializeApc(apc, APC_Thread, 0,(PKKERNEL_ROUTINE)&MyRoutine, 0,(PKNORMAL_ROUTINE)addr, 1, (PVOID)arg1);
KeInsertQueueApc(apc, (PVOID)arg2, (PVOID)arg3, 0);
}

void MapBuf(PVOID p)
{
PHYSICAL_ADDRESS pa;
pa=MmGetPhysicalAddress(p);
DbgPrint(\"%S:p:%08x,pa:%08x.\\n\",DRIVER_DEVICE_NAME,p,pa.LowPart);

Buf=MmMapIoSpace(pa,1024*4,FALSE);
if (Buf==NULL)

{
DbgPrint(\"%S:MmMapIoSpace Fail.\\n\",DRIVER_DEVICE_NAME);
return;

}
else
{
DbgPrint(\"%S:MmMapIoSpace OK:%08x.\\n\",DRIVER_DEVICE_NAME,Buf);
}


}


NTSTATUS
DriverEntry(IN PDRIVER_OBJECT  DriverObject,IN PUNICODE_STRING RegistryPath)
{

PDEVICE_OBJECT         deviceObject        = NULL;
NTSTATUS               ntStatus;
WCHAR                  deviceNameBuffer[]  = L\"\\\\Device\\\\\"DRIVER_DEVICE_NAME;
UNICODE_STRING         deviceNameUnicodeString;
WCHAR                  deviceLinkBuffer[]  = L\"\\\\DosDevices\\\\\"DRIVER_DEVICE_NAME;
UNICODE_STRING         deviceLinkUnicodeString;

DbgPrint(\"%S:DriverEntry\\n\",DRIVER_DEVICE_NAME);
RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer);
ntStatus = IoCreateDevice (DriverObject,
  0,
  &deviceNameUnicodeString,
  FILE_DEVICE_TESTSYS,
  0,
  FALSE,
  &deviceObject
  );

if (!NT_SUCCESS(ntStatus)) return ntStatus;
   RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer);
   ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,  &deviceNameUnicodeString);
   if (!NT_SUCCESS(ntStatus))
   {
       IoDeleteDevice (deviceObject);
       return ntStatus;
   }

ntStatus=init();

if (!NT_SUCCESS(ntStatus))
{
      IoDeleteDevice (deviceObject);
      IoDeleteSymbolicLink(&deviceLinkUnicodeString);
      return ntStatus;
}


   DriverObject->MajorFunction[IRP_MJ_CREATE]         = \\
  DriverObject->MajorFunction[IRP_MJ_CLOSE]          = \\
   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch;
   DriverObject->DriverUnload                         = DriverUnload;
   return STATUS_SUCCESS;

}


NTSTATUS
DriverDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
{
    PIO_STACK_LOCATION pCurStack;
    //NTSTATUS status;
    pmydata pData;
  
    
    
    pCurStack =IoGetCurrentIrpStackLocation(Irp);
    pData= (pmydata)Irp->AssociatedIrp.SystemBuffer;
    
    switch(pCurStack->MajorFunction)
    {
     case IRP_MJ_DEVICE_CONTROL:
     DbgPrint(\"%S: DriverDispatch:IRP_MJ_DEVICE_CONTROL\\n\",DRIVER_DEVICE_NAME);
     switch(pCurStack->Parameters.DeviceIoControl.IoControlCode)
     {
     case IOCTL_PASS_HANDLE:
     switch(pData->cmdType)
     {
     case PASS_APC_ROUTINE:
     APC_Routine=pData->APC_Routine;
     APC_Thread=KeGetCurrentThread();
     MapBuf(pData->Buf);
     DbgPrint(\"%S: APC_Routine:%08x,APC_Thread:%08x.\\n\",DRIVER_DEVICE_NAME,APC_Routine,APC_Thread);
     break;
    
     case CALL_APC_ROUTINE:
     if(APC_Routine) SendAPC(APC_Routine,0,0,0);
     break;
    
     default:
     break;
     }
     break;
     default:
    
     break;
    
     }
    
    
     break;
    
     case IRP_MJ_CREATE:
     DbgPrint(\"%S: DriverDispatch:IRP_MJ_CREATE\\n\",DRIVER_DEVICE_NAME);
     break;
    
     case IRP_MJ_CLOSE:
     DbgPrint(\"%S: DriverDispatch:IRP_MJ_CLOSE\\n\",DRIVER_DEVICE_NAME);
     break;
     default:
     break;
    }
    
    Irp->IoStatus.Status      = STATUS_SUCCESS;
    IoCompleteRequest (Irp,
                       IO_NO_INCREMENT
                       );
    return STATUS_SUCCESS; //Irp->IoStatus.Status;
}



VOID
DriverUnload(
    IN PDRIVER_OBJECT DriverObject
    )
{
    WCHAR                  deviceLinkBuffer[]  = L\"\\\\DosDevices\\\\\"DRIVER_DEVICE_NAME;
    UNICODE_STRING         deviceLinkUnicodeString;

    
    if (Buf) MmUnmapIoSpace(Buf,1024*4);      
    
    RtlInitUnicodeString (&deviceLinkUnicodeString,
                          deviceLinkBuffer
                          );

    IoDeleteSymbolicLink (&deviceLinkUnicodeString);
    IoDeleteDevice (DriverObject->DeviceObject);

    DbgPrint(\"%S:DriverUnload\\n\",DRIVER_DEVICE_NAME);
}

测试程序:
#include <windows.h>
#include <winioctl.h>

#include \".\\APC.h\"
void MyApcRoutine(ULONG arg1, ULONG arg2, ULONG arg3);
DWORD MyThread(PVOID param);

ULONG buf[1024]={0};


void main(int argc,char *argv[])
{

HANDLE Handle=0;
DWORD ThreadID;
 
Handle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&MyThread,0,0,&ThreadID);
if(Handle)
{
CloseHandle(Handle);
printf(\"APC Thread is running.\\n\");
}
else
{
printf(\"APC Thread Create fail.\\n\");
return;
}


printf(\"Press any key to end.\\n\");
_getch();


}


void MyApcRoutine(ULONG arg1, ULONG arg2, ULONG arg3)
{

printf(\"APC is called.\\n\");
printf(\"Buf:%S\\n\",(char *)buf);
//printf(\"arg1:%08x,arg2:%08x,arg3:%08x.\\n\",arg1,arg2,arg3);


}

DWORD MyThread(PVOID param)
{
DWORD retBytes;
HANDLE Handle;
mydata pData;
  int ret;



Handle = CreateFile(\"\\\\\\\\.\\\\sys_apc\",
   GENERIC_READ | GENERIC_WRITE,
   0,
   NULL,
   OPEN_EXISTING,
   0,
   NULL);
if (Handle == INVALID_HANDLE_VALUE)
{
printf(\"CreateFile Fail:%lx\\n\",GetLastError());
return 0;

}


pData.cmdType=PASS_APC_ROUTINE;
pData.APC_Routine=(ULONG)MyApcRoutine;
pData.Buf=(PVOID)&buf;
ret=DeviceIoControl(Handle,IOCTL_PASS_HANDLE,&pData,sizeof(pData),NULL,0,&retBytes,NULL);
if (ret==0)
{
printf(\"DeviceIoControl Error:%lx\\n\",GetLastError());
CloseHandle(Handle);
return 0;
}

 
CloseHandle(Handle);

printf(\"buf:%08x\\n\",pData.Buf);

printf(\"Wait APC CALL.\\n\");
while (TRUE)
SleepEx(-1, TRUE);

return 0;
}

hummingbird
驱动牛犊
驱动牛犊
  • 注册日期2003-10-13
  • 最后登录2004-02-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2003-12-24 09:52
天,晕哦,不过还是得仔细看,谢谢老大先
wangyupup
驱动牛犊
驱动牛犊
  • 注册日期2002-09-28
  • 最后登录2007-10-24
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2003-12-24 10:23
可以先用DDK函数:MmAllocateContiguousMemory()分配物理连续内存,然后将物理地址映射(map)成虚拟地址使用,DMA操作时使用物理地址,应用程序使用虚拟地址。可参考DDK文档或PLX SDK中的程序。
游客

返回顶部