📄 rw.c
字号:
deviceExtension->OpenPipeCount++;
PrepareWriteIntUrb(
DeviceObject,
&interface->Pipes[1]
);
deviceExtension->PipeInfo[1].fPipeOpened = TRUE;
deviceExtension->OpenPipeCount++;
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
if(fileObject == NULL)
goto done;
// fscontext is null for device
fileObject->FsContext = NULL;
if ( 0 == fileObject->FileName.Length ) // this is the case if opening device as opposed to pipe
goto done; // nothing more to do
ourPipeInfo = USB2COM_PipeWithName( DeviceObject, &fileObject->FileName );
if ( !ourPipeInfo ) {
ntStatus = STATUS_INVALID_PARAMETER;
goto done;
}
// init status to bad; will set good in below loop on success
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
for (i=0; i<interface->NumberOfPipes; i++) {
PipeInfo = &interface->Pipes[i]; // PUSBD_PIPE_INFORMATION PipeInfo;
if ( ourPipeInfo == &deviceExtension->PipeInfo[i] ) {
//
// found a match
//
USB2COM_KdPrint( DBGLVL_DEFAULT,("open pipe %d\n", i));
fileObject->FsContext = PipeInfo;
ourPipeInfo->fPipeOpened = TRUE; // set flag for opened
ntStatus = STATUS_SUCCESS;
deviceExtension->OpenPipeCount++;
// try to power up device if its not in D0
actStat = USB2COM_SelfSuspendOrActivate( DeviceObject, FALSE );
break;
}
}
done:
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
USB2COM_DecrementIoCount(DeviceObject);
USB2COM_KdPrint( DBGLVL_DEFAULT,("exit USB2COM_Create %x\n", ntStatus));
return ntStatus;
}
BOOLEAN
USB2COM_CancelPendingIo(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Cancels pending IO, as on a sudden IRP_MN_REMOVE_DEVICE
This driver maintains and array of info structs (USB2COM_RW_CONTEXT)
on self-generated IRPS for staged read/writes; This routine traverses
it and cancels all pending IO irps
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
device.
Return Value:
TRUE if cancelled any, else FALSE
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KIRQL OldIrql;
USB2COM_KdPrint( DBGLVL_DEFAULT,("enter USB2COM_CancelPendingIo\n"));
StopReadIntUrb(deviceExtension);
StopWriteIntUrb(deviceExtension);
//ASSERT(IsListEmpty(&deviceExtension->WriteQueue));
//ASSERT(IsListEmpty(&deviceExtension->ReadQueue));
USB2COM_KdPrint( DBGLVL_DEFAULT,("exit USB2COM_CancelPendingIo\n"));
return TRUE;
}
NTSTATUS
USB2COM_AbortPipes(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Called as part of sudden device removal handling.
Cancels any pending transfers for all open pipes.
If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
Also marks the pipe 'closed' in our saved configuration info.
Arguments:
Ptrs to our FDO
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
ULONG i;
PUSBD_INTERFACE_INFORMATION interface;
PUSB2COM_PIPEINFO PipeInfo;
PUCHAR pInf = (PUCHAR ) deviceExtension->PipeInfo;
interface = deviceExtension->UsbInterface;
for (i=0; i<interface->NumberOfPipes; i++) {
PipeInfo = (PUSB2COM_PIPEINFO) pInf; // PUSB2COM_PIPEINFO PipeInfo;
if ( PipeInfo->fPipeOpened ) { // we set this if open, clear if closed
USB2COM_KdPrint( DBGLVL_HIGH,("USB2COM_AbortPipes() Aborting open Pipe %d\n", i));
urb = USB2COM_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST));
if (urb) {
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
urb->UrbPipeRequest.PipeHandle =
interface->Pipes[i].PipeHandle;
ntStatus = USB2COM_CallUSBD(DeviceObject, urb);
USB2COM_ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
USB2COM_KdPrint( DBGLVL_HIGH,("USB2COM_AbortPipes() FAILED urb alloc\n" ));
break;
}
if (!(NT_SUCCESS(ntStatus))) {
// if we failed, dump out
#if DBG
if ( gpDbg )
gpDbg->PipeErrorCount++;
#endif
break;
}
else {
PipeInfo->fPipeOpened = FALSE; // mark the pipe 'closed'
deviceExtension->OpenPipeCount--;
#if DBG
if ( gpDbg )
gpDbg->AbortPipeCount++;
#endif
}
} // end, if pipe open
pInf += sizeof ( USB2COM_PIPEINFO );
} // end, for all pipes
return ntStatus;
}
BOOLEAN
USB2COM_CanAcceptIoRequests(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Check device extension status flags;
Can't accept a new io request if device:
1) is removed,
2) has never been started,
3) is stopped,
4) has a remove request pending, or
5) has a stop device pending
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
device.
Return Value:
return TRUE if can accept new io requests, else FALSE
--*/
{
PDEVICE_EXTENSION deviceExtension;
BOOLEAN fCan = FALSE;
deviceExtension = DeviceObject->DeviceExtension;
//flag set when processing IRP_MN_REMOVE_DEVICE
if ( !deviceExtension->DeviceRemoved &&
// device must be started( enabled )
deviceExtension->DeviceStarted &&
// flag set when driver has answered success to IRP_MN_QUERY_REMOVE_DEVICE
!deviceExtension->RemoveDeviceRequested &&
// flag set when driver has answered success to IRP_MN_QUERY_STOP_DEVICE
!deviceExtension->StopDeviceRequested ){
fCan = TRUE;
}
USB2COM_KdPrintCond( DBGLVL_MAXIMUM, !fCan, ("**** FALSE return from USB2COM_CanAcceptIoRequests()!\n"));
return fCan;
}
NTSTATUS QueueOrCompleteReadIrp(PDEVICE_EXTENSION deviceExtension, PIRP Irp)
{
PDRIVER_CANCEL oldCancelRoutine;
KIRQL oldIrql;
NTSTATUS status = STATUS_PENDING;
ULONG haveLen;
BOOLEAN returnWhatsPresent = FALSE;
PUCHAR ioBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority );
ULONG ioLength = MmGetMdlByteCount(Irp->MdlAddress);
DbgPrint("QueueOrCompleteReadIrp Enter\n");
if((ioLength <= 0) || (ioBuffer == NULL))
{
DbgPrint("ioBuffer %p ioLength %d\n",ioBuffer,ioLength);
//DbgBreakPoint();
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
//DbgBreakPoint();
return STATUS_INVALID_PARAMETER;
}
if ( !USB2COM_CanAcceptIoRequests( deviceExtension->DeviceObject )
|| (deviceExtension->ReadIntUrbs[0].Irp == NULL)
|| (deviceExtension->ReadIntUrbs[0].Urb == NULL) )
{
// got sudden remove! ( i.e. plug was yanked )
//DbgBreakPoint();
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
//DbgBreakPoint();
return STATUS_DELETE_PENDING;
}
/*Platform SDK: Files and I/O About Communications Time-Outs
Interval timing forces a read operation to return when
there is a lull in reception. A process using interval
time-outs can set a fairly short interval parameter,
so it can respond quickly to small, isolated bursts of
one or a few characters, yet it can still collect
large buffers of characters with a single call
when data is received in a steady stream.
*/
if(deviceExtension->SerialTimeOuts.ReadIntervalTimeout &&
( deviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0) &&
( deviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0)
){
returnWhatsPresent = TRUE;
}
KeAcquireSpinLock(&deviceExtension->InputBufferLock, &oldIrql);
haveLen = CircularBufferDataLen(&deviceExtension->InputBuffer);
if( (ioLength <= haveLen) || (returnWhatsPresent && (haveLen > 0)) )
{
ioLength = (ioLength < haveLen) ? ioLength : haveLen;
DbgPrint("Complete ReadIrp ioLength=%d\n",ioLength);
status = PopCircularBufferEntry(&deviceExtension->InputBuffer,ioBuffer,ioLength);
KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
Irp->IoStatus.Information = ioLength;
Irp->IoStatus.Status = status;
IoCompleteRequest( Irp,IO_NO_INCREMENT);
return status;
}
KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
// Queue the IRP and call IoMarkIrpPending
// to indicate that the IRP may complete on a different thread.
// N.B. It's okay to call these inside the spin lock because they're macros, not functions.
IoMarkIrpPending(Irp);
InsertTailList(&deviceExtension->ReadQueue, &Irp->Tail.Overlay.ListEntry);
// Must set a Cancel routine before checking the Cancel flag.
oldCancelRoutine = IoSetCancelRoutine(Irp, IrpCancelRoutine);
ASSERT(!oldCancelRoutine);
if (Irp->Cancel){
// The IRP was canceled. Check whether our cancel routine was called.
oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
if (oldCancelRoutine){
// The cancel routine was NOT called.
// So dequeue the IRP now and complete it after releasing the spin lock.
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
status = Irp->IoStatus.Status = STATUS_CANCELLED;
} //endif
else {
// The cancel routine WAS called.
// As soon as we drop our spin lock it will dequeue and complete the IRP.
// So leave the IRP in the queue and otherwise don't touch it.
// Return pending since we're not completing the IRP here.
} //end else
} // endif
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
// Normally you shouldn't call IoMarkIrpPending
// and return a status other than STATUS_PENDING.
// But you can break this rule if you complete the IRP.
if (status != STATUS_PENDING){
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
DbgPrint("QueueOrCompleteReadIrp Exit\n");
return status;
}
PIRP DequeueReadIrp(PDEVICE_EXTENSION deviceExtension)
{
KIRQL oldIrql;
PIRP nextIrp = NULL;
DbgPrint("DequeueReadIrp Enter\n");
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
while (!nextIrp && !IsListEmpty(&deviceExtension ->ReadQueue)){
PDRIVER_CANCEL oldCancelRoutine;
PLIST_ENTRY listEntry = RemoveHeadList(&deviceExtension ->ReadQueue);
// Get the next IRP off the queue.
nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
// Clear the IRP's cancel routine
oldCancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
// IoCancelIrp() could have just been called on this IRP.
// What we're interested in is not whether IoCancelIrp() was called (nextIrp->Cancel flag set),
// but whether IoCancelIrp() called (or is about to call) our cancel routine.
// To check that, check the result of the test-and-set macro IoSetCancelRoutine.
if (oldCancelRoutine){
// Cancel routine not called for this IRP. Return this IRP.
ASSERT(oldCancelRoutine == IrpCancelRoutine);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -