📄 rw.c
字号:
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION nextStack;
UCHAR length;
KIRQL oldIrql;
PIRP CurrentOpIrp;
DbgPrint("StartWriteIntUrb Enter.\n");
deviceExtension = DeviceObject->DeviceExtension;
//deviceExtension->CurrentWriteIrpDataPtr = (UCHAR *)MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority );
//deviceExtension->CurrentWriteIrpDataLen = MmGetMdlByteCount(Irp->MdlAddress);
deviceExtension->WriteIntUrb.Idle = FALSE;
if(deviceExtension->CurrentWriteIrpDataLen > 7)
{
//deviceExtension->CurrentWriteIrpDataLen -= 7;
length = 7;
}else{
length = (UCHAR)deviceExtension->CurrentWriteIrpDataLen;
//deviceExtension->CurrentWriteIrpDataLen = 0;
}
deviceExtension->WriteIntUrb.TransferBuffer[0] = length;
RtlCopyMemory(
&deviceExtension->WriteIntUrb.TransferBuffer[1],
deviceExtension->CurrentWriteIrpDataPtr,
length
);
//deviceExtension->CurrentWriteIrpDataPtr += length;
InitIntUrb(
deviceExtension->WriteIntUrb.Urb,
deviceExtension->WriteIntUrb.PipeInfo->PipeHandle,
deviceExtension->WriteIntUrb.TransferBuffer,
length+1,
TRUE);
// IoReuseIrp(deviceExtension->WriteIntUrb.Irp,STATUS_SUCCESS);
nextStack = IoGetNextIrpStackLocation(deviceExtension->WriteIntUrb.Irp);
USB2COM_ASSERT(nextStack != NULL);
USB2COM_ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = deviceExtension->WriteIntUrb.Urb;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(deviceExtension->WriteIntUrb.Irp,
WriteIntUrbComplete,
&deviceExtension->WriteIntUrb, // pass the context array element to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
USB2COM_IncrementIoCount(DeviceObject);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, deviceExtension->WriteIntUrb.Irp );
//ASSERT( ntStatus == STATUS_PENDING);
DbgPrint("StartWriteIntUrb Exit\n");
return ntStatus;
}
NTSTATUS
StopWriteIntUrb(
IN PDEVICE_EXTENSION deviceExtension
)
{
KIRQL oldIrql;
DbgPrint("StopWriteIntUrb Enter\n");
//KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
if(deviceExtension->WriteIntUrb.Irp
&& !deviceExtension->WriteIntUrb.Idle)
{
//KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
DbgPrint("Cancel WriteIntUrb.Irp\n");
IoCancelIrp(deviceExtension->WriteIntUrb.Irp);
}else{
// KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}
DbgPrint("StopWriteIntUrb Exit\n");
return STATUS_SUCCESS;
}
void
FreeWriteIntUrb(
IN PDEVICE_EXTENSION deviceExtension
)
{
KIRQL oldIrql;
DbgPrint("FreeWriteIntUrb enter\n");
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
if(deviceExtension->WriteIntUrb.Irp)
{
IoFreeIrp(deviceExtension->WriteIntUrb.Irp);
deviceExtension->WriteIntUrb.Irp = NULL;
}
if(deviceExtension->WriteIntUrb.Urb)
{
USB2COM_ExFreePool(deviceExtension->WriteIntUrb.Urb);
deviceExtension->WriteIntUrb.Urb = NULL;
}
DbgPrint("FreeWriteIntUrb exit\n");
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}
NTSTATUS
WriteIntUrbComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_OBJECT deviceObject;
NTSTATUS ntStatus;
USBD_STATUS usbdStatus;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION nextStack;
PINT_URBS pIntUrbs;
PIRP irp;
PURB urb;
KIRQL oldIrql;
DbgPrint("WriteIntUrbComplete Enter: DeviceObject=%p, Irp=%p, Context=%p\n",
DeviceObject,
Irp,
Context);
pIntUrbs = (PINT_URBS)Context;
irp = pIntUrbs->Irp;
urb = pIntUrbs->Urb;
deviceObject = pIntUrbs->deviceObject;
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
DbgPrint("irp = %p, urb = %p, deviceObject = %p\n",irp,urb,deviceObject);
ASSERT(irp == Irp);
ASSERT(pIntUrbs->TransferBuffer == urb->UrbBulkOrInterruptTransfer.TransferBuffer);
ntStatus = irp->IoStatus.Status;
usbdStatus = urb->UrbHeader.Status;
DbgPrint("ntStatus=%x,usbdStatus=%x\n",ntStatus,usbdStatus);
if((ntStatus == STATUS_CANCELLED)
|| (ntStatus == STATUS_DEVICE_NOT_CONNECTED)
|| (usbdStatus == STATUS_DEVICE_NOT_CONNECTED))
{
PIRP CurrentOpIrp;
pIntUrbs->Idle = TRUE;
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
//IoFreeIrp(Irp);
//pIntUrbs->Irp = NULL;
//USB2COM_ExFreePool(pIntUrbs->Urb);
//pIntUrbs->Urb = NULL;
//DbgBreakPoint();
CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentWriteIrp, NULL);
if(CurrentOpIrp) {
CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
CurrentOpIrp->IoStatus.Information = 0;
IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
}
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
//DbgBreakPoint();
USB2COM_DecrementIoCount(deviceObject);
return STATUS_MORE_PROCESSING_REQUIRED;
}
if(USBD_SUCCESS(usbdStatus))
{
ULONG length = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
DbgPrint("WriteIntUrbComplete: length = %d\n",length);
length -= 1;
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
deviceExtension->CurrentWriteIrpDataLen -= length;
deviceExtension->CurrentWriteIrpDataPtr += length;
deviceExtension->TotalCharsQueued -= length;
//check whether we can complete the current Write Irp;
if(deviceExtension->CurrentWriteIrpDataLen <= 0)
{
DbgPrint("Complete CurrentWriteIrp %d\n",
deviceExtension->CurrentWriteIrpRequestLen);
if(deviceExtension->CurrentWriteIrp)
{
deviceExtension->CurrentWriteIrp->IoStatus.Information =
deviceExtension->CurrentWriteIrpRequestLen;
deviceExtension->CurrentWriteIrp->IoStatus.Status = ntStatus;
IoCompleteRequest(deviceExtension->CurrentWriteIrp,IO_NO_INCREMENT);
}
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
deviceExtension->CurrentWriteIrp = DequeueWriteIrp(deviceExtension);
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
if(deviceExtension->CurrentWriteIrp)
{
deviceExtension->CurrentWriteIrpDataPtr =
(UCHAR *)MmGetSystemAddressForMdlSafe(
deviceExtension->CurrentWriteIrp->MdlAddress,
NormalPagePriority );
deviceExtension->CurrentWriteIrpRequestLen =
deviceExtension->CurrentWriteIrpDataLen =
MmGetMdlByteCount(
deviceExtension->CurrentWriteIrp->MdlAddress
);
}
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}else
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}
USB2COM_DecrementIoCount(deviceObject);
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
pIntUrbs->Idle = TRUE;
if(deviceExtension->CurrentWriteIrp)
{
//
//circulate the irps.
//
DbgPrint("Circulate the irp\n");
StartWriteIntUrb(deviceObject);
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}else{
ASSERT(deviceExtension->TotalCharsQueued == 0);
deviceExtension->HistoryMask |= SERIAL_EV_TXEMPTY;
if(deviceExtension->CurrentWaitIrp &&
(deviceExtension->HistoryMask & deviceExtension->WaitMask))
{
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
SerialCompleteCurrentWait(
deviceExtension->CurrentWaitIrp,
deviceExtension->HistoryMask & deviceExtension->WaitMask);
}else
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID WriteIrpCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KIRQL oldIrql;
DbgPrint("WriteIrpCancelRoutine Enter\n");
// Release the global cancel spin lock.
// Do this while not holding any other spin locks so that we exit at the right IRQL.
IoReleaseCancelSpinLock(Irp->CancelIrql);
//
// Dequeue and complete the IRP.
// The enqueue and dequeue functions synchronize properly so that if this cancel routine is called,
// the dequeue is safe and only the cancel routine will complete the IRP. Hold the spin lock for the IRP
// queue while we do this.
//
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
// Complete the IRP. This is a call outside the driver, so all spin locks must be released by this point.
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DbgPrint("WriteIrpCancelRoutine Exit\n");
return;
}
NTSTATUS QueueOrStartWriteIrp(PDEVICE_EXTENSION deviceExtension, PIRP Irp)
{
PDRIVER_CANCEL oldCancelRoutine;
KIRQL oldIrql;
NTSTATUS status = STATUS_PENDING;
PIRP CurrentOpIrp;
PUCHAR ioBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority );
ULONG ioLength = MmGetMdlByteCount(Irp->MdlAddress);
DbgPrint("QueueOrStartWriteIrp Enter\n");
if((ioLength <= 0) || (ioBuffer == NULL))
{
DbgPrint("CurrentWriteIrpDataLen %d\n",
deviceExtension->CurrentWriteIrpDataLen);
//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->WriteIntUrb.Irp == NULL)
|| (deviceExtension->WriteIntUrb.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;
}
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
deviceExtension->TotalCharsQueued += ioLength;
if(IsListEmpty(&deviceExtension ->WriteQueue) && !deviceExtension->CurrentWriteIrp)
{
DbgPrint("WriteQueue is Empty, StartWriteIrp immediately\n");
deviceExtension->CurrentWriteIrp = Irp;
deviceExtension->CurrentWriteIrpDataPtr = ioBuffer;
deviceExtension->CurrentWriteIrpRequestLen =
deviceExtension->CurrentWriteIrpDataLen = ioLength;
IoMarkIrpPending(Irp);
status = StartWriteIntUrb(deviceExtension->DeviceObject);
}else{
// 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->WriteQueue, &Irp->Tail.Overlay.ListEntry);
// Must set a Cancel routine before checking the Cancel flag.
oldCancelRoutine = IoSetCancelRoutine(Irp, WriteIrpCancelRoutine);
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->WriteQueueSpinLock, 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_CANCELLED){
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
DbgPrint("QueueOrStartWriteIrp Exit\n");
return status;
}
PIRP DequeueWriteIrp(PDEVICE_EXTENSION deviceExtension)
{
KIRQL oldIrql;
PIRP nextIrp = NULL;
DbgPrint("DequeueWriteIrp Enter\n");
KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
while (!nextIrp && !IsListEmpty(&deviceExtension ->WriteQueue)){
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);
}
else {
// This IRP was just canceled and the cancel routine was (or will be) called.
// The cancel routine will complete this IRP as soon as we drop the spin lock,
// so don't do anything with the IRP.
// Also, the cancel routine will try to dequeue the IRP,
// so make the IRP's listEntry point to itself.
ASSERT(nextIrp->Cancel);
InitializeListHead(&nextIrp->Tail.Overlay.ListEntry);
nextIrp = NULL;
}
}
KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
DbgPrint("DequeueWriteIrp Exit\n");
return nextIrp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -