📄 usb2com.write.cpp
字号:
//********************************************************************
// created: 11:7:2008 21:30
// file: usb2com.write.cpp
// author: tiamo
// purpose: write
//********************************************************************
#include "stdafx.h"
//
// write dispatch routine
//
NTSTATUS Usb2ComWrite(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp)
{
PUSB2COM_DEVICE_EXTENSION DevExt = static_cast<PUSB2COM_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status = STATUS_SUCCESS;
//
// check zero-length write
//
if(!IrpSp->Parameters.Write.Length)
{
Irp->IoStatus.Status = Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return Status;
}
//
// acquire remove lock
//
Status = IoAcquireRemoveLock(&DevExt->RemoveLock,Irp);
if(!NT_SUCCESS(Status))
{
//
// we are removing
//
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return Status;
}
//
// set information with zero
//
Irp->IoStatus.Information = 0;
//
// protected by write lock
//
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);
//
// if there is a pending write irp,just queue this irp
//
if(DevExt->CurrentWriteIrp)
{
PDRIVER_CANCEL OldCancel = IoSetCancelRoutine(Irp,&Usb2ComQueuedWriteIrpCancel);
ASSERT(!OldCancel);
//
// IoCancelIrp called
//
if(Irp->Cancel)
{
OldCancel = IoSetCancelRoutine(Irp,0);
if(OldCancel)
{
//
// our cancel routine has not been called,complete it here
//
ASSERT(OldCancel == &Usb2ComQueuedWriteIrpCancel);
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
Status = STATUS_CANCELLED;
}
else
{
//
// our cancel routine will be called as soon as we release the write lock
//
IoMarkIrpPending(Irp);
InitializeListHead(&Irp->Tail.Overlay.ListEntry);
DevExt->PendingWriteCharsCount += IrpSp->Parameters.Write.Length;
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
Status = STATUS_PENDING;
}
}
else
{
//
// mark it pending and queue it
//
IoMarkIrpPending(Irp);
InsertTailList(&DevExt->WriteQueueListHead,&Irp->Tail.Overlay.ListEntry);
DevExt->PendingWriteCharsCount += IrpSp->Parameters.Write.Length;
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
Status = STATUS_PENDING;
}
}
else
{
//
// set as the current write irp,and start it
//
DevExt->CurrentWriteIrp = Irp;
DevExt->PendingWriteCharsCount += IrpSp->Parameters.Write.Length;
Status = Usb2ComStartCurrentWriteIrp(DevExt,SavedIrql);
}
return Status;
}
//
// cancel all write irps
//
VOID Usb2ComCancelAllWriteIrps(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);
LIST_ENTRY CompleteIrpListHead;
InitializeListHead(&CompleteIrpListHead);
PIRP Irp = Usb2ComGetNextWriteIrp(DevExt);
while(Irp)
{
InsertTailList(&CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);
Irp = Usb2ComGetNextWriteIrp(DevExt);
}
Irp = DevExt->CurrentWriteIrp;
if(Irp)
{
PDRIVER_CANCEL OldCancel = IoSetCancelRoutine(Irp,0);
if(OldCancel)
InsertTailList(&CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);
DevExt->CurrentWriteIrp = 0;
}
DevExt->PendingWriteCharsCount = 0;
DevExt->WriteBuffer = 0;
DevExt->WriteBufferLength = 0;
DevExt->WriteBufferOffset = 0;
InterlockedIncrement(&DevExt->CurrentWriteIrpSignature);
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
while(!IsListEmpty(&CompleteIrpListHead))
{
PLIST_ENTRY ListEntry = RemoveHeadList(&CompleteIrpListHead);
PIRP Irp = CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}
}
//
// start current write irp
//
NTSTATUS Usb2ComStartCurrentWriteIrp(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in KIRQL SavedIrql)
{
PIRP Irp = DevExt->CurrentWriteIrp;
NTSTATUS Status = STATUS_PENDING;
BOOLEAN TheFirstIrp = TRUE;
LIST_ENTRY CancelIrpListHead;
//
// we put canceled irps into this list
//
InitializeListHead(&CancelIrpListHead);
do
{
//
// setup a cancel routine
//
PDRIVER_CANCEL OldCancelRoutine = IoSetCancelRoutine(Irp,&Usb2ComCurrentWriteIrpCancel);
ASSERT(!OldCancelRoutine);
//
// IoCancelIrp is called on this irp
//
if(Irp->Cancel)
{
OldCancelRoutine = IoSetCancelRoutine(Irp,0);
if(OldCancelRoutine)
{
//
// our cancel routine has not been called
//
Irp->IoStatus.Status = STATUS_CANCELLED;
//
// put it into canceled irp list
//
InsertHeadList(&CancelIrpListHead,&Irp->Tail.Overlay.ListEntry);
DevExt->PendingWriteCharsCount -= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);
if(TheFirstIrp)
{
Status = STATUS_CANCELLED;
TheFirstIrp = FALSE;
}
}
else
{
//
// our cancel routine will be called as soon as we release the write lock
//
TheFirstIrp = FALSE;
IoMarkIrpPending(Irp);
}
}
else
{
//
// mark this irp pending
//
IoMarkIrpPending(Irp);
//
// setup buffer info
//
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
DevExt->WriteBufferLength = IrpSp->Parameters.Write.Length;
DevExt->WriteBufferOffset = 0;
DevExt->WriteBuffer = static_cast<PUCHAR>(Irp->AssociatedIrp.SystemBuffer);
InterlockedIncrement(&DevExt->CurrentWriteIrpSignature);
//
// start bulk out urb
//
Usb2ComStartBulkOutUrb(DevExt,TRUE,SavedIrql);
break;
}
DevExt->CurrentWriteIrp = Usb2ComGetNextWriteIrp(DevExt);
Irp = DevExt->CurrentWriteIrp;
}while(Irp);
//
// if irp is NULL,it means that we did not start any bulk urb,so we need release write lock first
//
if(!Irp)
KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
//
// complete canceled irps
//
while(!IsListEmpty(&CancelIrpListHead))
{
PLIST_ENTRY ListEntry = RemoveHeadList(&CancelIrpListHead);
Irp = CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
IoCompleteRequest(Irp,IO_NO_INCREMENT);
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}
return Status;
}
//
// current write irp cancel routine
//
VOID Usb2ComCurrentWriteIrpCancel(__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);
//
// if it is the current write irp,complete it and start the next one
//
if(Irp == DevExt->CurrentWriteIrp)
{
Usb2ComCompleteCurrentWriteIrp(DevExt,STATUS_CANCELLED,SavedIrql);
}
else
{
DevExt->PendingWriteCharsCount -= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -