阅读:2157回复:14
应用程序与驱动的交互问题(DeviceIoControl()函数)
我现在要用DeviceIoControl()函数来向设备写数据,我把数据存放在如下函数中的buffer里。
bResult = DeviceIoControl (hDevice, IOCTL_EZUSB_BULK_WRITE,//写数据 &bulkControl,//管道(pipes) sizeof (BULK_TRANSFER_CONTROL), buffer,//存储数据的缓冲区 length,//读取的字节数 (unsigned long *)&nBytes, NULL); 在驱动程序中,我要UsbBuildInterruptOrBulkTransferRequest()生成一个urb发给usbd,那么存储要传输数据的buffer地址存放在那个参数里?是Irp->AssociatedIrp.SystemBuffer还是Irp->MdlAddress?或者是其他的?还请知道的指点一下,多谢了。 |
|
沙发#
发布于:2003-04-06 23:10
那要看你的IOCTL_EZUSB_BULK_WRITE是怎么定义的了。DW Help里面有个How to就对此有详细的解释。
|
|
|
板凳#
发布于:2003-04-08 13:28
斑竹就是斑竹,一语中的,偶在msdn上找不到ioctl code的参数说明,原来在ddk的帮助里,多谢斑竹了!
|
|
地板#
发布于:2003-04-09 16:13
在应用程序中:
typedef struct _BULK_TRANSFER_CONTROL { ULONG pipeNum; } BULK_TRANSFER_CONTROL, *PBULK_TRANSFER_CONTROL; bResult = DeviceIoControl(hFile,//设备句柄 IOCTL_ISP1581_BULK_WRITE,//ctl code &bulkControl,//选择端点 sizeof(BULK_TRANSFER_CONTROL), threadParam->pcIoBuffer,//传输数据存储地址是个char型指针 threadParam->uiLength,//传输数据长度(uint) &nBytes,//实际传输的数据 NULL); 在驱动程序中: PVOID ioBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG bufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb (USHORT) urbSize, //size of urb pipeHandle, //usbd pipe handle这个参数没问题 ioBuffer, //TransferBuffer NULL, //mdl bufferLength, //bufferlength USBD_SHORT_TRANSFER_OK, //flags NULL); //link ntStatus = D12_CallUSBD(DeviceObject, urb); if (NT_SUCCESS(ntStatus)) { Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; D12_KdPrint((\"Successfully transfered 0x%x bytes\\n\",Irp->IoStatus.Information)); } 我用softice跟踪了一下,发现ioBuffer指向的地址中的数据不是我在应用程序中传过去的数据地址, 但是运行后有数据发送到设备方,而且urb->UrbBulkOrInterruptTransfer.TransferBufferLength中的数据也是我要求传输的数据数量,但是返回到app后,bResult却是0 !不知道为什么???希望知道的大虾给小弟指点指点,先谢过了 |
|
地下室#
发布于:2003-04-09 17:19
当应用程序发起一个读或写操作时,通过给出一个用户模式虚拟地址和长度,应用程序向I/O管理器提供了一个数据缓冲区。正如我在第三章中提到的,内核模式驱动程序几乎从不使用用户模式虚拟地址访问内存,因为你不能把线程上下文确定下来。Windows 2000为驱动程序访问用户模式数据缓冲区提供了三种方法:
在buffered方式中,I/O管理器先创建一个与用户模式数据缓冲区大小相等的系统缓冲区。而你的驱动程序将使用这个系统缓冲区工作。I/O管理器负责在系统缓冲区和用户模式缓冲区之间复制数据。 在direct方式中,I/O管理器锁定了包含用户模式缓冲区的物理内存页,并创建一个称为MDL(内存描述符表)的辅助数据结构来描述锁定页。因此你的驱动程序将使用MDL工作。 在neither方式中,I/O管理器仅简单地把用户模式的虚拟地址传递给你。而使用用户模式地址的驱动程序应十分小心。 -----此文中得“我”,是waltoney,不知道这段话可不可以解释 “我用softice跟踪了一下,发现ioBuffer指向的地址中的数据不是我在应用程序中传过去的数据地址,” bResult却是0 !我想可能是Irp->IoStatus.Status没有正确的填充。 我是菜鸟,不对的地方请指正。 |
|
|
5楼#
发布于:2003-04-09 19:07
首先感谢kilroy_guo大虾的热心回答,但是我还有一些问题,根据下面这段话:
“在buffered方式中,I/O管理器先创建一个与用户模式数据缓冲区大小相等的系统缓冲区。而你的驱动程序将使用这个系统缓冲区工作。I/O管理器负责在系统缓冲区和用户模式缓冲区之间复制数据。 ” 是不是说复制数据的过程我是无法监测到的?因为我发现ioBuffer指向地址中的内容也不是我期望的呀,难道我用softice跟进去也不能得到传到驱动中的数据吗?还有就是我根据上面的方法传到设备的数据是不正确的,也就是说传过去的根本不是我之前确定的数据,因为我在设备方存储了这些数据并作了比较 可是根据ddk帮助里所说的,我用的方法没有错呀,而且我也用第二种方法试了(就是direct),问题是一样的,所以怀疑是UsbBuildInterruptOrBulkTransferRequest里面的ioBuffer里的数据根本就不是我要传输的! |
|
6楼#
发布于:2003-04-10 11:38
METHOD_BUFFERED方式:
应用程序中的输入输出缓冲在驱动程序中用一个指针访问,即IRP中的AssociatedIrp.SystemBuffer指针,当应用程序的数据传入到驱动时,驱动先从AssociatedIrp.SystemBuffer中取得应用程序的数据,在irp完成之前,驱动将要传给应用程序的数据考入AssociatedIrp.SystemBuffer中并设置IoStatus.Information为要传给应用程序的数据长度即可。 METHOD_IN_DIRECT和METHOD_OUT_DIRECT模式: 他们都以相同方式处理。仅有的不同是它们访问用户模式缓冲区时所需的访问权限;METHOD_IN_DIRECT需要读权限;METHOD_OUT_DIRECT既需要读权限又需要写权限,驱动程序以AssociatedIrp.SystemBuffer访问输入缓冲区,以MDL访问输出缓冲区,MDL缓冲地址可以用MmGetSystemAddressForMdl(Irp->MdlAddress)获得。 你的做法应该是对得阿,数据应该能够正确的传到kernel里面,你的ioBuffer指向的数据是什么?你用这个指针的时候有没有把他转换成PBULK_TRANSFER_CONTROL,也就是说你是怎么在设备方存储的? 我也不是大虾,我是菜鸟,上面这些话是我乱猜得,不对的地方请多多包涵 |
|
|
7楼#
发布于:2003-04-10 11:49
你比我厉害,虽然代码不是你写的,但是你还是看出了问题在那,我想问题出现在deviceiocontrol函数上,我用的是buffer方式。我想往设备写数据,所以应该把要写的数据地址和长度放在&bulkcontrol和sizeof(bulkcontrol)的位置上,但是我在这两个位置上放的是个端点信息,所以要传输的数据地址根本就没有传到驱动里!你觉得是不是这样呢,多谢你了!等问题解决了开帖子放分给你! :)
|
|
8楼#
发布于:2003-04-10 11:50
threadParam->pcIoBuffer指向的数据,是不是被别的thread修改了?
|
|
|
9楼#
发布于:2003-04-10 11:57
先谢谢斑竹,我觉得应该是没传过去吧,因为我想传的pipe信息(在bulkcontrol里)都传过去了,所以我要是把数据的地址放在它的位置上,一定也能传到驱动里,是我没想清楚函数的参数用法,害你们费神,真该打! :)
|
|
10楼#
发布于:2003-04-10 12:05
我是半路出家搞usb驱动,以前是搞vc做app的,最近一个月开始研究usb驱动,我主要是做iso传输的,最近碰到不少头疼的事,都是和PVOID指针乱用有关,我对这个有切肤之痛。交个朋友,共同学习,共同进步。
:) :) :) |
|
|
11楼#
发布于:2003-04-10 22:09
呵呵,我也是半路出家呀,而且是被逼的,没办法呀,说不想做一些轻松的活呀,我现在对固件、驱动和app都多少有点了解,大家多交流交流吧,我的qq:36180633,邮箱:jinghuiren@163.com
|
|
12楼#
发布于:2003-04-19 12:38
我对程序进行了修改,现在数据是传输正确了,可是ioctl函数的返回值总是0,我没觉得我的程序那里除了问题呀!
在应用程序中: bResult = DeviceIoControl(hFile,//设备句柄 IOCTL_ISP1581_BULK_WRITE,//ctl code,用的是buffer方式 Buffer,//传输数据存储地址是个char型指针 Length,//传输数据长度(uint) NULL, 0, &nBytes,//实际传输的数据 NULL); 在驱动程序中: PVOID ioBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG bufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; urbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER); urb = ExAllocatePool(NonPagedPool,urbSize); UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb (USHORT) urbSize, //size of urb pipeHandle, //usbd pipe handle这个参数没问题 ioBuffer, //TransferBuffer NULL, //mdl bufferLength, //bufferlength USBD_SHORT_TRANSFER_OK, //flags NULL); //link ntStatus = D12_CallUSBD(DeviceObject, urb); //返回至是正确的 if (NT_SUCCESS(ntStatus)) { Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; //上面这个值也是正确的 D12_KdPrint((\"Successfully transfered 0x%x bytes\\n\",Irp->IoStatus.Information)); } Irp->IoStatus.Status = ntStatus; ExFreePool(urb); return ntStatus;//这个返回值也没问题 可是我的app中ioctl函数获得的返回值却总是0,我看了固件中的得到数据,和我主机发过去的一模一样! [编辑 - 4/21/03 by jinghuiren] [编辑 - 4/23/03 by jinghuiren] |
|
13楼#
发布于:2003-04-19 14:51
你对deviceiocontrol()函数理解错误。你开始用的方法是对的。写到设备的数据还是应该在OUTBUFFER中,INBUFFER中的东西是与操作有关的,是给驱动部分的信息。
|
|
14楼#
发布于:2003-04-23 13:53
首先感谢楼上老兄的回复,我由仔细看了该函数的相关描述,觉得系到设备的数据应该放在deviceiocontrol的inputbuffer中,关于函数返回值总是0我觉得是不是我没有提供outputbuffer的原因呀。真是郁闷呀 :(
|
|