📄 vcom_device.c
字号:
//============================================================================
//
// N8VB_vcom - Virtual COM Port
// Copyright (c) 2005 Philip A Covington, N8VB
//
// Email: p.covington@gmail.com
//
// 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
//
//============================================================================
#include "vCOM.h"
const SERIAL_COMMPROP vCOMProperties = {sizeof(SERIAL_COMMPROP), // PacketLength
2, // PacketVersion
SERIAL_SP_SERIALCOMM, // ServiceMask
0, // Reserved1
BUFFERLENGTH, // MaxTxQueue
BUFFERLENGTH, // MaxRxQueue
SERIAL_BAUD_USER, // MaxBaud
SERIAL_SP_RS232, // ProvSubType
SERIAL_PCF_DTRDSR |
SERIAL_PCF_RTSCTS |
SERIAL_PCF_CD |
SERIAL_PCF_PARITY_CHECK |
SERIAL_PCF_TOTALTIMEOUTS |
SERIAL_PCF_INTTIMEOUTS, // ProvCapabilities
SERIAL_SP_PARITY |
SERIAL_SP_BAUD |
SERIAL_SP_DATABITS |
SERIAL_SP_STOPBITS |
SERIAL_SP_HANDSHAKING |
SERIAL_SP_PARITY_CHECK |
SERIAL_SP_CARRIER_DETECT, // SettableParams
SERIAL_BAUD_075 |
SERIAL_BAUD_110 |
SERIAL_BAUD_150 |
SERIAL_BAUD_300 |
SERIAL_BAUD_600 |
SERIAL_BAUD_1200 |
SERIAL_BAUD_1800 |
SERIAL_BAUD_2400 |
SERIAL_BAUD_4800 |
SERIAL_BAUD_7200 |
SERIAL_BAUD_9600 |
SERIAL_BAUD_14400 |
SERIAL_BAUD_19200 |
SERIAL_BAUD_38400 |
SERIAL_BAUD_56K |
SERIAL_BAUD_128K |
SERIAL_BAUD_115200 |
SERIAL_BAUD_57600 |
SERIAL_BAUD_USER, // SettableBaud
SERIAL_DATABITS_5 |
SERIAL_DATABITS_6 |
SERIAL_DATABITS_7 |
SERIAL_DATABITS_8, // SettableData
SERIAL_STOPBITS_10 |
SERIAL_STOPBITS_15 |
SERIAL_STOPBITS_20 |
SERIAL_PARITY_NONE |
SERIAL_PARITY_ODD |
SERIAL_PARITY_EVEN |
SERIAL_PARITY_MARK |
SERIAL_PARITY_SPACE, // SettableStopParity
BUFFERLENGTH, // CurrentTxQueue
BUFFERLENGTH, // CurrentRxQueue
0, // ProvSpec1
0, // ProvSpec2
0, // ProvChar
};
NTSTATUS vCOMAddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pPDO)
{
NTSTATUS status;
PDEVICE_OBJECT pFDO;
PDEVICE_OBJECT pTwinFDO;
PvCOM_DEVICE_EXTENSION pDeviceExtension;
PvCOM_DEVICE_EXTENSION pTwinDeviceExtension;
HANDLE hRegistry;
ULONG pCount = 0;
ULONG i;
status = IoOpenDeviceRegistryKey(pPDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &hRegistry);
if (!NT_SUCCESS(status))
{
KdPrint(("error in AddDevice IoOpenDeviceRegistryKey...\n"));
return status;
}
status = vCOMGetRegistryKeyValue(hRegistry, L"NumberOfPairs", &pCount, sizeof(ULONG));
if (!NT_SUCCESS(status))
{
ZwClose(hRegistry);
KdPrint(("AddDevice vCOMGetRegistryKeyValue failed...\n"));
return status;
}
devpaircount = (ULONG)pCount;
ZwClose(hRegistry);
if (devpaircount > MAX_PAIR_COUNT)
devpaircount = MAX_PAIR_COUNT;
KdPrint(("AddDevice will create %d pairs or %d devices...\n", devpaircount, devpaircount*2));
for (i=0; i < devpaircount*2; i+=2)
{
status = vCOMCreateFDO(DriverObject, pPDO, &pFDO, i);
if (!NT_SUCCESS(status))
{
return status;
}
KdPrint(("Device %d created...\n", i));
pFDO->Flags &= ~DO_DEVICE_INITIALIZING;
status = vCOMCreateFDO(DriverObject, pPDO, &pTwinFDO, i+1);
if (!NT_SUCCESS(status))
{
return status;
}
KdPrint(("Device %d created...\n", i+1));
pTwinFDO->Flags &= ~DO_DEVICE_INITIALIZING;
pDeviceExtension = (PvCOM_DEVICE_EXTENSION)pFDO->DeviceExtension;
pTwinDeviceExtension = (PvCOM_DEVICE_EXTENSION)pTwinFDO->DeviceExtension;
pDeviceExtension->pMe = pFDO;
pDeviceExtension->pTwin = pTwinFDO;
pTwinDeviceExtension->pMe = pTwinFDO;
pTwinDeviceExtension->pTwin = pFDO;
pTwinDeviceExtension->pNextDriver = pDeviceExtension->pNextDriver;
pDeviceExtension->inBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);
if (pDeviceExtension->inBuffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
pDeviceExtension->outBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);
if (pDeviceExtension->outBuffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
pDeviceExtension->inBufferSize = BUFFERLENGTH;
pDeviceExtension->outBufferSize = BUFFERLENGTH;
pDeviceExtension->inBufferReadPosition = 0;
pDeviceExtension->inBufferWritePosition = 0;
pDeviceExtension->outBufferReadPosition = 0;
pDeviceExtension->outBufferWritePosition = 0;
pDeviceExtension->inBufferCount = 0;
pDeviceExtension->outBufferCount = 0;
pDeviceExtension->pReadIrpCurrent = NULL;
pDeviceExtension->pWriteIrpCurrent = NULL;
pDeviceExtension->fastRead = FALSE;
//default delay loop timeout is 20 mS
pDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 20);
// 60 secs
pDeviceExtension->readWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 60000);
// 5 secs
pDeviceExtension->transferWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 5000);
pTwinDeviceExtension->inBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);
if (pTwinDeviceExtension->inBuffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
pTwinDeviceExtension->outBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);
if (pTwinDeviceExtension->outBuffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
pTwinDeviceExtension->inBufferSize = BUFFERLENGTH;
pTwinDeviceExtension->outBufferSize = BUFFERLENGTH;
pTwinDeviceExtension->inBufferReadPosition = 0;
pTwinDeviceExtension->inBufferWritePosition = 0;
pTwinDeviceExtension->outBufferReadPosition = 0;
pTwinDeviceExtension->outBufferWritePosition = 0;
pTwinDeviceExtension->inBufferCount = 0;
pTwinDeviceExtension->outBufferCount = 0;
pTwinDeviceExtension->pReadIrpCurrent = NULL;
pTwinDeviceExtension->pWriteIrpCurrent = NULL;
pTwinDeviceExtension->fastRead = FALSE;
//default delay loop timeout is 20 mS
pTwinDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 20);
// 60 secs
pTwinDeviceExtension->readWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 60000);
// 5 secs
pTwinDeviceExtension->transferWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 5000);
pDevices[i] = pFDO;
pDevices[i+1] = pTwinFDO;
if (pDeviceExtension->deviceNumber == 0) //only register once
{
status = IoRegisterDeviceInterface(pPDO, &vCOMGUID, NULL, &pDeviceExtension->interfaceName);
if (!NT_SUCCESS(status))
{
pDeviceExtension->interfaceName.Buffer = NULL;
KdPrint(("IoRegisterDeviceInterface failed...\n"));
goto StartThreads;
}
status = IoSetDeviceInterfaceState(&pDeviceExtension->interfaceName, TRUE);
if (!NT_SUCCESS(status))
{
pDeviceExtension->isSet = FALSE;
KdPrint(("IoSetDeviceInterfaceState failed...\n"));
goto StartThreads;
}
pDeviceExtension->isSet = TRUE;
}
StartThreads:
vCOMTransferThreadStart(pFDO);
vCOMTransferThreadStart(pTwinFDO);
vCOMReadThreadStart(pFDO);
vCOMReadThreadStart(pTwinFDO);
vCOMWriteThreadStart(pFDO);
vCOMWriteThreadStart(pTwinFDO);
}
return STATUS_SUCCESS;
}
NTSTATUS vCOMCreateFDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pPDO, PDEVICE_OBJECT* pvCOMFDO, ULONG devNumber)
{
NTSTATUS status;
PvCOM_DEVICE_EXTENSION pDeviceExtension;
UNICODE_STRING ntDeviceName;
PUNICODE_STRING pSymbolicName;
HANDLE hRegistry;
WCHAR* pRegistryName;
RtlInitUnicodeString(&ntDeviceName, vCOMDevNames[devNumber]);
status = IoCreateDevice(DriverObject, sizeof(vCOM_DEVICE_EXTENSION), &ntDeviceName,
FILE_DEVICE_SERIAL_PORT, 0, TRUE, pvCOMFDO);
if (!NT_SUCCESS(status))
{
KdPrint(("error creating device...\n"));
return status;
}
KdPrint(("IOCreateDevice succeeded...\n"));
pDeviceExtension = (PvCOM_DEVICE_EXTENSION)(*pvCOMFDO)->DeviceExtension;
status = IoOpenDeviceRegistryKey(pPDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &hRegistry);
if (!NT_SUCCESS(status))
{
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
KdPrint(("error in IoOpenDeviceRegistryKey...\n"));
return status;
}
KdPrint(("IoOpenDeviceRegistryKey succeeded...\n"));
pRegistryName = ExAllocatePool(PagedPool, 129 * sizeof(WCHAR));
if (pRegistryName == NULL)
{
ZwClose(hRegistry);
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
KdPrint(("error in ExAllocatePool for registry name...\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
pSymbolicName = &pDeviceExtension->symbolicLinkName;
pSymbolicName->MaximumLength = 128 * sizeof(WCHAR);
pSymbolicName->Buffer = ExAllocatePool(PagedPool, 129 * sizeof(WCHAR));
if (pSymbolicName->Buffer == NULL)
{
ZwClose(hRegistry);
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
KdPrint(("error in ExAllocatePool for symbolic name...\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
KdPrint(("calling vCOMGetRegistryKeyValue...\n"));
status = vCOMGetRegistryKeyValue(hRegistry, vCOMPortNumbers[devNumber], pRegistryName, 128 * sizeof(WCHAR));
KdPrint(("Device %d will be created with name: %ws -- %ws\n", devNumber, pRegistryName, vCOMPortNumbers[devNumber]));
if (!NT_SUCCESS(status))
{
ZwClose(hRegistry);
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
KdPrint(("vCOMGetRegistryKeyValue failed...\n"));
return status;
}
KdPrint(("vCOMGetRegistryKeyValue succeeded...\n"));
RtlZeroMemory(pSymbolicName->Buffer, 129 * sizeof(WCHAR));
RtlAppendUnicodeToString(pSymbolicName, L"\\DosDevices\\");
RtlAppendUnicodeToString(pSymbolicName, pRegistryName);
status = IoCreateSymbolicLink(pSymbolicName, &ntDeviceName);
if (!NT_SUCCESS(status)) //try to delete the symbolic link first
{
IoDeleteSymbolicLink(pSymbolicName);
status = IoCreateSymbolicLink(pSymbolicName, &ntDeviceName);
}
if (!NT_SUCCESS(status)) //deleting failed
{
pDeviceExtension->symbolicLinkIsDone = FALSE;
ZwClose(hRegistry);
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
KdPrint(("IoCreateSymbolicLink failed...\n"));
return status;
}
KdPrint(("IoCreateSymbolicLink succeeded: %ws\n", pSymbolicName));
pDeviceExtension->symbolicLinkIsDone = TRUE;
status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, ntDeviceName.Buffer, REG_SZ,
pRegistryName, (wcslen(pRegistryName) + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(status))
{
pDeviceExtension->deviceMapEntryIsCreated = FALSE;
ZwClose(hRegistry);
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
KdPrint(("RtlWriteRegistryValue failed...\n"));
return status;
}
pDeviceExtension->deviceMapEntryIsCreated = TRUE;
ZwClose(hRegistry);
(*pvCOMFDO)->Flags |= DO_POWER_PAGABLE + DO_BUFFERED_IO;
pDeviceExtension->pMe = pPDO;
if (devNumber == 0) //don't attach device n+1 or it will be above device 1!!!
{
pDeviceExtension->pNextDriver = IoAttachDeviceToDeviceStack(*pvCOMFDO, pPDO);
if (pDeviceExtension->pNextDriver == NULL)
{
vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
return STATUS_NO_SUCH_DEVICE;
}
pDeviceExtension->isAttached = TRUE;
}
else
{
pDeviceExtension->isAttached = FALSE;
}
pDeviceExtension->deviceNumber = devNumber;
// initialize objects
ExInitializeFastMutex(&pDeviceExtension->openMutex);
KeInitializeSpinLock(&pDeviceExtension->readSpinLock);
KeInitializeSpinLock(&pDeviceExtension->writeSpinLock);
KeInitializeSpinLock(&pDeviceExtension->controlSpinLock);
KeInitializeSpinLock(&pDeviceExtension->readQueueSpinLock);
KeInitializeSpinLock(&pDeviceExtension->writeQueueSpinLock);
KeInitializeSemaphore(&pDeviceExtension->readIRPQueueSemaphore, 0, MAXLONG);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -