|
|
/*++
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)); }
|