📄 usb2com.write.cpp
字号:
//
// complete it directly,this is only happened if IoCancelIrp get called when we are in StartCurrentWriteIrp routine
//
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}
}
//
// queued write irp cancel routine
//
VOID Usb2ComQueuedWriteIrpCancel(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp)
{
PUSB2COM_DEVICE_EXTENSION DevExt = static_cast<PUSB2COM_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
//
// release global spin lock
//
IoReleaseCancelSpinLock(Irp->CancelIrql);
//
// acquire our write queue lock
//
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);
//
// remove the irp from write queue
//
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
DevExt->PendingWriteCharsCount -= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
//
// complete this irp with canceled
//
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
//
// release remove lock on this irp
//
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}
//
// get next write irp
//
PIRP Usb2ComGetNextWriteIrp(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
PIRP Irp = 0;
while(!Irp && !IsListEmpty(&DevExt->WriteQueueListHead))
{
PLIST_ENTRY ListEntry = RemoveHeadList(&DevExt->WriteQueueListHead);
Irp = CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
//
// handle irp cancel
//
PDRIVER_CANCEL OldCancelRoutine = IoSetCancelRoutine(Irp,0);
//
// IoCancelIrp could just been called on this irp,
//
if(OldCancelRoutine)
{
//
// our cancel routine has not been called,return it
//
ASSERT(OldCancelRoutine == &Usb2ComQueuedWriteIrpCancel);
}
else
{
//
// our cancel routine will be called on this irp,reinitialize list entry to make cancel routine happy
// this irp will be completed as soon as we release the write queue spin lock
//
ASSERT(Irp->Cancel);
InitializeListHead(&Irp->Tail.Overlay.ListEntry);
Irp = 0;
}
}
return Irp;
}
//
// complete current write irp
//
NTSTATUS Usb2ComCompleteCurrentWriteIrp(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in NTSTATUS Status,__in KIRQL SavedIrql)
{
PIRP Irp = DevExt->CurrentWriteIrp;
ASSERT(Irp);
PDRIVER_CANCEL OldCancel = IoSetCancelRoutine(Irp,0);
BOOLEAN CompleteCurrentIrpHere = TRUE;
if(OldCancel)
{
//
// our cancel routine has not been call
//
ASSERT(OldCancel == &Usb2ComCurrentWriteIrpCancel);
Irp->IoStatus.Status = Status;
DevExt->PendingWriteCharsCount -= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);
}
else
{
//
// our cancel routine will be called as soon as we release the write lock
//
CompleteCurrentIrpHere = FALSE;
}
DevExt->WriteBufferLength = 0;
DevExt->WriteBufferOffset = 0;
DevExt->WriteBuffer = 0;
InterlockedIncrement(&DevExt->CurrentWriteIrpSignature);
DevExt->CurrentWriteIrp = Usb2ComGetNextWriteIrp(DevExt);
ULONG EventFlags = 0;
if(DevExt->CurrentWriteIrp)
{
Usb2ComStartCurrentWriteIrp(DevExt,SavedIrql);
}
else
{
EventFlags = SERIAL_EV_TXEMPTY;
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
}
if(CompleteCurrentIrpHere)
{
IoCompleteRequest(Irp,IO_NO_INCREMENT);
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}
if(EventFlags)
Usb2ComProcessEvent(DevExt,EventFlags);
return Status;
}
//
// bulk out urb complete routine
//
NTSTATUS Usb2ComBulkOutUrbComplete(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp,__in PVOID Context)
{
PUSB2COM_DEVICE_EXTENSION DevExt = static_cast<PUSB2COM_DEVICE_EXTENSION>(Context);
NTSTATUS Status = Irp->IoStatus.Status;
PURB Urb = DevExt->BulkOutUrb;
ULONG TransferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);
//
// current bulk out urb is finished
//
DevExt->BulkOutUrbIsRunning = FALSE;
//
// check the signature
// if the signature is not the same,it means that we have already complete the current write irp
// then we should not touch those WriteBuffer* fields
//
if(DevExt->CurrentBulkOutUrbSignature == DevExt->CurrentWriteIrpSignature && DevExt->CurrentWriteIrp)
{
if(NT_SUCCESS(Status))
{
//
// update write buffer info
//
DevExt->WriteBufferLength -= TransferLength;
DevExt->WriteBufferOffset += TransferLength;
Irp = DevExt->CurrentWriteIrp;
Irp->IoStatus.Information += TransferLength;
DevExt->PendingWriteCharsCount -= TransferLength;
//
// complete current write irp
//
if(!DevExt->WriteBufferLength)
Usb2ComCompleteCurrentWriteIrp(DevExt,STATUS_SUCCESS,SavedIrql);
else
Usb2ComStartBulkOutUrb(DevExt,TRUE,SavedIrql);
}
else
{
Usb2ComCompleteCurrentWriteIrp(DevExt,Status,SavedIrql);
}
}
else
{
if(DevExt->CurrentWriteIrp)
Usb2ComStartCurrentWriteIrp(DevExt,SavedIrql);
else
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
//
// start bulk out urb
//
VOID Usb2ComStartBulkOutUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in BOOLEAN AlreadyLocked,__in KIRQL SavedIrql)
{
BOOLEAN ReleaseLock = TRUE;
__try
{
//
// acquire write lock
//
if(!AlreadyLocked)
KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);
//
// check write urb is running
//
if(!DevExt->BulkOutUrbIsRunning)
{
//
// check hold condition
//
if(DevExt->TxHoldReason)
try_leave(NOTHING);
//
// check buffer length
//
if(!DevExt->WriteBufferLength)
try_leave(NOTHING);
//
// copy write buffer to urb buffer and set its length
//
ULONG Length = DevExt->WriteBufferLength > 0x40 ? 0x40 : DevExt->WriteBufferLength;
RtlCopyMemory(DevExt->BulkOutBuffer,DevExt->WriteBuffer + DevExt->WriteBufferOffset,Length);
//
// set urb signature with irp signature
//
DevExt->CurrentBulkOutUrbSignature = DevExt->CurrentWriteIrpSignature;
//
// reuse write irp
//
IoReuseIrp(DevExt->BulkOutIrp,STATUS_SUCCESS);
UsbBuildInterruptOrBulkTransferRequest(DevExt->BulkOutUrb,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),DevExt->UsbInterfaceInfo->Pipes[1].PipeHandle,
DevExt->BulkOutBuffer,0,Length,USBD_TRANSFER_DIRECTION_OUT,0);
PIO_STACK_LOCATION NextIrpSp = IoGetNextIrpStackLocation(DevExt->BulkOutIrp);
NextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpSp->Parameters.Others.Argument1 = DevExt->BulkOutUrb;
NextIrpSp->Parameters.Others.Argument2 = 0;
NextIrpSp->Parameters.Others.Argument3 = reinterpret_cast<PVOID>(IOCTL_INTERNAL_USB_SUBMIT_URB);
NextIrpSp->Parameters.Others.Argument4 = 0;
IoSetCompletionRoutine(DevExt->BulkOutIrp,&Usb2ComBulkOutUrbComplete,DevExt,TRUE,TRUE,TRUE);
if(!DevExt->ForceBulkOutUrbStop)
{
DevExt->BulkOutUrbIsRunning = TRUE;
KeResetEvent(&DevExt->BulkOutUrbStopEvent);
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
ReleaseLock = FALSE;
IoCallDriver(DevExt->LowerDeviceObject,DevExt->BulkOutIrp);
}
}
}
__finally
{
if(ReleaseLock)
{
BOOLEAN SetEvent = !DevExt->BulkOutUrbIsRunning;
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
if(SetEvent)
KeSetEvent(&DevExt->BulkOutUrbStopEvent,IO_NO_INCREMENT,FALSE);
}
}
}
//
// stop bulk out urb
//
VOID Usb2ComStopBulkOutUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);
DevExt->ForceBulkOutUrbStop = TRUE;
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
IoCancelIrp(DevExt->BulkOutIrp);
}
//
// wait bulk out urb stop
//
VOID Usb2ComWaitBulkOutUrbStopped(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
KeWaitForSingleObject(&DevExt->BulkOutUrbStopEvent,Executive,KernelMode,FALSE,0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -