NTSTATUS
  MakeDeviceControl(PDEVICE_OBJECT DeviceObject,
  ULONG IoctlCode,
  PVOID InputBuffer,
  ULONG InputBufferSize,
  PVOID OutputBuffer,
  ULONG OutputBufferSize)
{
  PIRP Irp;
  NTSTATUS Status;
  KEVENT Event;
  IO_STATUS_BLOCK Iosb;

  //
  // First, start by initializing the event
  //

  KeInitializeEvent(&Event, SynchronizationEvent, FALSE);

  //
  // Build the request, using the I/O Manager routine...
  //

  Irp = IoBuildDeviceIoControlRequest(IoctlCode,
    DeviceObject,
    InputBuffer,
    InputBufferSize,
    OutputBuffer,
    OutputBufferSize,
    FALSE,
    &Event,
    &Iosb);

  //
  // Send the request to the lower layer driver.
  //

  KdPrint(("current irql: %d\n", KeGetCurrentIrql()));
  Status = IoCallDriver(DeviceObject, Irp);

  //
  // Wait, if necessary
  //

  if (Status == STATUS_PENDING) {

    //
    // We must wait here in non-interruptable mode.    Why?    Because our
    // event is on the stack. If we were to return out of here (because
    // of an APC, for example) we might return from this function BEFORE
    // the event is set.    When the event is set later, at a minimum we'll
    // trash the stack.    Worse yet, the stack might be paged out and the
    // system will die.
    //

    (void) KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
    /*
    if (KeGetCurrentIrql() < DISPATCH_LEVEL)
    {
      (void) KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
    }
    else
    {
      LARGE_INTEGER dueTime;
      dueTime.QuadPart = 0;
      (void) KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, &dueTime);
    }*/
  }

  return (Status);

}