windows-nt/Source/XPSP1/NT/net/rras/ndis/asyncmac/serial.c
2020-09-26 16:20:57 +08:00

646 lines
17 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
serial.c
Abstract:
Author:
Thomas J. Dimitri (TommyD) 08-May-1992
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
--*/
#include "asyncall.h"
#define IopQueueThreadIrp( Irp ) { \
KIRQL irql; \
KeRaiseIrql( (KIRQL)APC_LEVEL, &irql ); \
InsertHeadList( &Irp->Tail.Overlay.Thread->IrpList, \
&Irp->ThreadListEntry ); \
KeLowerIrql( irql ); \
}
VOID
InitSerialIrp(
PIRP irp,
PASYNC_INFO pInfo,
ULONG IoControlCode,
ULONG InputBufferLength)
{
PIO_STACK_LOCATION irpSp;
PFILE_OBJECT fileObject = pInfo->FileObject;
irpSp = IoGetNextIrpStackLocation(irp);
irp->Tail.Overlay.OriginalFileObject = fileObject;
irp->RequestorMode = KernelMode;
irp->PendingReturned = FALSE;
//
// Fill in the service independent parameters in the IRP.
//
irp->UserEvent = NULL;
irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
irp->Flags = IRP_BUFFERED_IO;
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
//
// stuff in file object
//
irpSp->FileObject = fileObject ;
irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
irpSp->Parameters.DeviceIoControl.OutputBufferLength = InputBufferLength;
}
NTSTATUS
SerialIoSyncCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PASYNC_IO_CTX AsyncIoCtx = (PASYNC_IO_CTX)Context;
DbgTracef(0,("SerialIoSyncCompletion returns 0x%.8x\n", Irp->IoStatus.Status));
ASSERT(AsyncIoCtx->Sync == TRUE);
AsyncIoCtx->IoStatus = Irp->IoStatus;
KeSetEvent(&AsyncIoCtx->Event, // Event
1, // Priority
(BOOLEAN)FALSE); // Wait (does not follow)
//
// We return STATUS_MORE_PROCESSING_REQUIRED so that the
// IoCompletionRoutine will stop working on the IRP.
return(STATUS_MORE_PROCESSING_REQUIRED);
}
NTSTATUS
SerialIoAsyncCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
DbgTracef(0,("SerialIoAsyncCompletion returns 0x%.8x\n", Irp->IoStatus.Status));
ASSERT(((PASYNC_IO_CTX)Context)->Sync == FALSE);
//
// Free the irp here. Hopefully this has no disastrous
// side effects such as the IO system trying to reference
// the irp when we complete.
IoFreeIrp(Irp);
AsyncFreeIoCtx((PASYNC_IO_CTX)Context);
//
// We return STATUS_MORE_PROCESSING_REQUIRED so that the
// IoCompletionRoutine will stop working on the IRP.
return(STATUS_MORE_PROCESSING_REQUIRED);
}
//*
// Note: we ignore the irp passed in to work around a problem where the SET_QUEUE_SIZE ioctl
// is not completed synchronously
//
//*
VOID
SetSerialStuff(
PIRP unusedirp,
PASYNC_INFO pInfo,
ULONG linkSpeed)
{
NTSTATUS status;
PIRP irp ;
PASYNC_IO_CTX AsyncIoCtx;
//
// We deallocate the irp in SerialIoAsyncCompletionRoutine
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_SET_QUEUE_SIZE,
sizeof(SERIAL_QUEUE_SIZE));
AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
AsyncIoCtx->SerialQueueSize.InSize=4096;
AsyncIoCtx->SerialQueueSize.OutSize=4096;
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialQueueSize;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoAsyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
status = IoCallDriver(pInfo->DeviceObject, irp);
DbgTracef(0,("IoctlSetQueueSize status 0x%.8x\n", status));
SetSerialTimeouts(pInfo,linkSpeed);
}
VOID
CancelSerialRequests(
PASYNC_INFO pInfo)
/*++
--*/
{
NTSTATUS status;
PASYNC_IO_CTX AsyncIoCtx;
PIRP irp;
//
// For PPP we must clear the WAIT MASK if it exists
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_SET_WAIT_MASK,
sizeof(ULONG));
AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
AsyncIoCtx->WaitMask = 0;
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->WaitMask;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoSyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
KeClearEvent(&AsyncIoCtx->Event);
status = IoCallDriver(pInfo->DeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&AsyncIoCtx->Event,
Executive,
KernelMode,
FALSE,
NULL);
status = AsyncIoCtx->IoStatus.Status;
}
DbgTracef(0,("IoctlSerialWaitMask returned with 0x%.8x\n", status));
if (status != STATUS_SUCCESS) {
KeSetEvent(&pInfo->ClosingEvent, // Event
1, // Priority
(BOOLEAN)FALSE); // Wait (does not follow)
}
InitSerialIrp(irp, pInfo, IOCTL_SERIAL_PURGE, sizeof(ULONG));
RtlZeroMemory(&AsyncIoCtx->IoStatus, sizeof(IO_STATUS_BLOCK));
// kill all read and write threads.
AsyncIoCtx->SerialPurge = SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT;
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialPurge;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoSyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
KeClearEvent(&AsyncIoCtx->Event);
status = IoCallDriver(pInfo->DeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&AsyncIoCtx->Event,
Executive,
KernelMode,
FALSE,
NULL);
status = AsyncIoCtx->IoStatus.Status;
}
if (status != STATUS_SUCCESS) {
KeSetEvent(&pInfo->ClosingEvent, // Event
1, // Priority
(BOOLEAN)FALSE); // Wait (does not follow)
}
IoFreeIrp(irp);
AsyncFreeIoCtx(AsyncIoCtx);
DbgTracef(0,("IoctlSerialPurge returned with 0x%.8x\n", status));
}
VOID
SetSerialTimeouts(
PASYNC_INFO pInfo,
ULONG linkSpeed)
/*++
--*/
{
NTSTATUS status;
PIRP irp;
PASYNC_ADAPTER pAdapter=pInfo->Adapter;
PASYNC_IO_CTX AsyncIoCtx;
//
// We deallocate the irp in SerialIoAsyncCompletionRoutine
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_SET_TIMEOUTS,
sizeof(SERIAL_TIMEOUTS));
AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
//
// The assumption here is that V.42bis is using 256 byte frames.
// Thus, it takes (256000 / 8) / (linkspeed in 100's of bits per sec)
// time in millisecs to get that frame across.
//
// 500 or 1/2 sec is the fudge factor for satellite delay on
// a long distance call
//
//
// If the linkSpeed is high, we assume we are trying to resync
// so we set the timeout low. linkSpeed is in 100s of bits per sec.
//
if (linkSpeed == 0) {
//
// return immediately (PPP or SLIP framing)
//
AsyncIoCtx->SerialTimeouts.ReadIntervalTimeout= MAXULONG;
} else if (linkSpeed > 20000) {
AsyncIoCtx->SerialTimeouts.ReadIntervalTimeout= pAdapter->TimeoutReSync;
} else {
AsyncIoCtx->SerialTimeouts.ReadIntervalTimeout=
pAdapter->TimeoutBase + (pAdapter->TimeoutBaud / linkSpeed);
}
AsyncIoCtx->SerialTimeouts.ReadTotalTimeoutMultiplier= 0; // none
AsyncIoCtx->SerialTimeouts.ReadTotalTimeoutConstant= 0; // none
AsyncIoCtx->SerialTimeouts.WriteTotalTimeoutMultiplier= 4; // 2400 baud
AsyncIoCtx->SerialTimeouts.WriteTotalTimeoutConstant= 4000; // 4 secs
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialTimeouts;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoAsyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
status = IoCallDriver(pInfo->DeviceObject, irp);
DbgTracef(0,("IoctlSetSerialTimeouts returned 0x%.8x\n", status));
}
VOID
SerialSetEscapeChar(
PASYNC_INFO pInfo,
UCHAR EscapeChar) {
NTSTATUS status;
PIRP irp;
PASYNC_IO_CTX AsyncIoCtx;
//
// We deallocate the irp in SerialIoAsyncCompletionRoutine
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_LSRMST_INSERT,
sizeof(UCHAR));
AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
AsyncIoCtx->EscapeChar = EscapeChar;
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->EscapeChar;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoAsyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
status = IoCallDriver(pInfo->DeviceObject, irp);
DbgTracef(0,("IoctlSetEscapeChar returned with 0x%.8x\n", status));
}
VOID
SerialSetWaitMask(
PASYNC_INFO pInfo,
ULONG WaitMask) {
NTSTATUS status;
PIRP irp;
PASYNC_IO_CTX AsyncIoCtx;
//
// We deallocate the irp in SerialIoAsyncCompletionRoutine
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_SET_WAIT_MASK,
sizeof(ULONG));
AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
AsyncIoCtx->WaitMask = WaitMask;
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->WaitMask;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoAsyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
status = IoCallDriver(pInfo->DeviceObject, irp);
DbgTracef(0,("IoctlSetWaitMask returned with 0x%.8x\n", status));
}
VOID
SerialSetEventChar(
PASYNC_INFO pInfo,
UCHAR EventChar) {
NTSTATUS status;
PIRP irp;
PASYNC_IO_CTX AsyncIoCtx;
//
// We deallocate the irp in SerialIoAsyncCompletionRoutine
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_GET_CHARS,
sizeof(SERIAL_CHARS));
AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialChars;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoSyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
KeClearEvent(&AsyncIoCtx->Event);
status = IoCallDriver(pInfo->DeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&AsyncIoCtx->Event,
Executive,
KernelMode,
FALSE,
NULL);
status = AsyncIoCtx->IoStatus.Status;
}
DbgTracef(0,("IoctlGetChars returned with 0x%.8x\n", status));
if (status != STATUS_SUCCESS) {
IoFreeIrp(irp);
AsyncFreeIoCtx(AsyncIoCtx);
return;
}
AsyncIoCtx->SerialChars.EventChar = EventChar;
AsyncIoCtx->Sync = FALSE;
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_SET_CHARS,
sizeof(SERIAL_CHARS));
IoSetCompletionRoutine(
irp, // irp to use
SerialIoAsyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
status = IoCallDriver(pInfo->DeviceObject, irp);
DbgTracef(0,("IoctlSetChars returned with 0x%.8x\n", status));
}
VOID
SerialFlushReads(
PASYNC_INFO pInfo) {
ULONG serialPurge;
NTSTATUS status;
PIRP irp;
PASYNC_IO_CTX AsyncIoCtx;
//
// We deallocate the irp in SerialIoAsyncCompletionRoutine
//
irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
if (irp == NULL) {
return;
}
InitSerialIrp(
irp,
pInfo,
IOCTL_SERIAL_PURGE,
sizeof(ULONG));
AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
if (AsyncIoCtx == NULL) {
IoFreeIrp(irp);
return;
}
// kill read buffer
AsyncIoCtx->SerialPurge=SERIAL_PURGE_RXCLEAR;
irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialPurge;
IoSetCompletionRoutine(
irp, // irp to use
SerialIoAsyncCompletionRoutine, // routine to call when irp is done
AsyncIoCtx, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
status = IoCallDriver(pInfo->DeviceObject, irp);
DbgTracef(0,("IoctlPurge returned with 0x%.8x\n", status));
}