?? io.c
字號:
/*
* $Id: io.c,v 1.29 2006/11/27 11:58:27 vfrolov Exp $
*
* Copyright (c) 2004-2006 Vyacheslav Frolov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* $Log: io.c,v $
* Revision 1.29 2006/11/27 11:58:27 vfrolov
* Fixed unexpected completing all queued read requests when
* completing the first one
*
* Revision 1.28 2006/06/21 16:23:57 vfrolov
* Fixed possible BSOD after one port of pair removal
*
* Revision 1.27 2006/05/17 15:31:14 vfrolov
* Implemented SERIAL_TRANSMIT_TOGGLE
*
* Revision 1.26 2006/02/26 08:39:19 vfrolov
* Added check for start/stop queue matching
* Fixed delayed BREAK losts
*
* Revision 1.25 2006/02/21 13:42:11 vfrolov
* Implemented SERIAL_BREAK_CHAR
*
* Revision 1.24 2006/02/17 07:55:13 vfrolov
* Implemented IOCTL_SERIAL_SET_BREAK_ON and IOCTL_SERIAL_SET_BREAK_OFF
*
* Revision 1.23 2006/01/10 10:17:23 vfrolov
* Implemented flow control and handshaking
* Implemented IOCTL_SERIAL_SET_XON and IOCTL_SERIAL_SET_XOFF
* Added setting of HoldReasons, WaitForImmediate and AmountInOutQueue
* fields of SERIAL_STATUS for IOCTL_SERIAL_GET_COMMSTATUS
*
* Revision 1.22 2005/12/06 13:04:32 vfrolov
* Fixed data types
*
* Revision 1.21 2005/12/05 10:54:55 vfrolov
* Implemented IOCTL_SERIAL_IMMEDIATE_CHAR
*
* Revision 1.20 2005/11/30 16:04:11 vfrolov
* Implemented IOCTL_SERIAL_GET_STATS and IOCTL_SERIAL_CLEAR_STATS
*
* Revision 1.19 2005/11/29 12:33:21 vfrolov
* Changed SetModemStatus() to ability set and clear bits simultaneously
*
* Revision 1.18 2005/11/29 08:35:13 vfrolov
* Implemented SERIAL_EV_RX80FULL
*
* Revision 1.17 2005/11/25 08:59:39 vfrolov
* Implemented SERIAL_EV_RXFLAG
*
* Revision 1.16 2005/09/14 13:14:47 vfrolov
* Fixed possible tick loss
*
* Revision 1.15 2005/09/14 10:42:38 vfrolov
* Implemented SERIAL_EV_TXEMPTY
*
* Revision 1.14 2005/09/13 14:56:16 vfrolov
* Implemented IRP_MJ_FLUSH_BUFFERS
*
* Revision 1.13 2005/09/13 08:55:41 vfrolov
* Disabled modem status tracing by default
*
* Revision 1.12 2005/09/06 07:23:44 vfrolov
* Implemented overrun emulation
*
* Revision 1.11 2005/08/26 08:35:05 vfrolov
* Fixed unwanted interference to baudrate emulation by read operations
*
* Revision 1.10 2005/08/25 15:38:17 vfrolov
* Some code moved from io.c to bufutils.c
*
* Revision 1.9 2005/08/25 08:25:40 vfrolov
* Fixed data types
*
* Revision 1.8 2005/08/23 15:49:21 vfrolov
* Implemented baudrate emulation
*
* Revision 1.7 2005/07/14 12:24:31 vfrolov
* Replaced ASSERT by HALT_UNLESS
*
* Revision 1.6 2005/05/19 08:23:41 vfrolov
* Fixed data types
*
* Revision 1.5 2005/05/14 17:07:02 vfrolov
* Implemented SERIAL_LSRMST_MST insertion
*
* Revision 1.4 2005/05/13 16:58:03 vfrolov
* Implemented IOCTL_SERIAL_LSRMST_INSERT
*
* Revision 1.3 2005/05/13 06:32:16 vfrolov
* Implemented SERIAL_EV_RXCHAR
*
* Revision 1.2 2005/02/01 08:36:27 vfrolov
* Changed SetModemStatus() to set multiple bits and set CD to DSR
*
* Revision 1.1 2005/01/26 12:18:54 vfrolov
* Initial revision
*
*/
#include "precomp.h"
#include "timeout.h"
#include "delay.h"
#include "bufutils.h"
#include "handflow.h"
/*
* FILE_ID used by HALT_UNLESS to put it on BSOD
*/
#define FILE_ID 1
#define GET_REST_BUFFER(pIrp, done) \
(((PUCHAR)(pIrp)->AssociatedIrp.SystemBuffer) + done)
typedef struct _RW_DATA {
#define RW_DATA_TYPE_IRP 1
#define RW_DATA_TYPE_CHR 2
short type;
union {
struct {
PIRP pIrp;
NTSTATUS status;
} irp;
struct {
UCHAR chr;
#define RW_DATA_TYPE_CHR_NONE 0
#define RW_DATA_TYPE_CHR_XCHR 1
#define RW_DATA_TYPE_CHR_BREAK 2
short type;
BOOLEAN isChr;
} chr;
} data;
} RW_DATA, *PRW_DATA;
#define CAN_WRITE_RW_DATA_CHR(pIoPort, dataChar) \
( \
((dataChar).data.chr.type == RW_DATA_TYPE_CHR_XCHR && \
((pIoPort)->writeHolding & ~SERIAL_TX_WAITING_FOR_XON) == 0) || \
((dataChar).data.chr.type == RW_DATA_TYPE_CHR_BREAK) \
) \
ULONG GetWriteLength(IN PIRP pIrp)
{
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
switch(pIrpStack->MajorFunction) {
case IRP_MJ_WRITE:
return pIrpStack->Parameters.Write.Length;
case IRP_MJ_DEVICE_CONTROL:
if (pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR)
return sizeof(UCHAR);
break;
}
return 0;
}
NTSTATUS ReadBuffer(PIRP pIrp, PC0C_BUFFER pBuf, PSIZE_T pReadDone)
{
NTSTATUS status;
SIZE_T readLength, information;
SIZE_T readDone;
readLength = IoGetCurrentIrpStackLocation(pIrp)->Parameters.Read.Length;
information = pIrp->IoStatus.Information;
readDone = ReadFromBuffer(pBuf, GET_REST_BUFFER(pIrp, information), readLength - information);
if (readDone) {
*pReadDone += readDone;
information += readDone;
pIrp->IoStatus.Information = information;
}
if (information == readLength)
status = STATUS_SUCCESS;
else
status = STATUS_PENDING;
return status;
}
VOID OnRxBreak(
PC0C_IO_PORT pReadIoPort,
PLIST_ENTRY pQueueToComplete)
{
pReadIoPort->errors |= SERIAL_ERROR_BREAK;
pReadIoPort->eventMask |= pReadIoPort->waitMask & (SERIAL_EV_BREAK | SERIAL_EV_ERR);
if (pReadIoPort->eventMask)
WaitComplete(pReadIoPort, pQueueToComplete);
}
VOID OnRxChars(
PC0C_IO_PORT pReadIoPort,
SIZE_T size,
PC0C_FLOW_FILTER pFlowFilter,
PLIST_ENTRY pQueueToComplete)
{
SetXonXoffHolding(pReadIoPort, pFlowFilter->lastXonXoff);
if (pFlowFilter->events & (C0C_FLOW_FILTER_EV_RXCHAR | C0C_FLOW_FILTER_EV_RXFLAG)) {
if (pFlowFilter->events & C0C_FLOW_FILTER_EV_RXCHAR)
pReadIoPort->eventMask |= SERIAL_EV_RXCHAR;
if (pFlowFilter->events & C0C_FLOW_FILTER_EV_RXFLAG)
pReadIoPort->eventMask |= SERIAL_EV_RXFLAG;
if (pReadIoPort->eventMask)
WaitComplete(pReadIoPort, pQueueToComplete);
}
pReadIoPort->perfStats.ReceivedCount += (ULONG)size;
}
VOID WriteBuffer(
PRW_DATA pDataWrite,
PC0C_IO_PORT pReadIoPort,
PLIST_ENTRY pQueueToComplete,
PSIZE_T pWriteLimit,
PSIZE_T pWriteDone)
{
SIZE_T writeLength, information;
SIZE_T writeDone;
C0C_FLOW_FILTER flowFilter;
PVOID pWriteBuf;
PC0C_BUFFER pBuf;
SIZE_T length;
BOOLEAN isBreak;
isBreak = FALSE;
if (pDataWrite->type == RW_DATA_TYPE_IRP) {
PIRP pIrp = pDataWrite->data.irp.pIrp;
information = pIrp->IoStatus.Information;
pWriteBuf = GET_REST_BUFFER(pIrp, information);
writeLength = GetWriteLength(pIrp);
} else {
HALT_UNLESS1(pDataWrite->type == RW_DATA_TYPE_CHR, pDataWrite->type);
information = 0;
pWriteBuf = &pDataWrite->data.chr.chr;
writeLength = pDataWrite->data.chr.isChr ? 1 : 0;
if (pDataWrite->data.chr.type == RW_DATA_TYPE_CHR_BREAK)
isBreak = TRUE;
}
pBuf = &pReadIoPort->readBuf;
length = writeLength - information;
if (pWriteLimit && length > *pWriteLimit)
length = *pWriteLimit;
FlowFilterInit(pReadIoPort, &flowFilter);
writeDone = WriteToBuffer(pBuf, pWriteBuf, length, &flowFilter);
if (writeDone) {
*pWriteDone += writeDone;
information += writeDone;
if (pDataWrite->type == RW_DATA_TYPE_IRP) {
pDataWrite->data.irp.pIrp->IoStatus.Information = information;
pReadIoPort->pIoPortRemote->amountInWriteQueue -= (ULONG)writeDone;
}
if (pWriteLimit)
*pWriteLimit -= writeDone;
OnRxChars(pReadIoPort, writeDone, &flowFilter, pQueueToComplete);
if (isBreak)
OnRxBreak(pReadIoPort, pQueueToComplete);
else
pReadIoPort->pIoPortRemote->perfStats.TransmittedCount += (ULONG)writeDone;
}
if (information == writeLength) {
if (pDataWrite->type == RW_DATA_TYPE_IRP) {
pDataWrite->data.irp.status = STATUS_SUCCESS;
} else {
HALT_UNLESS1(pDataWrite->type == RW_DATA_TYPE_CHR, pDataWrite->type);
pDataWrite->data.chr.isChr = FALSE;
}
}
}
VOID AlertOverrun(PC0C_IO_PORT pReadIoPort, PLIST_ENTRY pQueueToComplete)
{
pReadIoPort->errors |= SERIAL_ERROR_QUEUEOVERRUN;
if (pReadIoPort->handFlow.FlowReplace & SERIAL_ERROR_CHAR)
WriteMandatoryToBuffer(&pReadIoPort->readBuf, pReadIoPort->specialChars.ErrorChar);
if (pReadIoPort->handFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
CancelQueue(&pReadIoPort->irpQueues[C0C_QUEUE_READ], pQueueToComplete);
CancelQueue(&pReadIoPort->irpQueues[C0C_QUEUE_WRITE], pQueueToComplete);
}
}
VOID WriteOverrun(
PRW_DATA pDataWrite,
PC0C_IO_PORT pReadIoPort,
PLIST_ENTRY pQueueToComplete,
PSIZE_T pWriteLimit,
PSIZE_T pWriteDone)
{
SIZE_T writeLength, information;
SIZE_T writeDone, readDone;
C0C_FLOW_FILTER flowFilter;
PVOID pWriteBuf;
SIZE_T length;
BOOLEAN isBreak;
isBreak = FALSE;
if (pDataWrite->type == RW_DATA_TYPE_IRP) {
PIRP pIrp = pDataWrite->data.irp.pIrp;
information = pIrp->IoStatus.Information;
pWriteBuf = GET_REST_BUFFER(pIrp, information);
writeLength = GetWriteLength(pIrp);
} else {
HALT_UNLESS1(pDataWrite->type == RW_DATA_TYPE_CHR, pDataWrite->type);
information = 0;
pWriteBuf = &pDataWrite->data.chr.chr;
writeLength = pDataWrite->data.chr.isChr ? 1 : 0;
if (pDataWrite->data.chr.type == RW_DATA_TYPE_CHR_BREAK)
isBreak = TRUE;
}
length = writeLength - information;
if (pWriteLimit && length > *pWriteLimit)
length = *pWriteLimit;
FlowFilterInit(pReadIoPort, &flowFilter);
CopyCharsWithEscape(
&pReadIoPort->readBuf, &flowFilter,
NULL, 0,
pWriteBuf, length,
&readDone, &writeDone);
if (writeDone) {
*pWriteDone += writeDone;
information += writeDone;
if (pDataWrite->type == RW_DATA_TYPE_IRP) {
pDataWrite->data.irp.pIrp->IoStatus.Information = information;
pReadIoPort->pIoPortRemote->amountInWriteQueue -= (ULONG)writeDone;
}
if (pWriteLimit)
*pWriteLimit -= writeDone;
if (readDone) {
AlertOverrun(pReadIoPort, pQueueToComplete);
pReadIoPort->perfStats.BufferOverrunErrorCount += (ULONG)readDone;
}
OnRxChars(pReadIoPort, writeDone, &flowFilter, pQueueToComplete);
if (isBreak)
OnRxBreak(pReadIoPort, pQueueToComplete);
else
pReadIoPort->pIoPortRemote->perfStats.TransmittedCount += (ULONG)writeDone;
}
if (information == writeLength) {
if (pDataWrite->type == RW_DATA_TYPE_IRP) {
pDataWrite->data.irp.status = STATUS_SUCCESS;
} else {
HALT_UNLESS1(pDataWrite->type == RW_DATA_TYPE_CHR, pDataWrite->type);
pDataWrite->data.chr.isChr = FALSE;
}
}
}
VOID ReadWriteDirect(
PIRP pIrpRead,
PRW_DATA pDataWrite,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -