Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1607 lines
38 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
open.c
Abstract:
This module contains the code that is very specific to open
and close operations in the modem driver
Author:
Anthony V. Ercolano 13-Aug-1995
Environment:
Kernel mode
Revision History :
--*/
#include "precomp.h"
NTSTATUS
UniOpenCloseStarter(
IN PDEVICE_EXTENSION Extension
);
NTSTATUS
UniOpenStarter(
IN PDEVICE_EXTENSION Extension
);
NTSTATUS
UniCloseStarter(
IN PDEVICE_EXTENSION Extension
);
VOID
UniProcessDcbInfo(
IN PDEVICE_EXTENSION Extension,
IN PIRP Irp
);
NTSTATUS
UniProcessDcbDone(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessDcbFLOW(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessDcbCHAR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessDcbLINE(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessDcbBAUD(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessDcbDTR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessDcbRTS(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniProcessBadDcbDone(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
UniOpen(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
return UniStartOrQueue(
deviceExtension,
&deviceExtension->DeviceLock,
Irp,
&deviceExtension->OpenClose,
&deviceExtension->CurrentOpenClose,
UniOpenCloseStarter
);
}
NTSTATUS
UniClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
return UniStartOrQueue(
deviceExtension,
&deviceExtension->DeviceLock,
Irp,
&deviceExtension->OpenClose,
&deviceExtension->CurrentOpenClose,
UniOpenCloseStarter
);
}
NTSTATUS
UniOpenCloseStarter(
IN PDEVICE_EXTENSION Extension
)
{
NTSTATUS firstStatus;
NTSTATUS status;
BOOLEAN setFirstStatus = FALSE;
PIRP newIrp;
do {
if (IoGetCurrentIrpStackLocation(Extension->CurrentOpenClose)
->MajorFunction == IRP_MJ_CREATE) {
status = UniOpenStarter(Extension);
} else {
status = UniCloseStarter(Extension);
}
if (!setFirstStatus) {
setFirstStatus = TRUE;
firstStatus = status;
}
if (status != STATUS_PENDING) {
UniGetNextIrp(
&Extension->DeviceLock,
&Extension->CurrentOpenClose,
&Extension->OpenClose,
&newIrp,
TRUE
);
} else {
break;
}
} while (newIrp);
return firstStatus;
}
NTSTATUS
UniOpenStarter(
IN PDEVICE_EXTENSION Extension
)
{
NTSTATUS status = STATUS_SUCCESS;
PIRP irp = Extension->CurrentOpenClose;
//
// We use this to query into the registry for the attached
// device.
//
RTL_QUERY_REGISTRY_TABLE paramTable[6];
UNICODE_STRING attachedDevice = {0};
UNICODE_STRING attachedDosDevice = {0};
ACCESS_MASK accessMask = FILE_ALL_ACCESS;
PIO_STACK_LOCATION irpSp;
PIO_STACK_LOCATION waitSp;
HANDLE instanceHandle;
MODEM_REG_PROP localProp;
MODEM_REG_DEFAULT localDefault;
LPDCB localDCB;
UNICODE_STRING valueEntryName;
KEY_VALUE_PARTIAL_INFORMATION localKeyValue;
NTSTATUS junkStatus;
ULONG neededLength;
ULONG defaultInactivity = 10;
irpSp = IoGetCurrentIrpStackLocation(irp);
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;
//
// Make sure a stupid directory open isn't going on here.
//
if (irpSp->Parameters.Create.Options &
FILE_DIRECTORY_FILE) {
irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
return STATUS_NOT_A_DIRECTORY;
}
//
// We are the only ones here. If we are not the first
// then not much work to do.
//
if (Extension->OpenCount) {
//
// Already been opened once. We will succeed if there
// currently a controlling open. If not, then we should
// fail.
//
if (Extension->ProcAddress) {
if (IoGetCurrentProcess() != Extension->ProcAddress) {
status = STATUS_ACCESS_DENIED;
irp->IoStatus.Status = status;
goto leaveOpen;
}
//
//
// A ok. Increment the reference and
// leave.
//
Extension->OpenCount++;
goto leaveOpen;
} else {
status = STATUS_INVALID_PARAMETER;
irp->IoStatus.Status = status;
goto leaveOpen;
}
}
RtlInitUnicodeString(
&attachedDevice,
NULL
);
attachedDevice.MaximumLength = sizeof(WCHAR)*256;
attachedDevice.Buffer = ExAllocatePool(
PagedPool,
sizeof(WCHAR)*257
);
if (!attachedDevice.Buffer) {
UniLogError(
Extension->DeviceObject->DriverObject,
NULL,
0,
0,
0,
24,
STATUS_SUCCESS,
MODEM_INSUFFICIENT_RESOURCES,
0,
NULL,
0,
NULL
);
UniDump(
UNIERRORS,
("UNI32: Couldn't allocate buffer for the attached\n")
);
status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Status = status;
goto leaveOpen;
}
localDCB = ExAllocatePool(
NonPagedPool,
sizeof(DCB)
);
if (!localDCB) {
UniLogError(
Extension->DeviceObject->DriverObject,
NULL,
0,
0,
0,
124,
STATUS_SUCCESS,
MODEM_INSUFFICIENT_RESOURCES,
0,
NULL,
0,
NULL
);
UniDump(
UNIERRORS,
("UNI32: Couldn't allocate buffer for the dcb\n")
);
status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Status = status;
goto leaveOpen;
}
//
// Given our device instance go get a handle to the Device.
//
if (!NT_SUCCESS(IoOpenDeviceInstanceKey(
&UniServiceKeyName,
Extension->DeviceInstance,
PLUGPLAY_REGKEY_DRIVER,
accessMask,
&instanceHandle
))) {
status = STATUS_INVALID_PARAMETER;
irp->IoStatus.Status = status;
goto leaveOpen;
}
RtlZeroMemory(
&paramTable[0],
sizeof(paramTable)
);
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[0].Name = L"AttachedTo";
paramTable[0].EntryContext = &attachedDevice;
paramTable[0].DefaultType = REG_SZ;
paramTable[0].DefaultData = L"";
paramTable[0].DefaultLength = 0;
//
// Entry for the modem reg properties
//
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[1].Name = L"Properties";
paramTable[1].EntryContext = &localProp;
paramTable[1].DefaultType = REG_BINARY;
paramTable[1].DefaultLength = sizeof(localProp);
//
// Note that rtlqueryregistryvalues has a real hack
// way of getting binary data. We also have to add
// the *negative* length that we want to the beginning
// of the buffer.
//
*(PLONG)&localProp.dwDialOptions = -((LONG)sizeof(localProp));
//
// Read in the default config from the registry.
//
paramTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[2].Name = L"Default";
paramTable[2].EntryContext = &localDefault;
paramTable[2].DefaultType = REG_BINARY;
paramTable[2].DefaultLength = sizeof(localDefault);
*(PLONG)&localDefault.dwCallSetupFailTimer = -((LONG)sizeof(localDefault));
//
// Read in the default dcb from the registry.
//
paramTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[3].Name = L"DCB";
paramTable[3].EntryContext = localDCB;
paramTable[3].DefaultType = REG_BINARY;
paramTable[3].DefaultLength = sizeof(DCB);
*(PLONG)&localDCB->DCBlength = -((LONG)sizeof(DCB));
paramTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[4].Name = L"InactivityScale";
paramTable[4].EntryContext = &Extension->InactivityScale;
paramTable[4].DefaultType = REG_BINARY;
paramTable[4].DefaultLength = sizeof(Extension->InactivityScale);
paramTable[4].DefaultData = &defaultInactivity;
*(PLONG)&Extension->InactivityScale = -((LONG)sizeof(Extension->InactivityScale));
if (!NT_SUCCESS(RtlQueryRegistryValues(
RTL_REGISTRY_HANDLE,
instanceHandle,
&paramTable[0],
NULL,
NULL
))) {
status = STATUS_INVALID_PARAMETER;
irp->IoStatus.Status = status;
//
// Before we leave, Close the handle to the device instance.
//
ZwClose(instanceHandle);
goto leaveOpen;
}
//
// Clean out the old devcaps and settings.
//
RtlZeroMemory(
&Extension->ModemDevCaps,
sizeof(MODEMDEVCAPS)
);
RtlZeroMemory(
&Extension->ModemSettings,
sizeof(MODEMSETTINGS)
);
//
// Get the lengths each of the manufacture, model and version.
//
// We can get this by doing a query for the partial with a
// short buffer. The return value from the call will tell us
// how much we actually need (plus null termination).
//
RtlInitUnicodeString(
&valueEntryName,
L"Manufacturer"
);
localKeyValue.DataLength = sizeof(UCHAR);
junkStatus = ZwQueryValueKey(
instanceHandle,
&valueEntryName,
KeyValuePartialInformation,
&localKeyValue,
sizeof(localKeyValue),
&neededLength
);
if ((junkStatus == STATUS_SUCCESS) ||
(junkStatus == STATUS_BUFFER_OVERFLOW)) {
Extension->ModemDevCaps.dwModemManufacturerSize =
localKeyValue.DataLength;
} else {
Extension->ModemDevCaps.dwModemManufacturerSize = 0;
}
RtlInitUnicodeString(
&valueEntryName,
L"Model"
);
localKeyValue.DataLength = sizeof(UCHAR);
junkStatus = ZwQueryValueKey(
instanceHandle,
&valueEntryName,
KeyValuePartialInformation,
&localKeyValue,
sizeof(localKeyValue),
&neededLength
);
if ((junkStatus == STATUS_SUCCESS) ||
(junkStatus == STATUS_BUFFER_OVERFLOW)) {
Extension->ModemDevCaps.dwModemModelSize = localKeyValue.DataLength;
} else {
Extension->ModemDevCaps.dwModemModelSize = 0;
}
RtlInitUnicodeString(
&valueEntryName,
L"Version"
);
localKeyValue.DataLength = sizeof(UCHAR);
junkStatus = ZwQueryValueKey(
instanceHandle,
&valueEntryName,
KeyValuePartialInformation,
&localKeyValue,
sizeof(localKeyValue),
&neededLength
);
if ((junkStatus == STATUS_SUCCESS) ||
(junkStatus == STATUS_BUFFER_OVERFLOW)) {
Extension->ModemDevCaps.dwModemVersionSize = localKeyValue.DataLength;
} else {
Extension->ModemDevCaps.dwModemVersionSize = 0;
}
ZwClose(instanceHandle);
//
// Move the properties and the defaults into the extension.
//
Extension->ModemDevCaps.dwDialOptions = localProp.dwDialOptions;
Extension->ModemDevCaps.dwCallSetupFailTimer =
localProp.dwCallSetupFailTimer;
Extension->ModemDevCaps.dwInactivityTimeout =
localProp.dwInactivityTimeout;
Extension->ModemDevCaps.dwSpeakerVolume = localProp.dwSpeakerVolume;
Extension->ModemDevCaps.dwSpeakerMode = localProp.dwSpeakerMode;
Extension->ModemDevCaps.dwModemOptions = localProp.dwModemOptions;
Extension->ModemDevCaps.dwMaxDTERate = localProp.dwMaxDTERate;
Extension->ModemDevCaps.dwMaxDCERate = localProp.dwMaxDCERate;
Extension->ModemDevCaps.dwActualSize = sizeof(MODEMDEVCAPS);
Extension->ModemDevCaps.dwRequiredSize = sizeof(MODEMDEVCAPS) +
Extension->ModemDevCaps.dwModemManufacturerSize +
Extension->ModemDevCaps.dwModemModelSize +
Extension->ModemDevCaps.dwModemVersionSize;
Extension->ModemSettings.dwCallSetupFailTimer =
localDefault.dwCallSetupFailTimer;
Extension->ModemSettings.dwInactivityTimeout =
localDefault.dwInactivityTimeout * Extension->InactivityScale;
Extension->ModemSettings.dwSpeakerVolume = localDefault.dwSpeakerVolume;
Extension->ModemSettings.dwSpeakerMode = localDefault.dwSpeakerMode;
Extension->ModemSettings.dwPreferredModemOptions =
localDefault.dwPreferredModemOptions;
Extension->ModemSettings.dwActualSize = sizeof(MODEMSETTINGS);
Extension->ModemSettings.dwRequiredSize = sizeof(MODEMSETTINGS);
Extension->ModemSettings.dwDevSpecificOffset = 0;
Extension->ModemSettings.dwDevSpecificSize = 0;
//
// We have the attached device name. Append it to the
// object directory.
//
RtlInitUnicodeString(
&attachedDosDevice,
NULL
);
attachedDosDevice.MaximumLength =
sizeof(OBJECT_DIRECTORY) +
attachedDevice.Length+sizeof(WCHAR);
attachedDosDevice.Buffer = ExAllocatePool(
PagedPool,
attachedDosDevice.MaximumLength
);
if (!attachedDosDevice.Buffer) {
UniLogError(
Extension->DeviceObject->DriverObject,
NULL,
0,
0,
0,
24,
STATUS_SUCCESS,
MODEM_INSUFFICIENT_RESOURCES,
0,
NULL,
0,
NULL
);
UniDump(
UNIERRORS,
("UNI32: Couldn't allocate buffer for the attached Dos\n")
);
status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Status = status;
goto leaveOpen;
}
RtlZeroMemory(
attachedDosDevice.Buffer,
attachedDosDevice.MaximumLength
);
RtlAppendUnicodeToString(
&attachedDosDevice,
OBJECT_DIRECTORY
);
RtlAppendUnicodeStringToString(
&attachedDosDevice,
&attachedDevice
);
//
// Open up the attached device.
//
Extension->AttachedFileObject = NULL;
Extension->AttachedDeviceObject = NULL;
status = IoGetDeviceObjectPointer(
&attachedDosDevice,
accessMask,
&Extension->AttachedFileObject,
&Extension->AttachedDeviceObject
);
if (!NT_SUCCESS(status)) {
irp->IoStatus.Status = status;
goto leaveOpen;
}
//
// We have the device open. Increment our irp stack size
// by the stack size of the attached device.
//
Extension->DeviceObject->StackSize = 1 +
Extension->AttachedDeviceObject->StackSize;
irpSp->FileObject->FsContext = (PVOID)1;
Extension->PassThrough = MODEM_PASSTHROUGH;
Extension->OpenCount = 1;
Extension->ProcAddress = IoGetCurrentProcess();
//
// Allocate an IRP for use in processing wait operations.
//
Extension->OurWaitIrp = IoAllocateIrp(
Extension->DeviceObject->StackSize,
FALSE
);
if (!Extension->OurWaitIrp) {
status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Status = status;
//
// Call the close routine, it knows what to do with
// the various system objects.
//
UniCloseStarter(Extension);
goto leaveOpen;
}
Extension->OurWaitIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
Extension->OurWaitIrp->UserBuffer = NULL;
Extension->OurWaitIrp->AssociatedIrp.SystemBuffer = NULL;
Extension->OurWaitIrp->UserEvent = NULL;
Extension->OurWaitIrp->UserIosb = NULL;
Extension->OurWaitIrp->CurrentLocation--;
waitSp = IoGetNextIrpStackLocation(Extension->OurWaitIrp);
Extension->OurWaitIrp->Tail.Overlay.CurrentStackLocation = waitSp;
waitSp->DeviceObject = Extension->DeviceObject;
//
// Clean up any trash left in our maskstates.
//
Extension->MaskStates[0].SetMaskCount = 0;
Extension->MaskStates[1].SetMaskCount = 0;
Extension->MaskStates[0].SentDownSetMasks = 0;
Extension->MaskStates[1].SentDownSetMasks = 0;
Extension->MaskStates[0].Mask = 0;
Extension->MaskStates[1].Mask = 0;
Extension->MaskStates[0].HistoryMask = 0;
Extension->MaskStates[1].HistoryMask = 0;
Extension->MaskStates[0].ShuttledWait = 0;
Extension->MaskStates[1].ShuttledWait = 0;
Extension->MaskStates[0].PassedDownWait = 0;
Extension->MaskStates[1].PassedDownWait = 0;
status = STATUS_PENDING;
irp->IoStatus.Status = status;
IoMarkIrpPending(irp);
//
// The code to process the dcb will be calling down
// to the lower level serial driver numerous times
// (asynchronously). We return pending so that we
// don't try to start the next open or close code until
// the open stuff is all done. The code that is processing
// all the dcb stuff will finish off by getting the
// next irp. We can use our wait irp, cause until the
// open is done, nobody is going to be using it.
//
UniProcessDcbFLOW(
Extension->DeviceObject,
Extension->OurWaitIrp,
localDCB
);
leaveOpen:;
if (attachedDevice.Buffer) {
ExFreePool(attachedDevice.Buffer);
}
if (attachedDosDevice.Buffer) {
ExFreePool(attachedDosDevice.Buffer);
}
return status;
}
NTSTATUS
UniCloseStarter(
IN PDEVICE_EXTENSION Extension
)
{
NTSTATUS status = STATUS_SUCCESS;
PIRP irp = Extension->CurrentOpenClose;
Extension->OpenCount--;
//
// Here is where we should do the check whether
// we are the open handle for the controlling
// open. If we are then we should null the controlling
// open.
//
if (IoGetCurrentIrpStackLocation(irp)->FileObject->FsContext) {
Extension->ProcAddress = NULL;
IoGetCurrentIrpStackLocation(irp)->FileObject->FsContext = NULL;
Extension->PassThrough = MODEM_NOPASSTHROUGH;
}
if (!Extension->OpenCount) {
ObDereferenceObject(Extension->AttachedFileObject);
//
// No references to anything. It's safe to get
// rid of the irp that we allocated. (We check
// for non-null pointer incase this call is done
// in response to NOT being able to allocate
// this irp.)
//
if (Extension->OurWaitIrp) {
IoFreeIrp(Extension->OurWaitIrp);
}
}
irp->IoStatus.Status = status;
irp->IoStatus.Information=0L;
return status;
}
NTSTATUS
UniProcessDcbRTS(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
LPDCB localDCB = Context;
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
} else {
if (localDCB->fRtsControl == RTS_CONTROL_DISABLE) {
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_CLR_RTS;
} else if (localDCB->fRtsControl == RTS_CONTROL_ENABLE) {
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_SET_RTS;
} else {
UniProcessDcbBAUD(
DeviceObject,
Irp,
localDCB
);
return STATUS_MORE_PROCESSING_REQUIRED;
}
nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
nextSp->MinorFunction = 0UL;
nextSp->Flags = irpSp->Flags;
nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.InputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
IoSetCompletionRoutine(
Irp,
UniProcessDcbBAUD,
Context,
TRUE,
TRUE,
TRUE
);
IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessDcbDTR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
LPDCB localDCB = Context;
PVOID oldBuffer = Irp->AssociatedIrp.SystemBuffer;
UNI_RESTORE_IRP(
Irp,
IOCTL_SERIAL_CLR_RTS
);
if (oldBuffer) {
ExFreePool(oldBuffer);
}
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
} else {
if (localDCB->fDtrControl == DTR_CONTROL_DISABLE) {
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_CLR_DTR;
} else if (localDCB->fDtrControl == DTR_CONTROL_ENABLE) {
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_SET_DTR;
} else {
UniProcessDcbRTS(
DeviceObject,
Irp,
localDCB
);
return STATUS_MORE_PROCESSING_REQUIRED;
}
nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
nextSp->MinorFunction = 0UL;
nextSp->Flags = irpSp->Flags;
nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.InputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
IoSetCompletionRoutine(
Irp,
UniProcessDcbRTS,
Context,
TRUE,
TRUE,
TRUE
);
IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessDcbBAUD(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
LPDCB localDCB = Context;
PSERIAL_BAUD_RATE localBaud;
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
} else {
localBaud = ExAllocatePool(
NonPagedPool,
sizeof(SERIAL_BAUD_RATE)
);
UNI_SETUP_NEW_BUFFER(Irp);
Irp->AssociatedIrp.SystemBuffer = localBaud;
if (localBaud) {
localBaud->BaudRate = localDCB->BaudRate;
nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
nextSp->MinorFunction = 0UL;
nextSp->Flags = irpSp->Flags;
nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.InputBufferLength =
sizeof(SERIAL_BAUD_RATE);
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_SET_BAUD_RATE;
nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
IoSetCompletionRoutine(
Irp,
UniProcessDcbLINE,
Context,
TRUE,
TRUE,
TRUE
);
IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
} else {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessDcbLINE(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
LPDCB localDCB = Context;
PVOID oldBuffer = Irp->AssociatedIrp.SystemBuffer;
PSERIAL_LINE_CONTROL localLine;
UNI_RESTORE_IRP(
Irp,
IOCTL_SERIAL_CLR_RTS
);
if (oldBuffer) {
ExFreePool(oldBuffer);
}
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
} else {
localLine = ExAllocatePool(
NonPagedPool,
sizeof(SERIAL_LINE_CONTROL)
);
UNI_SETUP_NEW_BUFFER(Irp);
Irp->AssociatedIrp.SystemBuffer = localLine;
if (localLine) {
localLine->StopBits = localDCB->StopBits;
localLine->Parity = localDCB->Parity;
localLine->WordLength = localDCB->ByteSize;
nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
nextSp->MinorFunction = 0UL;
nextSp->Flags = irpSp->Flags;
nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.InputBufferLength =
sizeof(SERIAL_LINE_CONTROL);
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_SET_LINE_CONTROL;
nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
IoSetCompletionRoutine(
Irp,
UniProcessDcbCHAR,
Context,
TRUE,
TRUE,
TRUE
);
IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
} else {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessDcbCHAR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
LPDCB localDCB = Context;
PVOID oldBuffer = Irp->AssociatedIrp.SystemBuffer;
PSERIAL_CHARS localChars;
UNI_RESTORE_IRP(
Irp,
IOCTL_SERIAL_CLR_RTS
);
if (oldBuffer) {
ExFreePool(oldBuffer);
}
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
} else {
localChars = ExAllocatePool(
NonPagedPool,
sizeof(SERIAL_CHARS)
);
UNI_SETUP_NEW_BUFFER(Irp);
Irp->AssociatedIrp.SystemBuffer = localChars;
if (localChars) {
localChars->XonChar = localDCB->XonChar;
localChars->XoffChar = localDCB->XoffChar;
localChars->ErrorChar = localDCB->ErrorChar;
localChars->BreakChar = localDCB->ErrorChar;
localChars->EofChar = localDCB->EofChar;
localChars->EventChar = localDCB->EvtChar;
nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
nextSp->MinorFunction = 0UL;
nextSp->Flags = irpSp->Flags;
nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.InputBufferLength =
sizeof(SERIAL_CHARS);
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_SET_CHARS;
nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
IoSetCompletionRoutine(
Irp,
UniProcessDcbDone,
Context,
TRUE,
TRUE,
TRUE
);
IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
} else {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessDcbFLOW(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
LPDCB localDCB = Context;
PSERIAL_HANDFLOW handFlow;
//
// Allocate the serial handlflow structure
//
handFlow = ExAllocatePool(
NonPagedPool,
sizeof(SERIAL_HANDFLOW)
);
UNI_SETUP_NEW_BUFFER(Irp);
Irp->AssociatedIrp.SystemBuffer = handFlow;
if (handFlow) {
//
// Fill in all the fields in the handflow.
//
RtlZeroMemory(
handFlow,
sizeof(SERIAL_HANDFLOW)
);
handFlow->FlowReplace &= ~SERIAL_RTS_MASK;
switch (localDCB->fRtsControl) {
case RTS_CONTROL_DISABLE:
break;
case RTS_CONTROL_ENABLE:
handFlow->FlowReplace |= SERIAL_RTS_CONTROL;
break;
case RTS_CONTROL_HANDSHAKE:
handFlow->FlowReplace |= SERIAL_RTS_HANDSHAKE;
break;
case RTS_CONTROL_TOGGLE:
handFlow->FlowReplace |= SERIAL_TRANSMIT_TOGGLE;
break;
default:
handFlow->FlowReplace |= SERIAL_RTS_CONTROL;
break;
}
handFlow->ControlHandShake &= ~SERIAL_DTR_MASK;
switch (localDCB->fDtrControl) {
case DTR_CONTROL_DISABLE:
break;
case DTR_CONTROL_ENABLE:
handFlow->ControlHandShake |= SERIAL_DTR_CONTROL;
break;
case DTR_CONTROL_HANDSHAKE:
handFlow->ControlHandShake |= SERIAL_DTR_HANDSHAKE;
break;
default:
handFlow->ControlHandShake |= SERIAL_DTR_CONTROL;
break;
}
if (localDCB->fDsrSensitivity) {
handFlow->ControlHandShake |= SERIAL_DSR_SENSITIVITY;
}
if (localDCB->fOutxCtsFlow) {
handFlow->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
}
if (localDCB->fOutxDsrFlow) {
handFlow->ControlHandShake |= SERIAL_DSR_HANDSHAKE;
}
if (localDCB->fOutX) {
handFlow->FlowReplace |= SERIAL_AUTO_TRANSMIT;
}
if (localDCB->fInX) {
handFlow->FlowReplace |= SERIAL_AUTO_RECEIVE;
}
if (localDCB->fNull) {
handFlow->FlowReplace |= SERIAL_NULL_STRIPPING;
}
if (localDCB->fErrorChar) {
handFlow->FlowReplace |= SERIAL_ERROR_CHAR;
}
if (localDCB->fTXContinueOnXoff) {
handFlow->FlowReplace |= SERIAL_XOFF_CONTINUE;
}
if (localDCB->fAbortOnError) {
handFlow->ControlHandShake |= SERIAL_ERROR_ABORT;
}
handFlow->XonLimit = localDCB->XonLim;
handFlow->XoffLimit = localDCB->XoffLim;
nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
nextSp->MinorFunction = 0UL;
nextSp->Flags = irpSp->Flags;
nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0UL;
nextSp->Parameters.DeviceIoControl.InputBufferLength =
sizeof(SERIAL_HANDFLOW);
nextSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_SET_HANDFLOW;
nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
IoSetCompletionRoutine(
Irp,
UniProcessDcbDTR,
Context,
TRUE,
TRUE,
TRUE
);
IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
} else {
UniProcessBadDcbDone(
DeviceObject,
Irp,
Context
);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessDcbDone(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIRP newIrp;
PVOID oldBuffer = Irp->AssociatedIrp.SystemBuffer;
UNI_RESTORE_IRP(
Irp,
IOCTL_SERIAL_CLR_RTS
);
if (oldBuffer) {
ExFreePool(oldBuffer);
}
ExFreePool(Context);
//
// All done with processing the dcb. Get the
// next open/close irp and start it.
//
extension->CurrentOpenClose->IoStatus.Status = STATUS_SUCCESS;
extension->CurrentOpenClose->IoStatus.Information = 0UL;
UniGetNextIrp(
&extension->DeviceLock,
&extension->CurrentOpenClose,
&extension->OpenClose,
&newIrp,
TRUE
);
if (newIrp) {
UniOpenCloseStarter(extension);
}
//
// We return more processing required because the getnext call
// above should have completed the irp.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniProcessBadDcbDone(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
//
// This will get called if an error occured in the process of
// processing the dcb. If so, we will fail this open.
//
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIRP newIrp;
PVOID oldBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// The ioctl really doens't matter here. But we might as well be
// consistent.
//
UNI_RESTORE_IRP(
Irp,
IOCTL_SERIAL_CLR_RTS
);
if (oldBuffer) {
ExFreePool(oldBuffer);
}
ExFreePool(Context);
//
// All done with processing the dcb. Get the
// next open/close irp and start it.
//
extension->CurrentOpenClose->IoStatus.Status = STATUS_INVALID_PARAMETER;
extension->CurrentOpenClose->IoStatus.Information = 0UL;
UniCloseStarter(extension);
UniGetNextIrp(
&extension->DeviceLock,
&extension->CurrentOpenClose,
&extension->OpenClose,
&newIrp,
TRUE
);
if (newIrp) {
UniOpenCloseStarter(extension);
}
//
// We return more processing required because the getnext call
// above should have completed the irp.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
UniCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
KIRQL origIrql;
PMASKSTATE thisMaskState = &extension->MaskStates[
IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext?
CONTROL_HANDLE:
CLIENT_HANDLE
];
//
// If this open has a shuttled read or write kill it. We know that
// another won't come through because the IO subsystem won't let
// it.
//
KeAcquireSpinLock(
&extension->DeviceLock,
&origIrql
);
if (thisMaskState->ShuttledWait) {
PIRP savedIrp = thisMaskState->ShuttledWait;
thisMaskState->ShuttledWait = NULL;
UniRundownShuttledWait(
extension,
&thisMaskState->ShuttledWait,
UNI_REFERENCE_NORMAL_PATH,
savedIrp,
origIrql,
STATUS_SUCCESS,
0ul
);
} else {
KeReleaseSpinLock(
&extension->DeviceLock,
origIrql
);
}
//
// If this is the controlling open then we let the cleanup go
// on down. If we let every cleanup go down then clients closing
// could screw up the owners reads or writes.
//
if (IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext) {
Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;
return IoCallDriver(
extension->AttachedDeviceObject,
Irp
);
} else {
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0ul;
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
return STATUS_SUCCESS;
}
}