ioctl.cpp
来自「这个是串口驱动程序开发包」· C++ 代码 · 共 1,202 行 · 第 1/3 页
CPP
1,202 行
(LData | LParity | LStop));
m_ValidDataMask = Mask;
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK)SetLineControl);
m_ControlLock.Release();
break;
}
case IOCTL_SERIAL_GET_LINE_CONTROL:
{
PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp.SystemBuffer();
if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_LINE_CONTROL))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
m_ControlLock.Lock();
switch (m_LineControl & SERIAL_DATA_MASK)
{
case SERIAL_5_DATA:
Lc->WordLength = 5;
break;
case SERIAL_6_DATA:
Lc->WordLength = 6;
break;
case SERIAL_7_DATA:
Lc->WordLength = 7;
break;
case SERIAL_8_DATA:
Lc->WordLength = 8;
break;
}
switch (m_LineControl & SERIAL_PARITY_MASK)
{
case SERIAL_NONE_PARITY:
Lc->Parity = NO_PARITY;
break;
case SERIAL_ODD_PARITY:
Lc->Parity = ODD_PARITY;
break;
case SERIAL_EVEN_PARITY:
Lc->Parity = EVEN_PARITY;
break;
case SERIAL_SPACE_PARITY:
Lc->Parity = SPACE_PARITY;
break;
}
if (m_LineControl & SERIAL_2_STOP)
{
if (Lc->WordLength == 5)
Lc->StopBits = STOP_BITS_1_5;
else
Lc->StopBits = STOP_BITS_2;
}
else
Lc->StopBits = STOP_BIT_1;
Irp.Information() = sizeof(SERIAL_LINE_CONTROL);
m_ControlLock.Release();
break;
}
case IOCTL_SERIAL_SET_TIMEOUTS:
{
PSERIAL_TIMEOUTS NewTimeouts =
((PSERIAL_TIMEOUTS) Irp.SystemBuffer());
if (Irp.IoctlInputBufferLength() < sizeof(SERIAL_TIMEOUTS))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) &&
(NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
(NewTimeouts->ReadTotalTimeoutConstant == MAXULONG))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
m_ControlLock.Lock();
m_Timeouts.ReadIntervalTimeout =
NewTimeouts->ReadIntervalTimeout;
m_Timeouts.ReadTotalTimeoutMultiplier =
NewTimeouts->ReadTotalTimeoutMultiplier;
m_Timeouts.ReadTotalTimeoutConstant =
NewTimeouts->ReadTotalTimeoutConstant;
m_Timeouts.WriteTotalTimeoutMultiplier =
NewTimeouts->WriteTotalTimeoutMultiplier;
m_Timeouts.WriteTotalTimeoutConstant =
NewTimeouts->WriteTotalTimeoutConstant;
m_ControlLock.Release();
break;
}
case IOCTL_SERIAL_GET_TIMEOUTS:
if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_TIMEOUTS))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
m_ControlLock.Lock();
*((PSERIAL_TIMEOUTS)Irp.SystemBuffer()) = m_Timeouts;
Irp.Information() = sizeof(SERIAL_TIMEOUTS);
m_ControlLock.Release();
break;
case IOCTL_SERIAL_SET_CHARS:
{
PSERIAL_CHARS NewChars = (PSERIAL_CHARS)Irp.SystemBuffer();
if (Irp.IoctlInputBufferLength() < sizeof(SERIAL_CHARS))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
// The only thing that can be wrong with the chars
// is that the xon and xoff characters are the same.
#if 0
if (NewChars->XonChar == NewChars->XoffChar)
{
Status = STATUS_INVALID_PARAMETER;
break;
}
#endif
// We acquire the control lock so that only
// one request can GET or SET the characters
// at a time. The sets could be synchronized
// by the interrupt spinlock, but that wouldn't
// prevent multiple gets at the same time.
m_ControlLock.Lock();
// Under the protection of the lock, make sure that
// the xon and xoff characters aren't the same as
// the escape character.
if (m_EscapeChar)
{
if ((m_EscapeChar == NewChars->XonChar) ||
(m_EscapeChar == NewChars->XoffChar))
{
Status = STATUS_INVALID_PARAMETER;
m_ControlLock.Release();
break;
}
}
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) SetChars, (PVOID) NewChars);
m_ControlLock.Release();
break;
}
case IOCTL_SERIAL_GET_CHARS:
if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_CHARS))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
m_ControlLock.Lock();
*((PSERIAL_CHARS)Irp.SystemBuffer()) = m_SpecialChars;
Irp.Information() = sizeof(SERIAL_CHARS);
m_ControlLock.Release();
break;
case IOCTL_SERIAL_SET_DTR:
case IOCTL_SERIAL_CLR_DTR:
// We acquire the lock so that we can check whether
// automatic dtr flow control is enabled. If it is
// then we return an error since the app is not allowed
// to touch this if it is automatic.
m_ControlLock.Lock();
if ((m_HandFlow.ControlHandShake & SERIAL_DTR_MASK)
== SERIAL_DTR_HANDSHAKE)
{
Irp.Status() = STATUS_INVALID_PARAMETER;
}
else
{
m_KdInterrupt.SynchronizeExecution( (KDIRQ_SYNC_CALLBACK)
(Irp.IoctlCode() == IOCTL_SERIAL_SET_DTR ? SetDTR : ClrDTR ));
}
m_ControlLock.Release();
break;
case IOCTL_SERIAL_RESET_DEVICE:
break;
case IOCTL_SERIAL_SET_RTS:
case IOCTL_SERIAL_CLR_RTS:
// We acquire the lock so that we can check whether
// automatic rts flow control or transmit toggleing
// is enabled. If it is then we return an error since
// the app is not allowed to touch this if it is automatic
// or toggling.
m_ControlLock.Lock();
if (((m_HandFlow.FlowReplace & SERIAL_RTS_MASK)
== SERIAL_RTS_HANDSHAKE) ||
((m_HandFlow.FlowReplace & SERIAL_RTS_MASK)
== SERIAL_TRANSMIT_TOGGLE))
{
Irp.Status() = STATUS_INVALID_PARAMETER;
}
else
{
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK)
(Irp.IoctlCode() == IOCTL_SERIAL_SET_RTS ? SetRTS : ClrRTS ));
}
m_ControlLock.Release();
break;
case IOCTL_SERIAL_SET_XOFF:
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) PretendXoff);
break;
case IOCTL_SERIAL_SET_XON:
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) PretendXon);
break;
case IOCTL_SERIAL_SET_BREAK_ON:
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) TurnOnBreak);
break;
case IOCTL_SERIAL_SET_BREAK_OFF:
m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) TurnOffBreak);
break;
case IOCTL_SERIAL_SET_QUEUE_SIZE:
{
// Type ahead buffer is fixed, so we just validate
// the the users request is not bigger that our
// own internal buffer size.
PSERIAL_QUEUE_SIZE Rs = (PSERIAL_QUEUE_SIZE) Irp.SystemBuffer();
if (Irp.IoctlInputBufferLength() < sizeof(SERIAL_QUEUE_SIZE))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
// We have to allocate the memory for the new
// buffer while we're still in the context of the
// caller. We don't even try to protect this
// with a lock because the value could be stale
// as soon as we release the lock - The only time
// we will know for sure is when we actually try
// to do the resize.
if (Rs->InSize <= m_BufferSize)
{
Status = STATUS_SUCCESS;
break;
}
__try
{
Irp.IoctlType3InputBuffer() = ExAllocatePoolWithQuota(
NonPagedPool,
Rs->InSize
);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Irp.IoctlType3InputBuffer() = NULL;
Status = GetExceptionCode();
}
if (!Irp.IoctlType3InputBuffer())
break;
// Well the data passed was big enough. Do the request.
//
// There are two reason we place it in the read queue:
//
// 1) We want to serialize these resize requests so that
// they don't contend with each other.
//
// 2) We want to serialize these requests with reads since
// we don't want reads and resizes contending over the
// read buffer.
return StartOrQueue(
Irp,
&m_ReadQueue,
&m_CurrentReadIrp,
StartRead
);
break;
}
case IOCTL_SERIAL_GET_WAIT_MASK:
if (Irp.IoctlOutputBufferLength() < sizeof(ULONG))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
// Simple scalar read. No reason to acquire a lock.
Irp.Information() = sizeof(ULONG);
*((PULONG) Irp.SystemBuffer()) = m_IsrWaitMask;
break;
case IOCTL_SERIAL_SET_WAIT_MASK:
ULONG NewMask;
DebugDump(DBG_DIAG3 | DBG_DIAG6, ("In Ioctl processing for set mask\n") );
if (Irp.IoctlInputBufferLength() < sizeof(ULONG))
{
DebugDump(DBG_DIAG3, ("Invalid size fo the buffer %d\n", Irp.IoctlInputBufferLength()) );
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
else
NewMask = *((PULONG) Irp.SystemBuffer());
// Make sure that the mask only contains valid
// waitable events.
if (NewMask & ~(SERIAL_EV_RXCHAR |
SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING |
SERIAL_EV_PERR |
SERIAL_EV_RX80FULL |
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2)) {
DebugDump(DBG_DIAG3, ("Unknown mask %x\n",NewMask) );
Status = STATUS_INVALID_PARAMETER;
break;
}
// Either start this irp or put it on the
// queue.
DebugDump(DBG_DIAG3 | DBG_DIAG6, ("Starting or queuing set mask irp %x\n",Irp) );
return StartOrQueue(
Irp,
&m_MaskQueue,
&m_CurrentMaskIrp,
StartMask
);
case IOCTL_SERIAL_WAIT_ON_MASK:
DebugDump(DBG_DIAG3 | DBG_DIAG6, ("In Ioctl processing for wait mask\n") );
if (Irp.IoctlOutputBufferLength() < sizeof(ULONG))
{
DebugDump(DBG_DIAG3, ("Invalid size fo the buffer %d\n", Irp.IoctlInputBufferLength()) );
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
// Either start this irp or put it on the
// queue.
DebugDump(DBG_DIAG3 | DBG_DIAG6, ("Starting or queuing wait mask irp %x\n",Irp) );
return StartOrQueue(
Irp,
&m_MaskQueue,
&m_CurrentMaskIrp,
StartMask
);
case IOCTL_SERIAL_IMMEDIATE_CHAR:
KIRQL OldIrql;
if (Irp.IoctlInputBufferLength() < sizeof(UCHAR))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
IoAcquireCancelSpinLock(&OldIrql);
if (m_CurrentImmediateIrp)
{
Status = STATUS_INVALID_PARAMETER;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?