6073|10

76

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

USB驱动程序中接受到数据但应用程序接收的数据全部为零,问题在什么地方?高手帮忙看看 [复制链接]

USB驱动程序中接受到数据但应用程序接收的数据全部为零,问题在什么地方?

实际情况如下:
有一设备通过USB与主机通信。在主机上有该设备的USB驱动程序和实际应用程序:
驱动程序: 驱动程序提供Read和Write函数接口,并有OnReadWriteComplete函数,该函数在读写操作完成后调用。
在主机应用程序: 通过CreateFile,ReadFile,WaitForMultipleObjects,GetOverlappedResult接收USB数据。

目前问题:
大部分时候USB通信正常,主机应用程序接受到的数据与OnReadWriteComplete中打印(调试状态打印)的数据一直,到那时有时候在 OnReadWriteComplete打印出正常的数据(与设备端发送的数据完全一致),但是在主机应用程序中接收不到正确的数据,在 GetOverlappedResult函数中返回了正确的数据长度,但是接受数据全部为零。
问题很奇怪,如果说是USB驱动的问题,但是绝大部分时候通信正常,而且在驱动程序中也接收到了正确的数据。如果是应用程序出了问题,但是 CreateFile,ReadFile,WaitForMultipleObjects,GetOverlappedResult 都是kernel32.dll中的函数,应该不会有问题。
而且我也不清楚如何进行调试这些函数?
那位大侠有不同的见解,有没有软件或者调试工具可以截取到驱动和应用程序之间的通信? 3x

最新回复

我用DbgView看了下系统输出打印: 00002404        7:03:02 PM        [2380] My Test ReadFile begin: 0x153441C                 00002407        7:03:02 PM        [DispatchReadWrite] start        00002411                7:03:02 PM        [StartIo] Read Operation        00002412        7:03:02 PM        [StartIo] - Length 1024        00002413        7:03:02 PM        [StartPacket] end        00002414        7:03:02 PM        [DispatchReadWrite] end        00002415        7:03:02 PM        [2380] My Test ReadFile end. 00002416        7:03:02 PM        [2380] My Test WaitForMultipleObjects begin. 00002419        7:03:02 PM        [OnReadWriteComplete] start        00002420        7:03:02 PM        [OnReadWriteComplete] - NT Status:        SUCCESS                               - Length Remaining: 0                               - Cancel Irp:       FAILURE                               - Xfer Length:      40                               - Direction:        Read File        00002421        7:03:02 PM        Begin read data:         00002422        7:03:02 PM        TransferBufferMDL.ByteOffset:  28         00002423        7:03:02 PM        ctx data at 0x ba4db858: a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5!!!        00002427        7:03:02 PM        IRP data at 0x ba4db854: a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5!!!        00002431        7:03:02 PM        End read data.        00002432        7:03:02 PM        [OnReadWriteComplete] end        00002433        7:03:02 PM        [2380] My Test WaitForMultipleObjects end.         00002434        7:03:02 PM        [2380] My Test GetOverlappedResult begin.         00002435        7:03:02 PM        [2380] My Test GetOverlappedResult end. 00002438        7:03:02 PM        [2380] Read length: 40 00002438        7:03:02 PM        [2380] Read data:        [2380]后面对应的是应用程序打印的调试信息,其余为驱动程序中打印的信息。从打印的消息中可以看出 1. WaitForMultipleObjects确实阻塞,等到[OnReadWriteComplete]完成后才执行。 2. [OnReadWriteComplete]中接收到了数据,Irq和Ctx中的MDL缓冲区都有数据,数据完全相同。而且通过MmGetSystemAddressForMdlSafe函数取得的地址相差4个字节,不知道有什么含义?(比较过其它的数据包,都相差4个字节) 3. GetOverlappedResult执行成功,得到正确的数据长度,但是接收缓冲区为零。   详情 回复 发表于 2009-6-3 22:42
点赞 关注

回复
举报

60

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
关注~~
 
 

回复

60

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
1.createfile是否正确HANDLE了设备ID?
2.WaitForMultipleObjects,GetOverlappedResult只为保证READ,WRITE得到合理的延时,并不能保证数据正确.
3.我看你首先检查ReadFile的nByteRead参数,是否和发送端的长度一致.
4.如果nByteRead不为零,检查InBuffer[]里的数据格式要和发送端的一致,比如发送的N*8BIT你用int去读了.HEHE


softice,Windbg,都是
截取到驱动和应用程序之间的通信的工具,不过依你目前的认识基本不会用。


建议楼主自己去写USB驱动.用DriverWorks,简单的数据传送基本靠例子就行.但可以帮助你提高认识.不然你写出来的程序也是垃圾.
 
 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

4
 
关注...
 
 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

5
 
tonghengzhi,可能我没有把问题说清楚,不过你提到的几个错误是最基本的错误,我仔细检查过不是这些原因,还是多谢。
我的驱动程序和应用程序都可以工作,而且大部分情况下通信正常,发送和接收都正常,不可能是上面的问题。
目前拿到驱动程序源代码,大概研究了一下,以前没有怎么做过驱动方面的开发,从code上我的理解如下:
1. 驱动中指定了应用程序的入口函数,ReadFile应该对应:IRP_MJ_READ 函数: DispatchRead;
2. 驱动程序应该采用的Direct I/O读写方式,在AddDevice函数中有设置: fdo->Flags |= DO_DIRECT_IO;
3. 在读数据函数DispatchRead中有不行设置检测,不是很清楚各自的功能,不过主要应该是这几个函数UsbBuildInterruptOrBulkTransferRequest,IoSetCompletionRoutine,IoCallDriver。我自己理解是UsbBuildInterruptOrBulkTransferRequest创建一些USB通信需要的数据结构,IoSetCompletionRoutine将这些数据构建到IRP包中,IoCallDriver交给底层驱动去完成,应该是windows中的驱动去完成。
4. 在3中的IoSetCompletionRoutine函数中设置了OnReadWriteComplete,在每次接收完成后调用。
在应用程序方面采用的是 CreateFile,ReadFile,WaitForMultipleObjects,GetOverlappedResult等函数,都是kernel32.dll中的函数,应没有问题,而且大部分时候执行正常,丢包只是很少数,目前也没有什么规律,肯通信10分钟才开始丢包,也可能1分钟就开始丢吧。丢包都是GetOverlappedResult函数。
ReadFile函数时会传入读buffer和长度(我传入的长度够长,比发送的数据包长度要长),如果当前没有数据直接返回,调用WaitForMultipleObjects等待驱动接收到数据,到等到驱动接收到数据后用GetOverlappedResult函数得到接收到的结果。
目前GetOverlappedResult中得到的接收数据长度正确,但是读buffer中的数据都为零。
比较困惑,在驱动的OnReadWriteComplete中打印出读取的数据,显示都是对的,长度也是对的,但是应用程序中只得到接收数据的长度,既然在OnReadWriteComplete中得到了数据,那么驱动应该就将数据写到应用程序的buffer中了,然后才发消息通知,应用程序执行GetOverlappedResult得到结果,但是为什么GetOverlappedResult得到了正确的结果(没有返回如何错误),而且长度也是对的,而接收buffer中没有值? 而且驱动是Direct I/O,是不是驱动直接使用的是应用程序的缓冲区作为接收缓冲,那么应用程序的接收buffer应该是有值的?
还有我的应用程序是多线程的,大概运行的时候有5个以上的线程,收发线程是互斥的,但是还有解析线程和界面响应线程等在不停的运行,会是线程冲突?但是没有应该就接收buffer被冲了,我的循环接收的buffer是每次都new一个新的buffer,接收到数据后发个解析线程,有解析线程释放。
目前好像驱动也可能有问题,应用程序也可能有问题,但是具体是为什么完全没有头绪,那位大侠指点一下。3x
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

6
 
自己顶一下先
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

7
 
关注
 
 
 

回复

54

帖子

0

TA的资源

一粒金砂(初级)

8
 
目前GetOverlappedResult中得到的接收数据长度正确,但是读buffer中的数据都为零。 ????

你工作了一小时以后才出现上面问题?

贴你的驱动程序的READ段来看看,
              设备端的WRIE段,PIPE申明段,
                  程序的数据读取段.
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(中级)

9
 
我的驱动程序里面关键有两个函数StartIO和OnReadWriteComplete,read和write的入口函数里面只是做了些错误检查,然后都是调用StartIO函数。
VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp)
  {
          //KdPrint(("[ StartIo] start"));
          PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

          NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);
          if (!NT_SUCCESS(status))
          {
                  CompleteRequest(Irp, status, 0);
                  KdPrint(("[ .StartIo] end - !NT_STATUS(status)"));
                  return;
          }
          PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
          BOOLEAN read = stack->MajorFunction == IRP_MJ_READ;
          
          if (read)
                  KdPrint(("[StartIo] Read Operation"));
          else
                  KdPrint(("[StartIo] Write Operation"));
          
          USBD_PIPE_HANDLE hpipe = read ? pdx->hinpipe : pdx->houtpipe;
          
          PRWCONTEXT ctx = (PRWCONTEXT) ExAllocatePool(NonPagedPool, sizeof(RWCONTEXT));
          if (!ctx)
          {
                  KdPrint((DRIVERNAME " - Can't allocate memory for context structure\n"));
                  StartNextPacket(&pdx->dqReadWrite, fdo);
                  CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
                  IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
                  return;
          }
          RtlZeroMemory(ctx, sizeof(RWCONTEXT));
          ULONG length = Irp->MdlAddress ?  MmGetMdlByteCount(Irp->MdlAddress) : 0;
          KdPrint(("[StartIo] - Length %d\n", length));
          
          if (!length && !read && FALSE) // zero-length write
          {                                               
                  ....//零长度写,没有执行过
                  return;
          }
          
          if (!length) // zero-length read
          {                                               
                  .... //零长度读,没有执行过
                  return;
          }
          
          ULONG_PTR va = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
          ULONG urbflags =  USBD_SHORT_TRANSFER_OK |
                  (read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);
          
          ULONG seglen= length;
          if (seglen > pdx->maxtransfer)
          {
                  seglen = pdx->maxtransfer;
                  KdPrint((DRIVERNAME " - Read/write of %d bytes will be done in segments of %d\n",
                          length,
                          seglen));
          }
          //---------------------------------------------------------------------------
          // Allocate an MDL for each segment of the transfer. The parameters are chosen so
          // that the MDL will have room for a maximum-sized buffer in the worst case where
          // it starts just before a page boundary. (Note that the virtual address argument to
          // IoAllocateMdl is not actually used as an address.)
          //---------------------------------------------------------------------------
          PMDL mdl = IoAllocateMdl((PVOID) (PAGE_SIZE - 1), seglen, FALSE, FALSE, NULL);
          if (!mdl) // can't allocate MDL
          {
                  KdPrint((DRIVERNAME " - Can't allocate memory for MDL\n"));
                  ExFreePool(ctx);
                  StartNextPacket(&pdx->dqReadWrite, fdo);
                  CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
                  IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
          }
          
          //---------------------------------------------------------------------------
          // Initialize the (partial) MDL to describe the first segment's subset of the user  buffer.
          //---------------------------------------------------------------------------
          IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) va, seglen);
          
          //---------------------------------------------------------------------------
          // Reader Peter Diaconesco ran across an apparent bug in the Win2K version of
          // UHCD.SYS. Under heavy load conditions, UHCD was bug-checking because its
          // internal call to MmGetSystemAddressForMdl was apparently returning NULL
          // (even though it's not supposed to). We can prevent that problem by mapping
          // the pages in the following "safe" manner:
          //---------------------------------------------------------------------------
          
          if (!GenericGetSystemAddressForMdl(mdl)) // can't map transfer segment
          {
                  KdPrint((DRIVERNAME " - Can't map memory for read or write\n"));
                  ExFreePool(ctx);
                  StartNextPacket(&pdx->dqReadWrite, fdo);
                  CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
                  IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
                  return;
          }
          UsbBuildInterruptOrBulkTransferRequest(ctx,
                  sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
                  hpipe,
                  NULL,
                  mdl,
                  seglen,
                  urbflags,
                  NULL);
          //---------------------------------------------------------------------------
          // Set context structure parameters to pick up where we just left off
          //---------------------------------------------------------------------------
          ctx->va = va + seglen;
          ctx->length = length - seglen;
          ctx->mdl = mdl;
          ctx->numxfer = 0;
          //---------------------------------------------------------------------------
          // Use the original Read or Write IRP as a container for the URB
          //---------------------------------------------------------------------------
          stack = IoGetNextIrpStackLocation(Irp);
          stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
          stack->Parameters.Others.Argument1 = (PVOID) (PURB) ctx;
          stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
          //KdPrint((" \n TransferBufferMDL:        %x \n", ctx->UrbBulkOrInterruptTransfer.TransferBufferMDL));
          
          IoSetCompletionRoutine(Irp,
                  (PIO_COMPLETION_ROUTINE) OnReadWriteComplete,
                  (PVOID)ctx,
                  TRUE,
                  TRUE,
                  TRUE);
          IoCallDriver(pdx->LowerDeviceObject, Irp);
          //KdPrint(("[ .StartIo] end"));
  } //end:StartIo
 
 
 

回复

94

帖子

0

TA的资源

一粒金砂(初级)

10
 
NTSTATUS OnReadWriteComplete(PDEVICE_OBJECT fdo, PIRP Irp, PVOID p_ctx)
{
          PRWCONTEXT ctx = (PRWCONTEXT)p_ctx;
          KdPrint(("[OnReadWriteComplete] start"));
          PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
          BOOLEAN read = (ctx->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) != 0;
          ctx->numxfer += ctx->UrbBulkOrInterruptTransfer.TransferBufferLength;
          
          //---------------------------------------------------------------------------
          // If this stage completed without error, resubmit the URB to perform the
          // next stage
          //---------------------------------------------------------------------------
          NTSTATUS status = Irp->IoStatus.Status;
          KdPrint(("[OnReadWriteComplete] - NT Status:        %s"
                  "                               - Length Remaining: %d"
                  "                               - Cancel Irp:       %s"
                  "                               - Xfer Length:      %d"
                  "                               - Direction:        %s",
                  NT_SUCCESS(status) ? "SUCCESS" : "FAILURE",
                  ctx->length,
                  Irp->Cancel ? "SUCCESS" : "FAILURE",
                  ctx->UrbBulkOrInterruptTransfer.TransferBufferLength,
                  read ? "Read File" : "Write File"));
          
          if( read)
          {//我自己添加的打印接收数据的函数,目前打印的是ctx中的,Irp中不知道怎么打印
                          KdPrint(("Just test read data: "));
                        //Print out the read data.
                        if( ctx->UrbBulkOrInterruptTransfer.TransferBufferLength > 0)
                        {
                                unsigned char tempbuf[255];
                                if( ctx->UrbBulkOrInterruptTransfer.TransferBufferMDL != NULL)
                                {
                                        unsigned char buf[555];
                                        memset(buf ,0 ,555);
                                        PVOID pbuffer = MmGetSystemAddressForMdlSafe(ctx->UrbBulkOrInterruptTransfer.TransferBufferMDL, HighPagePriority);
                                        memcpy( buf, pbuffer, 200);
                                        KdPrint(("ctx data at 0x %x: %s!!!", &pbuffer, buf));
                                }
if( Irp->MdlAddress != NULL )
                {
                       
                        unsigned char buf1[555];
                        memset(buf1 ,0 ,555);
                        PVOID pbuffer1;
                        pbuffer1 = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
                        memcpy( buf1, pbuffer1, 200);
                        KdPrint(("IRP data at 0x %x: %s!!!", &pbuffer1, buf1));
                       
                }                       
                        }
          }
          
          if (NT_SUCCESS(status) && ctx->length && !Irp->Cancel) // start next stage
          {                                                // start next stage
                ...
                //数据包比较大需多次传输时使用的,没有执行过
          } //end:if (NT_SUCCESS(status) && ctx->length && !Irp->Cancel) // start next stage

          //---------------------------------------------------------------------------
          // The request is complete now
          //---------------------------------------------------------------------------
FinishCompletion: // label reached if MDL locking fails
          if (NT_SUCCESS(status))
                  Irp->IoStatus.Information = ctx->numxfer;
          else
          { // had an error
                  ....
                  
          } //end:else (NT_SUCCESS(status)) // had an error
          
          IoFreeMdl(ctx->mdl);
          ExFreePool(ctx);
          StartNextPacket(&pdx->dqReadWrite, fdo);
          IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
          
          KdPrint(("[OnReadWriteComplete] end"));
          return STATUS_SUCCESS; // allow IRP to continue completing
} //end:OnReadWriteComplete

我自己的理解:
1.        Read函数调用StartIO时应该已经创建了MDL缓冲区,就是Irp中的Irp->MdlAddress。问题是这个缓冲区和用户应用程序传入的缓冲用联系吗?指向同一块内存?
2.        在StartIO中,又创建了一个MDL缓冲区,并且通过IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) va, seglen);将两个MDL缓冲区映射联系起来,没有完全明白IoBuildPartialMdl函数有什么作用,将两个MDL关联起来,任何一个改动另外一个跟着改动?
3.        USB的数据应该都是通过URB进行传输的,看起来好像在StartIO中创建的URB用的是新建的MDL,而去不是Irp中的MDL。
 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(初级)

11
 
我用DbgView看了下系统输出打印:
00002404        7:03:02 PM        [2380] My Test ReadFile begin: 0x153441C                
00002407        7:03:02 PM        [DispatchReadWrite] start       
00002411                7:03:02 PM        [StartIo] Read Operation       
00002412        7:03:02 PM        [StartIo] - Length 1024       
00002413        7:03:02 PM        [StartPacket] end       
00002414        7:03:02 PM        [DispatchReadWrite] end       
00002415        7:03:02 PM        [2380] My Test ReadFile end.
00002416        7:03:02 PM        [2380] My Test WaitForMultipleObjects begin.
00002419        7:03:02 PM        [OnReadWriteComplete] start       
00002420        7:03:02 PM        [OnReadWriteComplete] - NT Status:        SUCCESS                               - Length Remaining: 0                               - Cancel Irp:       FAILURE                               - Xfer Length:      40                               - Direction:        Read File       
00002421        7:03:02 PM        Begin read data:        
00002422        7:03:02 PM        TransferBufferMDL.ByteOffset:  28        
00002423        7:03:02 PM        ctx data at 0x ba4db858: a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5!!!       
00002427        7:03:02 PM        IRP data at 0x ba4db854: a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5!!!       
00002431        7:03:02 PM        End read data.       
00002432        7:03:02 PM        [OnReadWriteComplete] end       
00002433        7:03:02 PM        [2380] My Test WaitForMultipleObjects end.        
00002434        7:03:02 PM        [2380] My Test GetOverlappedResult begin.        
00002435        7:03:02 PM        [2380] My Test GetOverlappedResult end.
00002438        7:03:02 PM        [2380] Read length: 40
00002438        7:03:02 PM        [2380] Read data:       

[2380]后面对应的是应用程序打印的调试信息,其余为驱动程序中打印的信息。从打印的消息中可以看出
1. WaitForMultipleObjects确实阻塞,等到[OnReadWriteComplete]完成后才执行。
2. [OnReadWriteComplete]中接收到了数据,Irq和Ctx中的MDL缓冲区都有数据,数据完全相同。而且通过MmGetSystemAddressForMdlSafe函数取得的地址相差4个字节,不知道有什么含义?(比较过其它的数据包,都相差4个字节)
3. GetOverlappedResult执行成功,得到正确的数据长度,但是接收缓冲区为零。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表