⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 这个是一个开源项目, 有能力的人可以一起来写
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * $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 + -