阅读:2893回复:9
passthru怎么用异步方式调用u盘呢?我的代码在IoCallDriver的时候老是bugcheck 0xa错误。
想在passthru的DISPATCH_LEVEL层次调用U盘读写特定数据,向U盘传输数据用的是spti的例子。程序运行到IoCallDriver的时候就蓝屏报0xa错误。如果不用spti的数据结构,直接将buffer映射的MDL传给u盘,则在IoCallDriver时没有问题,但这不能满足需求也得不到正确的结果。不知道诸位能否指点迷津。谢谢了。
ndis_status = NdisAllocateMemoryWithTag( &buffer, totallen, TAG ); if( ndis_status != NDIS_STATUS_SUCCESS ) { DBGPRINT( ( "cannot allocate memory for data to transfer\n" ) ); return FALSE; } NdisZeroMemory( buffer, totallen ); NdisMoveMemory( buffer, &keyprefix, sizeof(KEY_CMD_PREFIX) ); NdisMoveMemory( buffer + sizeof(KEY_CMD_PREFIX), pinput, inputlen ); ndis_status = NdisAllocateMemoryWithTag( &psptdwb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), TAG ); if( ndis_status != NDIS_STATUS_SUCCESS ) { DBGPRINT( ( "cannot allocate passthru direct with buffer memory\n" ) ); NdisFreeMemory( buffer, totallen, 0 ); return FALSE; } NdisZeroMemory( (u_char*)psptdwb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER) ); psptdwb->sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); psptdwb->sptd.PathId = 0; psptdwb->sptd.TargetId = 1; psptdwb->sptd.Lun = 0; psptdwb->sptd.CdbLength = CDB10GENERIC_LENGTH; psptdwb->sptd.SenseInfoLength = 24; psptdwb->sptd.DataIn = SCSI_IOCTL_DATA_OUT; psptdwb->sptd.DataTransferLength = totallen; psptdwb->sptd.TimeOutValue = 10; psptdwb->sptd.DataBuffer = buffer; psptdwb->sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf); psptdwb->sptd.Cdb[0] = 0xfd;//out NdisMoveMemory( psptdwb->sptd.Cdb + 1, "WATCH", 5 ); ulength = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); KeInitializeEvent( &event, NotificationEvent, FALSE ); pIrp = IoAllocateIrp( pDeviceObject->StackSize, FALSE ); if( ! pIrp ) { NdisFreeMemory( buffer, totallen, 0 ); NdisFreeMemory( psptdwb, ulength, 0 ); return FALSE; } pIoStackLocation = IoGetNextIrpStackLocation( pIrp ); pIoStackLocation->MajorFunction = IRP_MJ_DEVICE_CONTROL; pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength = ulength; pIoStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_PASS_THROUGH_DIRECT; if( pDeviceObject->Flags & DO_BUFFERED_IO ) { pIrp->AssociatedIrp.SystemBuffer = psptdwb; pIrp->MdlAddress = NULL; } else { pbufmdl = IoAllocateMdl( buffer, totallen, FALSE, FALSE, NULL ); if( pbufmdl == NULL ) { IoFreeIrp( pIrp ); NdisFreeMemory( buffer, totallen, 0 ); NdisFreeMemory( psptdwb, ulength, 0 ); return FALSE; } pIrp->MdlAddress = IoAllocateMdl( psptdwb, ulength, FALSE, FALSE, NULL ); if( pIrp->MdlAddress == NULL ) { if( pbufmdl != NULL ) { IoFreeMdl( pbufmdl ); } IoFreeIrp( pIrp ); NdisFreeMemory( buffer, totallen, 0 ); NdisFreeMemory( psptdwb, ulength, 0 ); return FALSE; } pIrp->MdlAddress->Next = pbufmdl; try { MmProbeAndLockPages( pIrp->MdlAddress, KernelMode, IoModifyAccess ); } except( EXCEPTION_EXECUTE_HANDLER ) { if( pIrp->MdlAddress != NULL ) { IoFreeMdl( pIrp->MdlAddress ); } if( pbufmdl != NULL ) { IoFreeMdl( pbufmdl ); } IoFreeIrp( pIrp ); NdisFreeMemory( buffer, totallen, 0 ); NdisFreeMemory( psptdwb, ulength, 0 ); return FALSE; } } IoSetCompletionRoutine( pIrp, RequestCompletion, (PVOID)&event, TRUE, TRUE, TRUE ); status = IoCallDriver( pDeviceObject, pIrp ); if( status == STATUS_PENDING ) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); status = pIrp->IoStatus.Status; } |
|
最新喜欢:![]() |
沙发#
发布于:2007-02-28 17:29
从目前的情况还看基本上确定是IoAllocateMdl调用时,对两个mdl处理在什么地方存在问题,导致运行在DISPATCH_LEVEL的IoCallDriver调用某些东西的时候,页面调不到。但搜遍了整个论坛也没有相关的示例,真是郁闷了:(
还望驱动牛哥们能够指点一下。 |
|
板凳#
发布于:2007-03-01 15:01
异步调用usb我做过,到时间就超时对吧,跟本用不到sptd这个结构,event和IoCallDriver和IoSetCompletionRoutine是要用的,提醒你一下超时的时间设定要注意格式。。。
|
|
地板#
发布于:2007-03-02 09:44
呵呵,终于找到救星了。楼上大哥,我就是不想用sptd这个结构,但我说实话真不知道怎么用?应该用什么东西呢?
|
|
地下室#
发布于:2007-03-02 15:43
上网不方便,手上没有原代码,只能凭记忆给你说下
首先获取usb的object,然后构键irp,设定event和io完成历程(超时用),最后调用IoCallDriver,就可以拉,助好运 |
|
5楼#
发布于:2007-03-02 17:02
谢谢你。可是我除了spti所说的SCSI_PASS_THROUGH_DIRECT结构外以及我要传给key的命令码(buffer)外,真不知道其他的东西,我倒是想直接传给key一个缓冲区数据,但是我不知道该传给它什么?怎么抛开SCSI_PASS_THROUGH_DIRECT结构,直接传给key一个缓冲区数据呢?缓冲区的数据应该如何构造呢?还望你能指教。不胜感激。
|
|
6楼#
发布于:2007-03-03 12:38
我用的跟你有点区别,usb是我们自己做的,usb驱动也是自己写的,所以没有填写那个结构,直接在ndis中获得usb的obj就可以了,但我想原理差不多吧,多调试下就ok了
|
|
7楼#
发布于:2007-03-03 21:09
呵呵,已经很感谢你了。我现在的情况和你的有所区别,我为了省事,想用那种无驱动型的usb设备,也就是说我们usb设备不用自己开发驱动,直接用微软的驱动。现在看来,这个路子确实有很大的难度啊,我这些日子几乎搜遍了整个互联网了,呵呵,总是找不到合适的回答。毕竟,我在DISPATCH_LEVEL调用IoCallDriver的,用的SCSI命令结构中还有一个内嵌的指针,这种情况可能本身就有很大的问题,这也是我孜孜以求,想找一个不用scsi命令结构的方法的原因。
昨天晚上又看了ddk里面的一个章节,其中发现有如下几句话,我想应该可以概括了。 A class driver or other higher-level driver can allocate IRPs for I/O control requests and send them to the next-lower driver as follows: Allocate an IRP with the major function code IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL. You can use the IoBuildDeviceIoControlRequest routine to specifically allocate an IOCTL IRP. You can also general-purpose IRP creation routines, such as IoAllocateIrp or IoInitializeIrp. For more information about IRP allocation, see Creating IRPs for Lower-Level Drivers. Set up the lower driver's I/O stack location for the IRP with the IOCTL_XXX code and appropriate parameters. Call IoSetCompletionRoutine with the IRP, so that the upper driver can supply an IoCompletion routine, if necessary, to: Determine how the lower driver handled a given request. Reuse the IRP to send another request or dispose of the driver-created IRP, after the lower driver completes a requested operation. The driver cannot reuse IRPs that IoBuildDeviceIoControlRequest created. For more information, see Reusing IRPs. Call IoCallDriver to pass the request on to the lower driver. To avoid synchronization problems and possible access violations, parameters for I/O control codes rarely include embedded pointers. With the exception of certain SCSI requests, the buffers at Irp->AssociatedIrp.SystemBuffer, at Irp->MdlAddress, and at Parameters.DeviceIoControl.Type3InputBuffer in a driver's I/O stack location do not contain pointers to other data buffers, nor do they contain structures that contain pointers, for system-defined I/O control codes. For more information about how data buffers are used with IRPs that contain I/O control codes, see Buffer Descriptions for I/O Control Codes. Nevertheless, a pair of class/port drivers that define internal I/O control codes can pass an embedded pointer to driver-allocated memory from the higher-level driver to the lower-level driver. Such a pair of class/port drivers is responsible for ensuring that: Only one driver at a time can access the data. Private data buffers are accessible in an arbitrary thread context by the port driver. 我想其中关于内嵌指针的讨论,可以说已经判了我的死刑,如果我要用DISPATCH_LEVEL调用IoCallDriver,就必须自己有USB的相关驱动。 不知道我理解的对不对?呵呵,再次感谢你,能够回答我的问题。我还以为没有人愿意回答了呢。 |
|
8楼#
发布于:2007-03-05 10:35
我不知道你们的usb是不是mass storage(我们的不是),我们开发的usb采用bulk传输方式,刚开始在ndis中调用U盘我用的是ZwXXX系列函数,的确可以调用,但是在读U盘的时候如果没有数据ZwRead会出不来,所以后来采用了IO完成历程自己构建irp用超时来解决该问题,看了你的描述认为根usb的驱动无关,关键是你的irp构建要正确,感觉应该你们的应该也可以自己构建,呵呵,有些东西就是要不停的调才行
|
|
9楼#
发布于:2007-03-05 20:39
呵呵,怎么说呢?我们的u盘也不是mass storage,应该和你们的一样。不过我图省事,想用u盘那种方式,这样推广起来,客户不用安装u盘的驱动啊。呵呵,看来我的算盘打错了,这几天搜了一下网上的东西,总结了一下,看来如果要在dispatch_level上面调用的话,只有实现usb驱动才能行。呵呵,我们的usb设备倒是有ddk的驱动,我想实现起来应该不难,如果有困难再向你请教。呵呵,你上网不方便还这么关照,真是谢谢你了。
呵呵,好像可以给分来者,但总是找不到,没法给你分了。请见谅。 |
|