📄 ioctl.c
字号:
Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
S.Extension = Extension;
S.Data = Irp->AssociatedIrp.SystemBuffer;
//
// Acquire the cancel spin lock so nothing much
// changes while were getting the state.
//
IoAcquireCancelSpinLock(&OldIrql);
KeSynchronizeExecution(
Extension->Interrupt,
SerialGetCommStatus,
&S
);
IoReleaseCancelSpinLock(OldIrql);
break;
}
case IOCTL_SERIAL_GET_PROPERTIES: {
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_COMMPROP)) {
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// No synchronization is required since this information
// is "static".
//
SerialGetProperties(
Extension,
Irp->AssociatedIrp.SystemBuffer
);
Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
}
case IOCTL_SERIAL_XOFF_COUNTER: {
PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_XOFF_COUNTER)) {
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (Xc->Counter <= 0) {
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// There is no output, so make that clear now
//
Irp->IoStatus.Information = 0;
//
// So far so good. Put the irp onto the write queue.
//
return SerialStartOrQueue(
Extension,
Irp,
&Extension->WriteQueue,
&Extension->CurrentWriteIrp,
SerialStartWrite
);
}
case IOCTL_SERIAL_LSRMST_INSERT: {
PUCHAR escapeChar = Irp->AssociatedIrp.SystemBuffer;
SERIAL_IOCTL_SYNC S;
//
// Make sure we get a byte.
//
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(UCHAR)) {
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeAcquireSpinLock(
&Extension->ControlLock,
&OldIrql
);
if (*escapeChar) {
//
// We've got some escape work to do. We will make sure that
// the character is not the same as the Xon or Xoff character,
// or that we are already doing error replacement.
//
if ((*escapeChar == Extension->SpecialChars.XoffChar) ||
(*escapeChar == Extension->SpecialChars.XonChar) ||
(Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) {
Status = STATUS_INVALID_PARAMETER;
KeReleaseSpinLock(
&Extension->ControlLock,
OldIrql
);
break;
}
}
S.Extension = Extension;
S.Data = Irp->AssociatedIrp.SystemBuffer;
KeSynchronizeExecution(
Extension->Interrupt,
SerialSetEscapeChar,
Irp
);
KeReleaseSpinLock(
&Extension->ControlLock,
OldIrql
);
break;
}
case IOCTL_SERIAL_CONFIG_SIZE: {
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
Irp->IoStatus.Status = STATUS_SUCCESS;
*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0;
break;
}
case IOCTL_SERIAL_GET_STATS: {
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIALPERF_STATS)) {
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
Irp->IoStatus.Status = STATUS_SUCCESS;
KeSynchronizeExecution(
Extension->Interrupt,
SerialGetStats,
Irp
);
break;
}
case IOCTL_SERIAL_CLEAR_STATS: {
KeSynchronizeExecution(
Extension->Interrupt,
SerialClearStats,
Extension
);
break;
}
default: {
Status = STATUS_INVALID_PARAMETER;
break;
}
}
DoneWithIoctl:;
Irp->IoStatus.Status = Status;
SerialCompleteRequest(Extension, Irp, 0);
return Status;
}
VOID
SerialGetProperties(
IN PSERIAL_DEVICE_EXTENSION Extension,
IN PSERIAL_COMMPROP Properties
)
/*++
Routine Description:
This function returns the capabilities of this particular
serial device.
Arguments:
Extension - The serial device extension.
Properties - The structure used to return the properties
Return Value:
None.
--*/
{
SERIAL_LOCKED_PAGED_CODE();
RtlZeroMemory(
Properties,
sizeof(SERIAL_COMMPROP)
);
Properties->PacketLength = sizeof(SERIAL_COMMPROP);
Properties->PacketVersion = 2;
Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
Properties->MaxTxQueue = 0;
Properties->MaxRxQueue = 0;
Properties->MaxBaud = SERIAL_BAUD_USER;
Properties->SettableBaud = Extension->SupportedBauds;
Properties->ProvSubType = SERIAL_SP_RS232;
Properties->ProvCapabilities = SERIAL_PCF_DTRDSR |
SERIAL_PCF_RTSCTS |
SERIAL_PCF_CD |
SERIAL_PCF_PARITY_CHECK |
SERIAL_PCF_XONXOFF |
SERIAL_PCF_SETXCHAR |
SERIAL_PCF_TOTALTIMEOUTS |
SERIAL_PCF_INTTIMEOUTS;
Properties->SettableParams = SERIAL_SP_PARITY |
SERIAL_SP_BAUD |
SERIAL_SP_DATABITS |
SERIAL_SP_STOPBITS |
SERIAL_SP_HANDSHAKING |
SERIAL_SP_PARITY_CHECK |
SERIAL_SP_CARRIER_DETECT;
Properties->SettableData = SERIAL_DATABITS_5 |
SERIAL_DATABITS_6 |
SERIAL_DATABITS_7 |
SERIAL_DATABITS_8;
Properties->SettableStopParity = SERIAL_STOPBITS_10 |
SERIAL_STOPBITS_15 |
SERIAL_STOPBITS_20 |
SERIAL_PARITY_NONE |
SERIAL_PARITY_ODD |
SERIAL_PARITY_EVEN |
SERIAL_PARITY_MARK |
SERIAL_PARITY_SPACE;
Properties->CurrentTxQueue = 0;
Properties->CurrentRxQueue = Extension->BufferSize;
}
NTSTATUS
SerialInternalIoControl(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++
Routine Description:
This routine provides the initial processing for all of the
internal Ioctrls for the serial device.
Arguments:
PDevObj - Pointer to the device object for this device
PIrp - Pointer to the IRP for the current request
Return Value:
The function value is the final status of the call
--*/
{
//
// The status that gets returned to the caller and
// set in the Irp.
//
NTSTATUS status;
//
// The current stack location. This contains all of the
// information we need to process this particular request.
//
PIO_STACK_LOCATION pIrpStack;
//
// Just what it says. This is the serial specific device
// extension of the device object create for the serial driver.
//
PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
//
// A temporary to hold the old IRQL so that it can be
// restored once we complete/validate this request.
//
KIRQL OldIrql;
NTSTATUS prologueStatus;
SYSTEM_POWER_STATE cap;
SERIAL_LOCKED_PAGED_CODE();
if ((prologueStatus = SerialIRPPrologue(PIrp, pDevExt))
!= STATUS_SUCCESS) {
if (prologueStatus != STATUS_PENDING) {
SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
}
return prologueStatus;
}
SerialDbgPrintEx(SERIRPPATH, "Dispatch entry for: %x\n", PIrp);
if (SerialCompleteIfError(PDevObj, PIrp) != STATUS_SUCCESS) {
return STATUS_CANCELLED;
}
pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
PIrp->IoStatus.Information = 0L;
status = STATUS_SUCCESS;
switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode) {
//
// Send a wait-wake IRP
//
case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE:
//
// Make sure we can do wait-wake based on what the device reported
//
for (cap = PowerSystemSleeping1; cap < PowerSystemMaximum; cap++) {
if ((pDevExt->DeviceStateMap[cap] >= PowerDeviceD0)
&& (pDevExt->DeviceStateMap[cap] <= pDevExt->DeviceWake)) {
break;
}
}
if (cap < PowerSystemMaximum) {
pDevExt->SendWaitWake = TRUE;
status = STATUS_SUCCESS;
} else {
status = STATUS_NOT_SUPPORTED;
}
break;
case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE:
pDevExt->SendWaitWake = FALSE;
if (pDevExt->PendingWakeIrp != NULL) {
IoCancelIrp(pDevExt->PendingWakeIrp);
}
status = STATUS_SUCCESS;
break;
//
// Put the serial port in a "filter-driver" appropriate state
//
// WARNING: This code assumes it is being called by a trusted kernel
// entity and no checking is done on the validity of the settings
// passed to IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS
//
// If validity checking is desired, the regular ioctl's should be used
//
case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS:
case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS: {
SERIAL_BASIC_SETTINGS basic;
PSERIAL_BASIC_SETTINGS pBasic;
SHORT AppropriateDivisor;
SERIAL_IOCTL_SYNC S;
if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
== IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS) {
//
// Check the buffer size
//
if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_BASIC_SETTINGS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Everything is 0 -- timeouts and flow control and fifos. If
// We add additional features, this zero memory method
// may not work.
//
RtlZeroMemory(&basic, sizeof(SERIAL_BASIC_SETTINGS));
basic.TxFifo = 1;
basic.RxFifo = SERIAL_1_BYTE_HIGH_WATER;
PIrp->IoStatus.Information = sizeof(SERIAL_BASIC_SETTINGS);
pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer;
//
// Save off the old settings
//
RtlCopyMemory(&pBasic->Timeouts, &pDevExt->Timeouts,
sizeof(SERIAL_TIMEOUTS));
RtlCopyMemory(&pBasic->HandFlow, &pDevExt->HandFlow,
sizeof(SERIAL_HANDFLOW));
pBasic->RxFifo = pDevExt->RxFifoTrigger;
pBasic->TxFifo = pDevExt->TxFifoAmount;
//
// Point to our new settings
//
pBasic = &basic;
} else { // restoring settings
if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength
< sizeof(SERIAL_BASIC_SETTINGS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer;
}
KeAcquireSpinLock(&pDevExt->ControlLock, &OldIrql);
//
// Set the timeouts
//
RtlCopyMemory(&pDevExt->Timeouts, &pBasic->Timeouts,
sizeof(SERIAL_TIMEOUTS));
//
// Set flowcontrol
//
S.Extension = pDevExt;
S.Data = &pBasic->HandFlow;
KeSynchronizeExecution(pDevExt->Interrupt, SerialSetHandFlow, &S);
if (pDevExt->FifoPresent) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -