📄 io.c
字号:
PDEVICE_OBJECT self;
LONG oldInterlock;
KIRQL irql;
Print(DeviceExtension, DBG_READ_TRACE, ("Start Read: Enter\n"));
irp = DeviceExtension->ReadIrp;
while (1) {
if ((DeviceExtension->Removed) ||
(!DeviceExtension->Started) ||
(DeviceExtension->EnableCount == 0)) {
Print(DeviceExtension, DBG_READ_INFO | DBG_READ_ERROR,
("removing lock on start read\n"));
//
// Set the event so that the stop code can continue processing
//
KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);
IoReleaseRemoveLock(&DeviceExtension->RemoveLock,
DeviceExtension->ReadIrp);
return STATUS_UNSUCCESSFUL;
}
//
// Make sure we have not been stopped
//
KeAcquireSpinLock(&DeviceExtension->PnpStateLock, &irql);
if (DeviceExtension->Stopped) {
KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql);
//
// Set the event so that the stop code can continue processing
//
KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);
//
// Release the remove lock that we acquired when we started the read
// spinner irp
//
IoReleaseRemoveLock(&DeviceExtension->RemoveLock,
DeviceExtension->ReadIrp);
return STATUS_SUCCESS;
}
//
// It is important to only reuse the irp when we are holding onto the
// spinlock, otherwise we can race
//
IoReuseIrp(irp, STATUS_SUCCESS);
KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql);
//
// This is where things get interesting. We don't want to call
// SerialMouseStartRead if this read was completed synchronously by the
// serial provider because we can potentially run out of stack space.
//
// Here is how we solve this:
// At the beginning of StartRead(), the interlock is set to START_READ
// IoCallDriver is called...
// o If the read will be completed asynchronously, then StartRead()
// will continue executing and set the interlock to END_READ.
// o If the request will be completed synchronously, then the
// completion routine will run before StartRead() has the chance of
// setting the interlock to END_READ. We note this situation by
// setting the interlock to IMMEDIATE_READ in the completion function.
// Furthermore, StartRead() will not be called from the completion
// routine as it would be in the async case
// o Upon setting the interlock to END_READ in StartReaD(), the
// previous value is examined. If it is IMMEDIATE_READ, then
// StartRead() loops and calls IoCallDriver from the same location
// within the (call) stack frame. If the previous value was *not*
// IMMEDIATE_READ, then StartRead() exits and the completion routine
// will be called in another context (and, thus, another stack) and
// make the next call to StartRead()
//
#if DBG
oldInterlock =
#endif
InterlockedExchange(&DeviceExtension->ReadInterlock,
SERIAL_MOUSE_START_READ);
//
// END_READ should be the only value here!!! If not, the state machine
// of the interlock has been broken
//
ASSERT(oldInterlock == SERIAL_MOUSE_END_READ);
//
// start this read.
//
self = DeviceExtension->Self;
//
// Set the stack location for the serenum stack
//
// Remember to get the file pointer correct.
// NOTE: we do not have any of the cool thread stuff set.
// therefore we need to make sure that we cut this IRP off
// at the knees when it returns. (STATUS_MORE_PROCESSING_REQUIRED)
//
// Note also that serial does buffered i/o
//
irp->AssociatedIrp.SystemBuffer = (PVOID) DeviceExtension->ReadBuffer;
stack = IoGetNextIrpStackLocation(irp);
stack->Parameters.Read.Length = 1;
stack->Parameters.Read.ByteOffset.QuadPart = (LONGLONG) 0;
stack->MajorFunction = IRP_MJ_READ;
//
// Hook a completion routine for when the device completes.
//
IoSetCompletionRoutine(irp,
SerialMouseReadComplete,
DeviceExtension,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(DeviceExtension->TopOfStack, irp);
if (InterlockedExchange(&DeviceExtension->ReadInterlock,
SERIAL_MOUSE_END_READ) !=
SERIAL_MOUSE_IMMEDIATE_READ) {
//
// The read is asynch, will call SerialMouseStartRead from the
// completion routine
//
Print(DeviceExtension, DBG_READ_NOISE, ("read is pending\n"));
break;
}
#if DBG
else {
//
// The read was synchronous (probably bytes in the buffer). The
// completion routine will not call SerialMouseStartRead, so we
// just loop here. This is to prevent us from running out of stack
// space if always call StartRead from the completion routine
//
Print(DeviceExtension, DBG_READ_NOISE, ("read is looping\n"));
}
#endif
}
return status;
}
//
// Stripped down version of SerialMouseIoSyncIoctlEx that
// doesn't use input or output buffers
//
NTSTATUS
SerialMousepIoSyncIoctl(
BOOLEAN Internal,
ULONG Ioctl,
PDEVICE_OBJECT DeviceObject,
PKEVENT Event,
PIO_STATUS_BLOCK Iosb)
{
return SerialMousepIoSyncIoctlEx(Internal,
Ioctl,
DeviceObject,
Event,
Iosb,
NULL,
0,
NULL,
0);
}
NTSTATUS
SerialMousepIoSyncIoctlEx(
BOOLEAN Internal,
ULONG Ioctl, // io control code
PDEVICE_OBJECT DeviceObject, // object to call
PKEVENT Event, // event to wait on
PIO_STATUS_BLOCK Iosb, // used inside IRP
PVOID InBuffer, OPTIONAL // input buffer
ULONG InBufferLen, OPTIONAL // input buffer length
PVOID OutBuffer, OPTIONAL // output buffer
ULONG OutBufferLen) OPTIONAL // output buffer length
/*++
Routine Description:
Performs a synchronous IO control request by waiting on the event object
passed to it. The IRP is deallocated by the IO system when finished.
Return value:
NTSTATUS
--*/
{
PIRP irp;
NTSTATUS status;
KeClearEvent(Event);
//
// Allocate an IRP - No need to release
// When the next-lower driver completes this IRP, the I/O Manager releases it.
//
if (NULL == (irp = IoBuildDeviceIoControlRequest(Ioctl,
DeviceObject,
InBuffer,
InBufferLen,
OutBuffer,
OutBufferLen,
Internal,
Event,
Iosb))) {
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(DeviceObject, irp);
if (STATUS_PENDING == status) {
//
// wait for it...
//
status = KeWaitForSingleObject(Event,
Executive,
KernelMode,
FALSE, // Not alertable
NULL); // No timeout structure
}
if (NT_SUCCESS(status)) {
status = Iosb->Status;
}
return status;
}
NTSTATUS
SerialMouseSetReadTimeouts(
PDEVICE_EXTENSION DeviceExtension,
ULONG Timeout
)
{
NTSTATUS status;
SERIAL_TIMEOUTS serialTimeouts;
KEVENT event;
IO_STATUS_BLOCK iosb;
KeInitializeEvent(&event, NotificationEvent, FALSE);
RtlZeroMemory(&serialTimeouts, sizeof(SERIAL_TIMEOUTS));
if (Timeout != 0) {
serialTimeouts.ReadIntervalTimeout = MAXULONG;
serialTimeouts.ReadTotalTimeoutMultiplier = MAXULONG;
serialTimeouts.ReadTotalTimeoutConstant = Timeout;
}
status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
DeviceExtension->TopOfStack,
&event,
&iosb,
&serialTimeouts,
sizeof(SERIAL_TIMEOUTS),
NULL,
0);
return status;
}
NTSTATUS
SerialMouseReadSerialPortComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
{
UNREFERENCED_PARAMETER(DeviceObject);
KeSetEvent(Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
SerialMouseReadSerialPort (
PDEVICE_EXTENSION DeviceExtension,
PCHAR ReadBuffer,
USHORT Buflen,
PUSHORT ActualBytesRead
)
/*++
Routine Description:
Performs a synchronous read on the serial port. Used during setup so that
the type of device can be determined.
Return value:
NTSTATUS - STATUS_SUCCESS if the read was successful, error code otherwise
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT self;
PIO_STACK_LOCATION stack;
SERIAL_TIMEOUTS serialTimeouts;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -