📄 io.c
字号:
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;
int i, numReads;
KeInitializeEvent(&event, NotificationEvent, FALSE);
if (!NT_SUCCESS(status)) {
return status;
}
self = DeviceExtension->Self;
irp = DeviceExtension->ReadIrp;
Print(DeviceExtension, DBG_SS_TRACE, ("Read pending...\n"));
*ActualBytesRead = 0;
while (*ActualBytesRead < Buflen) {
KeClearEvent(&event);
IoReuseIrp(irp, STATUS_SUCCESS);
irp->AssociatedIrp.SystemBuffer = ReadBuffer;
stack = IoGetNextIrpStackLocation(irp);
stack->Parameters.Read.Length = 1;
stack->Parameters.Read.ByteOffset.QuadPart = 0;
stack->MajorFunction = IRP_MJ_READ;
//
// Hook a completion routine for when the device completes.
//
IoSetCompletionRoutine(irp,
SerialMouseReadSerialPortComplete,
&event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(DeviceExtension->TopOfStack, irp);
if (status == STATUS_PENDING) {
//
// Wait for the IRP
//
status = KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
if (status == STATUS_SUCCESS) {
status = irp->IoStatus.Status;
}
}
if (!NT_SUCCESS(status) || status == STATUS_TIMEOUT) {
Print(DeviceExtension, DBG_SS_NOISE,
("IO Call failed with status %x\n", status));
return status;
}
ASSERT(irp->IoStatus.Information >= 0);
ASSERT(irp->IoStatus.Information <= 1);
*ActualBytesRead += (USHORT) irp->IoStatus.Information;
ReadBuffer += (USHORT) irp->IoStatus.Information;
}
return status;
}
NTSTATUS
SerialMouseWriteSerialPort (
PDEVICE_EXTENSION DeviceExtension,
PCHAR WriteBuffer,
ULONG NumBytes,
PIO_STATUS_BLOCK IoStatusBlock
)
/*++
Routine Description:
Performs a synchronous write on the serial port. Used during setup so that
the device can be configured.
Return value:
NTSTATUS - STATUS_SUCCESS if the read was successful, error code otherwise
--*/
{
NTSTATUS status;
PIRP irp;
LARGE_INTEGER startingOffset = RtlConvertLongToLargeInteger(0);
KEVENT event;
int i, numReads;
KeInitializeEvent(&event,
NotificationEvent,
FALSE);
Print(DeviceExtension, DBG_SS_TRACE, ("Write pending...\n"));
//
// Create a new IRP because there's a chance that it might get cancelled.
// Can't cancel irps that I received.
// IRP_MJ_READ with completion routine
//
if (NULL == (irp = IoBuildSynchronousFsdRequest(
IRP_MJ_WRITE,
DeviceExtension->TopOfStack,
WriteBuffer,
NumBytes,
&startingOffset,
&event,
IoStatusBlock
))) {
Print(DeviceExtension, DBG_SS_ERROR, ("Failed to allocate IRP\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(DeviceExtension->TopOfStack, irp);
if (status == STATUS_PENDING) {
// I don't know at this time if I can wait with the default time of
// 200 ms as I'm doing. In the help file for IoBuildSynchronousFsdRequest
// I think that it says I can't, but I'm not quite sure.
// Presently I will. I'll cancel the Irp if it isn't done.
status = KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE, // Not alertable
NULL);
}
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status)) {
Print(DeviceExtension, DBG_SS_ERROR,
("IO Call failed with status %x\n",
status
));
return status;
}
if (!NT_SUCCESS(status)) {
Print(DeviceExtension, DBG_SS_ERROR,
("IO Call failed with status %x\n",
status
));
}
return status;
}
NTSTATUS
SerialMouseWait (
IN PDEVICE_EXTENSION DeviceExtension,
IN LONG Timeout
)
/*++
Routine Description:
Performs a wait for the specified time.
NB: Negative time is relative to the current time. Positive time
represents an absolute time to wait until.
Return value:
NTSTATUS
--*/
{
LARGE_INTEGER time = RtlConvertLongToLargeInteger(Timeout);
Print(DeviceExtension, DBG_READ_NOISE,
("waiting for %d micro secs\n", Timeout));
if (KeSetTimer(&DeviceExtension->DelayTimer,
time,
NULL)) {
Print(DeviceExtension, DBG_SS_INFO, ("Timer already set\n"));
}
return KeWaitForSingleObject(&DeviceExtension->DelayTimer,
Executive,
KernelMode,
FALSE, // Not allertable
NULL); // No timeout structure
}
NTSTATUS
SerialMouseInitializePort(
PDEVICE_EXTENSION DeviceExtension
)
{
NTSTATUS status;
KEVENT event;
IO_STATUS_BLOCK iosb;
SERIAL_TIMEOUTS serialTimeouts;
SERIAL_HANDFLOW serialHandFlow;
KeInitializeEvent(&event, NotificationEvent, FALSE);
status =
SerialMouseIoSyncInternalIoctlEx(IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS,
DeviceExtension->TopOfStack,
&event,
&iosb,
NULL,
0,
&DeviceExtension->SerialBasicSettings,
sizeof(SERIAL_BASIC_SETTINGS));
//
// In case we are running on a port that does not support basic settings
//
if (!NT_SUCCESS(status)) {
SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_TIMEOUTS,
DeviceExtension->TopOfStack,
&event,
&iosb,
NULL,
0,
&DeviceExtension->SerialBasicSettings.Timeouts,
sizeof(SERIAL_TIMEOUTS));
RtlZeroMemory(&serialTimeouts, sizeof(SERIAL_TIMEOUTS));
SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
DeviceExtension->TopOfStack,
&event,
&iosb,
&serialTimeouts,
sizeof(SERIAL_TIMEOUTS),
NULL,
0);
SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_HANDFLOW,
DeviceExtension->TopOfStack,
&event,
&iosb,
NULL,
0,
&DeviceExtension->SerialBasicSettings.HandFlow,
sizeof(SERIAL_HANDFLOW));
serialHandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
serialHandFlow.FlowReplace = SERIAL_RTS_CONTROL;
serialHandFlow.XonLimit = 0;
serialHandFlow.XoffLimit = 0;
status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_HANDFLOW,
DeviceExtension->TopOfStack,
&event,
&iosb,
&serialHandFlow,
sizeof(SERIAL_HANDFLOW),
NULL,
0);
}
return status;
}
VOID
SerialMouseRestorePort(
PDEVICE_EXTENSION DeviceExtension
)
{
KEVENT event;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
status =
SerialMouseIoSyncInternalIoctlEx(IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS,
DeviceExtension->TopOfStack,
&event,
&iosb,
&DeviceExtension->SerialBasicSettings,
sizeof(SERIAL_BASIC_SETTINGS),
NULL,
0);
//
// 4-24 Once serial.sys supports this new IOCTL, this code can be removed
//
if (!NT_SUCCESS(status)) {
SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
DeviceExtension->TopOfStack,
&event,
&iosb,
&DeviceExtension->SerialBasicSettings.Timeouts,
sizeof(SERIAL_TIMEOUTS),
NULL,
0);
SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_HANDFLOW,
DeviceExtension->TopOfStack,
&event,
&iosb,
&DeviceExtension->SerialBasicSettings.HandFlow,
sizeof(SERIAL_HANDFLOW),
NULL,
0);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -