943 lines
20 KiB
C
943 lines
20 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
send.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that is very specific to initialization
|
|
and unload operations in the irenum driver
|
|
|
|
Author:
|
|
|
|
Brian Lieuallen, 7-13-2000
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "internal.h"
|
|
|
|
|
|
VOID
|
|
RemoveReferenceForBuffers(
|
|
PSEND_TRACKER SendTracker
|
|
);
|
|
|
|
VOID
|
|
ProcessSend(
|
|
PTDI_CONNECTION Connection
|
|
);
|
|
|
|
VOID
|
|
ProcessSendAtPassive(
|
|
PTDI_CONNECTION Connection
|
|
);
|
|
|
|
|
|
VOID
|
|
SendBufferToTdi(
|
|
PFILE_OBJECT FileObject,
|
|
PIRCOMM_BUFFER Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
SendCompletion(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
TryToCompleteCurrentIrp(
|
|
PSEND_TRACKER SendTracker
|
|
);
|
|
|
|
|
|
VOID
|
|
RemoveReferenceOnTracker(
|
|
PSEND_TRACKER SendTracker
|
|
)
|
|
|
|
|
|
{
|
|
LONG Count;
|
|
|
|
Count=InterlockedDecrement(&SendTracker->ReferenceCount);
|
|
|
|
if (Count == 0) {
|
|
|
|
REMOVE_REFERENCE_TO_CONNECTION(SendTracker->Connection);
|
|
|
|
FREE_POOL(SendTracker);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PIRP
|
|
GetCurrentIrpAndAddReference(
|
|
PSEND_TRACKER SendTracker
|
|
)
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
PIRP Irp;
|
|
|
|
KeAcquireSpinLock(
|
|
&SendTracker->Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
Irp=SendTracker->CurrentWriteIrp;
|
|
|
|
if (Irp != NULL) {
|
|
//
|
|
// irp is still around, add a ref coun to keep it around for a while.
|
|
//
|
|
SendTracker->IrpReferenceCount++;
|
|
}
|
|
|
|
|
|
KeReleaseSpinLock(
|
|
&SendTracker->Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
return Irp;
|
|
}
|
|
|
|
VOID
|
|
ReleaseIrpReference(
|
|
PSEND_TRACKER SendTracker
|
|
)
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
PIRP Irp=NULL;
|
|
CONNECTION_CALLBACK Callback=NULL;
|
|
PVOID Context;
|
|
|
|
KeAcquireSpinLock(
|
|
&SendTracker->Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
SendTracker->IrpReferenceCount--;
|
|
|
|
if (SendTracker->IrpReferenceCount==0) {
|
|
//
|
|
// done, with irp complete it now with the current status
|
|
//
|
|
Irp=SendTracker->CurrentWriteIrp;
|
|
|
|
SendTracker->CurrentWriteIrp=NULL;
|
|
|
|
Callback=SendTracker->CompletionRoutine;
|
|
Context=SendTracker->CompletionContext;
|
|
|
|
#if DBG
|
|
SendTracker->CompletionRoutine=NULL;
|
|
#endif
|
|
|
|
SendTracker->Connection->Send.CurrentSendTracker=NULL;
|
|
}
|
|
|
|
|
|
KeReleaseSpinLock(
|
|
&SendTracker->Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
if (Irp != NULL) {
|
|
//
|
|
// The ref count has gone to zero, complete the irp
|
|
//
|
|
(Callback)(
|
|
Context,
|
|
Irp
|
|
);
|
|
|
|
//
|
|
// release the reference for the irp
|
|
//
|
|
RemoveReferenceOnTracker(SendTracker);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SetIrpAndRefcounts(
|
|
PSEND_TRACKER SendTracker,
|
|
PIRP Irp
|
|
)
|
|
|
|
{
|
|
//
|
|
// set the tracker refcount to 2, one for the irp, and one for the rountine that called this
|
|
//
|
|
SendTracker->ReferenceCount=2;
|
|
//
|
|
// Set the irp count to one for the rountine that called this, it will release when it done
|
|
// setting up the tracker block
|
|
//
|
|
SendTracker->IrpReferenceCount=1;
|
|
|
|
//
|
|
// save the irp
|
|
//
|
|
SendTracker->CurrentWriteIrp=Irp;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
SendTimerProc(
|
|
PKDPC Dpc,
|
|
PVOID Context,
|
|
PVOID SystemParam1,
|
|
PVOID SystemParam2
|
|
)
|
|
|
|
{
|
|
PSEND_TRACKER SendTracker=Context;
|
|
PIRP Irp;
|
|
KIRQL OldIrql;
|
|
|
|
D_ERROR(DbgPrint("IRCOMM: SendTimerProc\n");)
|
|
|
|
ASSERT(SendTracker->TimerSet);
|
|
#if DBG
|
|
SendTracker->TimerExpired=TRUE;
|
|
#endif
|
|
|
|
SendTracker->TimerSet=FALSE;
|
|
|
|
//
|
|
// try to get a hold of the irp so we can set the status
|
|
//
|
|
Irp=GetCurrentIrpAndAddReference(SendTracker);
|
|
|
|
Irp->IoStatus.Status=STATUS_TIMEOUT;
|
|
|
|
//
|
|
// release on reference for the one we just added
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
|
|
TryToCompleteCurrentIrp(
|
|
SendTracker
|
|
);
|
|
|
|
//
|
|
// release the second reference for the timer being set in the first place
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SendCancelRoutine(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
|
|
{
|
|
PSEND_TRACKER SendTracker=Irp->Tail.Overlay.DriverContext[0];
|
|
KIRQL OldIrql;
|
|
|
|
D_ERROR(DbgPrint("IRCOMM: SendCancelRoutine\n");)
|
|
|
|
#if DBG
|
|
SendTracker->IrpCanceled=TRUE;
|
|
#endif
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
Irp->IoStatus.Status=STATUS_CANCELLED;
|
|
|
|
//
|
|
// clean up the timer
|
|
//
|
|
TryToCompleteCurrentIrp(SendTracker);
|
|
|
|
//
|
|
// release the reference held for the cancel routine
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
|
|
//
|
|
// send tracker maybe freed at this point
|
|
//
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
TryToCompleteCurrentIrp(
|
|
PSEND_TRACKER SendTracker
|
|
)
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PVOID OldCancelRoutine=NULL;
|
|
PIRP Irp;
|
|
BOOLEAN TimerCanceled=FALSE;
|
|
|
|
Irp=GetCurrentIrpAndAddReference(SendTracker);
|
|
|
|
KeAcquireSpinLock(
|
|
&SendTracker->Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
if (SendTracker->TimerSet) {
|
|
|
|
TimerCanceled=KeCancelTimer(
|
|
&SendTracker->Timer
|
|
);
|
|
|
|
if (TimerCanceled) {
|
|
//
|
|
// We ended up canceling the timer
|
|
//
|
|
SendTracker->TimerSet=FALSE;
|
|
|
|
} else {
|
|
//
|
|
// The timer is already running, we will just let it complete
|
|
// and do the clean up.
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
if (Irp != NULL) {
|
|
//
|
|
// the irp has not already been completed
|
|
//
|
|
OldCancelRoutine=IoSetCancelRoutine(
|
|
Irp,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
KeReleaseSpinLock(
|
|
&SendTracker->Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
if (TimerCanceled) {
|
|
//
|
|
// we canceled the timer before it could run, remove the reference for it
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
}
|
|
|
|
if (Irp != NULL) {
|
|
|
|
if (OldCancelRoutine != NULL) {
|
|
//
|
|
// since the cancel rountine had not run, release its reference to the irp
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
}
|
|
|
|
//
|
|
// if this routine got the irp, release the reference to it
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
SendOnConnection(
|
|
IRDA_HANDLE Handle,
|
|
PIRP Irp,
|
|
CONNECTION_CALLBACK Callback,
|
|
PVOID Context,
|
|
ULONG Timeout
|
|
)
|
|
|
|
{
|
|
|
|
PTDI_CONNECTION Connection=Handle;
|
|
PIO_STACK_LOCATION IrpSp=IoGetCurrentIrpStackLocation(Irp);
|
|
PSEND_TRACKER SendTracker;
|
|
BOOLEAN AlreadyCanceled;
|
|
KIRQL OldIrql;
|
|
KIRQL OldCancelIrql;
|
|
|
|
|
|
if (Connection->Send.CurrentSendTracker != NULL) {
|
|
//
|
|
// called when we already have an irp
|
|
//
|
|
(Callback)(
|
|
Context,
|
|
Irp
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
SendTracker=ALLOCATE_NONPAGED_POOL(sizeof(*SendTracker));
|
|
|
|
if (SendTracker == NULL) {
|
|
|
|
Irp->IoStatus.Status=STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
(Callback)(
|
|
Context,
|
|
Irp
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory(SendTracker,sizeof(*SendTracker));
|
|
|
|
|
|
KeInitializeTimer(
|
|
&SendTracker->Timer
|
|
);
|
|
|
|
KeInitializeDpc(
|
|
&SendTracker->TimerDpc,
|
|
SendTimerProc,
|
|
SendTracker
|
|
);
|
|
|
|
//
|
|
// set the irp and initialize the refcounts
|
|
//
|
|
SetIrpAndRefcounts(SendTracker,Irp);
|
|
|
|
ADD_REFERENCE_TO_CONNECTION(Connection);
|
|
|
|
//
|
|
// initialize these values
|
|
//
|
|
SendTracker->Connection=Connection;
|
|
SendTracker->BuffersOutstanding=0;
|
|
|
|
SendTracker->CompletionContext = Context;
|
|
SendTracker->CompletionRoutine = Callback;
|
|
SendTracker->BytesRemainingInIrp = IrpSp->Parameters.Write.Length;
|
|
|
|
if (Timeout > 0) {
|
|
//
|
|
// add a reference for the timer
|
|
//
|
|
GetCurrentIrpAndAddReference(SendTracker);
|
|
}
|
|
|
|
//
|
|
// add a reference to the irp for the cancel rountine
|
|
//
|
|
GetCurrentIrpAndAddReference(SendTracker);
|
|
|
|
|
|
KeAcquireSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
Connection->Send.CurrentSendTracker=SendTracker;
|
|
|
|
if (Timeout > 0) {
|
|
//
|
|
// need to set a timer
|
|
//
|
|
LARGE_INTEGER DueTime;
|
|
|
|
DueTime.QuadPart= (LONGLONG)(Timeout+100) * -10000;
|
|
|
|
SendTracker->TimerSet=TRUE;
|
|
|
|
|
|
KeSetTimer(
|
|
&SendTracker->Timer,
|
|
DueTime,
|
|
&SendTracker->TimerDpc
|
|
);
|
|
}
|
|
|
|
|
|
Irp->Tail.Overlay.DriverContext[0]=SendTracker;
|
|
|
|
IoAcquireCancelSpinLock(&OldCancelIrql);
|
|
|
|
|
|
AlreadyCanceled=Irp->Cancel;
|
|
|
|
if (!AlreadyCanceled) {
|
|
|
|
PIRCOMM_BUFFER Buffer;
|
|
|
|
//
|
|
// the irp has not been canceled already, set the cancel routine
|
|
//
|
|
IoSetCancelRoutine(
|
|
Irp,
|
|
SendCancelRoutine
|
|
);
|
|
|
|
|
|
} else {
|
|
//
|
|
// it was canceled when we got it
|
|
//
|
|
Irp->IoStatus.Status=STATUS_CANCELLED;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(OldCancelIrql);
|
|
|
|
KeReleaseSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
if (AlreadyCanceled) {
|
|
//
|
|
// The irp has already been canceled, just call the cancel rountine so the normal code runs
|
|
//
|
|
D_ERROR(DbgPrint("IRCOMM: SendOnConnection: irp already canceled\n");)
|
|
|
|
IoAcquireCancelSpinLock(&Irp->CancelIrql);
|
|
|
|
SendCancelRoutine(
|
|
NULL,
|
|
Irp
|
|
);
|
|
|
|
//
|
|
// the cancel rountine will release the cancel spinlock
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// release the reference for this routine
|
|
//
|
|
ReleaseIrpReference(SendTracker);
|
|
|
|
ProcessSendAtPassive(Connection);
|
|
|
|
RemoveReferenceOnTracker(SendTracker);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ProcessSendAtPassive(
|
|
PTDI_CONNECTION Connection
|
|
)
|
|
|
|
{
|
|
if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
|
|
//
|
|
// less than dispatch, just call directly
|
|
//
|
|
ProcessSend(Connection);
|
|
|
|
} else {
|
|
//
|
|
// Called at dispatch, queue the work item
|
|
//
|
|
LONG Count=InterlockedIncrement(&Connection->Send.WorkItemCount);
|
|
|
|
if (Count == 1) {
|
|
|
|
ExQueueWorkItem(&Connection->Send.WorkItem,CriticalWorkQueue);
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SendWorkItemRountine(
|
|
PVOID Context
|
|
)
|
|
|
|
{
|
|
PTDI_CONNECTION Connection=Context;
|
|
|
|
//
|
|
// the work item has run set the count to zero
|
|
//
|
|
InterlockedExchange(&Connection->Send.WorkItemCount,0);
|
|
|
|
ProcessSend(Connection);
|
|
}
|
|
|
|
|
|
VOID
|
|
ProcessSend(
|
|
PTDI_CONNECTION Connection
|
|
)
|
|
|
|
{
|
|
PSEND_TRACKER SendTracker;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PLIST_ENTRY ListEntry;
|
|
ULONG BytesUsedInBuffer;
|
|
PIRCOMM_BUFFER Buffer;
|
|
BOOLEAN ExitLoop;
|
|
PFILE_OBJECT FileObject;
|
|
CONNECTION_HANDLE ConnectionHandle;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
KeAcquireSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
if (Connection->Send.ProcessSendEntryCount == 0) {
|
|
|
|
Connection->Send.ProcessSendEntryCount++;
|
|
|
|
while ((Connection->Send.CurrentSendTracker != NULL)
|
|
&&
|
|
(!Connection->Send.OutOfBuffers)
|
|
&&
|
|
(Connection->LinkUp)
|
|
&&
|
|
(Connection->Send.CurrentSendTracker->BytesRemainingInIrp > 0)) {
|
|
|
|
|
|
SendTracker=Connection->Send.CurrentSendTracker;
|
|
|
|
InterlockedIncrement(&SendTracker->ReferenceCount);
|
|
|
|
KeReleaseSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
Irp=GetCurrentIrpAndAddReference(SendTracker);
|
|
|
|
if (Irp != NULL) {
|
|
//
|
|
// got the current irp
|
|
//
|
|
IrpSp=IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ConnectionHandle=GetCurrentConnection(Connection->LinkHandle);
|
|
|
|
if (ConnectionHandle != NULL) {
|
|
//
|
|
// we have a good connection
|
|
//
|
|
FileObject=ConnectionGetFileObject(ConnectionHandle);
|
|
|
|
Buffer=ConnectionGetBuffer(ConnectionHandle,BUFFER_TYPE_SEND);
|
|
|
|
if (Buffer != NULL) {
|
|
|
|
LONG BytesToCopy=min(SendTracker->BytesRemainingInIrp, (LONG)Buffer->BufferLength - 1);
|
|
|
|
//
|
|
// this buffer is going to be outstanding, set this before the bytes
|
|
// remaining count goes to zero
|
|
//
|
|
InterlockedIncrement(&SendTracker->BuffersOutstanding);
|
|
|
|
//
|
|
// start with a zero length of control bytes
|
|
//
|
|
Buffer->Data[0]=0;
|
|
|
|
//
|
|
// actual data starts one byte in, after the length byte
|
|
//
|
|
// move the data
|
|
//
|
|
RtlCopyMemory(
|
|
&Buffer->Data[1],
|
|
(PUCHAR)Irp->AssociatedIrp.SystemBuffer+(IrpSp->Parameters.Write.Length - SendTracker->BytesRemainingInIrp),
|
|
BytesToCopy
|
|
);
|
|
|
|
//
|
|
// the count has to include the control byte
|
|
//
|
|
Buffer->Mdl->ByteCount= 1 + BytesToCopy;
|
|
|
|
#if DBG
|
|
RtlFillMemory(
|
|
&Buffer->Data[Buffer->Mdl->ByteCount],
|
|
Buffer->BufferLength-Buffer->Mdl->ByteCount,
|
|
0xfb
|
|
);
|
|
|
|
#endif
|
|
|
|
InterlockedExchangeAdd(&SendTracker->BytesRemainingInIrp, -BytesToCopy);
|
|
|
|
|
|
Buffer->Mdl->Next=NULL;
|
|
|
|
Buffer->Context=SendTracker;
|
|
|
|
|
|
InterlockedIncrement(&SendTracker->ReferenceCount);
|
|
|
|
ASSERT(SendTracker->CurrentWriteIrp != NULL);
|
|
|
|
SendBufferToTdi(
|
|
FileObject,
|
|
Buffer
|
|
);
|
|
#if DBG
|
|
Buffer=NULL;
|
|
#endif
|
|
|
|
} else {
|
|
//
|
|
// No more buffers availible
|
|
//
|
|
Connection->Send.OutOfBuffers=TRUE;
|
|
|
|
}
|
|
|
|
ConnectionReleaseFileObject(ConnectionHandle,FileObject);
|
|
ReleaseConnection(ConnectionHandle);
|
|
|
|
} else {
|
|
//
|
|
// The connection, must be down
|
|
//
|
|
D_ERROR(DbgPrint("IRCOMM: ProcessSend: Link down\n");)
|
|
Connection->LinkUp=FALSE;
|
|
}
|
|
|
|
ReleaseIrpReference(SendTracker);
|
|
|
|
} else {
|
|
//
|
|
// the irp has already been completed from this tracking block
|
|
//
|
|
D_ERROR(DbgPrint("IRCOMM: ProcessSend: no irp\n");)
|
|
|
|
ASSERT(SendTracker->TimerExpired || SendTracker->IrpCanceled || SendTracker->SendAborted);
|
|
}
|
|
|
|
RemoveReferenceOnTracker(SendTracker);
|
|
|
|
KeAcquireSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
} // while
|
|
|
|
Connection->Send.ProcessSendEntryCount--;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeReleaseSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
SendBufferToTdi(
|
|
PFILE_OBJECT FileObject,
|
|
PIRCOMM_BUFFER Buffer
|
|
)
|
|
|
|
{
|
|
PDEVICE_OBJECT IrdaDeviceObject=IoGetRelatedDeviceObject(FileObject);
|
|
ULONG SendLength;
|
|
|
|
IoReuseIrp(Buffer->Irp,STATUS_SUCCESS);
|
|
|
|
Buffer->Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
|
|
|
|
|
SendLength = MmGetMdlByteCount(Buffer->Mdl);
|
|
|
|
TdiBuildSend(
|
|
Buffer->Irp,
|
|
IrdaDeviceObject,
|
|
FileObject,
|
|
SendCompletion,
|
|
Buffer,
|
|
Buffer->Mdl,
|
|
0, // send flags
|
|
SendLength
|
|
);
|
|
|
|
|
|
IoCallDriver(IrdaDeviceObject, Buffer->Irp);
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
SendCompletion(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP BufferIrp,
|
|
PVOID Context
|
|
)
|
|
|
|
{
|
|
PIRCOMM_BUFFER Buffer=Context;
|
|
PSEND_TRACKER SendTracker=Buffer->Context;
|
|
PTDI_CONNECTION Connection=SendTracker->Connection;
|
|
LONG BuffersOutstanding;
|
|
|
|
//
|
|
// save off the status for the sub transerfer
|
|
//
|
|
SendTracker->LastStatus=BufferIrp->IoStatus.Status;
|
|
|
|
D_TRACE(DbgPrint("IRCOMM: SendComplete: Status=%08lx, len=%d\n",BufferIrp->IoStatus.Status,BufferIrp->IoStatus.Information);)
|
|
|
|
#if DBG
|
|
RtlFillMemory(
|
|
&Buffer->Data[0],
|
|
Buffer->BufferLength,
|
|
0xfe
|
|
);
|
|
#endif
|
|
//
|
|
// return the buffer
|
|
//
|
|
Buffer->FreeBuffer(Buffer);
|
|
|
|
Connection->Send.OutOfBuffers=FALSE;
|
|
|
|
#if DBG
|
|
Buffer=NULL;
|
|
BufferIrp=NULL;
|
|
#endif
|
|
|
|
BuffersOutstanding=InterlockedDecrement(&SendTracker->BuffersOutstanding);
|
|
|
|
if ((BuffersOutstanding == 0) && (SendTracker->BytesRemainingInIrp == 0)) {
|
|
//
|
|
// All of the data in the irp has been sent and all of the irps send to
|
|
// the irda stack have completed
|
|
//
|
|
// Done with the irp in this tracker
|
|
//
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
Irp=GetCurrentIrpAndAddReference(SendTracker);
|
|
|
|
if (Irp != NULL) {
|
|
|
|
IrpSp=IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Irp->IoStatus.Information=IrpSp->Parameters.Write.Length;
|
|
|
|
Irp->IoStatus.Status=SendTracker->LastStatus;
|
|
|
|
ReleaseIrpReference(SendTracker);
|
|
|
|
TryToCompleteCurrentIrp(SendTracker);
|
|
|
|
} else {
|
|
//
|
|
// the irp has already been completed from this tracking block
|
|
//
|
|
D_ERROR(DbgPrint("IRCOMM: SendCompletion: no irp\n");)
|
|
|
|
//
|
|
// this should only happen if the timer expired or the irp was canceled
|
|
//
|
|
ASSERT(SendTracker->TimerExpired || SendTracker->IrpCanceled || SendTracker->SendAborted);
|
|
|
|
}
|
|
}
|
|
|
|
RemoveReferenceOnTracker(SendTracker);
|
|
|
|
ProcessSendAtPassive(Connection);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AbortSend(
|
|
IRDA_HANDLE Handle
|
|
)
|
|
|
|
{
|
|
|
|
PTDI_CONNECTION Connection=Handle;
|
|
PSEND_TRACKER SendTracker=NULL;
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
|
|
SendTracker=Connection->Send.CurrentSendTracker;
|
|
|
|
if (SendTracker != NULL) {
|
|
|
|
InterlockedIncrement(&SendTracker->ReferenceCount);
|
|
}
|
|
|
|
|
|
KeReleaseSpinLock(
|
|
&Connection->Send.ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
|
|
if (SendTracker != NULL) {
|
|
|
|
#if DBG
|
|
SendTracker->SendAborted=TRUE;
|
|
#endif
|
|
|
|
TryToCompleteCurrentIrp(SendTracker);
|
|
|
|
RemoveReferenceOnTracker(SendTracker);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|