hzangqiong
驱动牛犊
驱动牛犊
  • 注册日期2002-06-28
  • 最后登录2007-03-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2121回复:5

很急:IoCallDriver返回STATUS_PENDING,KeWaitForSingleObject永远不返回,怎么解决?(详细见内)

楼主#
更多 发布于:2004-07-14 17:22
   在获得配置描述表时,调用IoCallDriver返回STATUS_PENDING,KeWaitForSingleObject永远不返回,直到设备拔掉。
   有没有办法使其返回?
   如果在KeWaitForSingleObject设上timeout参数,是否在超时返回后IoCallDriver传递下去的irp依旧没完成?这样可以吗?
   我的需求是程序能正常的退出,不要总等在那里。请大虾给予点拨。

windrv
驱动牛犊
驱动牛犊
  • 注册日期2004-07-05
  • 最后登录2004-07-28
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-07-16 09:37
Yes. completion function is called by IO manager after the IRP is done in lower level driver.

Did you fix your problem?

I have sample code in hand. So here is a improved CallUSBDI()

NTSTATUS OnRequestComplete(IN PDEVICE_OBJECT fdo, IN PIRP Irp, IN PKEVENT pev)
{
    if (Irp->PendingReturned)
        KeSetEvent(pev, IO_NO_INCREMENT, FALSE);
    return STATUS_MORE_PROCESSING_REQUIRED;
}


NTSTATUS CallUSBDI( IN PCNSECUSB_DEVICE_EXTENSION dx, IN PVOID UrbEtc, IN ULONG IoControlCode,IN ULONG Arg2)
{
IO_STATUS_BLOCK IoStatus;
KEVENT event;

// Initialise IRP completion event
KeInitializeEvent(&event, NotificationEvent, FALSE);

// Build Internal IOCTL IRP
PIRP Irp = IoBuildDeviceIoControlRequest(IoControlCode, dx->NextStackDevice,NULL, 0,NULL, 0,TRUE, &event, &IoStatus);

// Get IRP stack location for next driver down (already set up)
PIO_STACK_LOCATION NextIrpStack = IoGetNextIrpStackLocation(Irp);

// Store pointer to the URB etc
NextIrpStack->Parameters.Others.Argument1 = UrbEtc;
NextIrpStack->Parameters.Others.Argument2 = (PVOID)Arg2;

IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete,(PVOID) &event, TRUE, TRUE, TRUE);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This function is the key


// Call the driver and wait for completion if necessary
NTSTATUS status = IoCallDriver( dx->NextStackDevice, Irp);
if (status == STATUS_PENDING)
{
status = KeWaitForSingleObject(
&event, Suspended, KernelMode, FALSE, NULL);
status = IoStatus.Status;
}

IoCompleteRequest(irp, IO_NO_INCREMENT);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Here is another one you missed

return status;
}


[编辑 -  7/16/04 by  windrv]

[编辑 -  7/16/04 by  windrv]
hzangqiong
驱动牛犊
驱动牛犊
  • 注册日期2002-06-28
  • 最后登录2007-03-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-07-15 16:31
据我理解, Completion函数应是在底层的驱动完成irp后才会调用的.
不知道是不是?
windrv
驱动牛犊
驱动牛犊
  • 注册日期2004-07-05
  • 最后登录2004-07-28
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-07-15 14:29
CallUSBDI函数有问题. 在IoCallDriver之前,应该设置一个Completion函数,在这个函数调用KeSetEvent().要不然,KeWaitForSingleObject()永远等不到那个event.Walter Oney特意在书中指出了这个问题,你可以参考他的书或看看DDK的例子.



[编辑 -  7/15/04 by  windrv]
hzangqiong
驱动牛犊
驱动牛犊
  • 注册日期2002-06-28
  • 最后登录2007-03-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-07-15 14:22
有一批硬件,是有一部分出错.
NTSTATUS CallUSBDI( IN PCNSECUSB_DEVICE_EXTENSION dx, IN PVOID UrbEtc,
IN ULONG IoControlCode/*=IOCTL_INTERNAL_USB_SUBMIT_URB*/,
   IN ULONG Arg2/*=0*/)
{
IO_STATUS_BLOCK IoStatus;
KEVENT event;

// Initialise IRP completion event
// DebugPrintMsg("Start Init IRP");
KeInitializeEvent(&event, NotificationEvent, FALSE);

// Build Internal IOCTL IRP
// DebugPrintMsg("start build IRP");
PIRP Irp = IoBuildDeviceIoControlRequest(
IoControlCode, dx->NextStackDevice,
NULL, 0, // Input buffer
NULL, 0, // Output buffer
TRUE, &event, &IoStatus);

// Get IRP stack location for next driver down (already set up)
// DebugPrintMsg("start Get IRP location");
PIO_STACK_LOCATION NextIrpStack = IoGetNextIrpStackLocation(Irp);
// Store pointer to the URB etc
NextIrpStack->Parameters.Others.Argument1 = UrbEtc;
NextIrpStack->Parameters.Others.Argument2 = (PVOID)Arg2;

// Call the driver and wait for completion if necessary
// DebugPrintMsg("start call the driver");
NTSTATUS status = IoCallDriver( dx->NextStackDevice, Irp);
if (status == STATUS_PENDING)
{
// DebugPrintMsg("CallUSBDI: waiting for URB completion");

/* ULONGLONG TimeOut100nSec;
PLARGE_INTEGER pTimeOut;
// Calculate wait as 100ns intervals.  Negative is relative
TimeOut100nSec = dx->UsbTimeout;
TimeOut100nSec *= -10000; // convert units
pTimeOut = PLARGE_INTEGER(&TimeOut100nSec);
*/
// DebugPrintMsg("start waitforsingle");
status = KeWaitForSingleObject(
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&event, Suspended, KernelMode, FALSE, NULL);
status = IoStatus.Status;
}
// DebugPrintMsg("return ");
// return IRP completion status
// DebugPrint("CallUSBDI returned %x",status);
return status;
}


NTSTATUS UsbGetConfigurationDescriptors( IN PCNSECUSB_DEVICE_EXTENSION dx,
OUT PUSB_CONFIGURATION_DESCRIPTOR& descriptors,
IN UCHAR ConfigIndex,
OUT ULONG& DescriptorsSize)
{
// Allocate memory for URB
USHORT UrbSize = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
PURB urb = (PURB)ExAllocatePool(NonPagedPool, UrbSize);
if( urb==NULL)
{
DebugPrintMsg("No URB memory");
return STATUS_INSUFFICIENT_RESOURCES;
}

// Allocate memory just for basic config descriptor
DescriptorsSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
descriptors = (PUSB_CONFIGURATION_DESCRIPTOR)ExAllocatePool(NonPagedPool, DescriptorsSize+16);
if( descriptors==NULL)
{
DebugPrintMsg("No initial descriptor memory");
return STATUS_INSUFFICIENT_RESOURCES;
}

// Build the Get Descriptor URB
UsbBuildGetDescriptorRequest(
urb, UrbSize,
USB_CONFIGURATION_DESCRIPTOR_TYPE, ConfigIndex, 0,
descriptors, NULL, DescriptorsSize,
NULL);

// Call the USB driver
DebugPrintMsg("Getting basic configuration descriptor");
NTSTATUS status = CallUSBDI( dx, urb);
// Check statuses
if( !NT_SUCCESS(status) || !USBD_SUCCESS( urb->UrbHeader.Status))
{
DebugPrint("status %x URB status %x", status, urb->UrbHeader.Status);
status = STATUS_UNSUCCESSFUL;
goto fail;
}
DebugPrint("Got basic config descr.  MaxPower %d units of 2mA", descriptors->MaxPower);

// Reallocate memory for config descriptor and associated descriptors
DescriptorsSize = descriptors->wTotalLength;
ExFreePool(descriptors);
descriptors = (PUSB_CONFIGURATION_DESCRIPTOR)ExAllocatePool(NonPagedPool, DescriptorsSize+16);
if( descriptors==NULL)
{
DebugPrintMsg("No full descriptors memory");
return STATUS_INSUFFICIENT_RESOURCES;
}

// Build the Get Descriptor URB
UsbBuildGetDescriptorRequest(
urb, UrbSize,
USB_CONFIGURATION_DESCRIPTOR_TYPE, ConfigIndex, 0,
descriptors, NULL, DescriptorsSize,
NULL);

// Call the USB driver
DebugPrintMsg("Getting full configuration descriptors");
status = CallUSBDI( dx, urb);//调用处
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
....
windrv
驱动牛犊
驱动牛犊
  • 注册日期2004-07-05
  • 最后登录2004-07-28
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2004-07-15 13:56
把你调用IoCallDriver的那段程序以及Completion程序贴上来看看.按Walter Oney所说,如果 IoCallDriver之前的设置不对,KeWaitForSingleObject等不到那个Event.
游客

返回顶部