I wrote a driver that is not allowing a console application which is blocked
on a synchronous ReadFile() to be killed
(ctrl-C or taskmanager). Nor can I remove the driver with out rebooting the
system. What am I doing wrong -- details below.

I have created a pure software driver that reads and writes from an internal
buffer. If data is available the read IRP
it will complete immedately, else it will PEND. A Device I/O Control is used
to indicate that data is available, and
if a read IRP is pending will complete it.

I have tested with a TestRead.exe that syncrhonously reads the device and a
TestRelease program that writes
and sends the IOCTL_RELEASE_READ. Things work fine with the test program
interaction, immediately reading or blocking until data is availalbe.
HOWEVER, when I run the TestRead and it blocks I can not Ctrl-C the program
or use the TaskManager to kill the program. Why is this? I understood that
the I/O Manager was support to clean all the synchronous calls/Reads and
allow exit of the program, but this is not happening. What am I missing?

Below are what I believe to be the critical pieces:


NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;

[ declarations ...]

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;

if (pDevExt->bDataReady) {

[fill read buffer ...]

// Now complete the IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = nBytes; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status;
} else {

pDevExt->pIrpPendingRead = pIrp; // save pointer to IRP

status = STATUS_PENDING;
IoMarkIrpPending(pIrp);
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; // bytes xfered
return status;
}
}

NTSTATUS DispatchIoControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp ) {

PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;

// Release read is send when data is available
if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
== IOCTL_RELEASE_READ ) {

if (pDevExt->pIrpPendingRead == NULL) {
pDevExt->bDataReady = TRUE
} else {

// The stack location contains the user buffer info
PIO_STACK_LOCATION pPendingIrpStack =
IoGetCurrentIrpStackLocation( pDevExt->pIrpPendingRead );

[decls and read Irp buffer copy stuff ...]

// Complete Pending Read IRP
pDevExt->pIrpPendingRead->IoStatus.Information = nBytes;
pDevExt->pIrpPendingRead->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest( pDevExt->pIrpPendingRead, IO_NO_INCREMENT );
pDevExt->pIrpPendingRead = NULL; // "remove from queue of one"

}

// Complete Device IO Irp
pIrp->IoStatus.Information = pDevExt->bSetPendingRead;
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;

} else {
[ not implemented completion of IRP ...]

return status;
}
}

Re: Application can't be killed while on a synchronous read by Don

Don
Thu Apr 21 14:58:25 CDT 2005

You have to handle cancel see IoSetCancelRoutine. Right now the system
tries to cancel the IRP but because you have not provided a cancel routine,
it waits 5 minutes then kill things.


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply



"mlc" <mc100ftj@yahoo.com> wrote in message
news:BfT9e.11657$lP1.552@newsread1.news.pas.earthlink.net...
>I wrote a driver that is not allowing a console application which is
>blocked
> on a synchronous ReadFile() to be killed
> (ctrl-C or taskmanager). Nor can I remove the driver with out rebooting
> the
> system. What am I doing wrong -- details below.
>
> I have created a pure software driver that reads and writes from an
> internal
> buffer. If data is available the read IRP
> it will complete immedately, else it will PEND. A Device I/O Control is
> used
> to indicate that data is available, and
> if a read IRP is pending will complete it.
>
> I have tested with a TestRead.exe that syncrhonously reads the device and
> a
> TestRelease program that writes
> and sends the IOCTL_RELEASE_READ. Things work fine with the test program
> interaction, immediately reading or blocking until data is availalbe.
> HOWEVER, when I run the TestRead and it blocks I can not Ctrl-C the
> program
> or use the TaskManager to kill the program. Why is this? I understood that
> the I/O Manager was support to clean all the synchronous calls/Reads and
> allow exit of the program, but this is not happening. What am I missing?
>
> Below are what I believe to be the critical pieces:
>
>
> NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
> {
> NTSTATUS status = STATUS_SUCCESS;
>
> [ declarations ...]
>
> PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> pDevObj->DeviceExtension;
>
> if (pDevExt->bDataReady) {
>
> [fill read buffer ...]
>
> // Now complete the IRP
> pIrp->IoStatus.Status = status;
> pIrp->IoStatus.Information = nBytes; // bytes xfered
> IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> return status;
> } else {
>
> pDevExt->pIrpPendingRead = pIrp; // save pointer to IRP
>
> status = STATUS_PENDING;
> IoMarkIrpPending(pIrp);
> pIrp->IoStatus.Status = status;
> pIrp->IoStatus.Information = 0; // bytes xfered
> return status;
> }
> }
>
> NTSTATUS DispatchIoControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp ) {
>
> PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
> PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> pDevObj->DeviceExtension;
>
> // Release read is send when data is available
> if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
> == IOCTL_RELEASE_READ ) {
>
> if (pDevExt->pIrpPendingRead == NULL) {
> pDevExt->bDataReady = TRUE
> } else {
>
> // The stack location contains the user buffer info
> PIO_STACK_LOCATION pPendingIrpStack =
> IoGetCurrentIrpStackLocation( pDevExt->pIrpPendingRead );
>
> [decls and read Irp buffer copy stuff ...]
>
> // Complete Pending Read IRP
> pDevExt->pIrpPendingRead->IoStatus.Information = nBytes;
> pDevExt->pIrpPendingRead->IoStatus.Status = STATUS_SUCCESS;
> IoCompleteRequest( pDevExt->pIrpPendingRead, IO_NO_INCREMENT );
> pDevExt->pIrpPendingRead = NULL; // "remove from queue of one"
>
> }
>
> // Complete Device IO Irp
> pIrp->IoStatus.Information = pDevExt->bSetPendingRead;
> pIrp->IoStatus.Status = STATUS_SUCCESS;
> IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> return STATUS_SUCCESS;
>
> } else {
> [ not implemented completion of IRP ...]
>
> return status;
> }
> }
>
>



Re: Application can't be killed while on a synchronous read by mlc

mlc
Thu Apr 21 16:13:06 CDT 2005

Thanks Don, but still not right. The application does not respond to ctrl-c
and while the taskmanager kill will kill the application (and the
CancelRequest callback is run) the driver is not getting a MJ_CLOSE or
MJ_CLEANUP, so the driver is left bad state thinking someone has a open
handle. What else can I be missing?

Also, previously before putting in the IoSetCanelRoutine() when I tried to
kill via the TaskManager I get an "Access Denied" messagebox rather than a
"will die in 5 minutes" messageBox.

I do an IoSetCancelRoutine() right before I pend the Irp with this routine:

static void CancelRequestCB(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp
)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;

KdPrint((DRIVERNAME " - Entering CancelRequest: DeviceObject %8.8lX IRP
%8.8lX\n", pDevObj, pIrp));
pDevExt->pIrpPendingRead = NULL;
}



"Don Burn" <burn@stopspam.acm.org> wrote in message
news:BBT9e.16991$Ow2.10883@fe06.lga...
> You have to handle cancel see IoSetCancelRoutine. Right now the system
> tries to cancel the IRP but because you have not provided a cancel
routine,
> it waits 5 minutes then kill things.
>
>
> --
> Don Burn (MVP, Windows DDK)
> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> Remove StopSpam from the email to reply
>
>
>
> "mlc" <mc100ftj@yahoo.com> wrote in message
> news:BfT9e.11657$lP1.552@newsread1.news.pas.earthlink.net...
> >I wrote a driver that is not allowing a console application which is
> >blocked
> > on a synchronous ReadFile() to be killed
> > (ctrl-C or taskmanager). Nor can I remove the driver with out rebooting
> > the
> > system. What am I doing wrong -- details below.
> >
> > I have created a pure software driver that reads and writes from an
> > internal
> > buffer. If data is available the read IRP
> > it will complete immedately, else it will PEND. A Device I/O Control is
> > used
> > to indicate that data is available, and
> > if a read IRP is pending will complete it.
> >
> > I have tested with a TestRead.exe that syncrhonously reads the device
and
> > a
> > TestRelease program that writes
> > and sends the IOCTL_RELEASE_READ. Things work fine with the test
program
> > interaction, immediately reading or blocking until data is availalbe.
> > HOWEVER, when I run the TestRead and it blocks I can not Ctrl-C the
> > program
> > or use the TaskManager to kill the program. Why is this? I understood
that
> > the I/O Manager was support to clean all the synchronous calls/Reads and
> > allow exit of the program, but this is not happening. What am I missing?
> >
> > Below are what I believe to be the critical pieces:
> >
> >
> > NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
> > {
> > NTSTATUS status = STATUS_SUCCESS;
> >
> > [ declarations ...]
> >
> > PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> > pDevObj->DeviceExtension;
> >
> > if (pDevExt->bDataReady) {
> >
> > [fill read buffer ...]
> >
> > // Now complete the IRP
> > pIrp->IoStatus.Status = status;
> > pIrp->IoStatus.Information = nBytes; // bytes xfered
> > IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> > return status;
> > } else {
> >
> > pDevExt->pIrpPendingRead = pIrp; // save pointer to IRP
> >
> > status = STATUS_PENDING;
> > IoMarkIrpPending(pIrp);
> > pIrp->IoStatus.Status = status;
> > pIrp->IoStatus.Information = 0; // bytes xfered
> > return status;
> > }
> > }
> >
> > NTSTATUS DispatchIoControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp ) {
> >
> > PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
> > PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> > pDevObj->DeviceExtension;
> >
> > // Release read is send when data is available
> > if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
> > == IOCTL_RELEASE_READ ) {
> >
> > if (pDevExt->pIrpPendingRead == NULL) {
> > pDevExt->bDataReady = TRUE
> > } else {
> >
> > // The stack location contains the user buffer info
> > PIO_STACK_LOCATION pPendingIrpStack =
> > IoGetCurrentIrpStackLocation( pDevExt->pIrpPendingRead );
> >
> > [decls and read Irp buffer copy stuff ...]
> >
> > // Complete Pending Read IRP
> > pDevExt->pIrpPendingRead->IoStatus.Information = nBytes;
> > pDevExt->pIrpPendingRead->IoStatus.Status = STATUS_SUCCESS;
> > IoCompleteRequest( pDevExt->pIrpPendingRead, IO_NO_INCREMENT );
> > pDevExt->pIrpPendingRead = NULL; // "remove from queue of one"
> >
> > }
> >
> > // Complete Device IO Irp
> > pIrp->IoStatus.Information = pDevExt->bSetPendingRead;
> > pIrp->IoStatus.Status = STATUS_SUCCESS;
> > IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> > return STATUS_SUCCESS;
> >
> > } else {
> > [ not implemented completion of IRP ...]
> >
> > return status;
> > }
> > }
> >
> >
>
>



Re: Application can't be killed while on a synchronous read by Don

Don
Thu Apr 21 16:32:50 CDT 2005


"mlc" <mc100ftj@yahoo.com> wrote in message
news:CHU9e.11679$lP1.9136@newsread1.news.pas.earthlink.net...
> Thanks Don, but still not right. The application does not respond to
> ctrl-c
> and while the taskmanager kill will kill the application (and the
> CancelRequest callback is run) the driver is not getting a MJ_CLOSE or
> MJ_CLEANUP, so the driver is left bad state thinking someone has a open
> handle. What else can I be missing?
>
> Also, previously before putting in the IoSetCanelRoutine() when I tried to
> kill via the TaskManager I get an "Access Denied" messagebox rather than a
> "will die in 5 minutes" messageBox.
>
> I do an IoSetCancelRoutine() right before I pend the Irp with this
> routine:
>
> static void CancelRequestCB(
> IN PDEVICE_OBJECT pDevObj,
> IN PIRP pIrp
> )
> {
> PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> pDevObj->DeviceExtension;
>
> KdPrint((DRIVERNAME " - Entering CancelRequest: DeviceObject %8.8lX IRP
> %8.8lX\n", pDevObj, pIrp));
> pDevExt->pIrpPendingRead = NULL;
> }
>
You need to complete the IRP in the cancel routine and release the cancel
spinlock, something like:

static NTSTATUS CancelRequestCB(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS status;
PIRP Irp1;
KIRQL cancelIrql;

status = STATUS_CANCELLED;
if (pDevExt->pIrpPendingRead == Irp)
{
Irp1 = pDevExt->pIrpPendingRead ;
pDevExt->pIrpPendingRead = NULL;
}
IoReleaseCancelSpinLock (Irp->CancelIrql);
if (Irp1 != NULL)
{
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
}
return(status); // Return status to caller!
}



--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply




Re: Application can't be killed while on a synchronous read by mlc

mlc
Thu Apr 21 16:58:54 CDT 2005

Thanks Don,

You were spot on ... I screwed up on the Cancel Routine details -- I didn't
read all the fine print ...

Here is working version:


static void CancelRequestCB(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp
)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;


// Release the global cancel spin lock.
// Do this while not holding any other spin locks so that we exit at the
right IRQL.
IoReleaseCancelSpinLock(pIrp->CancelIrql);

KdPrint((DRIVERNAME " - Entering CancelRequest: DeviceObject %8.8lX IRP
%8.8lX\n", pDevObj, pIrp));
pDevExt->pIrpPendingRead = NULL;

// Complete the IRP. This is a call outside the driver, so all spin locks
must be released by this point.
pIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

}

"Don Burn" <burn@stopspam.acm.org> wrote in message
news:BBT9e.16991$Ow2.10883@fe06.lga...
> You have to handle cancel see IoSetCancelRoutine. Right now the system
> tries to cancel the IRP but because you have not provided a cancel
routine,
> it waits 5 minutes then kill things.
>
>
> --
> Don Burn (MVP, Windows DDK)
> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> Remove StopSpam from the email to reply
>
>
>
> "mlc" <mc100ftj@yahoo.com> wrote in message
> news:BfT9e.11657$lP1.552@newsread1.news.pas.earthlink.net...
> >I wrote a driver that is not allowing a console application which is
> >blocked
> > on a synchronous ReadFile() to be killed
> > (ctrl-C or taskmanager). Nor can I remove the driver with out rebooting
> > the
> > system. What am I doing wrong -- details below.
> >
> > I have created a pure software driver that reads and writes from an
> > internal
> > buffer. If data is available the read IRP
> > it will complete immedately, else it will PEND. A Device I/O Control is
> > used
> > to indicate that data is available, and
> > if a read IRP is pending will complete it.
> >
> > I have tested with a TestRead.exe that syncrhonously reads the device
and
> > a
> > TestRelease program that writes
> > and sends the IOCTL_RELEASE_READ. Things work fine with the test
program
> > interaction, immediately reading or blocking until data is availalbe.
> > HOWEVER, when I run the TestRead and it blocks I can not Ctrl-C the
> > program
> > or use the TaskManager to kill the program. Why is this? I understood
that
> > the I/O Manager was support to clean all the synchronous calls/Reads and
> > allow exit of the program, but this is not happening. What am I missing?
> >
> > Below are what I believe to be the critical pieces:
> >
> >
> > NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
> > {
> > NTSTATUS status = STATUS_SUCCESS;
> >
> > [ declarations ...]
> >
> > PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> > pDevObj->DeviceExtension;
> >
> > if (pDevExt->bDataReady) {
> >
> > [fill read buffer ...]
> >
> > // Now complete the IRP
> > pIrp->IoStatus.Status = status;
> > pIrp->IoStatus.Information = nBytes; // bytes xfered
> > IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> > return status;
> > } else {
> >
> > pDevExt->pIrpPendingRead = pIrp; // save pointer to IRP
> >
> > status = STATUS_PENDING;
> > IoMarkIrpPending(pIrp);
> > pIrp->IoStatus.Status = status;
> > pIrp->IoStatus.Information = 0; // bytes xfered
> > return status;
> > }
> > }
> >
> > NTSTATUS DispatchIoControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp ) {
> >
> > PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
> > PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> > pDevObj->DeviceExtension;
> >
> > // Release read is send when data is available
> > if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
> > == IOCTL_RELEASE_READ ) {
> >
> > if (pDevExt->pIrpPendingRead == NULL) {
> > pDevExt->bDataReady = TRUE
> > } else {
> >
> > // The stack location contains the user buffer info
> > PIO_STACK_LOCATION pPendingIrpStack =
> > IoGetCurrentIrpStackLocation( pDevExt->pIrpPendingRead );
> >
> > [decls and read Irp buffer copy stuff ...]
> >
> > // Complete Pending Read IRP
> > pDevExt->pIrpPendingRead->IoStatus.Information = nBytes;
> > pDevExt->pIrpPendingRead->IoStatus.Status = STATUS_SUCCESS;
> > IoCompleteRequest( pDevExt->pIrpPendingRead, IO_NO_INCREMENT );
> > pDevExt->pIrpPendingRead = NULL; // "remove from queue of one"
> >
> > }
> >
> > // Complete Device IO Irp
> > pIrp->IoStatus.Information = pDevExt->bSetPendingRead;
> > pIrp->IoStatus.Status = STATUS_SUCCESS;
> > IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> > return STATUS_SUCCESS;
> >
> > } else {
> > [ not implemented completion of IRP ...]
> >
> > return status;
> > }
> > }
> >
> >
>
>



Re: Application can't be killed while on a synchronous read by Maxim

Maxim
Thu Apr 21 22:35:48 CDT 2005

Just support IRP cancellation in the driver. This will solve the issue.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
maxim@storagecraft.com
http://www.storagecraft.com

"mlc" <mc100ftj@yahoo.com> wrote in message
news:BfT9e.11657$lP1.552@newsread1.news.pas.earthlink.net...
> I wrote a driver that is not allowing a console application which is blocked
> on a synchronous ReadFile() to be killed
> (ctrl-C or taskmanager). Nor can I remove the driver with out rebooting the
> system. What am I doing wrong -- details below.
>
> I have created a pure software driver that reads and writes from an internal
> buffer. If data is available the read IRP
> it will complete immedately, else it will PEND. A Device I/O Control is used
> to indicate that data is available, and
> if a read IRP is pending will complete it.
>
> I have tested with a TestRead.exe that syncrhonously reads the device and a
> TestRelease program that writes
> and sends the IOCTL_RELEASE_READ. Things work fine with the test program
> interaction, immediately reading or blocking until data is availalbe.
> HOWEVER, when I run the TestRead and it blocks I can not Ctrl-C the program
> or use the TaskManager to kill the program. Why is this? I understood that
> the I/O Manager was support to clean all the synchronous calls/Reads and
> allow exit of the program, but this is not happening. What am I missing?
>
> Below are what I believe to be the critical pieces:
>
>
> NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
> {
> NTSTATUS status = STATUS_SUCCESS;
>
> [ declarations ...]
>
> PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> pDevObj->DeviceExtension;
>
> if (pDevExt->bDataReady) {
>
> [fill read buffer ...]
>
> // Now complete the IRP
> pIrp->IoStatus.Status = status;
> pIrp->IoStatus.Information = nBytes; // bytes xfered
> IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> return status;
> } else {
>
> pDevExt->pIrpPendingRead = pIrp; // save pointer to IRP
>
> status = STATUS_PENDING;
> IoMarkIrpPending(pIrp);
> pIrp->IoStatus.Status = status;
> pIrp->IoStatus.Information = 0; // bytes xfered
> return status;
> }
> }
>
> NTSTATUS DispatchIoControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp ) {
>
> PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
> PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
> pDevObj->DeviceExtension;
>
> // Release read is send when data is available
> if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
> == IOCTL_RELEASE_READ ) {
>
> if (pDevExt->pIrpPendingRead == NULL) {
> pDevExt->bDataReady = TRUE
> } else {
>
> // The stack location contains the user buffer info
> PIO_STACK_LOCATION pPendingIrpStack =
> IoGetCurrentIrpStackLocation( pDevExt->pIrpPendingRead );
>
> [decls and read Irp buffer copy stuff ...]
>
> // Complete Pending Read IRP
> pDevExt->pIrpPendingRead->IoStatus.Information = nBytes;
> pDevExt->pIrpPendingRead->IoStatus.Status = STATUS_SUCCESS;
> IoCompleteRequest( pDevExt->pIrpPendingRead, IO_NO_INCREMENT );
> pDevExt->pIrpPendingRead = NULL; // "remove from queue of one"
>
> }
>
> // Complete Device IO Irp
> pIrp->IoStatus.Information = pDevExt->bSetPendingRead;
> pIrp->IoStatus.Status = STATUS_SUCCESS;
> IoCompleteRequest( pIrp, IO_NO_INCREMENT );
> return STATUS_SUCCESS;
>
> } else {
> [ not implemented completion of IRP ...]
>
> return status;
> }
> }
>
>